@zintrust/trace 0.4.86 → 0.4.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.86",
4
- "buildDate": "2026-04-09T08:08:55.865Z",
3
+ "version": "0.4.92",
4
+ "buildDate": "2026-04-10T08:41:38.521Z",
5
5
  "buildEnvironment": {
6
6
  "node": "v20.20.2",
7
7
  "platform": "linux",
8
8
  "arch": "x64"
9
9
  },
10
10
  "git": {
11
- "commit": "a456e7ec",
11
+ "commit": "d195a996",
12
12
  "branch": "master"
13
13
  },
14
14
  "package": {
@@ -75,7 +75,7 @@
75
75
  },
76
76
  "index.js": {
77
77
  "size": 3255,
78
- "sha256": "faba7327d333f46340e9f6933510a88cb2439d14af9651cd8868a38782a44388"
78
+ "sha256": "683151fa06b666ec62b150a4fda949c3d35221228b8538644ef740252b63587d"
79
79
  },
80
80
  "migrations/20260331000001_create_zin_trace_entries_table.d.ts": {
81
81
  "size": 304,
@@ -130,8 +130,8 @@
130
130
  "sha256": "71d366165dd36f1675aa253a76262b226fb6c62e5ab632746b8aea61c0c625fc"
131
131
  },
132
132
  "register.js": {
133
- "size": 12522,
134
- "sha256": "66bccec7fac4d669702fa18e439788325d36ce17f228639005ffcde2cd968d70"
133
+ "size": 14225,
134
+ "sha256": "07e1643982cc93149c609d44beb11dea168ecf1cac3f78d95d6d22fedcafbc23"
135
135
  },
136
136
  "storage/TraceContentRedaction.d.ts": {
137
137
  "size": 207,
@@ -330,8 +330,8 @@
330
330
  "sha256": "f3ddc5f8b58c6c86ac6b464dd48e5a55e79ab2bf2e735feacffc7480e4ccc0c4"
331
331
  },
332
332
  "watchers/LogWatcher.js": {
333
- "size": 2026,
334
- "sha256": "c5d2227cd76ce10162993ac31f474b2460cd41264c36f01b5130152f14a0ad21"
333
+ "size": 3126,
334
+ "sha256": "e0944661b48b682520d60ee9e98b3fa9f8ba4694743f134f98b04b8b2dd479e6"
335
335
  },
336
336
  "watchers/MailWatcher.d.ts": {
337
337
  "size": 244,
@@ -370,8 +370,8 @@
370
370
  "sha256": "5d5046c65e5b683369c7709f1acd09b60aec3e7f44748fd1baeb35498836465b"
371
371
  },
372
372
  "watchers/QueryWatcher.js": {
373
- "size": 2935,
374
- "sha256": "577c6fec0282d2290db5c4b6c606b9b6ecdd64209af2b09f3205a15bf656bbef"
373
+ "size": 3002,
374
+ "sha256": "c7131284e75ab2f0193597cdf3ef0aa7eab1a3872fe9193579a140a41fadb57e"
375
375
  },
376
376
  "watchers/RedisWatcher.d.ts": {
377
377
  "size": 294,
package/dist/register.js CHANGED
@@ -39,6 +39,11 @@ const importCore = async () => {
39
39
  return {};
40
40
  }
41
41
  };
