@zintrust/trace 1.6.1 → 1.6.3

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 (50) hide show
  1. package/dist/register.js +19 -15
  2. package/package.json +2 -3
  3. package/src/TraceConnection.ts +0 -182
  4. package/src/cli-register.ts +0 -63
  5. package/src/config.ts +0 -383
  6. package/src/context.ts +0 -101
  7. package/src/dashboard/handlers.ts +0 -353
  8. package/src/dashboard/routes.ts +0 -114
  9. package/src/dashboard/ui.ts +0 -1262
  10. package/src/dashboard/zintrust-debuger.svg +0 -30
  11. package/src/index.ts +0 -102
  12. package/src/ingest/TraceIngestGateway.ts +0 -414
  13. package/src/plugin.ts +0 -9
  14. package/src/register.ts +0 -659
  15. package/src/storage/ProxyTraceStorage.ts +0 -190
  16. package/src/storage/TraceContentBudget.ts +0 -491
  17. package/src/storage/TraceContentRedaction.ts +0 -44
  18. package/src/storage/TraceEntryFiltering.ts +0 -92
  19. package/src/storage/TraceServiceTag.ts +0 -56
  20. package/src/storage/TraceStorage.ts +0 -543
  21. package/src/storage/TraceWriteDiagnostics.ts +0 -289
  22. package/src/storage/index.ts +0 -4
  23. package/src/types.ts +0 -430
  24. package/src/ui.ts +0 -9
  25. package/src/utils/authTag.ts +0 -20
  26. package/src/utils/entryFilter.ts +0 -131
  27. package/src/utils/familyHash.ts +0 -8
  28. package/src/utils/redact.ts +0 -112
  29. package/src/utils/requestFilter.ts +0 -79
  30. package/src/utils/stackFrame.ts +0 -44
  31. package/src/watchers/AuthWatcher.ts +0 -53
  32. package/src/watchers/BatchWatcher.ts +0 -55
  33. package/src/watchers/CacheWatcher.ts +0 -72
  34. package/src/watchers/CommandWatcher.ts +0 -58
  35. package/src/watchers/DumpWatcher.ts +0 -45
  36. package/src/watchers/EventWatcher.ts +0 -46
  37. package/src/watchers/ExceptionWatcher.ts +0 -130
  38. package/src/watchers/GateWatcher.ts +0 -53
  39. package/src/watchers/HttpClientWatcher.ts +0 -219
  40. package/src/watchers/HttpWatcher.ts +0 -220
  41. package/src/watchers/JobWatcher.ts +0 -124
  42. package/src/watchers/LogWatcher.ts +0 -120
  43. package/src/watchers/MailWatcher.ts +0 -65
  44. package/src/watchers/MiddlewareWatcher.ts +0 -54
  45. package/src/watchers/ModelWatcher.ts +0 -60
  46. package/src/watchers/NotificationWatcher.ts +0 -60
  47. package/src/watchers/QueryWatcher.ts +0 -107
  48. package/src/watchers/RedisWatcher.ts +0 -42
  49. package/src/watchers/ScheduleWatcher.ts +0 -57
  50. package/src/watchers/ViewWatcher.ts +0 -40
