@zintrust/trace 1.6.6 → 1.6.7

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.
Files changed (49) hide show
  1. package/package.json +2 -3
  2. package/src/TraceConnection.ts +0 -182
  3. package/src/cli-register.ts +0 -63
  4. package/src/config.ts +0 -383
  5. package/src/context.ts +0 -101
  6. package/src/dashboard/handlers.ts +0 -353
  7. package/src/dashboard/routes.ts +0 -114
  8. package/src/dashboard/ui.ts +0 -1262
  9. package/src/dashboard/zintrust-debuger.svg +0 -30
  10. package/src/index.ts +0 -102
  11. package/src/ingest/TraceIngestGateway.ts +0 -414
  12. package/src/plugin.ts +0 -9
  13. package/src/register.ts +0 -702
  14. package/src/storage/ProxyTraceStorage.ts +0 -190
  15. package/src/storage/TraceContentBudget.ts +0 -493
  16. package/src/storage/TraceContentRedaction.ts +0 -44
  17. package/src/storage/TraceEntryFiltering.ts +0 -50
  18. package/src/storage/TraceServiceTag.ts +0 -56
  19. package/src/storage/TraceStorage.ts +0 -543
  20. package/src/storage/TraceWriteDiagnostics.ts +0 -289
  21. package/src/storage/index.ts +0 -4
  22. package/src/types.ts +0 -430
  23. package/src/ui.ts +0 -9
  24. package/src/utils/authTag.ts +0 -20
  25. package/src/utils/entryFilter.ts +0 -131
  26. package/src/utils/familyHash.ts +0 -8
  27. package/src/utils/redact.ts +0 -112
  28. package/src/utils/requestFilter.ts +0 -79
  29. package/src/utils/stackFrame.ts +0 -44
  30. package/src/watchers/AuthWatcher.ts +0 -53
  31. package/src/watchers/BatchWatcher.ts +0 -55
  32. package/src/watchers/CacheWatcher.ts +0 -72
  33. package/src/watchers/CommandWatcher.ts +0 -58
  34. package/src/watchers/DumpWatcher.ts +0 -45
  35. package/src/watchers/EventWatcher.ts +0 -46
  36. package/src/watchers/ExceptionWatcher.ts +0 -130
  37. package/src/watchers/GateWatcher.ts +0 -53
  38. package/src/watchers/HttpClientWatcher.ts +0 -219
  39. package/src/watchers/HttpWatcher.ts +0 -249
  40. package/src/watchers/JobWatcher.ts +0 -124
  41. package/src/watchers/LogWatcher.ts +0 -120
  42. package/src/watchers/MailWatcher.ts +0 -65
  43. package/src/watchers/MiddlewareWatcher.ts +0 -54
  44. package/src/watchers/ModelWatcher.ts +0 -60
  45. package/src/watchers/NotificationWatcher.ts +0 -60
  46. package/src/watchers/QueryWatcher.ts +0 -105
  47. package/src/watchers/RedisWatcher.ts +0 -42
  48. package/src/watchers/ScheduleWatcher.ts +0 -57
  49. package/src/watchers/ViewWatcher.ts +0 -40
