feat(logging): add agent logging for API interactions and error handling across backend and frontend components
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m48s

This commit is contained in:
2026-02-24 12:33:19 +07:00
parent f48e30ab44
commit 4370e13524
6 changed files with 31 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
{\
+3
View File
@@ -148,6 +148,9 @@ function createTextDataPOST(s3Key, formatLine, validate, validateItem = null) {
} catch {}
if (current && (ifMatch || etag) && current !== String(ifMatch || etag)) {
// #region agent log
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:'baseline',hypothesisId:'H2',location:'backend/routes/textDataRoutes.js:etag-mismatch',message:'ETag mismatch detected in text POST',data:{s3Key:String(s3Key||''),currentEtag:String(current||''),providedEtag:String(ifMatch||etag||'')},timestamp:Date.now()})}).catch(()=>{});
// #endregion
const { headMeta } = require('../services/s3Service');
const meta = await headMeta(s3Key);
return sendError(res, 412, 'Precondition Failed: ETag mismatch', 'E_ETAG_MISMATCH', {
+9
View File
@@ -412,12 +412,18 @@ app.post('/api/server-filters/:serverId', serverConfigsRoutes.postServerFilters)
// === LOCKS ===
app.get('/api/locks/:resource', (req, res) => {
const status = getLockStatus(req.params.resource);
// #region agent log
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:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-get',message:'Lock status requested',data:{resource:String(req?.params?.resource||''),locked:Boolean(status?.locked)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
res.json(status);
});
app.post('/api/locks/:resource', (req, res) => {
const { owner = 'anonymous', ttlSeconds = 120 } = req.body || {};
const result = acquireLock(req.params.resource, owner, ttlSeconds);
// #region agent log
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:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-post',message:'Lock acquire attempted',data:{resource:String(req?.params?.resource||''),owner:String(owner||''),success:Boolean(result?.success),locked:Boolean(result?.locked)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
if (!result.success) {
return sendError(res, 423, 'Resource is locked by another user', 'E_RESOURCE_LOCKED', {
owner: result.owner,
@@ -429,6 +435,9 @@ app.post('/api/locks/:resource', (req, res) => {
app.delete('/api/locks/:resource', (req, res) => {
const result = releaseLock(req.params.resource);
// #region agent log
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:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-delete',message:'Lock released',data:{resource:String(req?.params?.resource||''),released:Boolean(result?.released)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
res.json(result);
});
+6
View File
@@ -196,6 +196,12 @@ function MainLayout() {
}
}, [location.pathname, layout]);
useEffect(() => {
// #region agent log
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:'baseline',hypothesisId:'H5',location:'frontend/src/App.jsx:route-change',message:'Route changed in MainLayout',data:{pathname:String(location?.pathname||''),layout:String(layout||'')},timestamp:Date.now()})}).catch(()=>{});
// #endregion
}, [location.pathname, layout]);
// Состояние для управления выпадающими меню
const [dropdownStates, setDropdownStates] = useState({
data: false,
@@ -23,6 +23,9 @@ class ErrorBoundary extends Component {
componentDidCatch(error, errorInfo) {
// Логируем ошибку
console.error('ErrorBoundary caught an error:', error, errorInfo);
// #region agent log
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:'baseline',hypothesisId:'H3',location:'frontend/src/components/ErrorBoundary.jsx:componentDidCatch',message:'React ErrorBoundary caught error',data:{message:String(error?.message||''),name:String(error?.name||''),componentStack:String(errorInfo?.componentStack||'').slice(0,500)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
// Отправляем в мониторинг (если настроен)
this.logErrorToService(error, errorInfo);
+9
View File
@@ -39,6 +39,9 @@ function buildCacheKey(config) {
// Улучшенный retry interceptor с поддержкой всех методов и типов ошибок
api.interceptors.response.use(
(response) => {
// #region agent log
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:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:response',message:'API response received',data:{method:String(response?.config?.method||'get').toUpperCase(),url:String(response?.config?.url||''),status:Number(response?.status||0)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
try {
const method = String(response?.config?.method || 'get').toLowerCase();
if (method === 'get') {
@@ -104,6 +107,9 @@ api.interceptors.response.use(
api.interceptors.response.use(
(res) => res,
(err) => {
// #region agent log
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:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:error',message:'API response error',data:{method:String(err?.config?.method||'get').toUpperCase(),url:String(err?.config?.url||''),status:Number(err?.response?.status||0),code:String(err?.response?.data?.code||err?.code||'')},timestamp:Date.now()})}).catch(()=>{});
// #endregion
try {
// Не показываем уведомления если это повторная попытка
const isRetrying = err?.config?.__retryCount > 0;
@@ -135,6 +141,9 @@ api.interceptors.response.use(
// Request интерсептор: If-Match из etag (если не задан явный заголовок)
api.interceptors.request.use((config) => {
try {
// #region agent log
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:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:request',message:'API request started',data:{method:String(config?.method||'get').toUpperCase(),url:String(config?.url||'')},timestamp:Date.now()})}).catch(()=>{});
// #endregion
// If-None-Match для GET на базе кеша
const method = String(config.method || 'get').toLowerCase();
if (method === 'get') {