@zintrust/trace 0.4.75

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 (128) hide show
  1. package/README.md +288 -0
  2. package/dist/build-manifest.json +365 -0
  3. package/dist/cli-register.d.ts +9 -0
  4. package/dist/cli-register.js +32 -0
  5. package/dist/config.d.ts +9 -0
  6. package/dist/config.js +38 -0
  7. package/dist/context.d.ts +18 -0
  8. package/dist/context.js +86 -0
  9. package/dist/dashboard/handlers.d.ts +15 -0
  10. package/dist/dashboard/handlers.js +179 -0
  11. package/dist/dashboard/routes.d.ts +19 -0
  12. package/dist/dashboard/routes.js +50 -0
  13. package/dist/dashboard/ui.d.ts +2 -0
  14. package/dist/dashboard/ui.js +870 -0
  15. package/dist/index.d.ts +35 -0
  16. package/dist/index.js +50 -0
  17. package/dist/migrations/20260331000001_create_zin_debugger_entries_table.d.ts +10 -0
  18. package/dist/migrations/20260331000001_create_zin_debugger_entries_table.js +28 -0
  19. package/dist/migrations/20260331000002_create_zin_debugger_entries_tags_table.d.ts +10 -0
  20. package/dist/migrations/20260331000002_create_zin_debugger_entries_tags_table.js +21 -0
  21. package/dist/migrations/20260331000003_create_zin_debugger_monitoring_table.d.ts +10 -0
  22. package/dist/migrations/20260331000003_create_zin_debugger_monitoring_table.js +17 -0
  23. package/dist/migrations/index.d.ts +6 -0
  24. package/dist/migrations/index.js +4 -0
  25. package/dist/plugin.d.ts +1 -0
  26. package/dist/plugin.js +3 -0
  27. package/dist/register.d.ts +1 -0
  28. package/dist/register.js +140 -0
  29. package/dist/storage/DebuggerStorage.d.ts +13 -0
  30. package/dist/storage/DebuggerStorage.js +195 -0
  31. package/dist/storage/TraceStorage.d.ts +13 -0
  32. package/dist/storage/TraceStorage.js +195 -0
  33. package/dist/storage/index.d.ts +2 -0
  34. package/dist/storage/index.js +1 -0
  35. package/dist/types.d.ts +270 -0
  36. package/dist/types.js +25 -0
  37. package/dist/ui.d.ts +8 -0
  38. package/dist/ui.js +7 -0
  39. package/dist/utils/authTag.d.ts +5 -0
  40. package/dist/utils/authTag.js +18 -0
  41. package/dist/utils/familyHash.d.ts +1 -0
  42. package/dist/utils/familyHash.js +8 -0
  43. package/dist/utils/redact.d.ts +6 -0
  44. package/dist/utils/redact.js +49 -0
  45. package/dist/utils/requestFilter.d.ts +4 -0
  46. package/dist/utils/requestFilter.js +26 -0
  47. package/dist/utils/stackFrame.d.ts +6 -0
  48. package/dist/utils/stackFrame.js +38 -0
  49. package/dist/watchers/AuthWatcher.d.ts +6 -0
  50. package/dist/watchers/AuthWatcher.js +49 -0
  51. package/dist/watchers/BatchWatcher.d.ts +6 -0
  52. package/dist/watchers/BatchWatcher.js +46 -0
  53. package/dist/watchers/CacheWatcher.d.ts +6 -0
  54. package/dist/watchers/CacheWatcher.js +51 -0
  55. package/dist/watchers/CommandWatcher.d.ts +6 -0
  56. package/dist/watchers/CommandWatcher.js +49 -0
  57. package/dist/watchers/DumpWatcher.d.ts +7 -0
  58. package/dist/watchers/DumpWatcher.js +41 -0
  59. package/dist/watchers/EventWatcher.d.ts +6 -0
  60. package/dist/watchers/EventWatcher.js +42 -0
  61. package/dist/watchers/ExceptionWatcher.d.ts +4 -0
  62. package/dist/watchers/ExceptionWatcher.js +103 -0
  63. package/dist/watchers/GateWatcher.d.ts +6 -0
  64. package/dist/watchers/GateWatcher.js +45 -0
  65. package/dist/watchers/HttpClientWatcher.d.ts +6 -0
  66. package/dist/watchers/HttpClientWatcher.js +50 -0
  67. package/dist/watchers/HttpWatcher.d.ts +2 -0
  68. package/dist/watchers/HttpWatcher.js +71 -0
  69. package/dist/watchers/JobWatcher.d.ts +10 -0
  70. package/dist/watchers/JobWatcher.js +108 -0
  71. package/dist/watchers/LogWatcher.d.ts +2 -0
  72. package/dist/watchers/LogWatcher.js +50 -0
  73. package/dist/watchers/MailWatcher.d.ts +6 -0
  74. package/dist/watchers/MailWatcher.js +45 -0
  75. package/dist/watchers/MiddlewareWatcher.d.ts +6 -0
  76. package/dist/watchers/MiddlewareWatcher.js +41 -0
  77. package/dist/watchers/ModelWatcher.d.ts +6 -0
  78. package/dist/watchers/ModelWatcher.js +42 -0
  79. package/dist/watchers/NotificationWatcher.d.ts +6 -0
  80. package/dist/watchers/NotificationWatcher.js +42 -0
  81. package/dist/watchers/QueryWatcher.d.ts +2 -0
  82. package/dist/watchers/QueryWatcher.js +72 -0
  83. package/dist/watchers/RedisWatcher.d.ts +7 -0
  84. package/dist/watchers/RedisWatcher.js +38 -0
  85. package/dist/watchers/ScheduleWatcher.d.ts +6 -0
  86. package/dist/watchers/ScheduleWatcher.js +46 -0
  87. package/dist/watchers/ViewWatcher.d.ts +6 -0
  88. package/dist/watchers/ViewWatcher.js +36 -0
  89. package/package.json +59 -0
  90. package/src/cli-register.ts +63 -0
  91. package/src/config.ts +46 -0
  92. package/src/context.ts +101 -0
  93. package/src/dashboard/handlers.ts +197 -0
  94. package/src/dashboard/routes.ts +101 -0
  95. package/src/dashboard/ui.ts +879 -0
  96. package/src/dashboard/zintrust-debuger.svg +30 -0
  97. package/src/index.ts +88 -0
  98. package/src/plugin.ts +9 -0
  99. package/src/register.ts +219 -0
  100. package/src/storage/TraceStorage.ts +306 -0
  101. package/src/storage/index.ts +2 -0
  102. package/src/types.ts +317 -0
  103. package/src/ui.ts +9 -0
  104. package/src/utils/authTag.ts +20 -0
  105. package/src/utils/familyHash.ts +8 -0
  106. package/src/utils/redact.ts +64 -0
  107. package/src/utils/requestFilter.ts +33 -0
  108. package/src/utils/stackFrame.ts +44 -0
  109. package/src/watchers/AuthWatcher.ts +50 -0
  110. package/src/watchers/BatchWatcher.ts +52 -0
  111. package/src/watchers/CacheWatcher.ts +58 -0
  112. package/src/watchers/CommandWatcher.ts +55 -0
  113. package/src/watchers/DumpWatcher.ts +42 -0
  114. package/src/watchers/EventWatcher.ts +43 -0
  115. package/src/watchers/ExceptionWatcher.ts +114 -0
  116. package/src/watchers/GateWatcher.ts +50 -0
  117. package/src/watchers/HttpClientWatcher.ts +56 -0
  118. package/src/watchers/HttpWatcher.ts +94 -0
  119. package/src/watchers/JobWatcher.ts +121 -0
  120. package/src/watchers/LogWatcher.ts +61 -0
  121. package/src/watchers/MailWatcher.ts +47 -0
  122. package/src/watchers/MiddlewareWatcher.ts +42 -0
  123. package/src/watchers/ModelWatcher.ts +48 -0
  124. package/src/watchers/NotificationWatcher.ts +43 -0
  125. package/src/watchers/QueryWatcher.ts +85 -0
  126. package/src/watchers/RedisWatcher.ts +39 -0
  127. package/src/watchers/ScheduleWatcher.ts +54 -0
  128. package/src/watchers/ViewWatcher.ts +37 -0