package/src/register.ts DELETED
@@ -1,702 +0,0 @@
1
- /**
2
- * @zintrust/trace register side-effect module.
3
- *
4
- * For plugin-file activation, prefer:
5
- * import '@zintrust/trace/plugin';
6
- *
7
- * The framework boot layer will lazy-load this register module once the app
8
- * runtime is ready. Importing this file directly is still supported for
9
- * advanced manual bootstrap flows that intentionally activate the trace
10
- * after databases and the kernel are available.
11
- *
12
- * Config is read from environment variables (TRACE_* keys) matching
13
- * the defaults in TraceConfig. For custom overrides supply them via
14
- * calling `initTrace(overrides)` instead.
15
- *
16
- * Routes are NOT auto-mounted here. Wire the dashboard into your router:
17
- * import { registerTraceDashboard } from '@zintrust/trace/ui';
18
- * registerTraceDashboard(router, {
19
- * middleware: ['admin'],
20
- * });
21
- */
22
- import { TraceConfig } from './config';
23
- import { TraceContext } from './context';
24
- import { ProxyTraceStorage, TraceServiceTag, TraceStorage } from './storage';
25
- import { TraceContentBudget } from './storage/TraceContentBudget';
26
- import { TraceContentRedaction } from './storage/TraceContentRedaction';
27
- import { TraceEntryFiltering } from './storage/TraceEntryFiltering';
28
- import { TraceWriteDiagnostics } from './storage/TraceWriteDiagnostics';
29
- import {
30
- assertTraceConnectionResolved,
31
- assertTraceStorageReady,
32
- resolveObservedConnectionName,
33
- resolveTraceConnectionName,
34
- } from './TraceConnection';
35
- import type { ITraceWatcherConfig, TraceConfigOverrides } from './types';
36
-
37
- export type {}; // side-effect ESM module
38
-
39
- type GlobalTraceRegisterState = {
40
- __zintrust_system_trace_register_initialized__?: boolean;
41
- __zintrust_system_trace_plugin_requested__?: boolean;
42
- __zintrust_system_trace_connection_name__?: string;
43
- __zintrust_system_trace_observe_connection_name__?: string;
44
- };
45
-
46
- const globalTraceRegisterState = globalThis as unknown as GlobalTraceRegisterState;
47
- const traceAlreadyInitialized =
48
- globalTraceRegisterState.__zintrust_system_trace_register_initialized__ === true;
49
-
50
- if (!traceAlreadyInitialized) {
51
- globalTraceRegisterState.__zintrust_system_trace_register_initialized__ = true;
52
- }
53
-
54
- const importCore = async (): Promise<unknown> => {
55
- try {
56
- return await import('@zintrust/core');
57
- } catch {
58
- return {};
59
- }
60
- };
61
-
62
- type CoreApi = {
63
- Env?: {
64
- getBool(key: string, fallback: boolean): boolean;
65
- get(key: string, fallback: string): string;
66
- getInt(key: string, fallback: number): number;
67
- };
68
- useDatabase?: (config?: unknown, connection?: string) => import('@zintrust/core').IDatabase;
69
- RequestContext?: {
70
- current(): unknown;
71
- };
72
- Logger?: {
73
- warn(message: string, context?: Record<string, unknown>): void;
74
- };
75
- ErrorFactory?: {
76
- createConfigError(message: string, details?: unknown): Error;
77
- };
78
- StartupConfigFile?: {
79
- Trace?: string;
80
- };
81
- StartupConfigFileRegistry?: {
82
- preload?(files: readonly string[]): Promise<void>;
83
- get<T>(file: string): T | undefined;
84
- has?(file: string): boolean;
85
- };
86
- };
87
-
88
- type GlobalMiddlewareRegistrarState = {
89
- __zintrust_register_global_middleware__?: ITraceWatcherConfig['registerMiddleware'];
90
- __zintrust_pending_global_middlewares__?: Array<
91
- Parameters<NonNullable<ITraceWatcherConfig['registerMiddleware']>>[0]
92
- >;
93
- };
94
-
95
- const resolveRegisterMiddleware = (): NonNullable<ITraceWatcherConfig['registerMiddleware']> => {
96
- const globalMiddlewareRegistrarState = globalThis as unknown as GlobalMiddlewareRegistrarState;
97
-
98
- return (middleware): void => {
99
- const registerMiddleware =
100
- globalMiddlewareRegistrarState.__zintrust_register_global_middleware__;
101
- if (typeof registerMiddleware === 'function') {
102
- registerMiddleware(middleware);
103
- return;
104
- }
105
-
106
- globalMiddlewareRegistrarState.__zintrust_pending_global_middlewares__ ??= [];
107
- globalMiddlewareRegistrarState.__zintrust_pending_global_middlewares__.push(middleware);
108
- };
109
- };
110
-
111
- const isObjectValue = (value: unknown): value is Record<string, unknown> => {
112
- return typeof value === 'object' && value !== null && !Array.isArray(value);
113
- };
114
-
115
- const parseEnvList = (rawValue: string): string[] | undefined => {
116
- const value = rawValue.trim();
117
- if (value === '') return undefined;
118
-
119
- if (value.startsWith('[')) {
120
- try {
121
- const parsed = JSON.parse(value) as unknown;
122
- if (Array.isArray(parsed)) {
123
- return parsed
124
- .filter((entry): entry is string => typeof entry === 'string')
125
- .map((entry) => entry.trim())
126
- .filter((entry) => entry !== '');
127
- }
128
- } catch {
129
- // fall through to CSV parsing
130
- }
131
- }
132
-
133
- return value
134
- .split(',')
135
- .map((entry) => entry.trim())
136
- .filter((entry) => entry !== '');
137
- };
138
-
139
- const parseEnvBool = (rawValue: string): boolean | undefined => {
140
- const value = rawValue.trim().toLowerCase();
141
- if (value === '') return undefined;
142
- if (['1', 'true', 'yes', 'on'].includes(value)) return true;
143
- if (['0', 'false', 'no', 'off'].includes(value)) return false;
144
- return undefined;
145
- };
146
-
147
- const resolveTraceStartupOverrides = async (
148
- core: CoreApi
149
- ): Promise<TraceConfigOverrides | undefined> => {
150
- const traceConfigFile = core.StartupConfigFile?.Trace;
151
- if (typeof traceConfigFile !== 'string' || traceConfigFile.trim() === '') return undefined;
152
-
153
- const registry = core.StartupConfigFileRegistry;
154
- if (registry?.has?.(traceConfigFile) !== true && typeof registry?.preload === 'function') {
155
- await registry.preload([traceConfigFile]);
156
- }
157
-
158
- const overrides = registry?.get<unknown>(traceConfigFile);
159
- return isObjectValue(overrides) ? (overrides as TraceConfigOverrides) : undefined;
160
- };
161
-
162
- const buildTraceRedactionOverrides = (input: {
163
- startupOverrides?: TraceConfigOverrides;
164
- redactionBody?: string[];
165
- redactionHeaders?: string[];
166
- redactionKeys?: string[];
167
- redactionQuery?: string[];
168
- }): TraceConfigOverrides['redaction'] | undefined => {
169
- const redaction: Partial<NonNullable<TraceConfigOverrides['redaction']>> = {
170
- ...(isObjectValue(input.startupOverrides?.redaction) ? input.startupOverrides?.redaction : {}),
171
- };
172
-
173
- if (input.redactionKeys === undefined) {
174
- // no-op
175
- } else {
176
- redaction.keys = input.redactionKeys;
177
- }
178
-
179
- if (input.redactionHeaders === undefined) {
180
- // no-op
181
- } else {
182
- redaction.headers = input.redactionHeaders;
183
- }
184
-
185
- if (input.redactionBody === undefined) {
186
- // no-op
187
- } else {
188
- redaction.body = input.redactionBody;
189
- }
190
-
191
- if (input.redactionQuery === undefined) {
192
- // no-op
193
- } else {
194
- redaction.query = input.redactionQuery;
195
- }
196
-
197
- return Object.keys(redaction).length > 0
198
- ? (redaction as NonNullable<TraceConfigOverrides['redaction']>)
199
- : undefined;
200
- };
201
-
202
- type TraceEnvApi = NonNullable<CoreApi['Env']>;
203
-
204
- type TraceEnvValues = {
205
- connectionRaw: string;
206
- observeConnectionRaw: string;
207
- pruneAfterHoursRaw: string;
208
- slowQueryThresholdRaw: string;
209
- logMinLevelRaw: string;
210
- traceProxyRaw: string;
211
- traceProxyUrlRaw: string;
212
- traceProxyPathRaw: string;
213
- traceProxyKeyIdRaw: string;
214
- traceProxySecretRaw: string;
215
- traceProxyTimeoutRaw: string;
216
- traceServiceTagRaw: string;
217
- appNameRaw: string;
218
- appKeyRaw: string;
219
- captureCachePayloadsRaw: string;
220
- captureQueryBindingsRaw: string;
221
- contentDispatchDriverRaw: string;
222
- contentDispatchQueueRaw: string;
223
- contentDispatchEnqueueTimeoutRaw: string;
224
- contentDispatchWorkerEnabledRaw: string;
225
- contentDispatchWorkerIntervalRaw: string;
226
- contentDispatchWorkerDurationRaw: string;
227
- contentDispatchWorkerConcurrencyRaw: string;
228
- redactionKeys?: string[];
229
- redactionHeaders?: string[];
230
- redactionBody?: string[];
231
- redactionQuery?: string[];
232
- };
233
-
234
- const readTraceEnvValues = (Env: TraceEnvApi): TraceEnvValues => {
235
- return {
236
- connectionRaw: Env.get('TRACE_DB_CONNECTION', '').trim(),
237
- observeConnectionRaw: Env.get('TRACE_QUERY_CONNECTION', '').trim(),
238
- pruneAfterHoursRaw: Env.get('TRACE_PRUNE_HOURS', '').trim(),
239
- slowQueryThresholdRaw: Env.get('TRACE_SLOW_QUERY_MS', '').trim(),
240
- logMinLevelRaw: Env.get('TRACE_LOG_LEVEL', '').trim(),
241
- traceProxyRaw: Env.get('TRACE_PROXY', '').trim(),
242
- traceProxyUrlRaw: Env.get('TRACE_PROXY_URL', '').trim(),
243
- traceProxyPathRaw: Env.get('TRACE_PROXY_PATH', '').trim(),
244
- traceProxyKeyIdRaw: Env.get('TRACE_PROXY_KEY_ID', '').trim(),
245
- traceProxySecretRaw: Env.get('TRACE_PROXY_SECRET', '').trim(),
246
- traceProxyTimeoutRaw: Env.get('TRACE_PROXY_TIMEOUT_MS', '').trim(),
247
- traceServiceTagRaw: Env.get('TRACE_SERVICE_TAG', '').trim(),
248
- appNameRaw: Env.get('APP_NAME', '').trim(),
249
- appKeyRaw: Env.get('APP_KEY', '').trim(),
250
- captureCachePayloadsRaw: Env.get('TRACE_CACHE_PAYLOADS', '').trim(),
251
- captureQueryBindingsRaw: Env.get('TRACE_QUERY_BINDINGS', '').trim(),
252
- contentDispatchDriverRaw: Env.get('TRACE_CONTENT_QUEUE_DRIVER', '').trim(),
253
- contentDispatchQueueRaw: Env.get('TRACE_CONTENT_QUEUE_NAME', '').trim(),
254
- contentDispatchEnqueueTimeoutRaw: Env.get('TRACE_CONTENT_QUEUE_ENQUEUE_TIMEOUT_MS', '').trim(),
255
- contentDispatchWorkerEnabledRaw: Env.get('TRACE_CONTENT_QUEUE_WORKER_ENABLED', '').trim(),
256
- contentDispatchWorkerIntervalRaw: Env.get('TRACE_CONTENT_QUEUE_WORKER_INTERVAL_MS', '').trim(),
257
- contentDispatchWorkerDurationRaw: Env.get(
258
- 'TRACE_CONTENT_QUEUE_WORKER_MAX_DURATION_MS',
259
- ''
260
- ).trim(),
261
- contentDispatchWorkerConcurrencyRaw: Env.get(
262
- 'TRACE_CONTENT_QUEUE_WORKER_CONCURRENCY',
263
- ''
264
- ).trim(),
265
- redactionKeys: parseEnvList(Env.get('TRACE_REDACT_KEYS', '')),
266
- redactionHeaders: parseEnvList(Env.get('TRACE_REDACT_HEADERS', '')),
267
- redactionBody: parseEnvList(Env.get('TRACE_REDACT_BODY', '')),
268
- redactionQuery: parseEnvList(Env.get('TRACE_REDACT_QUERY', '')),
269
- };
270
- };
271
-
272
- const resolveStringOverride = (
273
- rawValue: string,
274
- fallback: string | undefined
275
- ): string | undefined => {
276
- return rawValue === '' ? fallback : rawValue;
277
- };
278
-
279
- const resolveNumberOverride = (
280
- rawValue: string,
281
- fallback: number | undefined
282
- ): number | undefined => {
283
- return rawValue === '' ? fallback : Number.parseInt(rawValue, 10);
284
- };
285
-
286
- const resolveBooleanOverride = (
287
- rawValue: string,
288
- fallback: boolean | undefined
289
- ): boolean | undefined => {
290
- return parseEnvBool(rawValue) ?? fallback;
291
- };
292
-
293
- const resolveTraceProxyKeyId = (
294
- startupOverrides: TraceConfigOverrides | undefined,
295
- values: TraceEnvValues
296
- ): string | undefined => {
297
- return resolveStringOverride(
298
- values.traceProxyKeyIdRaw,
299
- startupOverrides?.proxy?.keyId ?? values.appNameRaw
300
- );
301
- };
302
-
303
- const resolveTraceProxySecret = (
304
- startupOverrides: TraceConfigOverrides | undefined,
305
- values: TraceEnvValues
306
- ): string | undefined => {
307
- return resolveStringOverride(
308
- values.traceProxySecretRaw,
309
- startupOverrides?.proxy?.secret ?? values.appKeyRaw
310
- );
311
- };
312
-
313
- const withStringProperty = (key: string, value: string | undefined): Record<string, string> => {
314
- return typeof value === 'string' && value !== '' ? { [key]: value } : {};
315
- };
316
-
317
- const withNumberProperty = (key: string, value: number | undefined): Record<string, number> => {
318
- return typeof value === 'number' && Number.isFinite(value) ? { [key]: value } : {};
319
- };
320
-
321
- const withBooleanProperty = (key: string, value: boolean | undefined): Record<string, boolean> => {
322
- return typeof value === 'boolean' ? { [key]: value } : {};
323
- };
324
-
325
- const resolveTraceServiceTag = (
326
- startupOverrides: TraceConfigOverrides | undefined,
327
- values: TraceEnvValues
328
- ): string | undefined => {
329
- const fallback = (startupOverrides?.serviceTag ?? values.appNameRaw).trim() || undefined;
330
- return resolveStringOverride(values.traceServiceTagRaw, fallback);
331
- };
332
-
333
- const resolveContentDispatchWorkerEnabled = (
334
- startupOverrides: TraceConfigOverrides | undefined,
335
- values: TraceEnvValues
336
- ): boolean | undefined => {
337
- return resolveBooleanOverride(
338
- values.contentDispatchWorkerEnabledRaw,
339
- startupOverrides?.contentDispatch?.worker?.enabled
340
- );
341
- };
342
-
343
- const resolveContentDispatchWorkerInterval = (
344
- startupOverrides: TraceConfigOverrides | undefined,
345
- values: TraceEnvValues
346
- ): number | undefined => {
347
- return resolveNumberOverride(
348
- values.contentDispatchWorkerIntervalRaw,
349
- startupOverrides?.contentDispatch?.worker?.intervalMs
350
- );
351
- };
352
-
353
- const resolveContentDispatchWorkerDuration = (
354
- startupOverrides: TraceConfigOverrides | undefined,
355
- values: TraceEnvValues
356
- ): number | undefined => {
357
- return resolveNumberOverride(
358
- values.contentDispatchWorkerDurationRaw,
359
- startupOverrides?.contentDispatch?.worker?.maxDurationMs
360
- );
361
- };
362
-
363
- const resolveContentDispatchWorkerConcurrency = (
364
- startupOverrides: TraceConfigOverrides | undefined,
365
- values: TraceEnvValues
366
- ): number | undefined => {
367
- return resolveNumberOverride(
368
- values.contentDispatchWorkerConcurrencyRaw,
369
- startupOverrides?.contentDispatch?.worker?.concurrency
370
- );
371
- };
372
-
373
- const buildTraceContentDispatchWorkerConfig = (
374
- startupOverrides: TraceConfigOverrides | undefined,
375
- values: TraceEnvValues
376
- ): NonNullable<NonNullable<TraceConfigOverrides['contentDispatch']>['worker']> => {
377
- const defaultWorker = TraceConfig.defaults().contentDispatch.worker;
378
- const startupWorker = startupOverrides?.contentDispatch?.worker;
379
- const contentDispatchWorkerEnabled = resolveContentDispatchWorkerEnabled(
380
- startupOverrides,
381
- values
382
- );
383
- const contentDispatchWorkerInterval = resolveContentDispatchWorkerInterval(
384
- startupOverrides,
385
- values
386
- );
387
- const contentDispatchWorkerDuration = resolveContentDispatchWorkerDuration(
388
- startupOverrides,
389
- values
390
- );
391
- const contentDispatchWorkerConcurrency = resolveContentDispatchWorkerConcurrency(
392
- startupOverrides,
393
- values
394
- );
395
-
396
- return {
397
- ...defaultWorker,
398
- ...startupWorker,
399
- enabled: contentDispatchWorkerEnabled ?? startupWorker?.enabled ?? defaultWorker.enabled,
400
- intervalMs:
401
- contentDispatchWorkerInterval ?? startupWorker?.intervalMs ?? defaultWorker.intervalMs,
402
- maxDurationMs:
403
- contentDispatchWorkerDuration ?? startupWorker?.maxDurationMs ?? defaultWorker.maxDurationMs,
404
- concurrency:
405
- contentDispatchWorkerConcurrency ?? startupWorker?.concurrency ?? defaultWorker.concurrency,
406
- };
407
- };
408
-
409
- const buildTraceProxyConfig = (
410
- startupOverrides: TraceConfigOverrides | undefined,
411
- values: TraceEnvValues
412
- ): TraceConfigOverrides['proxy'] => {
413
- const traceProxyEnabled = resolveBooleanOverride(
414
- values.traceProxyRaw,
415
- startupOverrides?.proxy?.enabled
416
- );
417
- const traceProxyUrl = resolveStringOverride(
418
- values.traceProxyUrlRaw,
419
- startupOverrides?.proxy?.url
420
- );
421
- const traceProxyPath = resolveStringOverride(
422
- values.traceProxyPathRaw,
423
- startupOverrides?.proxy?.path
424
- );
425
- const traceProxyKeyId = resolveTraceProxyKeyId(startupOverrides, values);
426
- const traceProxySecret = resolveTraceProxySecret(startupOverrides, values);
427
- const traceProxyTimeout = resolveNumberOverride(
428
- values.traceProxyTimeoutRaw,
429
- startupOverrides?.proxy?.timeoutMs
430
- );
431
-
432
- return {
433
- ...TraceConfig.defaults().proxy,
434
- ...startupOverrides?.proxy,
435
- ...withBooleanProperty('enabled', traceProxyEnabled),
436
- ...withStringProperty('url', traceProxyUrl),
437
- ...withStringProperty('path', traceProxyPath),
438
- ...withStringProperty('keyId', traceProxyKeyId),
439
- ...withStringProperty('secret', traceProxySecret),
440
- ...withNumberProperty('timeoutMs', traceProxyTimeout),
441
- };
442
- };
443
-
444
- const buildTraceContentDispatchConfig = (
445
- startupOverrides: TraceConfigOverrides | undefined,
446
- values: TraceEnvValues
447
- ): NonNullable<TraceConfigOverrides['contentDispatch']> => {
448
- const defaultContentDispatch = TraceConfig.defaults().contentDispatch;
449
- const startupContentDispatch = startupOverrides?.contentDispatch;
450
- const contentDispatchDriver = resolveStringOverride(
451
- values.contentDispatchDriverRaw,
452
- startupContentDispatch?.driver
453
- );
454
- const contentDispatchQueueName = resolveStringOverride(
455
- values.contentDispatchQueueRaw,
456
- startupContentDispatch?.queueName
457
- );
458
- const contentDispatchEnqueueTimeout = resolveNumberOverride(
459
- values.contentDispatchEnqueueTimeoutRaw,
460
- startupContentDispatch?.enqueueTimeoutMs
461
- );
462
-
463
- return {
464
- ...defaultContentDispatch,
465
- ...startupContentDispatch,
466
- ...withStringProperty('driver', contentDispatchDriver),
467
- ...withStringProperty('queueName', contentDispatchQueueName),
468
- ...withNumberProperty('enqueueTimeoutMs', contentDispatchEnqueueTimeout),
469
- worker: buildTraceContentDispatchWorkerConfig(startupOverrides, values),
470
- };
471
- };
472
-
473
- const buildTraceRuntimeConfig = (
474
- Env: TraceEnvApi,
475
- startupOverrides: TraceConfigOverrides | undefined
476
- ): ReturnType<typeof TraceConfig.merge> => {
477
- const values = readTraceEnvValues(Env);
478
- const enabled = startupOverrides?.enabled === true || Env.getBool('TRACE_ENABLED', false);
479
- const connection = resolveStringOverride(values.connectionRaw, startupOverrides?.connection);
480
- const observeConnection = resolveStringOverride(
481
- values.observeConnectionRaw,
482
- startupOverrides?.observeConnection
483
- );
484
- const pruneAfterHours = resolveNumberOverride(
485
- values.pruneAfterHoursRaw,
486
- startupOverrides?.pruneAfterHours
487
- );
488
- const slowQueryThreshold = resolveNumberOverride(
489
- values.slowQueryThresholdRaw,
490
- startupOverrides?.slowQueryThreshold
491
- );
492
- const logMinLevel = (
493
- values.logMinLevelRaw === '' ? startupOverrides?.logMinLevel : values.logMinLevelRaw
494
- ) as 'debug' | 'info' | 'warn' | 'error' | 'fatal';
495
- const captureCachePayloads = resolveBooleanOverride(
496
- values.captureCachePayloadsRaw,
497
- startupOverrides?.captureCachePayloads
498
- );
499
- const captureQueryBindings = resolveBooleanOverride(
500
- values.captureQueryBindingsRaw,
501
- startupOverrides?.captureQueryBindings
502
- );
503
- const traceServiceTag = resolveTraceServiceTag(startupOverrides, values);
504
- const redaction = buildTraceRedactionOverrides({
505
- startupOverrides,
506
- redactionBody: values.redactionBody,
507
- redactionHeaders: values.redactionHeaders,
508
- redactionKeys: values.redactionKeys,
509
- redactionQuery: values.redactionQuery,
510
- });
511
-
512
- return TraceConfig.merge({
513
- ...startupOverrides,
514
- enabled,
515
- connection,
516
- observeConnection,
517
- ...withStringProperty('serviceTag', traceServiceTag),
518
- proxy: buildTraceProxyConfig(startupOverrides, values),
519
- ...withNumberProperty('pruneAfterHours', pruneAfterHours),
520
- ...withNumberProperty('slowQueryThreshold', slowQueryThreshold),
521
- ...withBooleanProperty('captureCachePayloads', captureCachePayloads),
522
- ...withBooleanProperty('captureQueryBindings', captureQueryBindings),
523
- contentDispatch: buildTraceContentDispatchConfig(startupOverrides, values),
524
- logMinLevel,
525
- ...(redaction === undefined ? {} : { redaction }),
526
- });
527
- };
528
-
529
- const createTraceWatcherArgs = async (
530
- core: CoreApi,
531
- Env: TraceEnvApi,
532
- config: ReturnType<typeof TraceConfig.merge>
533
- ): Promise<Pick<ITraceWatcherConfig, 'storage' | 'config' | 'db'>> => {
534
- const resolvedConnectionName = resolveTraceConnectionName(Env, config.connection);
535
- const resolvedObservedConnectionName = resolveObservedConnectionName(
536
- Env,
537
- config.observeConnection,
538
- resolvedConnectionName
539
- );
540
- globalTraceRegisterState.__zintrust_system_trace_connection_name__ = resolvedConnectionName;
541
- globalTraceRegisterState.__zintrust_system_trace_observe_connection_name__ =
542
- resolvedObservedConnectionName;
543
-
544
- let resolvedStorage;
545
-
546
- if (config.proxy.enabled) {
547
- resolvedStorage = ProxyTraceStorage.create({
548
- baseUrl: config.proxy.url ?? '',
549
- path: config.proxy.path,
550
- keyId: config.proxy.keyId ?? '',
551
- secret: config.proxy.secret ?? '',
552
- timeoutMs: config.proxy.timeoutMs,
553
- });
554
- } else {
555
- const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
556
-
557
- assertTraceConnectionResolved(core, storageDb, {
558
- connectionName: resolvedConnectionName,
559
- envKey: 'TRACE_DB_CONNECTION',
560
- });
561
- await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
562
-
563
- resolvedStorage = TraceStorage.resolveStorage(storageDb);
564
- }
565
-
566
- const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
567
-
568
- assertTraceConnectionResolved(core, observedDb, {
569
- connectionName: resolvedObservedConnectionName,
570
- envKey: 'TRACE_QUERY_CONNECTION',
571
- });
572
-
573
- const storage = TraceWriteDiagnostics.wrapStorage(
574
- TraceContentBudget.wrapStorage(
575
- TraceContentRedaction.wrapStorage(
576
- TraceEntryFiltering.wrapStorage(
577
- TraceServiceTag.wrapStorage(resolvedStorage, config),
578
- config
579
- ),
580
- config.redaction
581
- ),
582
- config
583
- ),
584
- {
585
- connectionName: resolvedConnectionName,
586
- logger: core.Logger,
587
- }
588
- );
589
-
590
- return { storage, config, db: observedDb };
591
- };
592
-
593
- const registerTraceWatchers = async (
594
- watcherArgs: Pick<ITraceWatcherConfig, 'storage' | 'config' | 'db'>
595
- ): Promise<void> => {
596
- const [
597
- { HttpWatcher },
598
- { QueryWatcher },
599
- { LogWatcher },
600
- { ExceptionWatcher },
601
- { JobWatcher },
602
- { CacheWatcher },
603
- { ScheduleWatcher },
604
- { MailWatcher },
605
- { AuthWatcher },
606
- { EventWatcher },
607
- { ModelWatcher },
608
- { NotificationWatcher },
609
- { RedisWatcher },
610
- { GateWatcher },
611
- { MiddlewareWatcher },
612
- { CommandWatcher },
613
- { BatchWatcher },
614
- { DumpWatcher },
615
- { ViewWatcher },
616
- { HttpClientWatcher },
617
- ] = await Promise.all([
618
- import('./watchers/HttpWatcher'),
619
- import('./watchers/QueryWatcher'),
620
- import('./watchers/LogWatcher'),
621
- import('./watchers/ExceptionWatcher'),
622
- import('./watchers/JobWatcher'),
623
- import('./watchers/CacheWatcher'),
624
- import('./watchers/ScheduleWatcher'),
625
- import('./watchers/MailWatcher'),
626
- import('./watchers/AuthWatcher'),
627
- import('./watchers/EventWatcher'),
628
- import('./watchers/ModelWatcher'),
629
- import('./watchers/NotificationWatcher'),
630
- import('./watchers/RedisWatcher'),
631
- import('./watchers/GateWatcher'),
632
- import('./watchers/MiddlewareWatcher'),
633
- import('./watchers/CommandWatcher'),
634
- import('./watchers/BatchWatcher'),
635
- import('./watchers/DumpWatcher'),
636
- import('./watchers/ViewWatcher'),
637
- import('./watchers/HttpClientWatcher'),
638
- ]);
639
-
640
- HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
641
- QueryWatcher.register(watcherArgs);
642
- LogWatcher.register(watcherArgs);
643
- ExceptionWatcher.register(watcherArgs);
644
- JobWatcher.register(watcherArgs);
645
- CacheWatcher.register(watcherArgs);
646
- ScheduleWatcher.register(watcherArgs);
647
- MailWatcher.register(watcherArgs);
648
- AuthWatcher.register(watcherArgs);
649
- EventWatcher.register(watcherArgs);
650
- ModelWatcher.register(watcherArgs);
651
- NotificationWatcher.register(watcherArgs);
652
- RedisWatcher.register(watcherArgs);
653
- GateWatcher.register(watcherArgs);
654
- MiddlewareWatcher.register(watcherArgs);
655
- CommandWatcher.register(watcherArgs);
656
- BatchWatcher.register(watcherArgs);
657
- DumpWatcher.register(watcherArgs);
658
- ViewWatcher.register(watcherArgs);
659
- HttpClientWatcher.register(watcherArgs);
660
- };
661
-
662
- const activateTrace = async (
663
- core: CoreApi,
664
- Env: TraceEnvApi,
665
- startupOverrides: TraceConfigOverrides | undefined
666
- ): Promise<void> => {
667
- const config = buildTraceRuntimeConfig(Env, startupOverrides);
668
- if (!config.enabled) return;
669
-
670
- const watcherArgs = await createTraceWatcherArgs(core, Env, config);
671
-
672
- if (core.RequestContext) {
673
- TraceContext.setRequestContextImpl(
674
- core.RequestContext as {
675
- current?: () => unknown;
676
- peek?: () => unknown;
677
- }
678
- );
679
- }
680
-
681
- await registerTraceWatchers(watcherArgs);
682
- };
683
-
684
- const initializeTraceRegister = async (): Promise<void> => {
685
- const core = (await importCore()) as CoreApi;
686
- const Env = core.Env;
687
- const startupOverrides = await resolveTraceStartupOverrides(core);
688
-
689
- if (!traceAlreadyInitialized && Env) {
690
- await activateTrace(core, Env, startupOverrides);
691
-
692
- return;
693
- }
694
-
695
- if (!traceAlreadyInitialized) {
696
- // Running outside a ZinTrust project - skip init silently.
697
- // eslint-disable-next-line no-console
698
- console.warn('[trace] @zintrust/core not found - trace will not be activated.');
699
- }
700
- };
701
-
702
- export const registerTraceReady = initializeTraceRegister();