From 8035b7751f5fe5b8976f14f244e3874ef65c28cf Mon Sep 17 00:00:00 2001 From: shats Date: Tue, 24 Feb 2026 13:46:56 +0700 Subject: [PATCH] feat(logging): update debug logging endpoint and enhance resource stats logging for better diagnostics --- .cursor/debug-378b5f.log | 14 +++----- backend/routes/resourceStatsRoutes.js | 44 +++++++++++++++++++++++++ backend/services/networkMapScheduler.js | 2 +- frontend/src/ResourceStatsPage.jsx | 2 +- frontend/src/lib/api.js | 2 +- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/.cursor/debug-378b5f.log b/.cursor/debug-378b5f.log index 32b78b7..260e684 100644 --- a/.cursor/debug-378b5f.log +++ b/.cursor/debug-378b5f.log @@ -1,10 +1,4 @@ -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915099232} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915099568} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915128313} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915128707} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/mikrotik/address-lists"},"timestamp":1771915153565} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/mikrotik/address-lists","status":200},"timestamp":1771915154115} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915159241} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915159566} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915188306} -{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915188980} +{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915608308} +{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915608646} +{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:request","message":"API request started","data":{"method":"GET","url":"/alerts"},"timestamp":1771915615281} +{"sessionId":"378b5f","runId":"baseline","hypothesisId":"H1_H2","location":"frontend/src/lib/api.js:response","message":"API response received","data":{"method":"GET","url":"/alerts","status":200},"timestamp":1771915615733} diff --git a/backend/routes/resourceStatsRoutes.js b/backend/routes/resourceStatsRoutes.js index 7394e8c..a8e52ef 100644 --- a/backend/routes/resourceStatsRoutes.js +++ b/backend/routes/resourceStatsRoutes.js @@ -7,6 +7,25 @@ const { sendError } = require('../middleware/errorHandler'); const { decrypt } = require('../utils/encryption'); const { readServersFromS3 } = require('./serversRoutes'); const { createRosClient } = require('../services/mikrotikApplyService'); +const DEBUG_ENDPOINT = 'http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266'; + +function sendDebugLog(location, message, data, hypothesisId = 'H_RS_BACKEND_SLOW') { + // #region agent log + fetch(DEBUG_ENDPOINT, { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'X-Debug-Session-Id': '378b5f' }, + body: JSON.stringify({ + sessionId: '378b5f', + runId: 'resource-stats-investigation', + hypothesisId, + location, + message, + data: data || {}, + timestamp: Date.now(), + }), + }).catch(() => {}); + // #endregion +} function getMikrotikCredentials(server) { if (!server || (server.type !== 'jumphost' && server.type !== 'home')) return null; @@ -77,6 +96,7 @@ function parseResource(raw) { * Внутренняя функция: возвращает данные по ресурсам роутеров (без HTTP). */ async function getResourceStatsData() { + const startedAt = Date.now(); const servers = await readServersFromS3(); const routers = (Array.isArray(servers) ? servers : []).filter( (s) => @@ -84,9 +104,14 @@ async function getResourceStatsData() { (String(s.type || '').toLowerCase() === 'jumphost' || String(s.type || '').toLowerCase() === 'home') ); + sendDebugLog('backend/routes/resourceStatsRoutes.js:getResourceStatsData-routers', 'Resource stats routers loaded', { + serversCount: Array.isArray(servers) ? servers.length : 0, + routersCount: routers.length, + }); const results = await Promise.all( routers.map(async (server) => { + const routerStartedAt = Date.now(); const serverId = server.id || server.dns || server.ip; const name = server.name || server.dns || server.ip || serverId; const host = server.mikrotikHost || server.ip || server.dns; @@ -98,6 +123,7 @@ async function getResourceStatsData() { name, host, groupKey: server.groupKey || null, + durationMs: Date.now() - routerStartedAt, error: 'MikroTik API не настроен или нет пароля', resource: null, }; @@ -113,6 +139,7 @@ async function getResourceStatsData() { name, host, groupKey: server.groupKey || null, + durationMs: Date.now() - routerStartedAt, error: null, resource, }; @@ -123,6 +150,7 @@ async function getResourceStatsData() { name, host, groupKey: server.groupKey || null, + durationMs: Date.now() - routerStartedAt, error: msg, resource: null, }; @@ -130,6 +158,22 @@ async function getResourceStatsData() { }) ); + const totalDurationMs = Date.now() - startedAt; + const slowRouters = results + .map((r) => ({ + serverId: r.serverId, + durationMs: Number(r.durationMs || 0), + hasError: Boolean(r.error), + })) + .sort((a, b) => b.durationMs - a.durationMs) + .slice(0, 5); + sendDebugLog('backend/routes/resourceStatsRoutes.js:getResourceStatsData-done', 'Resource stats aggregate timing', { + totalDurationMs, + routersCount: results.length, + errorsCount: results.filter((r) => Boolean(r.error)).length, + slowRouters, + }); + return { routers: results }; } diff --git a/backend/services/networkMapScheduler.js b/backend/services/networkMapScheduler.js index c5ad8b5..7eb6d20 100644 --- a/backend/services/networkMapScheduler.js +++ b/backend/services/networkMapScheduler.js @@ -14,7 +14,7 @@ const NETWORK_MAP_CACHE_KEY = 'network-map-cache/latest.json'; const DEFAULT_INTERVAL_MINUTES = 5; const DEFAULT_LOG_MAX_LINES = 500; -const DEBUG_ENDPOINT = 'http://127.0.0.1:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266'; +const DEBUG_ENDPOINT = 'http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266'; function sendDebugLog(location, message, data, hypothesisId = 'H_STARTUP_SPEEDTEST') { // #region agent log diff --git a/frontend/src/ResourceStatsPage.jsx b/frontend/src/ResourceStatsPage.jsx index 1292887..0f712a0 100644 --- a/frontend/src/ResourceStatsPage.jsx +++ b/frontend/src/ResourceStatsPage.jsx @@ -153,7 +153,7 @@ export default function ResourceStatsPage() { setError(null); const opts = { timeout: REQUEST_TIMEOUT_MS, noRetry: true, ...(abortSignal ? { signal: abortSignal } : {}) }; // #region agent log - fetch('http://127.0.0.1:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'resource-stats-fix',hypothesisId:'H_RS_RETRY',location:'frontend/src/ResourceStatsPage.jsx:fetchStats',message:'Resource stats request started with noRetry',data:{timeoutMs:REQUEST_TIMEOUT_MS,noRetry:true,hasAbortSignal:Boolean(abortSignal)},timestamp:Date.now()})}).catch(()=>{}); + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'resource-stats-fix',hypothesisId:'H_RS_RETRY',location:'frontend/src/ResourceStatsPage.jsx:fetchStats',message:'Resource stats request started with noRetry',data:{timeoutMs:REQUEST_TIMEOUT_MS,noRetry:true,hasAbortSignal:Boolean(abortSignal)},timestamp:Date.now()})}).catch(()=>{}); // #endregion try { const res = await api.get('/resources/stats', opts); diff --git a/frontend/src/lib/api.js b/frontend/src/lib/api.js index fd8ac85..08e102b 100644 --- a/frontend/src/lib/api.js +++ b/frontend/src/lib/api.js @@ -78,7 +78,7 @@ api.interceptors.response.use( if (noRetry) { // #region agent log - fetch('http://127.0.0.1:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'resource-stats-fix',hypothesisId:'H_RS_RETRY',location:'frontend/src/lib/api.js:retry-disabled-by-config',message:'Skip retry due to noRetry flag',data:{method:String(method),url:String(config?.url||''),code:String(error?.code||''),retryCount:Number(config?.__retryCount||0)},timestamp:Date.now()})}).catch(()=>{}); + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'resource-stats-fix',hypothesisId:'H_RS_RETRY',location:'frontend/src/lib/api.js:retry-disabled-by-config',message:'Skip retry due to noRetry flag',data:{method:String(method),url:String(config?.url||''),code:String(error?.code||''),retryCount:Number(config?.__retryCount||0)},timestamp:Date.now()})}).catch(()=>{}); // #endregion return Promise.reject(error); }