42
+ const TRACE_REQUIRED_TABLES = [
43
+ 'zin_trace_entries',
44
+ 'zin_trace_entries_tags',
45
+ 'zin_trace_monitoring',
46
+ ];
42
47
  const resolveRegisterMiddleware = () => {
43
48
  const globalMiddlewareRegistrarState = globalThis;
44
49
  return (middleware) => {
@@ -69,7 +74,7 @@ const resolveObservedConnectionName = (env, configuredObservedConnection, storag
69
74
  configuredObservedConnection.trim() !== '') {
70
75
  return resolveTraceConnectionName(env, configuredObservedConnection);
71
76
  }
72
- const defaultConnectionName = resolveTraceConnectionName(env, undefined);
77
+ const defaultConnectionName = resolveTraceConnectionName(env);
73
78
  if (storageConnectionName !== defaultConnectionName) {
74
79
  return defaultConnectionName;
75
80
  }
@@ -150,6 +155,43 @@ const buildTraceRedactionOverrides = (input) => {
150
155
  ? redaction
151
156
  : undefined;
152
157
  };
158
+ const createTraceConfigError = (coreApi, message, details) => {
159
+ if (coreApi.ErrorFactory?.createConfigError !== undefined) {
160
+ return coreApi.ErrorFactory.createConfigError(message, details);
161
+ }
162
+ const error = new globalThis.Error(message);
163
+ error.name = 'ConfigError';
164
+ error.code = 'CONFIG_ERROR';
165
+ error.statusCode = 500;
166
+ error.details = details;
167
+ return error;
168
+ };
169
+ function assertTraceConnectionResolved(coreApi, db, params) {
170
+ if (db !== undefined) {
171
+ return;
172
+ }
173
+ throw createTraceConfigError(coreApi, `Trace connection "${params.connectionName}" could not be resolved.`, {
174
+ connectionName: params.connectionName,
175
+ envKey: params.envKey,
176
+ hint: params.envKey === 'TRACE_DB_CONNECTION'
177
+ ? 'Configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.'
178
+ : 'Configure TRACE_QUERY_CONNECTION, or ensure DB_CONNECTION resolves to an existing database connection.',
179
+ });
180
+ }
181
+ const assertTraceStorageReady = async (coreApi, db, connectionName) => {
182
+ try {
183
+ await Promise.all(TRACE_REQUIRED_TABLES.map(async (table) => {
184
+ await db.queryOne(`SELECT 1 AS ok FROM ${table} LIMIT 1`, []);
185
+ }));
186
+ }
187
+ catch (error) {
188
+ throw createTraceConfigError(coreApi, `Trace storage connection "${connectionName}" is not ready. Create the database if needed and run \`zin migrate:trace\` before enabling TRACE_ENABLED.`, {
189
+ connectionName,
190
+ error,
191
+ requiredTables: [...TRACE_REQUIRED_TABLES],
192
+ });
193
+ }
194
+ };
153
195
  const core = (await importCore());
154
196
  const Env = core.Env;
155
197
  const startupOverrides = resolveTraceStartupOverrides(core);
@@ -205,62 +247,65 @@ if (!traceAlreadyInitialized && Env) {
205
247
  const resolvedObservedConnectionName = resolveObservedConnectionName(Env, config.observeConnection, resolvedConnectionName);
206
248
  const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
207
249
  const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
208
- if (storageDb && observedDb) {
209
- const storage = TraceWriteDiagnostics.wrapStorage(TraceContentRedaction.wrapStorage(TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config), config.redaction), {
210
- connectionName: resolvedConnectionName,
211
- logger: core.Logger,
212
- });
213
- if (core.RequestContext) {
214
- TraceContext.setRequestContextImpl(core.RequestContext);
215
- }
216
- const [{ HttpWatcher }, { QueryWatcher }, { LogWatcher }, { ExceptionWatcher }, { JobWatcher }, { CacheWatcher }, { ScheduleWatcher }, { MailWatcher }, { AuthWatcher }, { EventWatcher }, { ModelWatcher }, { NotificationWatcher }, { RedisWatcher }, { GateWatcher }, { MiddlewareWatcher }, { CommandWatcher }, { BatchWatcher }, { DumpWatcher }, { ViewWatcher }, { HttpClientWatcher },] = await Promise.all([
217
- import('./watchers/HttpWatcher.js'),
218
- import('./watchers/QueryWatcher.js'),
219
- import('./watchers/LogWatcher.js'),
220
- import('./watchers/ExceptionWatcher.js'),
221
- import('./watchers/JobWatcher.js'),
222
- import('./watchers/CacheWatcher.js'),
223
- import('./watchers/ScheduleWatcher.js'),
224
- import('./watchers/MailWatcher.js'),
225
- import('./watchers/AuthWatcher.js'),
226
- import('./watchers/EventWatcher.js'),
227
- import('./watchers/ModelWatcher.js'),
228
- import('./watchers/NotificationWatcher.js'),
229
- import('./watchers/RedisWatcher.js'),
230
- import('./watchers/GateWatcher.js'),
231
- import('./watchers/MiddlewareWatcher.js'),
232
- import('./watchers/CommandWatcher.js'),
233
- import('./watchers/BatchWatcher.js'),
234
- import('./watchers/DumpWatcher.js'),
235
- import('./watchers/ViewWatcher.js'),
236
- import('./watchers/HttpClientWatcher.js'),
237
- ]);
238
- const watcherArgs = { storage, config, db: observedDb };
239
- HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
240
- QueryWatcher.register(watcherArgs);
241
- LogWatcher.register(watcherArgs);
242
- ExceptionWatcher.register(watcherArgs);
243
- JobWatcher.register(watcherArgs);
244
- CacheWatcher.register(watcherArgs);
245
- ScheduleWatcher.register(watcherArgs);
246
- MailWatcher.register(watcherArgs);
247
- AuthWatcher.register(watcherArgs);
248
- EventWatcher.register(watcherArgs);
249
- ModelWatcher.register(watcherArgs);
250
- NotificationWatcher.register(watcherArgs);
251
- RedisWatcher.register(watcherArgs);
252
- GateWatcher.register(watcherArgs);
253
- MiddlewareWatcher.register(watcherArgs);
254
- CommandWatcher.register(watcherArgs);
255
- BatchWatcher.register(watcherArgs);
256
- DumpWatcher.register(watcherArgs);
257
- ViewWatcher.register(watcherArgs);
258
- HttpClientWatcher.register(watcherArgs);
259
- }
260
- else {
261
- // eslint-disable-next-line no-console
262
- console.warn('[trace] Could not resolve database connection - skipping init.');
250
+ assertTraceConnectionResolved(core, storageDb, {
251
+ connectionName: resolvedConnectionName,
252
+ envKey: 'TRACE_DB_CONNECTION',
253
+ });
254
+ assertTraceConnectionResolved(core, observedDb, {
255
+ connectionName: resolvedObservedConnectionName,
256
+ envKey: 'TRACE_QUERY_CONNECTION',
257
+ });
258
+ await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
259
+ const storage = TraceWriteDiagnostics.wrapStorage(TraceContentRedaction.wrapStorage(TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config), config.redaction), {
260
+ connectionName: resolvedConnectionName,
261
+ logger: core.Logger,
262
+ });
263
+ if (core.RequestContext) {
264
+ TraceContext.setRequestContextImpl(core.RequestContext);
263
265
  }
266
+ const [{ HttpWatcher }, { QueryWatcher }, { LogWatcher }, { ExceptionWatcher }, { JobWatcher }, { CacheWatcher }, { ScheduleWatcher }, { MailWatcher }, { AuthWatcher }, { EventWatcher }, { ModelWatcher }, { NotificationWatcher }, { RedisWatcher }, { GateWatcher }, { MiddlewareWatcher }, { CommandWatcher }, { BatchWatcher }, { DumpWatcher }, { ViewWatcher }, { HttpClientWatcher },] = await Promise.all([
267
+ import('./watchers/HttpWatcher.js'),
268
+ import('./watchers/QueryWatcher.js'),
269
+ import('./watchers/LogWatcher.js'),
270
+ import('./watchers/ExceptionWatcher.js'),
271
+ import('./watchers/JobWatcher.js'),
272
+ import('./watchers/CacheWatcher.js'),
273
+ import('./watchers/ScheduleWatcher.js'),
274
+ import('./watchers/MailWatcher.js'),
275
+ import('./watchers/AuthWatcher.js'),
276
+ import('./watchers/EventWatcher.js'),
277
+ import('./watchers/ModelWatcher.js'),
278
+ import('./watchers/NotificationWatcher.js'),
279
+ import('./watchers/RedisWatcher.js'),
280
+ import('./watchers/GateWatcher.js'),
281
+ import('./watchers/MiddlewareWatcher.js'),
282
+ import('./watchers/CommandWatcher.js'),
283
+ import('./watchers/BatchWatcher.js'),
284
+ import('./watchers/DumpWatcher.js'),
285
+ import('./watchers/ViewWatcher.js'),
286
+ import('./watchers/HttpClientWatcher.js'),
287
+ ]);
288
+ const watcherArgs = { storage, config, db: observedDb };
289
+ HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
290
+ QueryWatcher.register(watcherArgs);
291
+ LogWatcher.register(watcherArgs);
292
+ ExceptionWatcher.register(watcherArgs);
293
+ JobWatcher.register(watcherArgs);
294
+ CacheWatcher.register(watcherArgs);
295
+ ScheduleWatcher.register(watcherArgs);
296
+ MailWatcher.register(watcherArgs);
297
+ AuthWatcher.register(watcherArgs);
298
+ EventWatcher.register(watcherArgs);
299
+ ModelWatcher.register(watcherArgs);
300
+ NotificationWatcher.register(watcherArgs);
301
+ RedisWatcher.register(watcherArgs);
302
+ GateWatcher.register(watcherArgs);
303
+ MiddlewareWatcher.register(watcherArgs);
304
+ CommandWatcher.register(watcherArgs);
305
+ BatchWatcher.register(watcherArgs);
306
+ DumpWatcher.register(watcherArgs);
307
+ ViewWatcher.register(watcherArgs);
308
+ HttpClientWatcher.register(watcherArgs);
264
309
  }
265
310
  }
