//////////////////////////////////////////////////////////////////////////////////////// //Page 전역 변수 //////////////////////////////////////////////////////////////////////////////////////// var MONITORING_BASE_URL = "/engine-search-api/engine/admin/monitoring"; var clusterHealthTable; var nodeStatsTable; var threadPoolTable; var indexingStatsTable; var summaryTable; var isHealthyTable; //Document Ready //////////////////////////////////////////////////////////////////////////////////////// function execDocReady() { let pluginGroups = [ [ "../reference/light-blue/lib/vendor/jquery.ui.widget.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Templates_js_tmpl.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Load-Image_js_load-image.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Canvas-to-Blob_js_canvas-to-blob.js", "../reference/light-blue/lib/jquery.iframe-transport.js", "../reference/light-blue/lib/jquery.fileupload.js", "../reference/light-blue/lib/jquery.fileupload-fp.js", "../reference/light-blue/lib/jquery.fileupload-ui.js" ], [ "../reference/jquery-plugins/select2-4.0.2/dist/css/select2_lightblue4.css", "../reference/jquery-plugins/lou-multi-select-0.9.12/css/multiselect-lightblue4.css", "../reference/jquery-plugins/multiple-select-1.5.2/dist/multiple-select-bluelight.css", "../reference/jquery-plugins/select2-4.0.2/dist/js/select2.min.js", "../reference/jquery-plugins/lou-multi-select-0.9.12/js/jquery.quicksearch.js", "../reference/jquery-plugins/lou-multi-select-0.9.12/js/jquery.multi-select.js", "../reference/jquery-plugins/multiple-select-1.5.2/dist/multiple-select.min.js" ], [ "../reference/jquery-plugins/datetimepicker-2.5.20/build/jquery.datetimepicker.min.css", "../reference/light-blue/lib/bootstrap-datepicker.js", "../reference/jquery-plugins/datetimepicker-2.5.20/build/jquery.datetimepicker.full.min.js", "../reference/lightblue4/docs/lib/widgster/widgster.js", "../reference/lightblue4/docs/lib/slimScroll/jquery.slimscroll.min.js", "../reference/lightblue4/docs/lib/jquery.sparkline/index.js", "../reference/lightblue4/docs/js/charts.js" ], [ "../reference/jquery-plugins/dataTables-1.10.16/media/css/jquery.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Responsive/css/responsive.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Select/css/select.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/media/js/jquery.dataTables.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Responsive/js/dataTables.responsive.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Select/js/dataTables.select.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/RowGroup/js/dataTables.rowsGroup.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/dataTables.buttons.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/buttons.html5.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/buttons.print.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/jszip.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/pdfmake.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/vfs_fonts.js", "../reference/jquery-plugins/kevalbhatt-timezone-picker-2.0.0/dist/timezone-picker.min.js", "../reference/jquery-plugins/kevalbhatt-timezone-picker-2.0.0/dist/styles/timezone-picker.css" ] ]; loadPluginGroupsParallelAndSequential(pluginGroups) .then(function () { console.log("모든 플러그인 로드 완료"); $(".widget").widgster(); setSideMenu("sidebar_menu_system", "sidebar_menu_system_es_monitoring"); // 데이터 테이블 초기화 initClusterHealthTable(); initNodeStatsTable(); initThreadPoolTable(); initIndexingStatsTable(); initSummaryTable(); initIsHealthyTable(); // 초기 데이터 로드 loadClusterHealth(); // 탭 전환 이벤트 setupTabEvents(); }) .catch(function (error) { console.error("플러그인 로드 중 오류 발생"); console.log(error); }); } // 데이터 테이블 열 클릭 이벤트 function dataTableClick(tempDataTable, selectedData) { let tableId = tempDataTable.context[0].sInstance; console.log("Table clicked: " + tableId); } // 데이터 테이블 렌더링 후 콜백 함수 function dataTableCallBack(settings, json) { } // 데이터 테이블 재그리기 후 콜백 함수 function dataTableDrawCallback(tableInfo) { console.log(tableInfo); $("#" + tableInfo.sInstance) .DataTable() .columns.adjust() .responsive.recalc(); } //////////////////////////////////////////////////////////////////////////////////////// // 탭 이벤트 설정 //////////////////////////////////////////////////////////////////////////////////////// function setupTabEvents() { $('a[data-toggle="tab"]').on("shown.bs.tab", function (e) { var target = $(e.target).attr("href"); switch (target) { case "#tabHealth": loadClusterHealth(); break; case "#tabNodes": loadNodeStats(); break; case "#tabThreadPool": loadThreadPool(); break; case "#tabIndexing": loadIndexingStats(); break; case "#tabSummary": loadSummary(); break; case "#tabIsHealthy": loadIsHealthy(); break; } }); } //////////////////////////////////////////////////////////////////////////////////////// // 공통 유틸 함수 //////////////////////////////////////////////////////////////////////////////////////// function renderValue(data) { return data ? "" + data + "" : "N/A"; } function formatBytes(bytes) { if (!bytes && bytes !== 0) return "N/A"; if (bytes === 0) return "0 B"; var k = 1024; var sizes = ["B", "KB", "MB", "GB", "TB"]; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; } //////////////////////////////////////////////////////////////////////////////////////// // Is Healthy 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initIsHealthyTable() { let columnList = [ { title: "정상여부", data: "isHealthy", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "상태메시지", data: "message", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; isHealthyTable = dataTable_build( "#isHealthyTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadIsHealthy() { $.ajax({ url: MONITORING_BASE_URL + "/is-healthy", type: "GET", dataType: "json", statusCode: { 200: function (data) { var isHealthy = data.response; var table = $("#isHealthyTable").DataTable(); var message = isHealthy === true ? "클러스터 정상. 모든 모니터링 지표가 정상 범위 내입니다." : "장애 발생. Summary 탭에서 상세 원인을 확인하세요."; table.clear(); table.rows.add([{ isHealthy: isHealthy, message: message }]); table.draw(); } }, error: function () { var table = $("#isHealthyTable").DataTable(); table.clear(); table.rows.add([{ isHealthy: null, message: "서버 연결에 실패했습니다." }]); table.draw(); } }); } //////////////////////////////////////////////////////////////////////////////////////// // Cluster Health 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initClusterHealthTable() { let columnList = [ { title: "클러스터명", data: "clusterName", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true }, { title: "상태", data: "status", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "전체노드수", data: "numberOfNodes", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "데이터노드수", data: "numberOfDataNodes", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "활성Primary샤드", data: "activePrimaryShards", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "활성샤드", data: "activeShards", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "미할당샤드", data: "unassignedShards", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "활성샤드비율(%)", data: "activeShardsPercentAsNumber", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "대기작업수", data: "numberOfPendingTasks", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "정상여부", data: "isHealthy", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "상태메시지", data: "healthMessage", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; clusterHealthTable = dataTable_build( "#clusterHealthTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadClusterHealth() { $.ajax({ url: MONITORING_BASE_URL + "/health", type: "GET", dataType: "json", statusCode: { 200: function (data) { var table = $("#clusterHealthTable").DataTable(); table.clear(); table.rows.add([data.response]); table.draw(); } }, error: function () { console.error("Cluster Health 데이터 로드 실패"); } }); } //////////////////////////////////////////////////////////////////////////////////////// // Node Stats 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initNodeStatsTable() { let columnList = [ { title: "노드명", data: "nodeName", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true }, { title: "IP", data: "ip", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "역할", data: "nodeRole", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "Master", data: "isMaster", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "Heap사용률(%)", data: "heapUsedPercent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "Heap사용량", data: "heapUsedBytes", render: function (data) { return renderValue(formatBytes(data)); }, className: "dt-body-center", visible: true }, { title: "Heap최대", data: "heapMaxBytes", render: function (data) { return renderValue(formatBytes(data)); }, className: "dt-body-center", visible: true }, { title: "CPU(%)", data: "cpuPercent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "1분평균부하", data: "loadAverage1m", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "디스크사용률(%)", data: "diskUsedPercent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "디스크여유공간", data: "diskFreeBytes", render: function (data) { return renderValue(formatBytes(data)); }, className: "dt-body-center", visible: true }, { title: "정상여부", data: "isHealthy", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "상태메시지", data: "healthMessage", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; nodeStatsTable = dataTable_build( "#nodeStatsTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadNodeStats() { $.ajax({ url: MONITORING_BASE_URL + "/nodes", type: "GET", dataType: "json", statusCode: { 200: function (data) { var table = $("#nodeStatsTable").DataTable(); table.clear(); table.rows.add(data.response); table.draw(); } }, error: function () { console.error("Node Stats 데이터 로드 실패"); } }); } //////////////////////////////////////////////////////////////////////////////////////// // Thread Pool 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initThreadPoolTable() { let columnList = [ { title: "노드명", data: "nodeName", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true }, { title: "스레드풀명", data: "threadPoolName", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "활성스레드수", data: "active", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "대기열", data: "queue", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "거부요청수", data: "rejected", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "최대스레드수", data: "largest", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "완료작업수", data: "completed", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "거부발생여부", data: "hasRejected", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "상태메시지", data: "healthMessage", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; threadPoolTable = dataTable_build( "#threadPoolTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadThreadPool() { $.ajax({ url: MONITORING_BASE_URL + "/thread-pool", type: "GET", dataType: "json", statusCode: { 200: function (data) { var table = $("#threadPoolTable").DataTable(); table.clear(); table.rows.add(data.response); table.draw(); } }, error: function () { console.error("Thread Pool 데이터 로드 실패"); } }); } //////////////////////////////////////////////////////////////////////////////////////// // Indexing Stats 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initIndexingStatsTable() { let columnList = [ { title: "총인덱싱수", data: "indexTotal", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "총인덱싱시간(ms)", data: "indexTimeInMillis", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "진행중인덱싱", data: "indexCurrent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "실패인덱싱수", data: "indexFailed", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "총검색수", data: "queryTotal", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "총검색시간(ms)", data: "queryTimeInMillis", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "진행중검색", data: "queryCurrent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "총Fetch수", data: "fetchTotal", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "총Fetch시간(ms)", data: "fetchTimeInMillis", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "진행중Fetch", data: "fetchCurrent", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "인덱싱실패여부", data: "hasIndexFailed", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "상태메시지", data: "healthMessage", render: function (data) { return renderValue(data); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; indexingStatsTable = dataTable_build( "#indexingStatsTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadIndexingStats() { $.ajax({ url: MONITORING_BASE_URL + "/indexing", type: "GET", dataType: "json", statusCode: { 200: function (data) { var table = $("#indexingStatsTable").DataTable(); table.clear(); table.rows.add([data.response]); table.draw(); } }, error: function () { console.error("Indexing Stats 데이터 로드 실패"); } }); } //////////////////////////////////////////////////////////////////////////////////////// // Summary 테이블 //////////////////////////////////////////////////////////////////////////////////////// function initSummaryTable() { let columnList = [ { title: "수집시각", data: "timestamp", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "클러스터상태", data: "clusterHealth", render: function (data) { return data ? renderValue(data.status) : "N/A"; }, className: "dt-body-center", visible: true }, { title: "노드수", data: "nodeStats", render: function (data) { return data ? renderValue(data.length) : "N/A"; }, className: "dt-body-center", visible: true }, { title: "스레드풀수", data: "threadPoolStats", render: function (data) { return data ? renderValue(data.length) : "N/A"; }, className: "dt-body-center", visible: true }, { title: "인덱싱실패", data: "indexingStats", render: function (data) { return data ? renderValue(data.indexFailed) : "N/A"; }, className: "dt-body-center", visible: true }, { title: "정상여부", data: "isHealthy", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "전체상태", data: "overallStatus", render: function (data) { return renderValue(data); }, className: "dt-body-center", visible: true }, { title: "문제목록", data: "issues", render: function (data) { if (!data || data.length === 0) return "감지된 문제가 없습니다."; return data.map(function (issue) { return "" + issue + ""; }).join("
"); }, className: "dt-body-left", visible: true } ]; let columnDefList = [{ "defaultContent": "
N/A
", "targets": "_all" }]; summaryTable = dataTable_build( "#summaryTable", "", "", columnList, [], columnDefList, {}, [], [], false, {}, [], false ); } function loadSummary() { $.ajax({ url: MONITORING_BASE_URL + "/summary", type: "GET", dataType: "json", statusCode: { 200: function (data) { var table = $("#summaryTable").DataTable(); table.clear(); table.rows.add([data.response]); table.draw(); } }, error: function () { console.error("Summary 데이터 로드 실패"); } }); } //////////////////////////////////////////////////////////////////////////////////////// // 데이터 테이블 렌더링 & Ajax 호출 종료 ////////////////////////////////////////////////////////////////////////////////////////