@@ -0,0 +1,108 @@
1
+ /**
2
+ * JobWatcher — records job dispatch, completion, and failure.
3
+ * Subsystems must call JobWatcher.onDispatch / onProcess / onFail from
4
+ * within their queue implementation for full tracking.
5
+ */
6
+ import { TraceContext } from '../context';
7
+ import { EntryType } from '../types';
8
+ import { RequestFilter } from '../utils/requestFilter';
9
+ import { parseStackFrameLine } from '../utils/stackFrame';
10
+ // Module-level storage ref so emit helpers can be called from outside.
11
+ let _storage = null;
12
+ let _ignoreRoutes = [];
13
+ const MAX_TRACKED_JOBS = 1000;
14
+ const pendingJobs = new Map();
15
+ const trackPendingJob = (name, job) => {
16
+ const jobs = pendingJobs.get(name) ?? [];
17
+ jobs.push(job);
18
+ if (jobs.length > MAX_TRACKED_JOBS) {
19
+ jobs.shift();
20
+ }
21
+ pendingJobs.set(name, jobs);
22
+ };
23
+ const takePendingJob = (name) => {
24
+ const jobs = pendingJobs.get(name);
25
+ if (!jobs || jobs.length === 0)
26
+ return null;
27
+ const job = jobs.shift() ?? null;
28
+ if (jobs.length === 0) {
29
+ pendingJobs.delete(name);
30
+ }
31
+ else {
32
+ pendingJobs.set(name, jobs);
33
+ }
34
+ return job;
35
+ };
36
+ const emitDispatch = (name, queue, connection, data) => {
37
+ if (!_storage)
38
+ return;
39
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
40
+ return;
41
+ const uuid = crypto.randomUUID();
42
+ const content = {
43
+ status: 'pending',
44
+ connection,
45
+ queue,
46
+ name,
47
+ data,
48
+ hostname: TraceContext.getHostname(),
49
+ };
50
+ _storage
51
+ .writeEntry({
52
+ uuid,
53
+ batchId: TraceContext.getBatchId(),
54
+ type: EntryType.JOB,
55
+ content,
56
+ tags: [name],
57
+ isLatest: true,
58
+ createdAt: TraceContext.now(),
59
+ })
60
+ .catch(() => undefined);
61
+ trackPendingJob(name, { uuid, content });
62
+ };
63
+ const emitProcessed = (name) => {
64
+ if (!_storage)
65
+ return;
66
+ const pendingJob = takePendingJob(name);
67
+ if (pendingJob === null)
68
+ return;
69
+ const patch = { ...pendingJob.content, status: 'processed' };
70
+ void _storage.updateEntry(pendingJob.uuid, { content: patch }).catch(() => undefined);
71
+ };
72
+ const emitFailed = (name, error) => {
73
+ if (!_storage)
74
+ return;
75
+ const pendingJob = takePendingJob(name);
76
+ if (pendingJob === null)
77
+ return;
78
+ const patch = {
79
+ ...pendingJob.content,
80
+ status: 'failed',
81
+ exception: {
82
+ message: error.message,
83
+ trace: (error.stack ?? '')
84
+ .split('\n')
85
+ .slice(1)
86
+ .map(parseStackFrameLine)
87
+ .filter((trace) => trace !== null)
88
+ .slice(0, 10),
89
+ },
90
+ };
91
+ void _storage.updateEntry(pendingJob.uuid, { content: patch }).catch(() => undefined);
92
+ };
93
+ export const JobWatcher = Object.freeze({
94
+ onDispatch: emitDispatch,
95
+ onProcessed: emitProcessed,
96
+ onFailed: emitFailed,
97
+ register({ storage, config }) {
98
+ if (config.watchers.job === false)
99
+ return () => undefined;
100
+ _storage = storage;
101
+ _ignoreRoutes = config.ignoreRoutes;
102
+ return () => {
103
+ _storage = null;
104
+ _ignoreRoutes = [];
105
+ pendingJobs.clear();
106
+ };
107
+ },
108
+ });
@@ -0,0 +1,2 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ export declare const LogWatcher: ITraceWatcher;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * LogWatcher — captures Logger output via Logger.addSink().
3
+ */
4
+ import { Logger } from '@zintrust/core';
5
+ import { TraceContext } from '../context';
6
+ import { EntryType } from '../types';
7
+ import { AuthTag } from '../utils/authTag';
8
+ import { RequestFilter } from '../utils/requestFilter';
9
+ const LEVEL_PRIORITY = {
10
+ debug: 0,
11
+ info: 1,
12
+ warn: 2,
13
+ error: 3,
14
+ fatal: 4,
15
+ };
16
+ export const LogWatcher = Object.freeze({
17
+ register({ storage, config }) {
18
+ if (config.watchers.log === false)
19
+ return () => undefined;
20
+ const minPriority = LEVEL_PRIORITY[config.logMinLevel] ?? 1;
21
+ const loggerWithSink = Logger;
22
+ if (typeof loggerWithSink.addSink !== 'function') {
23
+ return () => undefined;
24
+ }
25
+ const unsubscribe = loggerWithSink.addSink((level, message, context) => {
26
+ if ((LEVEL_PRIORITY[level] ?? 0) < minPriority)
27
+ return;
28
+ if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes))
29
+ return;
30
+ const content = {
31
+ level,
32
+ message,
33
+ context: context ?? undefined,
34
+ hostname: TraceContext.getHostname(),
35
+ };
36
+ storage
37
+ .writeEntry({
38
+ uuid: crypto.randomUUID(),
39
+ batchId: TraceContext.getBatchId(),
40
+ type: EntryType.LOG,
41
+ content,
42
+ tags: AuthTag.append([]),
43
+ isLatest: true,
44
+ createdAt: TraceContext.now(),
45
+ })
46
+ .catch(() => undefined);
47
+ });
48
+ return unsubscribe;
49
+ },
50
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ declare const emit: (to: string, subject: string, template?: string) => void;
3
+ export declare const MailWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * MailWatcher — records mail dispatch intent.
3
+ * Body is never captured; only to/subject/template.
4
+ */
5
+ import { TraceContext } from '../context';
6
+ import { EntryType } from '../types';
7
+ import { RequestFilter } from '../utils/requestFilter';
8
+ let _storage = null;
9
+ let _ignoreRoutes = [];
10
+ const emit = (to, subject, template) => {
11
+ if (!_storage)
12
+ return;
13
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
14
+ return;
15
+ const content = {
16
+ to,
17
+ subject,
18
+ template,
19
+ hostname: TraceContext.getHostname(),
20
+ };
21
+ _storage
22
+ .writeEntry({
23
+ uuid: crypto.randomUUID(),
24
+ batchId: TraceContext.getBatchId(),
25
+ type: EntryType.MAIL,
26
+ content,
27
+ tags: [],
28
+ isLatest: true,
29
+ createdAt: TraceContext.now(),
30
+ })
31
+ .catch(() => undefined);
32
+ };
33
+ export const MailWatcher = Object.freeze({
34
+ emit,
35
+ register({ storage, config }) {
36
+ if (config.watchers.mail === false)
37
+ return () => undefined;
38
+ _storage = storage;
39
+ _ignoreRoutes = config.ignoreRoutes;
40
+ return () => {
41
+ _storage = null;
42
+ _ignoreRoutes = [];
43
+ };
44
+ },
45
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher, MiddlewareContent } from '../types';
2
+ declare const emit: (name: string, event: MiddlewareContent["event"], duration?: number) => void;
3
+ export declare const MiddlewareWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,41 @@
1
+ import { TraceContext } from '../context';
2
+ import { EntryType } from '../types';
3
+ import { RequestFilter } from '../utils/requestFilter';
4
+ let _storage = null;
5
+ let _ignoreRoutes = [];
6
+ const emit = (name, event, duration) => {
7
+ if (!_storage)
8
+ return;
9
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
10
+ return;
11
+ const content = {
12
+ name,
13
+ event,
14
+ duration,
15
+ hostname: TraceContext.getHostname(),
16
+ };
17
+ _storage
18
+ .writeEntry({
19
+ uuid: crypto.randomUUID(),
20
+ batchId: TraceContext.getBatchId(),
21
+ type: EntryType.MIDDLEWARE,
22
+ content,
23
+ tags: [name, event],
24
+ isLatest: true,
25
+ createdAt: TraceContext.now(),
26
+ })
27
+ .catch(() => undefined);
28
+ };
29
+ export const MiddlewareWatcher = Object.freeze({
30
+ emit,
31
+ register({ storage, config }) {
32
+ if (config.watchers.middleware === false)
33
+ return () => undefined;
34
+ _storage = storage;
35
+ _ignoreRoutes = config.ignoreRoutes;
36
+ return () => {
37
+ _storage = null;
38
+ _ignoreRoutes = [];
39
+ };
40
+ },
41
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher, ModelContent } from '../types';
2
+ declare const emit: (action: ModelContent["action"], model: string, id?: string | number, changes?: Record<string, unknown>) => void;
3
+ export declare const ModelWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,42 @@
1
+ import { TraceContext } from '../context';
2
+ import { EntryType } from '../types';
3
+ import { RequestFilter } from '../utils/requestFilter';
4
+ let _storage = null;
5
+ let _ignoreRoutes = [];
6
+ const emit = (action, model, id, changes) => {
7
+ if (!_storage)
8
+ return;
9
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
10
+ return;
11
+ const content = {
12
+ action,
13
+ model,
14
+ id,
15
+ changes,
16
+ hostname: TraceContext.getHostname(),
17
+ };
18
+ _storage
19
+ .writeEntry({
20
+ uuid: crypto.randomUUID(),
21
+ batchId: TraceContext.getBatchId(),
22
+ type: EntryType.MODEL,
23
+ content,
24
+ tags: [model],
25
+ isLatest: true,
26
+ createdAt: TraceContext.now(),
27
+ })
28
+ .catch(() => undefined);
29
+ };
30
+ export const ModelWatcher = Object.freeze({
31
+ emit,
32
+ register({ storage, config }) {
33
+ if (config.watchers.model === false)
34
+ return () => undefined;
35
+ _storage = storage;
36
+ _ignoreRoutes = config.ignoreRoutes;
37
+ return () => {
38
+ _storage = null;
39
+ _ignoreRoutes = [];
40
+ };
41
+ },
42
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ declare const emit: (notification: string, channels: string[], notifiable?: string) => void;
3
+ export declare const NotificationWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,42 @@
1
+ import { TraceContext } from '../context';
2
+ import { EntryType } from '../types';
3
+ import { AuthTag } from '../utils/authTag';
4
+ import { RequestFilter } from '../utils/requestFilter';
5
+ let _storage = null;
6
+ let _ignoreRoutes = [];
7
+ const emit = (notification, channels, notifiable) => {
8
+ if (!_storage)
9
+ return;
10
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
11
+ return;
12
+ const content = {
13
+ notification,
14
+ channels,
15
+ notifiable,
16
+ hostname: TraceContext.getHostname(),
17
+ };
18
+ _storage
19
+ .writeEntry({
20
+ uuid: crypto.randomUUID(),
21
+ batchId: TraceContext.getBatchId(),
22
+ type: EntryType.NOTIFICATION,
23
+ content,
24
+ tags: AuthTag.append([notification, ...channels]),
25
+ isLatest: true,
26
+ createdAt: TraceContext.now(),
27
+ })
28
+ .catch(() => undefined);
29
+ };
30
+ export const NotificationWatcher = Object.freeze({
31
+ emit,
32
+ register({ storage, config }) {
33
+ if (config.watchers.notification === false)
34
+ return () => undefined;
35
+ _storage = storage;
36
+ _ignoreRoutes = config.ignoreRoutes;
37
+ return () => {
38
+ _storage = null;
39
+ _ignoreRoutes = [];
40
+ };
41
+ },
42
+ });
@@ -0,0 +1,2 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ export declare const QueryWatcher: ITraceWatcher;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * QueryWatcher — hooks into Database.onAfterQuery to record SQL entries.
3
+ */
4
+ import { TraceContext } from '../context';
5
+ import { TraceStorage } from '../storage';
6
+ import { EntryType } from '../types';
7
+ import { AuthTag } from '../utils/authTag';
8
+ import { RequestFilter } from '../utils/requestFilter';
9
+ const bindingsInterpolated = (sql, params) => {
10
+ // Inline params for display only — safe, not for re-execution.
11
+ let i = 0;
12
+ return sql.replaceAll('?', () => {
13
+ const val = params[i++];
14
+ if (val === null || val === undefined)
15
+ return 'NULL';
16
+ if (typeof val === 'string')
17
+ return `'${val.replaceAll("'", "''")}'`;
18
+ return String(val);
19
+ });
20
+ };
21
+ const isTraceStorageQuery = (sql) => {
22
+ const normalized = sql.toLowerCase();
23
+ return normalized.includes('zin_trace_entries') || normalized.includes('zin_trace_monitoring');
24
+ };
25
+ export const QueryWatcher = Object.freeze({
26
+ register({ storage, config, db: injectedDb }) {
27
+ if (config.watchers.query === false)
28
+ return () => undefined;
29
+ if (!injectedDb)
30
+ return () => undefined; // no db available
31
+ const db = injectedDb;
32
+ const handler = (query, params, duration) => {
33
+ if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes))
34
+ return;
35
+ if (isTraceStorageQuery(query))
36
+ return;
37
+ const batchId = TraceContext.getBatchId();
38
+ const sql = bindingsInterpolated(query, params);
39
+ const roundedDuration = Math.round(duration * 100) / 100;
40
+ const hash = TraceStorage.familyHash(query);
41
+ const slow = roundedDuration >= config.slowQueryThreshold;
42
+ const content = {
43
+ connection: 'default',
44
+ sql,
45
+ time: roundedDuration,
46
+ duration: roundedDuration,
47
+ slow,
48
+ hash,
49
+ hostname: TraceContext.getHostname(),
50
+ };
51
+ const tags = AuthTag.append([]);
52
+ if (slow)
53
+ tags.push('slow');
54
+ storage
55
+ .writeEntry({
56
+ uuid: crypto.randomUUID(),
57
+ batchId,
58
+ familyHash: hash,
59
+ type: EntryType.QUERY,
60
+ content,
61
+ tags,
62
+ isLatest: true,
63
+ createdAt: TraceContext.now(),
64
+ })
65
+ .catch(() => undefined);
66
+ };
67
+ db.onAfterQuery?.(handler);
68
+ return () => {
69
+ db.offAfterQuery?.(handler);
70
+ };
71
+ },
72
+ });
@@ -0,0 +1,7 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ /** Emit a redis command trace. Key/value payload is intentionally omitted for security. */
3
+ declare const emit: (command: string, duration: number) => void;
4
+ export declare const RedisWatcher: ITraceWatcher & {
5
+ emit: typeof emit;
6
+ };
7
+ export {};
@@ -0,0 +1,38 @@
1
+ import { TraceContext } from '../context';
2
+ import { EntryType } from '../types';
3
+ import { AuthTag } from '../utils/authTag';
4
+ import { RequestFilter } from '../utils/requestFilter';
5
+ let _storage = null;
6
+ let _ignoreRoutes = [];
7
+ /** Emit a redis command trace. Key/value payload is intentionally omitted for security. */
8
+ const emit = (command, duration) => {
9
+ if (!_storage)
10
+ return;
11
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
12
+ return;
13
+ const content = { command, duration, hostname: TraceContext.getHostname() };
14
+ _storage
15
+ .writeEntry({
16
+ uuid: crypto.randomUUID(),
17
+ batchId: TraceContext.getBatchId(),
18
+ type: EntryType.REDIS,
19
+ content,
20
+ tags: AuthTag.append([command.toUpperCase()]),
21
+ isLatest: true,
22
+ createdAt: TraceContext.now(),
23
+ })
24
+ .catch(() => undefined);
25
+ };
26
+ export const RedisWatcher = Object.freeze({
27
+ emit,
28
+ register({ storage, config }) {
29
+ if (config.watchers.redis === false)
30
+ return () => undefined;
31
+ _storage = storage;
32
+ _ignoreRoutes = config.ignoreRoutes;
33
+ return () => {
34
+ _storage = null;
35
+ _ignoreRoutes = [];
36
+ };
37
+ },
38
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher, ScheduleContent } from '../types';
2
+ declare const emit: (name: string, expression: string, status: ScheduleContent["status"], duration: number, output?: string) => void;
3
+ export declare const ScheduleWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ScheduleWatcher — records scheduled task runs and outcomes.
3
+ */
4
+ import { TraceContext } from '../context';
5
+ import { EntryType } from '../types';
6
+ import { RequestFilter } from '../utils/requestFilter';
7
+ let _storage = null;
8
+ let _ignoreRoutes = [];
9
+ const emit = (name, expression, status, duration, output) => {
10
+ if (!_storage)
11
+ return;
12
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
13
+ return;
14
+ const content = {
15
+ name,
16
+ expression,
17
+ status,
18
+ duration,
19
+ output,
20
+ hostname: TraceContext.getHostname(),
21
+ };
22
+ _storage
23
+ .writeEntry({
24
+ uuid: crypto.randomUUID(),
25
+ batchId: TraceContext.getBatchId(),
26
+ type: EntryType.SCHEDULE,
27
+ content,
28
+ tags: status === 'failed' ? ['failed'] : [],
29
+ isLatest: true,
30
+ createdAt: TraceContext.now(),
31
+ })
32
+ .catch(() => undefined);
33
+ };
34
+ export const ScheduleWatcher = Object.freeze({
35
+ emit,
36
+ register({ storage, config }) {
37
+ if (config.watchers.schedule === false)
38
+ return () => undefined;
39
+ _storage = storage;
40
+ _ignoreRoutes = config.ignoreRoutes;
41
+ return () => {
42
+ _storage = null;
43
+ _ignoreRoutes = [];
44
+ };
45
+ },
46
+ });
@@ -0,0 +1,6 @@
1
+ import type { ITraceWatcher } from '../types';
2
+ declare const emit: (template: string, duration: number) => void;
3
+ export declare const ViewWatcher: ITraceWatcher & {
4
+ emit: typeof emit;
5
+ };
6
+ export {};
@@ -0,0 +1,36 @@
1
+ import { TraceContext } from '../context';
2
+ import { EntryType } from '../types';
3
+ import { RequestFilter } from '../utils/requestFilter';
4
+ let _storage = null;
5
+ let _ignoreRoutes = [];
6
+ const emit = (template, duration) => {
7
+ if (!_storage)
8
+ return;
9
+ if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
10
+ return;
11
+ const content = { template, duration, hostname: TraceContext.getHostname() };
12
+ _storage
13
+ .writeEntry({
14
+ uuid: crypto.randomUUID(),
15
+ batchId: TraceContext.getBatchId(),
16
+ type: EntryType.VIEW,
17
+ content,
18
+ tags: [template],
19
+ isLatest: true,
20
+ createdAt: TraceContext.now(),
21
+ })
22
+ .catch(() => undefined);
23
+ };
24
+ export const ViewWatcher = Object.freeze({
25
+ emit,
26
+ register({ storage, config }) {
27
+ if (config.watchers.view === false)
28
+ return () => undefined;
29
+ _storage = storage;
30
+ _ignoreRoutes = config.ignoreRoutes;
31
+ return () => {
32
+ _storage = null;
33
+ _ignoreRoutes = [];
34
+ };
35
+ },
36
+ });
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@zintrust/trace",
3
+ "version": "0.4.75",
4
+ "description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
5
+ "private": false,
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "src"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "./ui": {
19
+ "types": "./dist/ui.d.ts",
20
+ "default": "./dist/ui.js"
21
+ },
22
+ "./cli-register": {
23
+ "types": "./dist/cli-register.d.ts",
24
+ "default": "./dist/cli-register.js"
25
+ },
26
+ "./plugin": {
27
+ "types": "./dist/plugin.d.ts",
28
+ "default": "./dist/plugin.js"
29
+ },
30
+ "./register": {
31
+ "types": "./dist/register.d.ts",
32
+ "default": "./dist/register.js"
33
+ },
34
+ "./migrations": {
35
+ "types": "./dist/migrations/index.d.ts",
36
+ "default": "./dist/migrations/index.js"
37
+ }
38
+ },
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ },
42
+ "peerDependencies": {
43
+ "@zintrust/core": "^0.4.74"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "keywords": [
49
+ "zintrust",
50
+ "trace",
51
+ "observability",
52
+ "tracing",
53
+ "telescope"
54
+ ],
55
+ "scripts": {
56
+ "build": "npx lint-staged",
57
+ "prepublishOnly": "npm run build"
58
+ }
59
+ }