@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.
- package/dist/register.js +19 -15
- package/package.json +2 -3
- package/src/TraceConnection.ts +0 -182
- package/src/cli-register.ts +0 -63
- package/src/config.ts +0 -383
- package/src/context.ts +0 -101
- package/src/dashboard/handlers.ts +0 -353
- package/src/dashboard/routes.ts +0 -114
- package/src/dashboard/ui.ts +0 -1262
- package/src/dashboard/zintrust-debuger.svg +0 -30
- package/src/index.ts +0 -102
- package/src/ingest/TraceIngestGateway.ts +0 -414
- package/src/plugin.ts +0 -9
- package/src/register.ts +0 -659
- package/src/storage/ProxyTraceStorage.ts +0 -190
- package/src/storage/TraceContentBudget.ts +0 -491
- package/src/storage/TraceContentRedaction.ts +0 -44
- package/src/storage/TraceEntryFiltering.ts +0 -92
- package/src/storage/TraceServiceTag.ts +0 -56
- package/src/storage/TraceStorage.ts +0 -543
- package/src/storage/TraceWriteDiagnostics.ts +0 -289
- package/src/storage/index.ts +0 -4
- package/src/types.ts +0 -430
- package/src/ui.ts +0 -9
- package/src/utils/authTag.ts +0 -20
- package/src/utils/entryFilter.ts +0 -131
- package/src/utils/familyHash.ts +0 -8
- package/src/utils/redact.ts +0 -112
- package/src/utils/requestFilter.ts +0 -79
- package/src/utils/stackFrame.ts +0 -44
- package/src/watchers/AuthWatcher.ts +0 -53
- package/src/watchers/BatchWatcher.ts +0 -55
- package/src/watchers/CacheWatcher.ts +0 -72
- package/src/watchers/CommandWatcher.ts +0 -58
- package/src/watchers/DumpWatcher.ts +0 -45
- package/src/watchers/EventWatcher.ts +0 -46
- package/src/watchers/ExceptionWatcher.ts +0 -130
- package/src/watchers/GateWatcher.ts +0 -53
- package/src/watchers/HttpClientWatcher.ts +0 -219
- package/src/watchers/HttpWatcher.ts +0 -220
- package/src/watchers/JobWatcher.ts +0 -124
- package/src/watchers/LogWatcher.ts +0 -120
- package/src/watchers/MailWatcher.ts +0 -65
- package/src/watchers/MiddlewareWatcher.ts +0 -54
- package/src/watchers/ModelWatcher.ts +0 -60
- package/src/watchers/NotificationWatcher.ts +0 -60
- package/src/watchers/QueryWatcher.ts +0 -107
- package/src/watchers/RedisWatcher.ts +0 -42
- package/src/watchers/ScheduleWatcher.ts +0 -57
- package/src/watchers/ViewWatcher.ts +0 -40
package/dist/register.js
CHANGED
|
@@ -291,26 +291,30 @@ const createTraceWatcherArgs = async (core, Env, config) => {
|
|
|
291
291
|
globalTraceRegisterState.__zintrust_system_trace_connection_name__ = resolvedConnectionName;
|
|
292
292
|
globalTraceRegisterState.__zintrust_system_trace_observe_connection_name__ =
|
|
293
293
|
resolvedObservedConnectionName;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
connectionName: resolvedConnectionName,
|
|
298
|
-
envKey: 'TRACE_DB_CONNECTION',
|
|
299
|
-
});
|
|
300
|
-
assertTraceConnectionResolved(core, observedDb, {
|
|
301
|
-
connectionName: resolvedObservedConnectionName,
|
|
302
|
-
envKey: 'TRACE_QUERY_CONNECTION',
|
|
303
|
-
});
|
|
304
|
-
await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
|
|
305
|
-
const resolvedStorage = config.proxy.enabled
|
|
306
|
-
? ProxyTraceStorage.create({
|
|
294
|
+
let resolvedStorage;
|
|
295
|
+
if (config.proxy.enabled) {
|
|
296
|
+
resolvedStorage = ProxyTraceStorage.create({
|
|
307
297
|
baseUrl: config.proxy.url ?? '',
|
|
308
298
|
path: config.proxy.path,
|
|
309
299
|
keyId: config.proxy.keyId ?? '',
|
|
310
300
|
secret: config.proxy.secret ?? '',
|
|
311
301
|
timeoutMs: config.proxy.timeoutMs,
|
|
312
|
-
})
|
|
313
|
-
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
|
|
306
|
+
assertTraceConnectionResolved(core, storageDb, {
|
|
307
|
+
connectionName: resolvedConnectionName,
|
|
308
|
+
envKey: 'TRACE_DB_CONNECTION',
|
|
309
|
+
});
|
|
310
|
+
await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
|
|
311
|
+
resolvedStorage = TraceStorage.resolveStorage(storageDb);
|
|
312
|
+
}
|
|
313
|
+
const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
|
|
314
|
+
assertTraceConnectionResolved(core, observedDb, {
|
|
315
|
+
connectionName: resolvedObservedConnectionName,
|
|
316
|
+
envKey: 'TRACE_QUERY_CONNECTION',
|
|
317
|
+
});
|
|
314
318
|
const storage = TraceWriteDiagnostics.wrapStorage(TraceContentBudget.wrapStorage(TraceContentRedaction.wrapStorage(TraceEntryFiltering.wrapStorage(TraceServiceTag.wrapStorage(resolvedStorage, config), config), config.redaction), config), {
|
|
315
319
|
connectionName: resolvedConnectionName,
|
|
316
320
|
logger: core.Logger,
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/trace",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
"src"
|
|
10
|
+
"dist"
|
|
12
11
|
],
|
|
13
12
|
"exports": {
|
|
14
13
|
".": {
|
package/src/TraceConnection.ts
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import type { IDatabase } from '@zintrust/core';
|
|
2
|
-
|
|
3
|
-
type TraceErrorFactory = {
|
|
4
|
-
createConfigError?(message: string, details?: unknown): Error;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
type TraceErrorApi = {
|
|
8
|
-
ErrorFactory?: TraceErrorFactory;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
type TraceEnvApi = {
|
|
12
|
-
get(key: string, fallback: string): string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type GlobalTraceConnectionState = {
|
|
16
|
-
__zintrust_system_trace_connection_name__?: string;
|
|
17
|
-
__zintrust_system_trace_plugin_requested__?: boolean;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const TRACE_REQUIRED_TABLES = [
|
|
21
|
-
'zin_trace_entries',
|
|
22
|
-
'zin_trace_entries_tags',
|
|
23
|
-
'zin_trace_monitoring',
|
|
24
|
-
] as const;
|
|
25
|
-
|
|
26
|
-
const createFallbackTraceConfigError = (message: string, details?: unknown): Error => {
|
|
27
|
-
const error = new globalThis.Error(message) as Error & {
|
|
28
|
-
code?: string;
|
|
29
|
-
details?: unknown;
|
|
30
|
-
name?: string;
|
|
31
|
-
statusCode?: number;
|
|
32
|
-
};
|
|
33
|
-
error.name = 'ConfigError';
|
|
34
|
-
error.code = 'CONFIG_ERROR';
|
|
35
|
-
error.statusCode = 500;
|
|
36
|
-
error.details = details;
|
|
37
|
-
return error;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const createTraceConfigError = (
|
|
41
|
-
coreApi: TraceErrorApi,
|
|
42
|
-
message: string,
|
|
43
|
-
details?: unknown
|
|
44
|
-
): Error => {
|
|
45
|
-
if (coreApi.ErrorFactory?.createConfigError !== undefined) {
|
|
46
|
-
return coreApi.ErrorFactory.createConfigError(message, details);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return createFallbackTraceConfigError(message, details);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export const getRuntimeTraceConnectionName = (): string | undefined => {
|
|
53
|
-
const runtimeConnection = (
|
|
54
|
-
globalThis as GlobalTraceConnectionState
|
|
55
|
-
).__zintrust_system_trace_connection_name__?.trim();
|
|
56
|
-
|
|
57
|
-
return runtimeConnection === undefined || runtimeConnection === ''
|
|
58
|
-
? undefined
|
|
59
|
-
: runtimeConnection;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const resolveDashboardTraceConnectionName = (
|
|
63
|
-
coreApi: TraceErrorApi,
|
|
64
|
-
input: {
|
|
65
|
-
explicitConnectionName?: string;
|
|
66
|
-
configuredConnectionName?: string;
|
|
67
|
-
}
|
|
68
|
-
): string => {
|
|
69
|
-
const explicitConnection = input.explicitConnectionName?.trim();
|
|
70
|
-
if (explicitConnection !== undefined && explicitConnection !== '') {
|
|
71
|
-
return explicitConnection;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const runtimeConnection = getRuntimeTraceConnectionName();
|
|
75
|
-
if (runtimeConnection !== undefined) {
|
|
76
|
-
return runtimeConnection;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const configuredConnection = input.configuredConnectionName?.trim();
|
|
80
|
-
if (configuredConnection !== undefined && configuredConnection !== '') {
|
|
81
|
-
return configuredConnection;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
throw createTraceConfigError(coreApi, 'Trace dashboard connection is not configured.', {
|
|
85
|
-
envKey: 'TRACE_DB_CONNECTION',
|
|
86
|
-
hint: 'Import @zintrust/trace/register before mounting the dashboard, pass connectionName explicitly, or set TRACE_DB_CONNECTION to the trace storage connection.',
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const resolveTraceConnectionName = (
|
|
91
|
-
env: Pick<TraceEnvApi, 'get'> | undefined,
|
|
92
|
-
configuredConnection?: string
|
|
93
|
-
): string => {
|
|
94
|
-
const resolveDefaultConnection = (): string => {
|
|
95
|
-
const defaultConnection = env?.get('DB_CONNECTION', '').trim() ?? '';
|
|
96
|
-
if (defaultConnection === '' || defaultConnection === 'default') return 'default';
|
|
97
|
-
return defaultConnection;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const explicitConnection = configuredConnection?.trim();
|
|
101
|
-
if (explicitConnection !== undefined && explicitConnection !== '') {
|
|
102
|
-
return explicitConnection === 'default' ? resolveDefaultConnection() : explicitConnection;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return resolveDefaultConnection();
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export const resolveObservedConnectionName = (
|
|
109
|
-
env: Pick<TraceEnvApi, 'get'> | undefined,
|
|
110
|
-
configuredObservedConnection: string | undefined,
|
|
111
|
-
storageConnectionName: string
|
|
112
|
-
): string => {
|
|
113
|
-
if (
|
|
114
|
-
typeof configuredObservedConnection === 'string' &&
|
|
115
|
-
configuredObservedConnection.trim() !== ''
|
|
116
|
-
) {
|
|
117
|
-
return resolveTraceConnectionName(env, configuredObservedConnection);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const defaultConnectionName = resolveTraceConnectionName(env);
|
|
121
|
-
if (storageConnectionName !== defaultConnectionName) {
|
|
122
|
-
return defaultConnectionName;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return storageConnectionName;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export function assertTraceConnectionResolved(
|
|
129
|
-
coreApi: TraceErrorApi,
|
|
130
|
-
db: IDatabase | undefined,
|
|
131
|
-
params: { connectionName: string; envKey: 'TRACE_DB_CONNECTION' | 'TRACE_QUERY_CONNECTION' }
|
|
132
|
-
): asserts db is IDatabase {
|
|
133
|
-
if (db !== undefined) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const pluginRequested =
|
|
138
|
-
(globalThis as GlobalTraceConnectionState).__zintrust_system_trace_plugin_requested__ === true;
|
|
139
|
-
let hint =
|
|
140
|
-
'Configure TRACE_QUERY_CONNECTION, or ensure DB_CONNECTION resolves to an existing database connection.';
|
|
141
|
-
|
|
142
|
-
if (params.envKey === 'TRACE_DB_CONNECTION') {
|
|
143
|
-
hint = pluginRequested
|
|
144
|
-
? 'Configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.'
|
|
145
|
-
: 'If this module is being imported from zintrust.plugins.*, switch that import to @zintrust/trace/plugin so trace registration runs after database runtime registration. Otherwise configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
throw createTraceConfigError(
|
|
149
|
-
coreApi,
|
|
150
|
-
`Trace connection "${params.connectionName}" could not be resolved.`,
|
|
151
|
-
{
|
|
152
|
-
connectionName: params.connectionName,
|
|
153
|
-
envKey: params.envKey,
|
|
154
|
-
hint,
|
|
155
|
-
}
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export const assertTraceStorageReady = async (
|
|
160
|
-
coreApi: TraceErrorApi,
|
|
161
|
-
db: IDatabase,
|
|
162
|
-
connectionName: string,
|
|
163
|
-
operation = 'Trace storage connection'
|
|
164
|
-
): Promise<void> => {
|
|
165
|
-
try {
|
|
166
|
-
await Promise.all(
|
|
167
|
-
TRACE_REQUIRED_TABLES.map(async (table) => {
|
|
168
|
-
await db.queryOne(`SELECT 1 AS ok FROM ${table} LIMIT 1`, []);
|
|
169
|
-
})
|
|
170
|
-
);
|
|
171
|
-
} catch (error) {
|
|
172
|
-
throw createTraceConfigError(
|
|
173
|
-
coreApi,
|
|
174
|
-
`${operation} "${connectionName}" is not ready. Create the database if needed and run \`zin migrate:trace\` before enabling TRACE_ENABLED.`,
|
|
175
|
-
{
|
|
176
|
-
connectionName,
|
|
177
|
-
error,
|
|
178
|
-
requiredTables: [...TRACE_REQUIRED_TABLES],
|
|
179
|
-
}
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
};
|
package/src/cli-register.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
type Registry = {
|
|
2
|
-
register: (id: string, provider: CliCommandProvider) => void;
|
|
3
|
-
};
|
|
4
|
-
|
|
5
|
-
type CliCommandProvider = {
|
|
6
|
-
getCommand: () => unknown;
|
|
7
|
-
name?: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type TraceCommandsModule = {
|
|
11
|
-
TraceCommands: {
|
|
12
|
-
createTracePruneProvider: () => CliCommandProvider;
|
|
13
|
-
createTraceClearProvider: () => CliCommandProvider;
|
|
14
|
-
createTraceStatusProvider: () => CliCommandProvider;
|
|
15
|
-
createTraceMigrateProvider: () => CliCommandProvider;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const commandModule = (await import('@zintrust/core/cli')) as unknown as TraceCommandsModule;
|
|
20
|
-
|
|
21
|
-
const getTraceProviders = (): Array<[string, CliCommandProvider]> => {
|
|
22
|
-
const { TraceCommands } = commandModule;
|
|
23
|
-
|
|
24
|
-
return [
|
|
25
|
-
['trace:prune', TraceCommands.createTracePruneProvider()],
|
|
26
|
-
['trace:clear', TraceCommands.createTraceClearProvider()],
|
|
27
|
-
['trace:status', TraceCommands.createTraceStatusProvider()],
|
|
28
|
-
['migrate:trace', TraceCommands.createTraceMigrateProvider()],
|
|
29
|
-
];
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export function registerTraceCliCommands(registry: Registry): void {
|
|
33
|
-
for (const [id, provider] of getTraceProviders()) {
|
|
34
|
-
registry.register(id, provider);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type GlobalWithRegistry = {
|
|
39
|
-
__zintrust_cli_command_registry__?: Map<string, CliCommandProvider>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const globalWithRegistry = globalThis as unknown as GlobalWithRegistry;
|
|
43
|
-
const globalRegistry =
|
|
44
|
-
globalWithRegistry.__zintrust_cli_command_registry__ ??
|
|
45
|
-
(globalWithRegistry.__zintrust_cli_command_registry__ = new Map<string, CliCommandProvider>());
|
|
46
|
-
|
|
47
|
-
registerTraceCliCommands({
|
|
48
|
-
register: (id, provider) => {
|
|
49
|
-
globalRegistry.set(id, provider);
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const coreCli = (await import('@zintrust/core/cli')) as unknown as {
|
|
55
|
-
OptionalCliCommandRegistry?: Registry;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
if (coreCli.OptionalCliCommandRegistry !== undefined) {
|
|
59
|
-
registerTraceCliCommands(coreCli.OptionalCliCommandRegistry);
|
|
60
|
-
}
|
|
61
|
-
} catch {
|
|
62
|
-
// no-op
|
|
63
|
-
}
|
package/src/config.ts
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TraceConfig — defaults and merge helper for @zintrust/trace
|
|
3
|
-
*/
|
|
4
|
-
import type {
|
|
5
|
-
ITraceConfig,
|
|
6
|
-
TraceClientRequestCaptureRule,
|
|
7
|
-
TraceClientRequestWatcherToggle,
|
|
8
|
-
TraceConfigOverrides,
|
|
9
|
-
TraceContentDispatchConfig,
|
|
10
|
-
TraceFilterRule,
|
|
11
|
-
TraceProxyConfig,
|
|
12
|
-
TraceRequestWatcherConfig,
|
|
13
|
-
TraceWatcherToggle,
|
|
14
|
-
} from './types';
|
|
15
|
-
|
|
16
|
-
const mergeStringLists = (base: string[], override?: string[]): string[] => {
|
|
17
|
-
const merged = new Set<string>();
|
|
18
|
-
|
|
19
|
-
for (const value of [...base, ...(override ?? [])]) {
|
|
20
|
-
if (typeof value !== 'string') continue;
|
|
21
|
-
const normalized = value.trim();
|
|
22
|
-
if (normalized !== '') merged.add(normalized);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return [...merged];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const isObjectValue = (value: unknown): value is Record<string, unknown> => {
|
|
29
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const resolveEnabled = (
|
|
33
|
-
base?: TraceFilterRule,
|
|
34
|
-
override?: TraceFilterRule
|
|
35
|
-
): boolean | undefined => {
|
|
36
|
-
return override?.enabled ?? base?.enabled;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const hasMergedRuleValues = (
|
|
40
|
-
include: string[],
|
|
41
|
-
exclude: string[],
|
|
42
|
-
enabled: boolean | undefined
|
|
43
|
-
): boolean => {
|
|
44
|
-
return include.length > 0 || exclude.length > 0 || enabled !== undefined;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const buildFilterRule = (input: {
|
|
48
|
-
include: string[];
|
|
49
|
-
exclude: string[];
|
|
50
|
-
enabled: boolean | undefined;
|
|
51
|
-
}): TraceFilterRule => {
|
|
52
|
-
return Object.freeze({
|
|
53
|
-
...(input.enabled === undefined ? {} : { enabled: input.enabled }),
|
|
54
|
-
...(input.include.length > 0 ? { include: input.include } : {}),
|
|
55
|
-
...(input.exclude.length > 0 ? { exclude: input.exclude } : {}),
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const mergeFilterRule = (
|
|
60
|
-
base?: TraceFilterRule,
|
|
61
|
-
override?: TraceFilterRule
|
|
62
|
-
): TraceFilterRule | undefined => {
|
|
63
|
-
const include = mergeStringLists(base?.include ?? [], override?.include);
|
|
64
|
-
const exclude = mergeStringLists(base?.exclude ?? [], override?.exclude);
|
|
65
|
-
const enabled = resolveEnabled(base, override);
|
|
66
|
-
|
|
67
|
-
if (!hasMergedRuleValues(include, exclude, enabled)) return undefined;
|
|
68
|
-
|
|
69
|
-
return buildFilterRule({ include, exclude, enabled });
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const mergeWatcherToggle = (
|
|
73
|
-
base?: TraceWatcherToggle,
|
|
74
|
-
override?: TraceWatcherToggle
|
|
75
|
-
): TraceWatcherToggle | undefined => {
|
|
76
|
-
if (override === undefined) return base;
|
|
77
|
-
if (override === false || override === true) return override;
|
|
78
|
-
|
|
79
|
-
const baseRule = isObjectValue(base) ? base : undefined;
|
|
80
|
-
return mergeFilterRule(baseRule, override);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
type ClientRequestCaptureFlags = Pick<
|
|
84
|
-
TraceClientRequestCaptureRule,
|
|
85
|
-
'requestHeaders' | 'requestBody' | 'responseHeaders' | 'responseBody'
|
|
86
|
-
>;
|
|
87
|
-
|
|
88
|
-
const resolveClientRequestCaptureFlags = (
|
|
89
|
-
base?: TraceClientRequestCaptureRule,
|
|
90
|
-
override?: TraceClientRequestCaptureRule
|
|
91
|
-
): ClientRequestCaptureFlags => {
|
|
92
|
-
return {
|
|
93
|
-
requestHeaders: override?.requestHeaders ?? base?.requestHeaders,
|
|
94
|
-
requestBody: override?.requestBody ?? base?.requestBody,
|
|
95
|
-
responseHeaders: override?.responseHeaders ?? base?.responseHeaders,
|
|
96
|
-
responseBody: override?.responseBody ?? base?.responseBody,
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const hasClientRequestCaptureFlags = (flags: ClientRequestCaptureFlags): boolean => {
|
|
101
|
-
return Object.values(flags).some((value) => value !== undefined);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const buildClientRequestCaptureRule = (
|
|
105
|
-
mergedRule: TraceFilterRule | undefined,
|
|
106
|
-
flags: ClientRequestCaptureFlags
|
|
107
|
-
): TraceClientRequestCaptureRule => {
|
|
108
|
-
const baseRule = mergedRule ? { ...mergedRule } : {};
|
|
109
|
-
|
|
110
|
-
return Object.freeze({
|
|
111
|
-
...baseRule,
|
|
112
|
-
...(flags.requestHeaders === undefined ? {} : { requestHeaders: flags.requestHeaders }),
|
|
113
|
-
...(flags.requestBody === undefined ? {} : { requestBody: flags.requestBody }),
|
|
114
|
-
...(flags.responseHeaders === undefined ? {} : { responseHeaders: flags.responseHeaders }),
|
|
115
|
-
...(flags.responseBody === undefined ? {} : { responseBody: flags.responseBody }),
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const mergeClientRequestCaptureRule = (
|
|
120
|
-
base?: TraceClientRequestCaptureRule,
|
|
121
|
-
override?: TraceClientRequestCaptureRule
|
|
122
|
-
): TraceClientRequestCaptureRule | undefined => {
|
|
123
|
-
const mergedRule = mergeFilterRule(base, override);
|
|
124
|
-
const flags = resolveClientRequestCaptureFlags(base, override);
|
|
125
|
-
|
|
126
|
-
if (mergedRule === undefined && !hasClientRequestCaptureFlags(flags)) {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return buildClientRequestCaptureRule(mergedRule, flags);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const collectClientRequestSourceKeys = (
|
|
134
|
-
base?: TraceClientRequestWatcherToggle,
|
|
135
|
-
override?: Exclude<TraceClientRequestWatcherToggle, boolean>
|
|
136
|
-
): string[] => {
|
|
137
|
-
const overrideSources = override?.sources ?? {};
|
|
138
|
-
const sourceKeys = new Set<string>([
|
|
139
|
-
...Object.keys(isObjectValue(base) ? (base.sources ?? {}) : {}),
|
|
140
|
-
...Object.keys(overrideSources),
|
|
141
|
-
]);
|
|
142
|
-
|
|
143
|
-
return [...sourceKeys];
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const mergeClientRequestSources = (
|
|
147
|
-
base?: TraceClientRequestWatcherToggle,
|
|
148
|
-
override?: Exclude<TraceClientRequestWatcherToggle, boolean>
|
|
149
|
-
): Record<string, TraceClientRequestCaptureRule> | undefined => {
|
|
150
|
-
if (override === undefined) return undefined;
|
|
151
|
-
|
|
152
|
-
const sources: Record<string, TraceClientRequestCaptureRule> = {};
|
|
153
|
-
|
|
154
|
-
for (const key of collectClientRequestSourceKeys(base, override)) {
|
|
155
|
-
const baseSources = isObjectValue(base) ? base.sources : undefined;
|
|
156
|
-
const sourceRule = mergeClientRequestCaptureRule(baseSources?.[key], override.sources?.[key]);
|
|
157
|
-
if (sourceRule !== undefined) {
|
|
158
|
-
sources[key] = sourceRule;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return Object.keys(sources).length === 0 ? undefined : sources;
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const mergeClientRequestWatcherToggle = (
|
|
166
|
-
base?: TraceClientRequestWatcherToggle,
|
|
167
|
-
override?: TraceClientRequestWatcherToggle
|
|
168
|
-
): TraceClientRequestWatcherToggle | undefined => {
|
|
169
|
-
if (override === undefined) return base;
|
|
170
|
-
if (override === false || override === true) return override;
|
|
171
|
-
|
|
172
|
-
const baseConfig = isObjectValue(base) ? base : undefined;
|
|
173
|
-
const merged = mergeClientRequestCaptureRule(baseConfig, override) ?? {};
|
|
174
|
-
const sources = mergeClientRequestSources(base, override);
|
|
175
|
-
|
|
176
|
-
if (sources === undefined) {
|
|
177
|
-
return merged;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return Object.freeze({
|
|
181
|
-
...merged,
|
|
182
|
-
sources,
|
|
183
|
-
});
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
const REQUEST_METHOD_KEYS = ['all', 'get', 'post', 'put', 'patch', 'delete'] as const;
|
|
187
|
-
|
|
188
|
-
const mergeRequestWatcherToggle = (
|
|
189
|
-
base?: ITraceConfig['watchers']['request'],
|
|
190
|
-
override?: ITraceConfig['watchers']['request']
|
|
191
|
-
): ITraceConfig['watchers']['request'] | undefined => {
|
|
192
|
-
if (override === undefined) return base;
|
|
193
|
-
if (override === false || override === true) return override;
|
|
194
|
-
|
|
195
|
-
const baseConfig = isObjectValue(base) ? base : undefined;
|
|
196
|
-
const merged: TraceRequestWatcherConfig = mergeFilterRule(baseConfig, override) ?? {};
|
|
197
|
-
|
|
198
|
-
for (const key of REQUEST_METHOD_KEYS) {
|
|
199
|
-
const rule = mergeFilterRule(baseConfig?.[key], override[key]);
|
|
200
|
-
if (rule !== undefined) merged[key] = rule;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return merged;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
const mergeWatchers = (
|
|
207
|
-
base: ITraceConfig['watchers'],
|
|
208
|
-
override?: TraceConfigOverrides['watchers']
|
|
209
|
-
): ITraceConfig['watchers'] => {
|
|
210
|
-
if (override === undefined) return { ...base };
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
...base,
|
|
214
|
-
...override,
|
|
215
|
-
request: mergeRequestWatcherToggle(base.request, override.request),
|
|
216
|
-
query: mergeWatcherToggle(base.query, override.query),
|
|
217
|
-
exception: mergeWatcherToggle(base.exception, override.exception),
|
|
218
|
-
log: mergeWatcherToggle(base.log, override.log),
|
|
219
|
-
job: mergeWatcherToggle(base.job, override.job),
|
|
220
|
-
cache: mergeWatcherToggle(base.cache, override.cache),
|
|
221
|
-
schedule: mergeWatcherToggle(base.schedule, override.schedule),
|
|
222
|
-
mail: mergeWatcherToggle(base.mail, override.mail),
|
|
223
|
-
auth: mergeWatcherToggle(base.auth, override.auth),
|
|
224
|
-
event: mergeWatcherToggle(base.event, override.event),
|
|
225
|
-
model: mergeWatcherToggle(base.model, override.model),
|
|
226
|
-
notification: mergeWatcherToggle(base.notification, override.notification),
|
|
227
|
-
redis: mergeWatcherToggle(base.redis, override.redis),
|
|
228
|
-
gate: mergeWatcherToggle(base.gate, override.gate),
|
|
229
|
-
middleware: mergeWatcherToggle(base.middleware, override.middleware),
|
|
230
|
-
command: mergeWatcherToggle(base.command, override.command),
|
|
231
|
-
batch: mergeWatcherToggle(base.batch, override.batch),
|
|
232
|
-
dump: mergeWatcherToggle(base.dump, override.dump),
|
|
233
|
-
view: mergeWatcherToggle(base.view, override.view),
|
|
234
|
-
clientRequest: mergeClientRequestWatcherToggle(base.clientRequest, override.clientRequest),
|
|
235
|
-
};
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const mergeContentDispatch = (
|
|
239
|
-
base: TraceContentDispatchConfig,
|
|
240
|
-
override?: TraceConfigOverrides['contentDispatch']
|
|
241
|
-
): TraceContentDispatchConfig => {
|
|
242
|
-
const workerOverride = override?.worker;
|
|
243
|
-
|
|
244
|
-
return {
|
|
245
|
-
...base,
|
|
246
|
-
...override,
|
|
247
|
-
worker:
|
|
248
|
-
workerOverride === undefined
|
|
249
|
-
? base.worker
|
|
250
|
-
: {
|
|
251
|
-
...base.worker,
|
|
252
|
-
...workerOverride,
|
|
253
|
-
},
|
|
254
|
-
};
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
const mergeProxyConfig = (
|
|
258
|
-
base: TraceProxyConfig,
|
|
259
|
-
override?: TraceConfigOverrides['proxy']
|
|
260
|
-
): TraceProxyConfig => {
|
|
261
|
-
if (override === undefined) return base;
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
...base,
|
|
265
|
-
...override,
|
|
266
|
-
};
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const DEFAULTS: ITraceConfig = Object.freeze({
|
|
270
|
-
enabled: false,
|
|
271
|
-
connection: undefined,
|
|
272
|
-
observeConnection: undefined,
|
|
273
|
-
serviceTag: undefined,
|
|
274
|
-
proxy: {
|
|
275
|
-
enabled: false,
|
|
276
|
-
url: undefined,
|
|
277
|
-
path: '/zin/trace/write',
|
|
278
|
-
keyId: undefined,
|
|
279
|
-
secret: undefined,
|
|
280
|
-
timeoutMs: 30000,
|
|
281
|
-
},
|
|
282
|
-
pruneAfterHours: 24,
|
|
283
|
-
ignoreRoutes: ['/trace', '/health', '/ping'],
|
|
284
|
-
ignorePaths: [],
|
|
285
|
-
slowQueryThreshold: 100,
|
|
286
|
-
captureCachePayloads: false,
|
|
287
|
-
captureQueryBindings: true,
|
|
288
|
-
logMinLevel: 'info',
|
|
289
|
-
contentDispatch: {
|
|
290
|
-
driver: undefined,
|
|
291
|
-
queueName: 'trace-content',
|
|
292
|
-
enqueueTimeoutMs: 25,
|
|
293
|
-
worker: {
|
|
294
|
-
enabled: true,
|
|
295
|
-
intervalMs: 1000,
|
|
296
|
-
maxDurationMs: 250,
|
|
297
|
-
concurrency: 1,
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
watchers: {},
|
|
301
|
-
redaction: {
|
|
302
|
-
keys: [
|
|
303
|
-
'password',
|
|
304
|
-
'pass',
|
|
305
|
-
'passwd',
|
|
306
|
-
'token',
|
|
307
|
-
'accessToken',
|
|
308
|
-
'access_token',
|
|
309
|
-
'refreshToken',
|
|
310
|
-
'refresh_token',
|
|
311
|
-
'secret',
|
|
312
|
-
'secretKey',
|
|
313
|
-
'secret_key',
|
|
314
|
-
'apiKey',
|
|
315
|
-
'api_key',
|
|
316
|
-
'auth',
|
|
317
|
-
'authToken',
|
|
318
|
-
'auth_token',
|
|
319
|
-
'authorization',
|
|
320
|
-
'cookie',
|
|
321
|
-
'session',
|
|
322
|
-
'sessionId',
|
|
323
|
-
'session_id',
|
|
324
|
-
'card',
|
|
325
|
-
'cardNumber',
|
|
326
|
-
'card_number',
|
|
327
|
-
'cardToken',
|
|
328
|
-
'card_token',
|
|
329
|
-
'cvv',
|
|
330
|
-
'cvc',
|
|
331
|
-
'pan',
|
|
332
|
-
],
|
|
333
|
-
headers: ['authorization', 'cookie', 'x-api-key', 'x-auth-token'],
|
|
334
|
-
body: ['password', 'token', 'secret', 'apiKey', 'api_key', 'jwt', 'bearer'],
|
|
335
|
-
query: [],
|
|
336
|
-
},
|
|
337
|
-
} satisfies ITraceConfig);
|
|
338
|
-
|
|
339
|
-
const isWatcherEnabled = (config: ITraceConfig, key: keyof ITraceConfig['watchers']): boolean => {
|
|
340
|
-
const override = config.watchers[key];
|
|
341
|
-
if (override === false) return false;
|
|
342
|
-
if (isObjectValue(override) && override.enabled === false) return false;
|
|
343
|
-
return true; // undefined = enabled by default; explicit false = disabled
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
const getRedactionFields = (
|
|
347
|
-
config: ITraceConfig,
|
|
348
|
-
key: keyof ITraceConfig['redaction']
|
|
349
|
-
): string[] => {
|
|
350
|
-
if (key === 'keys') {
|
|
351
|
-
return mergeStringLists([], config.redaction.keys);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return mergeStringLists(config.redaction.keys, config.redaction[key]);
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
export const TraceConfig = Object.freeze({
|
|
358
|
-
defaults(): ITraceConfig {
|
|
359
|
-
return DEFAULTS;
|
|
360
|
-
},
|
|
361
|
-
|
|
362
|
-
merge(overrides?: TraceConfigOverrides): ITraceConfig {
|
|
363
|
-
if (overrides === undefined || overrides === null) return DEFAULTS;
|
|
364
|
-
return Object.freeze({
|
|
365
|
-
...DEFAULTS,
|
|
366
|
-
...overrides,
|
|
367
|
-
proxy: mergeProxyConfig(DEFAULTS.proxy, overrides.proxy),
|
|
368
|
-
contentDispatch: mergeContentDispatch(DEFAULTS.contentDispatch, overrides.contentDispatch),
|
|
369
|
-
watchers: mergeWatchers(DEFAULTS.watchers, overrides.watchers),
|
|
370
|
-
redaction: {
|
|
371
|
-
keys: mergeStringLists(DEFAULTS.redaction.keys, overrides.redaction?.keys),
|
|
372
|
-
headers: mergeStringLists(DEFAULTS.redaction.headers, overrides.redaction?.headers),
|
|
373
|
-
body: mergeStringLists(DEFAULTS.redaction.body, overrides.redaction?.body),
|
|
374
|
-
query: mergeStringLists(DEFAULTS.redaction.query, overrides.redaction?.query),
|
|
375
|
-
},
|
|
376
|
-
ignoreRoutes: overrides.ignoreRoutes ?? DEFAULTS.ignoreRoutes,
|
|
377
|
-
ignorePaths: overrides.ignorePaths ?? DEFAULTS.ignorePaths,
|
|
378
|
-
});
|
|
379
|
-
},
|
|
380
|
-
|
|
381
|
-
getRedactionFields,
|
|
382
|
-
isWatcherEnabled,
|
|
383
|
-
});
|