package/src/register.ts DELETED
@@ -1,659 +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('TRACE_CONTENT_QUEUE_WORKER_MAX_DURATION_MS', '').trim(),
258
- contentDispatchWorkerConcurrencyRaw: Env.get('TRACE_CONTENT_QUEUE_WORKER_CONCURRENCY', '').trim(),
259
- redactionKeys: parseEnvList(Env.get('TRACE_REDACT_KEYS', '')),
260
- redactionHeaders: parseEnvList(Env.get('TRACE_REDACT_HEADERS', '')),
261
- redactionBody: parseEnvList(Env.get('TRACE_REDACT_BODY', '')),
262
- redactionQuery: parseEnvList(Env.get('TRACE_REDACT_QUERY', '')),
263
- };
264
- };
265
-
266
- const resolveStringOverride = (rawValue: string, fallback: string | undefined): string | undefined => {
267
- return rawValue === '' ? fallback : rawValue;
268
- };
269
-
270
- const resolveNumberOverride = (rawValue: string, fallback: number | undefined): number | undefined => {
271
- return rawValue === '' ? fallback : Number.parseInt(rawValue, 10);
272
- };
273
-
274
- const resolveBooleanOverride = (
275
- rawValue: string,
276
- fallback: boolean | undefined
277
- ): boolean | undefined => {
278
- return parseEnvBool(rawValue) ?? fallback;
279
- };
280
-
281
- const resolveTraceProxyKeyId = (
282
- startupOverrides: TraceConfigOverrides | undefined,
283
- values: TraceEnvValues
284
- ): string | undefined => {
285
- return resolveStringOverride(values.traceProxyKeyIdRaw, startupOverrides?.proxy?.keyId ?? values.appNameRaw);
286
- };
287
-
288
- const resolveTraceProxySecret = (
289
- startupOverrides: TraceConfigOverrides | undefined,
290
- values: TraceEnvValues
291
- ): string | undefined => {
292
- return resolveStringOverride(values.traceProxySecretRaw, startupOverrides?.proxy?.secret ?? values.appKeyRaw);
293
- };
294
-
295
- const withStringProperty = (key: string, value: string | undefined): Record<string, string> => {
296
- return typeof value === 'string' && value !== '' ? { [key]: value } : {};
297
- };
298
-
299
- const withNumberProperty = (key: string, value: number | undefined): Record<string, number> => {
300
- return typeof value === 'number' && Number.isFinite(value) ? { [key]: value } : {};
301
- };
302
-
303
- const withBooleanProperty = (
304
- key: string,
305
- value: boolean | undefined
306
- ): Record<string, boolean> => {
307
- return typeof value === 'boolean' ? { [key]: value } : {};
308
- };
309
-
310
- const resolveTraceServiceTag = (
311
- startupOverrides: TraceConfigOverrides | undefined,
312
- values: TraceEnvValues
313
- ): string | undefined => {
314
- const fallback = (startupOverrides?.serviceTag ?? values.appNameRaw).trim() || undefined;
315
- return resolveStringOverride(values.traceServiceTagRaw, fallback);
316
- };
317
-
318
- const resolveContentDispatchWorkerEnabled = (
319
- startupOverrides: TraceConfigOverrides | undefined,
320
- values: TraceEnvValues
321
- ): boolean | undefined => {
322
- return resolveBooleanOverride(
323
- values.contentDispatchWorkerEnabledRaw,
324
- startupOverrides?.contentDispatch?.worker?.enabled
325
- );
326
- };
327
-
328
- const resolveContentDispatchWorkerInterval = (
329
- startupOverrides: TraceConfigOverrides | undefined,
330
- values: TraceEnvValues
331
- ): number | undefined => {
332
- return resolveNumberOverride(
333
- values.contentDispatchWorkerIntervalRaw,
334
- startupOverrides?.contentDispatch?.worker?.intervalMs
335
- );
336
- };
337
-
338
- const resolveContentDispatchWorkerDuration = (
339
- startupOverrides: TraceConfigOverrides | undefined,
340
- values: TraceEnvValues
341
- ): number | undefined => {
342
- return resolveNumberOverride(
343
- values.contentDispatchWorkerDurationRaw,
344
- startupOverrides?.contentDispatch?.worker?.maxDurationMs
345
- );
346
- };
347
-
348
- const resolveContentDispatchWorkerConcurrency = (
349
- startupOverrides: TraceConfigOverrides | undefined,
350
- values: TraceEnvValues
351
- ): number | undefined => {
352
- return resolveNumberOverride(
353
- values.contentDispatchWorkerConcurrencyRaw,
354
- startupOverrides?.contentDispatch?.worker?.concurrency
355
- );
356
- };
357
-
358
- const buildTraceContentDispatchWorkerConfig = (
359
- startupOverrides: TraceConfigOverrides | undefined,
360
- values: TraceEnvValues
361
- ): NonNullable<NonNullable<TraceConfigOverrides['contentDispatch']>['worker']> => {
362
- const defaultWorker = TraceConfig.defaults().contentDispatch.worker;
363
- const startupWorker = startupOverrides?.contentDispatch?.worker;
364
- const contentDispatchWorkerEnabled = resolveContentDispatchWorkerEnabled(startupOverrides, values);
365
- const contentDispatchWorkerInterval = resolveContentDispatchWorkerInterval(startupOverrides, values);
366
- const contentDispatchWorkerDuration = resolveContentDispatchWorkerDuration(startupOverrides, values);
367
- const contentDispatchWorkerConcurrency = resolveContentDispatchWorkerConcurrency(
368
- startupOverrides,
369
- values
370
- );
371
-
372
- return {
373
- ...defaultWorker,
374
- ...startupWorker,
375
- enabled: contentDispatchWorkerEnabled ?? startupWorker?.enabled ?? defaultWorker.enabled,
376
- intervalMs: contentDispatchWorkerInterval ?? startupWorker?.intervalMs ?? defaultWorker.intervalMs,
377
- maxDurationMs:
378
- contentDispatchWorkerDuration ?? startupWorker?.maxDurationMs ?? defaultWorker.maxDurationMs,
379
- concurrency:
380
- contentDispatchWorkerConcurrency ?? startupWorker?.concurrency ?? defaultWorker.concurrency,
381
- };
382
- };
383
-
384
- const buildTraceProxyConfig = (
385
- startupOverrides: TraceConfigOverrides | undefined,
386
- values: TraceEnvValues
387
- ): TraceConfigOverrides['proxy'] => {
388
- const traceProxyEnabled = resolveBooleanOverride(values.traceProxyRaw, startupOverrides?.proxy?.enabled);
389
- const traceProxyUrl = resolveStringOverride(values.traceProxyUrlRaw, startupOverrides?.proxy?.url);
390
- const traceProxyPath = resolveStringOverride(values.traceProxyPathRaw, startupOverrides?.proxy?.path);
391
- const traceProxyKeyId = resolveTraceProxyKeyId(startupOverrides, values);
392
- const traceProxySecret = resolveTraceProxySecret(startupOverrides, values);
393
- const traceProxyTimeout = resolveNumberOverride(
394
- values.traceProxyTimeoutRaw,
395
- startupOverrides?.proxy?.timeoutMs
396
- );
397
-
398
- return {
399
- ...TraceConfig.defaults().proxy,
400
- ...startupOverrides?.proxy,
401
- ...withBooleanProperty('enabled', traceProxyEnabled),
402
- ...withStringProperty('url', traceProxyUrl),
403
- ...withStringProperty('path', traceProxyPath),
404
- ...withStringProperty('keyId', traceProxyKeyId),
405
- ...withStringProperty('secret', traceProxySecret),
406
- ...withNumberProperty('timeoutMs', traceProxyTimeout),
407
- };
408
- };
409
-
410
- const buildTraceContentDispatchConfig = (
411
- startupOverrides: TraceConfigOverrides | undefined,
412
- values: TraceEnvValues
413
- ): NonNullable<TraceConfigOverrides['contentDispatch']> => {
414
- const defaultContentDispatch = TraceConfig.defaults().contentDispatch;
415
- const startupContentDispatch = startupOverrides?.contentDispatch;
416
- const contentDispatchDriver = resolveStringOverride(
417
- values.contentDispatchDriverRaw,
418
- startupContentDispatch?.driver
419
- );
420
- const contentDispatchQueueName = resolveStringOverride(
421
- values.contentDispatchQueueRaw,
422
- startupContentDispatch?.queueName
423
- );
424
- const contentDispatchEnqueueTimeout = resolveNumberOverride(
425
- values.contentDispatchEnqueueTimeoutRaw,
426
- startupContentDispatch?.enqueueTimeoutMs
427
- );
428
-
429
- return {
430
- ...defaultContentDispatch,
431
- ...startupContentDispatch,
432
- ...withStringProperty('driver', contentDispatchDriver),
433
- ...withStringProperty('queueName', contentDispatchQueueName),
434
- ...withNumberProperty('enqueueTimeoutMs', contentDispatchEnqueueTimeout),
435
- worker: buildTraceContentDispatchWorkerConfig(startupOverrides, values),
436
- };
437
- };
438
-
439
- const buildTraceRuntimeConfig = (
440
- Env: TraceEnvApi,
441
- startupOverrides: TraceConfigOverrides | undefined
442
- ): ReturnType<typeof TraceConfig.merge> => {
443
- const values = readTraceEnvValues(Env);
444
- const enabled = startupOverrides?.enabled === true || Env.getBool('TRACE_ENABLED', false);
445
- const connection = resolveStringOverride(values.connectionRaw, startupOverrides?.connection);
446
- const observeConnection = resolveStringOverride(
447
- values.observeConnectionRaw,
448
- startupOverrides?.observeConnection
449
- );
450
- const pruneAfterHours = resolveNumberOverride(
451
- values.pruneAfterHoursRaw,
452
- startupOverrides?.pruneAfterHours
453
- );
454
- const slowQueryThreshold = resolveNumberOverride(
455
- values.slowQueryThresholdRaw,
456
- startupOverrides?.slowQueryThreshold
457
- );
458
- const logMinLevel = (
459
- values.logMinLevelRaw === '' ? startupOverrides?.logMinLevel : values.logMinLevelRaw
460
- ) as 'debug' | 'info' | 'warn' | 'error' | 'fatal';
461
- const captureCachePayloads = resolveBooleanOverride(
462
- values.captureCachePayloadsRaw,
463
- startupOverrides?.captureCachePayloads
464
- );
465
- const captureQueryBindings = resolveBooleanOverride(
466
- values.captureQueryBindingsRaw,
467
- startupOverrides?.captureQueryBindings
468
- );
469
- const traceServiceTag = resolveTraceServiceTag(startupOverrides, values);
470
- const redaction = buildTraceRedactionOverrides({
471
- startupOverrides,
472
- redactionBody: values.redactionBody,
473
- redactionHeaders: values.redactionHeaders,
474
- redactionKeys: values.redactionKeys,
475
- redactionQuery: values.redactionQuery,
476
- });
477
-
478
- return TraceConfig.merge({
479
- ...startupOverrides,
480
- enabled,
481
- connection,
482
- observeConnection,
483
- ...withStringProperty('serviceTag', traceServiceTag),
484
- proxy: buildTraceProxyConfig(startupOverrides, values),
485
- ...withNumberProperty('pruneAfterHours', pruneAfterHours),
486
- ...withNumberProperty('slowQueryThreshold', slowQueryThreshold),
487
- ...withBooleanProperty('captureCachePayloads', captureCachePayloads),
488
- ...withBooleanProperty('captureQueryBindings', captureQueryBindings),
489
- contentDispatch: buildTraceContentDispatchConfig(startupOverrides, values),
490
- logMinLevel,
491
- ...(redaction === undefined ? {} : { redaction }),
492
- });
493
- };
494
-
495
- const createTraceWatcherArgs = async (
496
- core: CoreApi,
497
- Env: TraceEnvApi,
498
- config: ReturnType<typeof TraceConfig.merge>
499
- ): Promise<Pick<ITraceWatcherConfig, 'storage' | 'config' | 'db'>> => {
500
- const resolvedConnectionName = resolveTraceConnectionName(Env, config.connection);
501
- const resolvedObservedConnectionName = resolveObservedConnectionName(
502
- Env,
503
- config.observeConnection,
504
- resolvedConnectionName
505
- );
506
- globalTraceRegisterState.__zintrust_system_trace_connection_name__ = resolvedConnectionName;
507
- globalTraceRegisterState.__zintrust_system_trace_observe_connection_name__ =
508
- resolvedObservedConnectionName;
509
-
510
- const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
511
- const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
512
-
513
- assertTraceConnectionResolved(core, storageDb, {
514
- connectionName: resolvedConnectionName,
515
- envKey: 'TRACE_DB_CONNECTION',
516
- });
517
- assertTraceConnectionResolved(core, observedDb, {
518
- connectionName: resolvedObservedConnectionName,
519
- envKey: 'TRACE_QUERY_CONNECTION',
520
- });
521
- await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
522
-
523
- const resolvedStorage = config.proxy.enabled
524
- ? ProxyTraceStorage.create({
525
- baseUrl: config.proxy.url ?? '',
526
- path: config.proxy.path,
527
- keyId: config.proxy.keyId ?? '',
528
- secret: config.proxy.secret ?? '',
529
- timeoutMs: config.proxy.timeoutMs,
530
- })
531
- : TraceStorage.resolveStorage(storageDb);
532
-
533
- const storage = TraceWriteDiagnostics.wrapStorage(
534
- TraceContentBudget.wrapStorage(
535
- TraceContentRedaction.wrapStorage(
536
- TraceEntryFiltering.wrapStorage(TraceServiceTag.wrapStorage(resolvedStorage, config), config),
537
- config.redaction
538
- ),
539
- config
540
- ),
541
- {
542
- connectionName: resolvedConnectionName,
543
- logger: core.Logger,
544
- }
545
- );
546
-
547
- return { storage, config, db: observedDb };
548
- };
549
-
550
- const registerTraceWatchers = async (
551
- watcherArgs: Pick<ITraceWatcherConfig, 'storage' | 'config' | 'db'>
552
- ): Promise<void> => {
553
- const [
554
- { HttpWatcher },
555
- { QueryWatcher },
556
- { LogWatcher },
557
- { ExceptionWatcher },
558
- { JobWatcher },
559
- { CacheWatcher },
560
- { ScheduleWatcher },
561
- { MailWatcher },
562
- { AuthWatcher },
563
- { EventWatcher },
564
- { ModelWatcher },
565
- { NotificationWatcher },
566
- { RedisWatcher },
567
- { GateWatcher },
568
- { MiddlewareWatcher },
569
- { CommandWatcher },
570
- { BatchWatcher },
571
- { DumpWatcher },
572
- { ViewWatcher },
573
- { HttpClientWatcher },
574
- ] = await Promise.all([
575
- import('./watchers/HttpWatcher'),
576
- import('./watchers/QueryWatcher'),
577
- import('./watchers/LogWatcher'),
578
- import('./watchers/ExceptionWatcher'),
579
- import('./watchers/JobWatcher'),
580
- import('./watchers/CacheWatcher'),
581
- import('./watchers/ScheduleWatcher'),
582
- import('./watchers/MailWatcher'),
583
- import('./watchers/AuthWatcher'),
584
- import('./watchers/EventWatcher'),
585
- import('./watchers/ModelWatcher'),
586
- import('./watchers/NotificationWatcher'),
587
- import('./watchers/RedisWatcher'),
588
- import('./watchers/GateWatcher'),
589
- import('./watchers/MiddlewareWatcher'),
590
- import('./watchers/CommandWatcher'),
591
- import('./watchers/BatchWatcher'),
592
- import('./watchers/DumpWatcher'),
593
- import('./watchers/ViewWatcher'),
594
- import('./watchers/HttpClientWatcher'),
595
- ]);
596
-
597
- HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
598
- QueryWatcher.register(watcherArgs);
599
- LogWatcher.register(watcherArgs);
600
- ExceptionWatcher.register(watcherArgs);
601
- JobWatcher.register(watcherArgs);
602
- CacheWatcher.register(watcherArgs);
603
- ScheduleWatcher.register(watcherArgs);
604
- MailWatcher.register(watcherArgs);
605
- AuthWatcher.register(watcherArgs);
606
- EventWatcher.register(watcherArgs);
607
- ModelWatcher.register(watcherArgs);
608
- NotificationWatcher.register(watcherArgs);
609
- RedisWatcher.register(watcherArgs);
610
- GateWatcher.register(watcherArgs);
611
- MiddlewareWatcher.register(watcherArgs);
612
- CommandWatcher.register(watcherArgs);
613
- BatchWatcher.register(watcherArgs);
614
- DumpWatcher.register(watcherArgs);
615
- ViewWatcher.register(watcherArgs);
616
- HttpClientWatcher.register(watcherArgs);
617
- };
618
-
619
- const activateTrace = async (
620
- core: CoreApi,
621
- Env: TraceEnvApi,
622
- startupOverrides: TraceConfigOverrides | undefined
623
- ): Promise<void> => {
624
- const config = buildTraceRuntimeConfig(Env, startupOverrides);
625
- if (!config.enabled) return;
626
-
627
- const watcherArgs = await createTraceWatcherArgs(core, Env, config);
628
-
629
- if (core.RequestContext) {
630
- TraceContext.setRequestContextImpl(
631
- core.RequestContext as {
632
- current?: () => unknown;
633
- peek?: () => unknown;
634
- }
635
- );
636
- }
637
-
638
- await registerTraceWatchers(watcherArgs);
639
- };
640
-
641
- const initializeTraceRegister = async (): Promise<void> => {
642
- const core = (await importCore()) as CoreApi;
643
- const Env = core.Env;
644
- const startupOverrides = await resolveTraceStartupOverrides(core);
645
-
646
- if (!traceAlreadyInitialized && Env) {
647
- await activateTrace(core, Env, startupOverrides);
648
-
649
- return;
650
- }
651
-
652
- if (!traceAlreadyInitialized) {
653
- // Running outside a ZinTrust project - skip init silently.
654
- // eslint-disable-next-line no-console
655
- console.warn('[trace] @zintrust/core not found - trace will not be activated.');
656
- }
657
- };
658
-
659
- export const registerTraceReady = initializeTraceRegister();