266
311
  else if (!traceAlreadyInitialized) {
@@ -17,8 +17,37 @@ const TRACE_INFRASTRUCTURE_LOG_MESSAGES = new Set([
17
17
  '[MySQLProxyAdapter] Proxy request failed',
18
18
  '[trace] Trace storage write degraded',
19
19
  ]);
20
- const shouldSkipTraceInfrastructureLog = (message) => {
21
- return TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim());
20
+ const TRACE_STORAGE_TABLE_NAMES = [
21
+ 'zin_trace_entries',
22
+ 'zin_trace_entries_tags',
23
+ 'zin_trace_monitoring',
24
+ ];
25
+ const isTraceStorageQuery = (sql) => {
26
+ const normalized = sql.toLowerCase();
27
+ return TRACE_STORAGE_TABLE_NAMES.some((tableName) => normalized.includes(tableName));
28
+ };
29
+ const extractSqlFromLog = (message, context) => {
30
+ const contextSql = context?.['sql'];
31
+ if (typeof contextSql === 'string')
32
+ return contextSql;
33
+ const trimmed = message.trim();
34
+ const rawPrefix = 'Raw SQL Query executed:';
35
+ if (trimmed.startsWith(rawPrefix)) {
36
+ const sql = trimmed.slice(rawPrefix.length).trim();
37
+ return sql === '' ? undefined : sql;
38
+ }
39
+ return undefined;
40
+ };
41
+ const isTraceStorageQueryLog = (message, context) => {
42
+ const normalizedMessage = message.trim().toLowerCase();
43
+ if (!normalizedMessage.includes('query executed'))
44
+ return false;
45
+ const sql = extractSqlFromLog(message, context);
46
+ return typeof sql === 'string' && isTraceStorageQuery(sql);
47
+ };
48
+ const shouldSkipTraceInfrastructureLog = (message, context) => {
49
+ return (TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim()) ||
50
+ isTraceStorageQueryLog(message, context));
22
51
  };
