@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/ui.ts DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * Lightweight UI/dashboard entrypoint for @zintrust/trace.
3
- *
4
- * Import this subpath when you only need trace dashboard registration
5
- * without pulling in the package root re-export surface.
6
- */
7
-
8
- export { registerTraceDashboard, registerTraceRoutes } from './dashboard/routes';
9
- export type { TraceDashboardOptions, TraceDashboardRegistrationOptions } from './dashboard/routes';
@@ -1,20 +0,0 @@
1
- import { TraceContext } from '../context';
2
-
3
- const resolveAuthTag = (): string | undefined => {
4
- const userId = TraceContext.getUserId();
5
- if (userId === undefined || userId === '') return undefined;
6
- return `Auth:${userId}`;
7
- };
8
-
9
- const appendAuthTag = (tags: string[]): string[] => {
10
- const authTag = resolveAuthTag();
11
- if (authTag === undefined || tags.includes(authTag)) return tags;
12
- return [...tags, authTag];
13
- };
14
-
15
- export const AuthTag = Object.freeze({
16
- append: appendAuthTag,
17
- resolve: resolveAuthTag,
18
- });
19
-
20
- export default AuthTag;
@@ -1,131 +0,0 @@
1
- import type {
2
- ITraceConfig,
3
- ITraceEntry,
4
- TraceClientRequestWatcherConfig,
5
- TraceFilterRule,
6
- TraceRequestWatcherConfig,
7
- WatcherToggles,
8
- } from '../types';
9
- import { EntryType } from '../types';
10
-
11
- const isObjectValue = (value: unknown): value is Record<string, unknown> => {
12
- return typeof value === 'object' && value !== null && !Array.isArray(value);
13
- };
14
-
15
- const normalizeTerms = (terms?: string[]): string[] => {
16
- if (!Array.isArray(terms)) return [];
17
-
18
- return terms
19
- .filter((term): term is string => typeof term === 'string')
20
- .map((term) => term.trim().toLowerCase())
21
- .filter((term) => term !== '');
22
- };
23
-
24
- const matchesRule = (haystack: string, rule?: TraceFilterRule): boolean => {
25
- if (!rule) return true;
26
- if (rule.enabled === false) return false;
27
-
28
- const include = normalizeTerms(rule.include);
29
- const exclude = normalizeTerms(rule.exclude);
30
-
31
- if (exclude.some((term) => haystack.includes(term))) return false;
32
- if (include.length === 0) return true;
33
-
34
- return include.some((term) => haystack.includes(term));
35
- };
36
-
37
- const toSearchableText = (entry: ITraceEntry): string => {
38
- const sections = [entry.type, entry.batchId, ...(entry.tags ?? [])];
39
-
40
- try {
41
- sections.push(JSON.stringify(entry.content) ?? '');
42
- } catch {
43
- sections.push(String(entry.content ?? ''));
44
- }
45
-
46
- return sections.join(' ').toLowerCase();
47
- };
48
-
49
- const watcherKeyByEntryType: Record<ITraceEntry['type'], keyof WatcherToggles> = {
50
- [EntryType.REQUEST]: 'request',
51
- [EntryType.QUERY]: 'query',
52
- [EntryType.EXCEPTION]: 'exception',
53
- [EntryType.LOG]: 'log',
54
- [EntryType.JOB]: 'job',
55
- [EntryType.CACHE]: 'cache',
56
- [EntryType.SCHEDULE]: 'schedule',
57
- [EntryType.MAIL]: 'mail',
58
- [EntryType.AUTH]: 'auth',
59
- [EntryType.EVENT]: 'event',
60
- [EntryType.MODEL]: 'model',
61
- [EntryType.NOTIFICATION]: 'notification',
62
- [EntryType.REDIS]: 'redis',
63
- [EntryType.GATE]: 'gate',
64
- [EntryType.MIDDLEWARE]: 'middleware',
65
- [EntryType.COMMAND]: 'command',
66
- [EntryType.BATCH]: 'batch',
67
- [EntryType.DUMP]: 'dump',
68
- [EntryType.VIEW]: 'view',
69
- [EntryType.CLIENT_REQUEST]: 'clientRequest',
70
- };
71
-
72
- const getRequestMethodRule = (
73
- watcher: TraceRequestWatcherConfig,
74
- entry: ITraceEntry
75
- ): TraceFilterRule | undefined => {
76
- if (entry.type !== EntryType.REQUEST) return undefined;
77
-
78
- const content = isObjectValue(entry.content) ? entry.content : undefined;
79
- const methodValue = content?.['method'];
80
- const method = typeof methodValue === 'string' ? methodValue.trim().toLowerCase() : '';
81
-
82
- if (method === 'get') return watcher.get;
83
- if (method === 'post') return watcher.post;
84
- if (method === 'put') return watcher.put;
85
- if (method === 'patch') return watcher.patch;
86
- if (method === 'delete' || method === 'del') return watcher.delete;
87
-
88
- return watcher.all;
89
- };
90
-
91
- const getClientRequestSourceRule = (
92
- watcher: TraceClientRequestWatcherConfig,
93
- entry: ITraceEntry
94
- ): TraceFilterRule | undefined => {
95
- if (entry.type !== EntryType.CLIENT_REQUEST) return undefined;
96
-
97
- const content = isObjectValue(entry.content) ? entry.content : undefined;
98
- const sourceValue = content?.['source'];
99
- const source = typeof sourceValue === 'string' ? sourceValue.trim().toLowerCase() : '';
100
-
101
- if (source === '') return undefined;
102
- return watcher.sources?.[source];
103
- };
104
-
105
- export const TraceEntryFilter = Object.freeze({
106
- shouldCapture(entry: ITraceEntry, config: ITraceConfig): boolean {
107
- const watcherKey = watcherKeyByEntryType[entry.type];
108
- const watcher = config.watchers[watcherKey];
109
- if (watcher === false) return false;
110
- if (!isObjectValue(watcher)) return true;
111
-
112
- const haystack = toSearchableText(entry);
113
- if (!matchesRule(haystack, watcher)) return false;
114
-
115
- if (watcherKey === 'request') {
116
- const requestWatcher = watcher as TraceRequestWatcherConfig;
117
- const methodRule = getRequestMethodRule(requestWatcher, entry);
118
- if (!matchesRule(haystack, requestWatcher.all)) return false;
119
- if (!matchesRule(haystack, methodRule)) return false;
120
- }
121
-
122
- if (watcherKey === 'clientRequest') {
123
- const clientRequestWatcher = watcher as TraceClientRequestWatcherConfig;
124
- const sourceRule = getClientRequestSourceRule(clientRequestWatcher, entry);
125
- if (sourceRule?.enabled === false) return false;
126
- if (!matchesRule(haystack, sourceRule)) return false;
127
- }
128
-
129
- return true;
130
- },
131
- });
@@ -1,8 +0,0 @@
1
- export const familyHash = (input: string): string => {
2
- let hash = 2166136261;
3
- for (let index = 0; index < input.length; index++) {
4
- hash ^= input.codePointAt(index) ?? 0;
5
- hash = (hash * 16777619) >>> 0;
6
- }
7
- return hash.toString(16).padStart(8, '0');
8
- };
@@ -1,112 +0,0 @@
1
- /**
2
- * Redaction helpers for @zintrust/trace watchers.
3
- */
4
-
5
- const REDACTED = '****';
6
-
7
- const isArrayValue = (value: unknown): value is unknown[] => Array.isArray(value);
8
-
9
- const isObjectValue = (value: unknown): value is Record<string, unknown> => {
10
- return typeof value === 'object' && value !== null && !Array.isArray(value);
11
- };
12
-
13
- const normalizeFields = (fields: string[]): Set<string> => {
14
- const normalized = new Set<string>();
15
-
16
- for (const field of fields) {
17
- if (typeof field !== 'string') continue;
18
- const key = field.trim().toLowerCase();
19
- if (key !== '') normalized.add(key);
20
- }
21
-
22
- return normalized;
23
- };
24
-
25
- const redactUnknownValue = (
26
- value: unknown,
27
- fields: Set<string>,
28
- seen: WeakSet<object>
29
- ): unknown => {
30
- if (isArrayValue(value)) {
31
- return value.map((item) => redactUnknownValue(item, fields, seen));
32
- }
33
-
34
- if (!isObjectValue(value)) {
35
- return value;
36
- }
37
-
38
- if (seen.has(value)) {
39
- return '[Circular]';
40
- }
41
-
42
- seen.add(value);
43
- const out: Record<string, unknown> = {};
44
-
45
- for (const [key, entryValue] of Object.entries(value)) {
46
- out[key] = fields.has(key.toLowerCase())
47
- ? REDACTED
48
- : redactUnknownValue(entryValue, fields, seen);
49
- }
50
-
51
- seen.delete(value);
52
- return out;
53
- };
54
-
55
- const redactQuerySegment = (segment: string, fields: Set<string>): string => {
56
- const separatorIndex = segment.indexOf('=');
57
- if (separatorIndex <= 0) return segment;
58
-
59
- const key = segment.slice(0, separatorIndex);
60
- const value = segment.slice(separatorIndex + 1);
61
- if (!fields.has(key.toLowerCase())) return `${key}=${value}`;
62
-
63
- return `${key}=${REDACTED}`;
64
- };
65
-
66
- export const redactHeaders = (
67
- headers: Record<string, string>,
68
- fields: string[]
69
- ): Record<string, string> => {
70
- const lower = normalizeFields(fields);
71
- const out: Record<string, string> = {};
72
- for (const [k, v] of Object.entries(headers)) {
73
- out[k] = lower.has(k.toLowerCase()) ? REDACTED : v;
74
- }
75
- return out;
76
- };
77
-
78
- export const redactUnknown = (value: unknown, fields: string[]): unknown => {
79
- return redactUnknownValue(value, normalizeFields(fields), new WeakSet<object>());
80
- };
81
-
82
- export const redactObject = (
83
- obj: Record<string, unknown>,
84
- fields: string[]
85
- ): Record<string, unknown> => {
86
- const redacted = redactUnknown(obj, fields);
87
- return isObjectValue(redacted) ? redacted : {};
88
- };
89
-
90
- export const redactString = (value: string, fields: string[]): string => {
91
- const lower = normalizeFields(fields);
92
- if (value === '') return value;
93
-
94
- let output = '';
95
- let segmentStart = 0;
96
-
97
- for (let index = 0; index <= value.length; index += 1) {
98
- const isBoundary = index === value.length || value[index] === '&';
99
- if (!isBoundary) continue;
100
-
101
- const segment = value.slice(segmentStart, index);
102
- output += redactQuerySegment(segment, lower);
103
-
104
- if (index < value.length) {
105
- output += '&';
106
- }
107
-
108
- segmentStart = index + 1;
109
- }
110
-
111
- return output;
112
- };
@@ -1,79 +0,0 @@
1
- import { TraceContext } from '../context';
2
-
3
- type RequestIgnoreRules = {
4
- ignoreRoutes?: string[];
5
- ignorePaths?: string[];
6
- };
7
-
8
- const normalizePath = (input: string): string => {
9
- const trimmed = input.trim();
10
- const [pathOnly] = trimmed.split('?');
11
- if (!pathOnly || pathOnly === '') return '/';
12
- return pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}`;
13
- };
14
-
15
- const normalizeContainsPattern = (input: string): string => {
16
- const trimmed = input.trim();
17
- const [pathOnly] = trimmed.split('?');
18
- return pathOnly ?? '';
19
- };
20
-
21
- const resolveRules = (
22
- ignoreRoutesOrRules: string[] | RequestIgnoreRules,
23
- ignorePaths?: string[]
24
- ): Required<RequestIgnoreRules> => {
25
- if (Array.isArray(ignoreRoutesOrRules)) {
26
- return {
27
- ignoreRoutes: ignoreRoutesOrRules,
28
- ignorePaths: ignorePaths ?? [],
29
- };
30
- }
31
-
32
- return {
33
- ignoreRoutes: ignoreRoutesOrRules.ignoreRoutes ?? [],
34
- ignorePaths: ignoreRoutesOrRules.ignorePaths ?? [],
35
- };
36
- };
37
-
38
- const matchesIgnoredPath = (
39
- path: string,
40
- ignoreRoutesOrRules: string[] | RequestIgnoreRules,
41
- ignorePaths?: string[]
42
- ): boolean => {
43
- const normalizedPath = normalizePath(path);
44
- const rules = resolveRules(ignoreRoutesOrRules, ignorePaths);
45
-
46
- if (
47
- rules.ignoreRoutes.some((route) => {
48
- const normalizedRoute = normalizePath(route);
49
- return (
50
- normalizedPath === normalizedRoute ||
51
- normalizedPath.startsWith(
52
- normalizedRoute.endsWith('/') ? normalizedRoute : `${normalizedRoute}/`
53
- )
54
- );
55
- })
56
- ) {
57
- return true;
58
- }
59
-
60
- return rules.ignorePaths.some((route) => {
61
- const containsPattern = normalizeContainsPattern(route);
62
- if (containsPattern === '') return false;
63
- return normalizedPath.includes(containsPattern);
64
- });
65
- };
66
-
67
- const shouldIgnoreCurrentRequest = (
68
- ignoreRoutesOrRules: string[] | RequestIgnoreRules,
69
- ignorePaths?: string[]
70
- ): boolean => {
71
- const currentPath = TraceContext.getRequestPath();
72
- if (typeof currentPath !== 'string' || currentPath === '') return false;
73
- return matchesIgnoredPath(currentPath, ignoreRoutesOrRules, ignorePaths);
74
- };
75
-
76
- export const RequestFilter = Object.freeze({
77
- matchesIgnoredPath,
78
- shouldIgnoreCurrentRequest,
79
- });
@@ -1,44 +0,0 @@
1
- type StackFrame = { file: string; line: number };
2
-
3
- const FRAME_PREFIX = 'at ';
4
-
5
- const parsePositiveInt = (value: string): number | null => {
6
- if (value === '') return null;
7
-
8
- for (const char of value) {
9
- if (char < '0' || char > '9') return null;
10
- }
11
-
12
- const parsed = Number.parseInt(value, 10);
13
- return Number.isNaN(parsed) ? null : parsed;
14
- };
15
-
16
- const parseFrameLocation = (value: string): StackFrame | null => {
17
- const columnSeparatorIndex = value.lastIndexOf(':');
18
- if (columnSeparatorIndex <= 0) return null;
19
-
20
- const lineSeparatorIndex = value.lastIndexOf(':', columnSeparatorIndex - 1);
21
- if (lineSeparatorIndex <= 0) return null;
22
-
23
- const file = value.slice(0, lineSeparatorIndex).trim();
24
- const line = parsePositiveInt(value.slice(lineSeparatorIndex + 1, columnSeparatorIndex));
25
- const column = parsePositiveInt(value.slice(columnSeparatorIndex + 1));
26
-
27
- if (file === '' || line === null || column === null) return null;
28
- return { file, line };
29
- };
30
-
31
- export const parseStackFrameLine = (line: string): StackFrame | null => {
32
- const trimmed = line.trim();
33
- if (!trimmed.startsWith(FRAME_PREFIX)) return null;
34
-
35
- const body = trimmed.slice(FRAME_PREFIX.length).trim();
36
- if (body === '') return null;
37
-
38
- const wrappedStartIndex = body.lastIndexOf(' (');
39
- if (wrappedStartIndex !== -1 && body.endsWith(')')) {
40
- return parseFrameLocation(body.slice(wrappedStartIndex + 2, -1));
41
- }
42
-
43
- return parseFrameLocation(body);
44
- };
@@ -1,53 +0,0 @@
1
- /**
2
- * AuthWatcher — records login/logout/failed auth events.
3
- * Credentials are never stored; only the outcome.
4
- */
5
- import { TraceContext } from '../context';
6
- import type { AuthContent, ITraceWatcher, ITraceWatcherConfig } from '../types';
7
- import { EntryType } from '../types';
8
- import { RequestFilter } from '../utils/requestFilter';
9
-
10
- let _storage: ITraceWatcherConfig['storage'] | null = null;
11
- let _ignoreRoutes: string[] = [];
12
- let _ignorePaths: string[] = [];
13
-
14
- const emit = (event: AuthContent['event'], userId?: string): void => {
15
- if (!_storage) return;
16
- if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
17
- const content: AuthContent = {
18
- event,
19
- userId,
20
- hostname: TraceContext.getHostname(),
21
- };
22
- const tags: string[] = [];
23
- if (userId) tags.push(`Auth:${userId}`);
24
- if (event === 'failed') tags.push('failed');
25
-
26
- _storage
27
- .writeEntry({
28
- uuid: crypto.randomUUID(),
29
- batchId: TraceContext.getBatchId(),
30
- type: EntryType.AUTH,
31
- content,
32
- tags,
33
- isLatest: true,
34
- createdAt: TraceContext.now(),
35
- })
36
- .catch(() => undefined);
37
- };
38
-
39
- export const AuthWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze({
40
- emit,
41
-
42
- register({ storage, config }: ITraceWatcherConfig): () => void {
43
- if (config.watchers.auth === false) return () => undefined;
44
- _storage = storage;
45
- _ignoreRoutes = config.ignoreRoutes;
46
- _ignorePaths = config.ignorePaths;
47
- return () => {
48
- _storage = null;
49
- _ignoreRoutes = [];
50
- _ignorePaths = [];
51
- };
52
- },
53
- });
@@ -1,55 +0,0 @@
1
- import { TraceContext } from '../context';
2
- import type { BatchContent, ITraceWatcher, ITraceWatcherConfig } from '../types';
3
- import { EntryType } from '../types';
4
- import { RequestFilter } from '../utils/requestFilter';
5
-
6
- let _storage: ITraceWatcherConfig['storage'] | null = null;
7
- let _ignoreRoutes: string[] = [];
8
- let _ignorePaths: string[] = [];
9
-
10
- const emit = (
11
- name: string,
12
- total: number,
13
- processed: number,
14
- failed: number,
15
- status: BatchContent['status']
16
- ): void => {
17
- if (!_storage) return;
18
- if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
19
- const tags = [name];
20
- if (failed > 0) tags.push('failed');
21
- const content: BatchContent = {
22
- name,
23
- total,
24
- processed,
25
- failed,
26
- status,
27
- hostname: TraceContext.getHostname(),
28
- };
29
- _storage
30
- .writeEntry({
31
- uuid: crypto.randomUUID(),
32
- batchId: TraceContext.getBatchId(),
33
- type: EntryType.BATCH,
34
- content,
35
- tags,
36
- isLatest: true,
37
- createdAt: TraceContext.now(),
38
- })
39
- .catch(() => undefined);
40
- };
41
-
42
- export const BatchWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze({
43
- emit,
44
- register({ storage, config }: ITraceWatcherConfig): () => void {
45
- if (config.watchers.batch === false) return () => undefined;
46
- _storage = storage;
47
- _ignoreRoutes = config.ignoreRoutes;
48
- _ignorePaths = config.ignorePaths;
49
- return () => {
50
- _storage = null;
51
- _ignoreRoutes = [];
52
- _ignorePaths = [];
53
- };
54
- },
55
- });
@@ -1,72 +0,0 @@
1
- /**
2
- * CacheWatcher — records cache operations.
3
- * Call CacheWatcher.emit() from within your cache driver instrumentation.
4
- */
5
- import { TraceContext } from '../context';
6
- import type { CacheContent, ITraceWatcher, ITraceWatcherConfig } from '../types';
7
- import { EntryType } from '../types';
8
- import { AuthTag } from '../utils/authTag';
9
- import { redactString, redactUnknown } from '../utils/redact';
10
- import { RequestFilter } from '../utils/requestFilter';
11
-
12
- let _storage: ITraceWatcherConfig['storage'] | null = null;
13
- let _config: ITraceWatcherConfig['config'] | null = null;
14
- let _redactionFields: string[] = [];
15
- let _ignoreRoutes: string[] = [];
16
- let _ignorePaths: string[] = [];
17
-
18
- const emit = (
19
- operation: CacheContent['operation'],
20
- key: string,
21
- duration: number,
22
- hit?: boolean,
23
- payload?: unknown,
24
- store?: string,
25
- ttl?: number
26
- ): void => {
27
- if (!_storage) return;
28
- if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
29
- const safeKey = redactString(key, _redactionFields);
30
- const shouldLogPayload = _config?.captureCachePayloads === true;
31
- const content: CacheContent = {
32
- operation,
33
- key: safeKey,
34
- hit,
35
- ...(typeof store === 'string' && store !== '' ? { store } : {}),
36
- ...(typeof ttl === 'number' ? { ttl } : {}),
37
- payloadLogged: shouldLogPayload,
38
- ...(shouldLogPayload ? { payload: redactUnknown(payload, _redactionFields) } : {}),
39
- duration,
40
- hostname: TraceContext.getHostname(),
41
- };
42
- _storage
43
- .writeEntry({
44
- uuid: crypto.randomUUID(),
45
- batchId: TraceContext.getBatchId(),
46
- type: EntryType.CACHE,
47
- content,
48
- tags: AuthTag.append([]),
49
- isLatest: true,
50
- createdAt: TraceContext.now(),
51
- })
52
- .catch(() => undefined);
53
- };
54
-
55
- export const CacheWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze({
56
- emit,
57
-
58
- register({ storage, config }: ITraceWatcherConfig): () => void {
59
- if (config.watchers.cache === false) return () => undefined;
60
- _storage = storage;
61
- _config = config;
62
- _redactionFields = config.redaction.query;
63
- _ignoreRoutes = config.ignoreRoutes;
64
- _ignorePaths = config.ignorePaths;
65
- return () => {
66
- _storage = null;
67
- _config = null;
68
- _ignoreRoutes = [];
69
- _ignorePaths = [];
70
- };
71
- },
72
- });
@@ -1,58 +0,0 @@
1
- import { TraceContext } from '../context';
2
- import type { CommandContent, ITraceWatcher, ITraceWatcherConfig } from '../types';
3
- import { EntryType } from '../types';
4
- import { redactObject } from '../utils/redact';
5
- import { RequestFilter } from '../utils/requestFilter';
6
-
7
- let _storage: ITraceWatcherConfig['storage'] | null = null;
8
- let _redactKeys: string[] = [];
9
- let _ignoreRoutes: string[] = [];
10
- let _ignorePaths: string[] = [];
11
-
12
- const emit = (
13
- name: string,
14
- args: Record<string, unknown>,
15
- exitCode: number,
16
- duration: number,
17
- output?: string
18
- ): void => {
19
- if (!_storage) return;
20
- if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
21
- const tags = [name];
22
- if (exitCode !== 0) tags.push('failed');
23
- const content: CommandContent = {
24
- name,
25
- arguments: redactObject(args, _redactKeys),
26
- exitCode,
27
- duration,
28
- output,
29
- hostname: TraceContext.getHostname(),
30
- };
31
- _storage
32
- .writeEntry({
33
- uuid: crypto.randomUUID(),
34
- batchId: TraceContext.getBatchId(),
35
- type: EntryType.COMMAND,
36
- content,
37
- tags,
38
- isLatest: true,
39
- createdAt: TraceContext.now(),
40
- })
41
- .catch(() => undefined);
42
- };
43
-
44
- export const CommandWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze({
45
- emit,
46
- register({ storage, config }: ITraceWatcherConfig): () => void {
47
- if (config.watchers.command === false) return () => undefined;
48
- _storage = storage;
49
- _redactKeys = [...(config.redaction?.keys ?? []), ...(config.redaction?.body ?? [])];
50
- _ignoreRoutes = config.ignoreRoutes;
51
- _ignorePaths = config.ignorePaths;
52
- return () => {
53
- _storage = null;
54
- _ignoreRoutes = [];
55
- _ignorePaths = [];
56
- };
57
- },
58
- });
@@ -1,45 +0,0 @@
1
- import { TraceContext } from '../context';
2
- import type { DumpContent, ITraceWatcher, ITraceWatcherConfig } from '../types';
3
- import { EntryType } from '../types';
4
- import { RequestFilter } from '../utils/requestFilter';
5
-
6
- let _storage: ITraceWatcherConfig['storage'] | null = null;
7
- let _enabled = false;
8
- let _ignoreRoutes: string[] = [];
9
- let _ignorePaths: string[] = [];
10
-
11
- /** Explicitly opt-in (enabled only when config.watchers.dump === true, not just non-false). */
12
- const emit = (value: unknown, file?: string, line?: number): void => {
13
- if (!_storage || !_enabled) return;
14
- if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
15
- const content: DumpContent = { value, file, line, hostname: TraceContext.getHostname() };
16
- _storage
17
- .writeEntry({
18
- uuid: crypto.randomUUID(),
19
- batchId: TraceContext.getBatchId(),
20
- type: EntryType.DUMP,
21
- content,
22
- tags: [],
23
- isLatest: true,
24
- createdAt: TraceContext.now(),
25
- })
26
- .catch(() => undefined);
27
- };
28
-
29
- export const DumpWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze({
30
- emit,
31
- register({ storage, config }: ITraceWatcherConfig): () => void {
32
- // DumpWatcher requires explicit opt-in (=== true), not just absence of false
33
- if (config.watchers.dump !== true) return () => undefined;
34
- _storage = storage;
35
- _enabled = true;
36
- _ignoreRoutes = config.ignoreRoutes;
37
- _ignorePaths = config.ignorePaths;
38
- return () => {
39
- _storage = null;
40
- _enabled = false;
41
- _ignoreRoutes = [];
42
- _ignorePaths = [];
43
- };
44
- },
45
- });