diff --git a/WebContent/jsp/onl/kjb/statistics/apiStatsHourMan.jsp b/WebContent/jsp/onl/kjb/statistics/apiStatsHourMan.jsp index 0169457..e9ea8c7 100644 --- a/WebContent/jsp/onl/kjb/statistics/apiStatsHourMan.jsp +++ b/WebContent/jsp/onl/kjb/statistics/apiStatsHourMan.jsp @@ -10,7 +10,7 @@ %> - API 시간별 통계 + 시간별 통계 조회 @@ -33,7 +41,7 @@ var url_view = ''; var url_minute_view = ''; - var callChart, respChart; + var totalDonutChart, seq900DonutChart, callChart, respChart; function numberFormatter(cellvalue, options, rowObject) { if (cellvalue == null || cellvalue == '') return '0'; @@ -46,9 +54,131 @@ } function initCharts() { + totalDonutChart = echarts.init(document.getElementById('totalDonutChart')); + seq900DonutChart = echarts.init(document.getElementById('seq900DonutChart')); callChart = echarts.init(document.getElementById('callChart')); respChart = echarts.init(document.getElementById('respChart')); + // 총건수 도넛 차트 + var totalDonutOption = { + title: { + text: '총 건수 분포', + left: 'center', + top: 10, + textStyle: { fontSize: 14 } + }, + tooltip: { + trigger: 'item', + formatter: '{b}: {c} ({d}%)' + }, + legend: { + orient: 'horizontal', + bottom: 10, + data: ['성공', 'Timeout', '시스템오류', '업무오류'] + }, + series: [{ + name: '총건수', + type: 'pie', + radius: ['40%', '70%'], + center: ['50%', '50%'], + avoidLabelOverlap: true, + label: { + show: true, + formatter: '{b}: {c}' + }, + emphasis: { + label: { + show: true, + fontSize: 16, + fontWeight: 'bold' + } + }, + labelLine: { + show: true + }, + data: [ + { value: 0, name: '성공', itemStyle: { color: '#91CC75' } }, + { value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } }, + { value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }, + { value: 0, name: '업무오류', itemStyle: { color: '#FC8452' } } + ] + }], + graphic: [{ + type: 'text', + left: 'center', + top: 'center', + style: { + text: '0', + textAlign: 'center', + fill: '#333', + fontSize: 24, + fontWeight: 'bold' + } + }] + }; + + totalDonutChart.setOption(totalDonutOption); + + // Seq900 도넛 차트 + var seq900DonutOption = { + title: { + text: 'Seq900 에러 분포', + left: 'center', + top: 10, + textStyle: { fontSize: 14 } + }, + tooltip: { + trigger: 'item', + formatter: '{b}: {c} ({d}%)' + }, + legend: { + orient: 'horizontal', + bottom: 10, + data: ['Timeout', '시스템오류', '업무오류'] + }, + series: [{ + name: 'Seq900 에러', + type: 'pie', + radius: ['40%', '70%'], + center: ['50%', '50%'], + avoidLabelOverlap: true, + label: { + show: true, + formatter: '{b}: {c}' + }, + emphasis: { + label: { + show: true, + fontSize: 16, + fontWeight: 'bold' + } + }, + labelLine: { + show: true + }, + data: [ + { value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } }, + { value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }, + { value: 0, name: '업무오류', itemStyle: { color: '#FC8452' } } + ] + }], + graphic: [{ + type: 'text', + left: 'center', + top: 'center', + style: { + text: '0', + textAlign: 'center', + fill: '#333', + fontSize: 24, + fontWeight: 'bold' + } + }] + }; + + seq900DonutChart.setOption(seq900DonutOption); + + // 호출량 차트 var callOption = { title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } }, tooltip: { @@ -60,13 +190,16 @@ xAxis: { type: 'category', boundaryGap: false, data: [] }, yAxis: { type: 'value', minInterval: 1 }, series: [ - { name: '성공', type: 'line', stack: 'Total', areaStyle: { opacity: 0.5 }, itemStyle: { color: '#5470C6' }, data: [] }, - { name: 'Timeout', type: 'line', stack: 'Total', areaStyle: { opacity: 0.5 }, itemStyle: { color: '#FAC858' }, data: [] }, - { name: '시스템오류', type: 'line', stack: 'Total', areaStyle: { opacity: 0.5 }, itemStyle: { color: '#EE6666' }, data: [] }, - { name: '업무오류', type: 'line', stack: 'Total', areaStyle: { opacity: 0.5 }, itemStyle: { color: '#FC8452' }, data: [] } + { name: '성공', type: 'line', stack: 'Total', smooth: true, areaStyle: { opacity: 0.5 }, itemStyle: { color: '#5470C6' }, data: [] }, + { name: 'Timeout', type: 'line', stack: 'Total', smooth: true, areaStyle: { opacity: 0.5 }, itemStyle: { color: '#FAC858' }, data: [] }, + { name: '시스템오류', type: 'line', stack: 'Total', smooth: true, areaStyle: { opacity: 0.5 }, itemStyle: { color: '#EE6666' }, data: [] }, + { name: '업무오류', type: 'line', stack: 'Total', smooth: true, areaStyle: { opacity: 0.5 }, itemStyle: { color: '#FC8452' }, data: [] } ] }; + callChart.setOption(callOption); + + // 응답시간 차트 var respOption = { title: { text: '응답시간 추이 (ms)', left: 'center', textStyle: { fontSize: 14 } }, tooltip: { @@ -78,13 +211,12 @@ xAxis: { type: 'category', boundaryGap: false, data: [] }, yAxis: { type: 'value' }, series: [ - { name: 'P95', type: 'line', itemStyle: { color: '#EE6666' }, lineStyle: { type: 'dashed' }, data: [] }, - { name: 'P50', type: 'line', itemStyle: { color: '#5470C6' }, data: [] }, - { name: '평균', type: 'line', itemStyle: { color: '#91CC75' }, data: [] } + { name: 'P95', type: 'line', smooth: true, itemStyle: { color: '#EE6666' }, lineStyle: { type: 'dashed' }, data: [] }, + { name: 'P50', type: 'line', smooth: true, itemStyle: { color: '#5470C6' }, data: [] }, + { name: '평균', type: 'line', smooth: true, itemStyle: { color: '#91CC75' }, data: [] } ] }; - callChart.setOption(callOption); respChart.setOption(respOption); // 드릴다운 이벤트 (시간 클릭 시 분단위 화면으로 이동) @@ -101,18 +233,34 @@ // rawData에서 실제 statTime 가져오기 (yyyyMMddHH00 형식) var statTime = chart.rawData[dataIndex].statTime; - var date = statTime.substring(0, 4) + '-' + statTime.substring(4, 6) + '-' + statTime.substring(6, 8); - var hour = statTime.substring(8, 10); - var startTime = hour + ':00'; - var endTime = hour + ':59'; + var year = statTime.substring(0, 4); + var month = statTime.substring(4, 6); + var day = statTime.substring(6, 8); + var hour = parseInt(statTime.substring(8, 10)); - var params = '?searchStartDate=' + date + '&searchStartTime=' + startTime - + '&searchEndDate=' + date + '&searchEndTime=' + endTime; + var startDate = year + '-' + month + '-' + day; + var startTime = (hour < 10 ? '0' + hour : hour) + ':00'; + + // 1시간 후 계산 (23시인 경우 다음날 00시로 자동 계산) + var d = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), hour, 0, 0); + d.setHours(d.getHours() + 1); + + var endDate = d.getFullYear() + '-' + + (d.getMonth() + 1 < 10 ? '0' : '') + (d.getMonth() + 1) + '-' + + (d.getDate() < 10 ? '0' : '') + d.getDate(); + var endTime = (d.getHours() < 10 ? '0' : '') + d.getHours() + ':00'; + + var params = '?searchStartDate=' + startDate + '&searchStartTime=' + startTime + + '&searchEndDate=' + endDate + '&searchEndTime=' + endTime; + params += '&menuId='+'${param.menuId}'; + params += '&cmd='+'LIST'; + params += '&serviceType='+'APIGW'; location.href = url_minute_view + params; } function updateCharts(data) { + // 시계열 차트용 변수 var times = []; var successData = []; var timeoutData = []; @@ -122,10 +270,19 @@ var p50RespData = []; var p95RespData = []; + // 도넛 차트용 총계 변수 + var totalSuccess = 0; + var totalTimeout = 0; + var totalSystemErr = 0; + var totalBizErr = 0; + var seq900Timeout = 0; + var seq900SystemErr = 0; + var seq900BizErr = 0; + data.forEach(function(item) { - // statTime: yyyyMMddHH00 -> HH시 형식으로 표시 - var hour = item.statTime.substring(8, 10); times.push(item.statTime); + + // 시계열 차트 데이터 successData.push(item.successCnt); timeoutData.push(item.timeoutCnt); systemErrData.push(item.systemErrCnt); @@ -133,8 +290,53 @@ avgRespData.push(item.avgRespTime); p50RespData.push(item.p50RespTime); p95RespData.push(item.p95RespTime); + + // 도넛 차트용 합산 + totalSuccess += (item.successCnt || 0); + totalTimeout += (item.timeoutCnt || 0); + totalSystemErr += (item.systemErrCnt || 0); + totalBizErr += (item.bizErrCnt || 0); + seq900Timeout += (item.seq900TimeoutCnt || 0); + seq900SystemErr += (item.seq900SystemErrCnt || 0); + seq900BizErr += (item.seq900BizErrCnt || 0); }); + // 총건수 도넛 차트 업데이트 + var grandTotal = totalSuccess + totalTimeout + totalSystemErr + totalBizErr; + totalDonutChart.setOption({ + series: [{ + data: [ + { value: totalSuccess, name: '성공' }, + { value: totalTimeout, name: 'Timeout' }, + { value: totalSystemErr, name: '시스템오류' }, + { value: totalBizErr, name: '업무오류' } + ] + }], + graphic: [{ + style: { + text: grandTotal.toLocaleString() + } + }] + }); + + // Seq900 도넛 차트 업데이트 + var seq900Total = seq900Timeout + seq900SystemErr + seq900BizErr; + seq900DonutChart.setOption({ + series: [{ + data: [ + { value: seq900Timeout, name: 'Timeout' }, + { value: seq900SystemErr, name: '시스템오류' }, + { value: seq900BizErr, name: '업무오류' } + ] + }], + graphic: [{ + style: { + text: seq900Total.toLocaleString() + } + }] + }); + + // 호출량 차트 업데이트 callChart.setOption({ xAxis: { data: times.map(function(t) { return t.substring(8, 10) + '시'; }) }, series: [ @@ -145,6 +347,7 @@ ] }); + // 응답시간 차트 업데이트 respChart.setOption({ xAxis: { data: times.map(function(t) { return t.substring(8, 10) + '시'; }) }, series: [ @@ -214,6 +417,7 @@ '통계시간', 'API명', '인스턴스', '업무구분', '클라이언트ID', 'Inbound Adapter', 'Outbound Adapter', '총건수', '성공', 'Timeout', '시스템오류', '업무오류', + 'Seq900 Timeout', 'Seq900 시스템오류', 'Seq900 업무오류', '평균응답(ms)', '최소응답(ms)', '최대응답(ms)', 'P50(ms)', 'P95(ms)' ], colModel: [ @@ -229,6 +433,9 @@ { name: 'timeoutCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, { name: 'systemErrCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, { name: 'bizErrCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, + { name: 'seq900TimeoutCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, + { name: 'seq900SystemErrCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, + { name: 'seq900BizErrCnt', align: 'right', width: '70', formatter: numberFormatter, sortable: false }, { name: 'avgRespTime', align: 'right', width: '80', formatter: decimalFormatter, sortable: false }, { name: 'minRespTime', align: 'right', width: '80', formatter: decimalFormatter, sortable: false }, { name: 'maxRespTime', align: 'right', width: '80', formatter: decimalFormatter, sortable: false }, @@ -281,6 +488,8 @@ // 윈도우 리사이즈 시 차트 리사이즈 $(window).resize(function() { + if (totalDonutChart) totalDonutChart.resize(); + if (seq900DonutChart) seq900DonutChart.resize(); if (callChart) callChart.resize(); if (respChart) respChart.resize(); }); @@ -344,6 +553,12 @@ + +
+
+
+
+
diff --git a/WebContent/jsp/onl/kjb/statistics/apiStatsMinuteMan.jsp b/WebContent/jsp/onl/kjb/statistics/apiStatsMinuteMan.jsp index 7013212..203e86f 100644 --- a/WebContent/jsp/onl/kjb/statistics/apiStatsMinuteMan.jsp +++ b/WebContent/jsp/onl/kjb/statistics/apiStatsMinuteMan.jsp @@ -10,7 +10,7 @@ %> - API 분단위 통계 + 분별 통계 조회