23
52
  export const LogWatcher = Object.freeze({
24
53
  register({ storage, config }) {
@@ -34,7 +63,7 @@ export const LogWatcher = Object.freeze({
34
63
  return;
35
64
  if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes))
36
65
  return;
37
- if (shouldSkipTraceInfrastructureLog(message))
66
+ if (shouldSkipTraceInfrastructureLog(message, context))
38
67
  return;
39
68
  const content = {
40
69
  level,
@@ -22,7 +22,9 @@ const bindingsInterpolated = (sql, params) => {
22
22
  };
23
23
  const isTraceStorageQuery = (sql) => {
24
24
  const normalized = sql.toLowerCase();
25
- return normalized.includes('zin_trace_entries') || normalized.includes('zin_trace_monitoring');
25
+ return (normalized.includes('zin_trace_entries') ||
26
+ normalized.includes('zin_trace_entries_tags') ||
27
+ normalized.includes('zin_trace_monitoring'));
26
28
  };
27
29
  const emit = (query, params, duration, connection = 'default') => {
28
30
  if (_storage === null || _config === null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.86",
3
+ "version": "0.4.92",
4
4
  "description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@zintrust/core": "^0.4.84"
43
+ "@zintrust/core": "^0.4.91"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
package/src/register.ts CHANGED
@@ -64,6 +64,9 @@ type CoreApi = {
64
64
  Logger?: {
65
65
  warn(message: string, context?: Record<string, unknown>): void;
66
66
  };
67
+ ErrorFactory?: {
68
+ createConfigError(message: string, details?: unknown): Error;
69
+ };
67
70
  StartupConfigFile?: {
68
71
  Trace?: string;
69
72
  };
@@ -72,6 +75,14 @@ type CoreApi = {
72
75
  };
73
76
  };
74
77
 
78
+ type CoreDatabase = import('@zintrust/core').IDatabase;
79
+
80
+ const TRACE_REQUIRED_TABLES = [
81
+ 'zin_trace_entries',
82
+ 'zin_trace_entries_tags',
83
+ 'zin_trace_monitoring',
84
+ ] as const;
85
+
75
86
  type GlobalMiddlewareRegistrarState = {
76
87
  __zintrust_register_global_middleware__?: ITraceWatcherConfig['registerMiddleware'];
77
88
  __zintrust_pending_global_middlewares__?: Array<
@@ -125,7 +136,7 @@ const resolveObservedConnectionName = (
125
136
  return resolveTraceConnectionName(env, configuredObservedConnection);
126
137
  }
127
138
 
128
- const defaultConnectionName = resolveTraceConnectionName(env, undefined);
139
+ const defaultConnectionName = resolveTraceConnectionName(env);
129
140
  if (storageConnectionName !== defaultConnectionName) {
130
141
  return defaultConnectionName;
131
142
  }
@@ -217,6 +228,71 @@ const buildTraceRedactionOverrides = (input: {
217
228
  : undefined;
218
229
  };
219
230
 
231
+ const createTraceConfigError = (coreApi: CoreApi, message: string, details?: unknown): Error => {
232
+ if (coreApi.ErrorFactory?.createConfigError !== undefined) {
233
+ return coreApi.ErrorFactory.createConfigError(message, details);
234
+ }
235
+
236
+ const error = new globalThis.Error(message) as Error & {
237
+ code?: string;
238
+ details?: unknown;
239
+ name?: string;
240
+ statusCode?: number;
241
+ };
242
+ error.name = 'ConfigError';
243
+ error.code = 'CONFIG_ERROR';
244
+ error.statusCode = 500;
245
+ error.details = details;
246
+ return error;
247
+ };
248
+
249
+ function assertTraceConnectionResolved(
250
+ coreApi: CoreApi,
251
+ db: CoreDatabase | undefined,
252
+ params: { connectionName: string; envKey: 'TRACE_DB_CONNECTION' | 'TRACE_QUERY_CONNECTION' }
253
+ ): asserts db is CoreDatabase {
254
+ if (db !== undefined) {
255
+ return;
256
+ }
257
+
258
+ throw createTraceConfigError(
259
+ coreApi,
260
+ `Trace connection "${params.connectionName}" could not be resolved.`,
261
+ {
262
+ connectionName: params.connectionName,
263
+ envKey: params.envKey,
264
+ hint:
265
+ params.envKey === 'TRACE_DB_CONNECTION'
266
+ ? 'Configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.'
267
+ : 'Configure TRACE_QUERY_CONNECTION, or ensure DB_CONNECTION resolves to an existing database connection.',
268
+ }
269
+ );
270
+ }
271
+
272
+ const assertTraceStorageReady = async (
273
+ coreApi: CoreApi,
274
+ db: CoreDatabase,
275
+ connectionName: string
276
+ ): Promise<void> => {
277
+ try {
278
+ await Promise.all(
279
+ TRACE_REQUIRED_TABLES.map(async (table) => {
280
+ await db.queryOne(`SELECT 1 AS ok FROM ${table} LIMIT 1`, []);
281
+ })
282
+ );
283
+ } catch (error) {
284
+ throw createTraceConfigError(
285
+ coreApi,
286
+ `Trace storage connection "${connectionName}" is not ready. Create the database if needed and run \`zin migrate:trace\` before enabling TRACE_ENABLED.`,
287
+ {
288
+ connectionName,
289
+ error,
290
+ requiredTables: [...TRACE_REQUIRED_TABLES],
291
+ }
292
+ );
293
+ }
294
+ };
295
+
220
296
  const core = (await importCore()) as CoreApi;
221
297
  const Env = core.Env;
222
298
  const startupOverrides = resolveTraceStartupOverrides(core);
@@ -292,98 +368,103 @@ if (!traceAlreadyInitialized && Env) {
292
368
  const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
293
369
  const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
294
370
 
295
- if (storageDb && observedDb) {
296
- const storage = TraceWriteDiagnostics.wrapStorage(
297
- TraceContentRedaction.wrapStorage(
298
- TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config),
299
- config.redaction
300
- ),
301
- {
302
- connectionName: resolvedConnectionName,
303
- logger: core.Logger,
304
- }
305
- );
306
-
307
- if (core.RequestContext) {
308
- TraceContext.setRequestContextImpl(
309
- core.RequestContext as {
310
- current?: () => unknown;
311
- peek?: () => unknown;
312
- }
313
- );
371
+ assertTraceConnectionResolved(core, storageDb, {
372
+ connectionName: resolvedConnectionName,
373
+ envKey: 'TRACE_DB_CONNECTION',
374
+ });
375
+ assertTraceConnectionResolved(core, observedDb, {
376
+ connectionName: resolvedObservedConnectionName,
377
+ envKey: 'TRACE_QUERY_CONNECTION',
378
+ });
379
+ await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
380
+
381
+ const storage = TraceWriteDiagnostics.wrapStorage(
382
+ TraceContentRedaction.wrapStorage(
383
+ TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config),
384
+ config.redaction
385
+ ),
386
+ {
387
+ connectionName: resolvedConnectionName,
388
+ logger: core.Logger,
314
389
  }
390
+ );
315
391
 
316
- const [
317
- { HttpWatcher },
318
- { QueryWatcher },
319
- { LogWatcher },
320
- { ExceptionWatcher },
321
- { JobWatcher },
322
- { CacheWatcher },
323
- { ScheduleWatcher },
324
- { MailWatcher },
325
- { AuthWatcher },
326
- { EventWatcher },
327
- { ModelWatcher },
328
- { NotificationWatcher },
329
- { RedisWatcher },
330
- { GateWatcher },
331
- { MiddlewareWatcher },
332
- { CommandWatcher },
333
- { BatchWatcher },
334
- { DumpWatcher },
335
- { ViewWatcher },
336
- { HttpClientWatcher },
337
- ] = await Promise.all([
338
- import('./watchers/HttpWatcher'),
339
- import('./watchers/QueryWatcher'),
340
- import('./watchers/LogWatcher'),
341
- import('./watchers/ExceptionWatcher'),
342
- import('./watchers/JobWatcher'),
343
- import('./watchers/CacheWatcher'),
344
- import('./watchers/ScheduleWatcher'),
345
- import('./watchers/MailWatcher'),
346
- import('./watchers/AuthWatcher'),
347
- import('./watchers/EventWatcher'),
348
- import('./watchers/ModelWatcher'),
349
- import('./watchers/NotificationWatcher'),
350
- import('./watchers/RedisWatcher'),
351
- import('./watchers/GateWatcher'),
352
- import('./watchers/MiddlewareWatcher'),
353
- import('./watchers/CommandWatcher'),
354
- import('./watchers/BatchWatcher'),
355
- import('./watchers/DumpWatcher'),
356
- import('./watchers/ViewWatcher'),
357
- import('./watchers/HttpClientWatcher'),
358
- ]);
359
-
360
- const watcherArgs = { storage, config, db: observedDb };
361
-
362
- HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
363
-
364
- QueryWatcher.register(watcherArgs);
365
- LogWatcher.register(watcherArgs);
366
- ExceptionWatcher.register(watcherArgs);
367
- JobWatcher.register(watcherArgs);
368
- CacheWatcher.register(watcherArgs);
369
- ScheduleWatcher.register(watcherArgs);
370
- MailWatcher.register(watcherArgs);
371
- AuthWatcher.register(watcherArgs);
372
- EventWatcher.register(watcherArgs);
373
- ModelWatcher.register(watcherArgs);
374
- NotificationWatcher.register(watcherArgs);
375
- RedisWatcher.register(watcherArgs);
376
- GateWatcher.register(watcherArgs);
377
- MiddlewareWatcher.register(watcherArgs);
378
- CommandWatcher.register(watcherArgs);
379
- BatchWatcher.register(watcherArgs);
380
- DumpWatcher.register(watcherArgs);
381
- ViewWatcher.register(watcherArgs);
382
- HttpClientWatcher.register(watcherArgs);
383
- } else {
384
- // eslint-disable-next-line no-console
385
- console.warn('[trace] Could not resolve database connection - skipping init.');
392
+ if (core.RequestContext) {
393
+ TraceContext.setRequestContextImpl(
394
+ core.RequestContext as {
395
+ current?: () => unknown;
396
+ peek?: () => unknown;
397
+ }
398
+ );
386
399
  }
400
+
401
+ const [
402
+ { HttpWatcher },
403
+ { QueryWatcher },
404
+ { LogWatcher },
405
+ { ExceptionWatcher },
406
+ { JobWatcher },
407
+ { CacheWatcher },
408
+ { ScheduleWatcher },
409
+ { MailWatcher },
410
+ { AuthWatcher },
411
+ { EventWatcher },
412
+ { ModelWatcher },
413
+ { NotificationWatcher },
414
+ { RedisWatcher },
415
+ { GateWatcher },
416
+ { MiddlewareWatcher },
417
+ { CommandWatcher },
418
+ { BatchWatcher },
419
+ { DumpWatcher },
420
+ { ViewWatcher },
421
+ { HttpClientWatcher },
422
+ ] = await Promise.all([
423
+ import('./watchers/HttpWatcher'),
424
+ import('./watchers/QueryWatcher'),
425
+ import('./watchers/LogWatcher'),
426
+ import('./watchers/ExceptionWatcher'),
427
+ import('./watchers/JobWatcher'),
428
+ import('./watchers/CacheWatcher'),
429
+ import('./watchers/ScheduleWatcher'),
430
+ import('./watchers/MailWatcher'),
431
+ import('./watchers/AuthWatcher'),
432
+ import('./watchers/EventWatcher'),
433
+ import('./watchers/ModelWatcher'),
434
+ import('./watchers/NotificationWatcher'),
435
+ import('./watchers/RedisWatcher'),
436
+ import('./watchers/GateWatcher'),
437
+ import('./watchers/MiddlewareWatcher'),
438
+ import('./watchers/CommandWatcher'),
439
+ import('./watchers/BatchWatcher'),
440
+ import('./watchers/DumpWatcher'),
441
+ import('./watchers/ViewWatcher'),
442
+ import('./watchers/HttpClientWatcher'),
443
+ ]);
444
+
445
+ const watcherArgs = { storage, config, db: observedDb };
446
+
447
+ HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
448
+
449
+ QueryWatcher.register(watcherArgs);
450
+ LogWatcher.register(watcherArgs);
451
+ ExceptionWatcher.register(watcherArgs);
452
+ JobWatcher.register(watcherArgs);
453
+ CacheWatcher.register(watcherArgs);
454
+ ScheduleWatcher.register(watcherArgs);
455
+ MailWatcher.register(watcherArgs);
456
+ AuthWatcher.register(watcherArgs);
457
+ EventWatcher.register(watcherArgs);
458
+ ModelWatcher.register(watcherArgs);
459
+ NotificationWatcher.register(watcherArgs);
460
+ RedisWatcher.register(watcherArgs);
461
+ GateWatcher.register(watcherArgs);
462
+ MiddlewareWatcher.register(watcherArgs);
463
+ CommandWatcher.register(watcherArgs);
464
+ BatchWatcher.register(watcherArgs);
465
+ DumpWatcher.register(watcherArgs);
466
+ ViewWatcher.register(watcherArgs);
467
+ HttpClientWatcher.register(watcherArgs);
387
468
  }
388
469
  } else if (!traceAlreadyInitialized) {
389
470
  // Running outside a ZinTrust project - skip init silently.
@@ -21,8 +21,50 @@ const TRACE_INFRASTRUCTURE_LOG_MESSAGES = new Set<string>([
21
21
  '[trace] Trace storage write degraded',
22
22
  ]);
23
23
 
24
- const shouldSkipTraceInfrastructureLog = (message: string): boolean => {
25
- return TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim());
24
+ const TRACE_STORAGE_TABLE_NAMES = [
25
+ 'zin_trace_entries',
26
+ 'zin_trace_entries_tags',
27
+ 'zin_trace_monitoring',
28
+ ];
29
+
30
+ const isTraceStorageQuery = (sql: string): boolean => {
31
+ const normalized = sql.toLowerCase();
32
+ return TRACE_STORAGE_TABLE_NAMES.some((tableName) => normalized.includes(tableName));
33
+ };
34
+
35
+ const extractSqlFromLog = (
36
+ message: string,
37
+ context?: Record<string, unknown>
38
+ ): string | undefined => {
39
+ const contextSql = context?.['sql'];
40
+ if (typeof contextSql === 'string') return contextSql;
41
+
42
+ const trimmed = message.trim();
43
+ const rawPrefix = 'Raw SQL Query executed:';
44
+ if (trimmed.startsWith(rawPrefix)) {
45
+ const sql = trimmed.slice(rawPrefix.length).trim();
46
+ return sql === '' ? undefined : sql;
47
+ }
48
+
49
+ return undefined;
50
+ };
51
+
52
+ const isTraceStorageQueryLog = (message: string, context?: Record<string, unknown>): boolean => {
53
+ const normalizedMessage = message.trim().toLowerCase();
54
+ if (!normalizedMessage.includes('query executed')) return false;
55
+
56
+ const sql = extractSqlFromLog(message, context);
57
+ return typeof sql === 'string' && isTraceStorageQuery(sql);
58
+ };
59
+
60
+ const shouldSkipTraceInfrastructureLog = (
61
+ message: string,
62
+ context?: Record<string, unknown>
63
+ ): boolean => {
64
+ return (
65
+ TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim()) ||
66
+ isTraceStorageQueryLog(message, context)
67
+ );
26
68
  };
27
69
 
28
70
  export const LogWatcher: ITraceWatcher = Object.freeze({
@@ -41,7 +83,7 @@ export const LogWatcher: ITraceWatcher = Object.freeze({
41
83
  (level: string, message: string, context?: Record<string, unknown>) => {
42
84
  if ((LEVEL_PRIORITY[level] ?? 0) < minPriority) return;
43
85
  if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes)) return;
44
- if (shouldSkipTraceInfrastructureLog(message)) return;
86
+ if (shouldSkipTraceInfrastructureLog(message, context)) return;
45
87
 
46
88
  const content: LogContent = {
47
89
  level,
@@ -24,7 +24,11 @@ const bindingsInterpolated = (sql: string, params: unknown[]): string => {
24
24
 
25
25
  const isTraceStorageQuery = (sql: string): boolean => {
26
26
  const normalized = sql.toLowerCase();
27
- return normalized.includes('zin_trace_entries') || normalized.includes('zin_trace_monitoring');
27
+ return (
28
+ normalized.includes('zin_trace_entries') ||
29
+ normalized.includes('zin_trace_entries_tags') ||
30
+ normalized.includes('zin_trace_monitoring')
31
+ );
28
32
  };
29
33
 
30
34
  const emit = (query: string, params: unknown[], duration: number, connection = 'default'): void => {