@zintrust/trace 0.9.3 → 0.9.4
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/README.md +31 -0
- package/dist/build-manifest.json +59 -23
- package/dist/config.js +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/ingest/TraceIngestGateway.d.ts +22 -0
- package/dist/ingest/TraceIngestGateway.js +215 -0
- package/dist/register.js +58 -2
- package/dist/storage/DebuggerStorage.d.ts +13 -0
- package/dist/storage/DebuggerStorage.js +195 -0
- package/dist/storage/ProxyTraceStorage.d.ts +12 -0
- package/dist/storage/ProxyTraceStorage.js +102 -0
- package/dist/storage/TraceContentBudget.js +1 -0
- package/dist/storage/TraceServiceTag.d.ts +5 -0
- package/dist/storage/TraceServiceTag.js +43 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +2 -0
- package/dist/types.d.ts +10 -0
- package/package.json +2 -2
- package/src/config.ts +23 -0
- package/src/index.ts +1 -0
- package/src/ingest/TraceIngestGateway.ts +317 -0
- package/src/register.ts +67 -2
- package/src/storage/ProxyTraceStorage.ts +182 -0
- package/src/storage/TraceContentBudget.ts +1 -0
- package/src/storage/TraceServiceTag.ts +56 -0
- package/src/storage/index.ts +2 -0
- package/src/types.ts +11 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { familyHash } from '../utils/familyHash.js';
|
|
2
|
+
const TABLE_ENTRIES = 'zin_trace_entries';
|
|
3
|
+
const TABLE_TAGS = 'zin_trace_entries_tags';
|
|
4
|
+
const TABLE_MONITORING = 'zin_trace_monitoring';
|
|
5
|
+
const generateUuid = () => crypto.randomUUID();
|
|
6
|
+
const rowToEntry = (row, tags) => ({
|
|
7
|
+
uuid: row.uuid,
|
|
8
|
+
batchId: row.batch_id,
|
|
9
|
+
familyHash: row.family_hash ?? undefined,
|
|
10
|
+
type: row.type,
|
|
11
|
+
content: JSON.parse(row.content),
|
|
12
|
+
tags,
|
|
13
|
+
isLatest: Boolean(row.is_latest),
|
|
14
|
+
createdAt: row.created_at,
|
|
15
|
+
});
|
|
16
|
+
const insertTags = async (db, uuid, tags) => {
|
|
17
|
+
if (tags.length === 0)
|
|
18
|
+
return;
|
|
19
|
+
await Promise.all(tags.map(async (tag) => {
|
|
20
|
+
await db.execute(`INSERT OR IGNORE INTO ${TABLE_TAGS} (entry_uuid, tag) VALUES (?, ?)`, [
|
|
21
|
+
uuid,
|
|
22
|
+
tag,
|
|
23
|
+
]);
|
|
24
|
+
}));
|
|
25
|
+
};
|
|
26
|
+
const buildEntryFilters = (opts) => {
|
|
27
|
+
const conditions = [];
|
|
28
|
+
const params = [];
|
|
29
|
+
if (opts.type) {
|
|
30
|
+
conditions.push('e.type = ?');
|
|
31
|
+
params.push(opts.type);
|
|
32
|
+
}
|
|
33
|
+
if (opts.batchId) {
|
|
34
|
+
conditions.push('e.batch_id = ?');
|
|
35
|
+
params.push(opts.batchId);
|
|
36
|
+
}
|
|
37
|
+
if (opts.from) {
|
|
38
|
+
conditions.push('e.created_at >= ?');
|
|
39
|
+
params.push(opts.from);
|
|
40
|
+
}
|
|
41
|
+
if (opts.to) {
|
|
42
|
+
conditions.push('e.created_at <= ?');
|
|
43
|
+
params.push(opts.to);
|
|
44
|
+
}
|
|
45
|
+
let joinClause = '';
|
|
46
|
+
if (opts.tag) {
|
|
47
|
+
joinClause = `INNER JOIN ${TABLE_TAGS} t ON t.entry_uuid = e.uuid AND t.tag = ?`;
|
|
48
|
+
params.unshift(opts.tag);
|
|
49
|
+
}
|
|
50
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
51
|
+
const countParams = opts.tag ? [opts.tag, ...params.slice(1)] : [...params];
|
|
52
|
+
return { joinClause, whereClause, params, countParams };
|
|
53
|
+
};
|
|
54
|
+
const loadTagsByUuid = async (db, uuids) => {
|
|
55
|
+
const tagsByUuid = new Map();
|
|
56
|
+
if (uuids.length === 0)
|
|
57
|
+
return tagsByUuid;
|
|
58
|
+
const tagRows = (await db.query(`SELECT entry_uuid, tag FROM ${TABLE_TAGS} WHERE entry_uuid IN (${uuids.map(() => '?').join(',')})`, uuids));
|
|
59
|
+
for (const tagRow of tagRows) {
|
|
60
|
+
const tags = tagsByUuid.get(tagRow.entry_uuid) ?? [];
|
|
61
|
+
tags.push(tagRow.tag);
|
|
62
|
+
tagsByUuid.set(tagRow.entry_uuid, tags);
|
|
63
|
+
}
|
|
64
|
+
return tagsByUuid;
|
|
65
|
+
};
|
|
66
|
+
// The storage facade intentionally groups related DB operations in one factory.
|
|
67
|
+
// eslint-disable-next-line max-lines-per-function
|
|
68
|
+
const createStorage = (db) => {
|
|
69
|
+
const writeEntry = async (entry) => {
|
|
70
|
+
const uuid = entry.uuid || generateUuid();
|
|
71
|
+
await db.execute(`INSERT INTO ${TABLE_ENTRIES} (uuid, batch_id, family_hash, type, content, is_latest, created_at)
|
|
72
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`, [
|
|
73
|
+
uuid,
|
|
74
|
+
entry.batchId,
|
|
75
|
+
entry.familyHash ?? null,
|
|
76
|
+
entry.type,
|
|
77
|
+
JSON.stringify(entry.content),
|
|
78
|
+
entry.isLatest ? 1 : 0,
|
|
79
|
+
entry.createdAt,
|
|
80
|
+
]);
|
|
81
|
+
await insertTags(db, uuid, entry.tags);
|
|
82
|
+
};
|
|
83
|
+
const updateEntry = async (uuid, patch) => {
|
|
84
|
+
const sets = [];
|
|
85
|
+
const params = [];
|
|
86
|
+
if (patch.content !== undefined) {
|
|
87
|
+
sets.push('content = ?');
|
|
88
|
+
params.push(JSON.stringify(patch.content));
|
|
89
|
+
}
|
|
90
|
+
if (patch.isLatest !== undefined) {
|
|
91
|
+
sets.push('is_latest = ?');
|
|
92
|
+
params.push(patch.isLatest ? 1 : 0);
|
|
93
|
+
}
|
|
94
|
+
if (sets.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
params.push(uuid);
|
|
97
|
+
await db.execute(`UPDATE ${TABLE_ENTRIES} SET ${sets.join(', ')} WHERE uuid = ?`, params);
|
|
98
|
+
};
|
|
99
|
+
const markFamilyStale = async (hash, exceptUuid) => {
|
|
100
|
+
await db.execute(`UPDATE ${TABLE_ENTRIES} SET is_latest = 0
|
|
101
|
+
WHERE family_hash = ? AND uuid != ? AND is_latest = 1`, [hash, exceptUuid]);
|
|
102
|
+
};
|
|
103
|
+
const queryEntries = async (opts) => {
|
|
104
|
+
const page = opts.page ?? 1;
|
|
105
|
+
const perPage = opts.perPage ?? 50;
|
|
106
|
+
const offset = (page - 1) * perPage;
|
|
107
|
+
const { joinClause, whereClause, params, countParams } = buildEntryFilters(opts);
|
|
108
|
+
const countResult = (await db.queryOne(`SELECT COUNT(*) as cnt FROM ${TABLE_ENTRIES} e ${joinClause} ${whereClause}`, countParams));
|
|
109
|
+
const total = countResult?.cnt ?? 0;
|
|
110
|
+
const rows = (await db.query(`SELECT e.id, e.uuid, e.batch_id, e.family_hash, e.type, e.content, e.is_latest, e.created_at
|
|
111
|
+
FROM ${TABLE_ENTRIES} e ${joinClause} ${whereClause}
|
|
112
|
+
ORDER BY e.created_at DESC, e.id DESC
|
|
113
|
+
LIMIT ? OFFSET ?`, [...params, perPage, offset]));
|
|
114
|
+
const tagsByUuid = await loadTagsByUuid(db, rows.map((row) => row.uuid));
|
|
115
|
+
return {
|
|
116
|
+
data: rows.map((row) => rowToEntry(row, tagsByUuid.get(row.uuid) ?? [])),
|
|
117
|
+
total,
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const getEntry = async (uuid) => {
|
|
121
|
+
const row = (await db.queryOne(`SELECT id, uuid, batch_id, family_hash, type, content, is_latest, created_at
|
|
122
|
+
FROM ${TABLE_ENTRIES}
|
|
123
|
+
WHERE uuid = ?`, [uuid]));
|
|
124
|
+
if (!row)
|
|
125
|
+
return null;
|
|
126
|
+
const tags = (await db.query(`SELECT tag FROM ${TABLE_TAGS} WHERE entry_uuid = ?`, [
|
|
127
|
+
uuid,
|
|
128
|
+
]));
|
|
129
|
+
return rowToEntry(row, tags.map((tag) => tag.tag));
|
|
130
|
+
};
|
|
131
|
+
const getBatch = async (batchId) => {
|
|
132
|
+
const rows = (await db.query(`SELECT id, uuid, batch_id, family_hash, type, content, is_latest, created_at
|
|
133
|
+
FROM ${TABLE_ENTRIES}
|
|
134
|
+
WHERE batch_id = ?
|
|
135
|
+
ORDER BY created_at ASC, id ASC`, [batchId]));
|
|
136
|
+
if (rows.length === 0)
|
|
137
|
+
return [];
|
|
138
|
+
const tagsByUuid = await loadTagsByUuid(db, rows.map((row) => row.uuid));
|
|
139
|
+
return rows.map((row) => rowToEntry(row, tagsByUuid.get(row.uuid) ?? []));
|
|
140
|
+
};
|
|
141
|
+
const prune = async (olderThanMs, keepExceptions = false) => {
|
|
142
|
+
const countResult = (await db.queryOne(`SELECT COUNT(*) as cnt FROM ${TABLE_ENTRIES}
|
|
143
|
+
WHERE created_at < ?
|
|
144
|
+
${keepExceptions ? "AND type != 'exception'" : ''}`, [olderThanMs]));
|
|
145
|
+
const deleted = countResult?.cnt ?? 0;
|
|
146
|
+
if (deleted === 0)
|
|
147
|
+
return 0;
|
|
148
|
+
await db.execute(`DELETE FROM ${TABLE_ENTRIES}
|
|
149
|
+
WHERE created_at < ?
|
|
150
|
+
${keepExceptions ? "AND type != 'exception'" : ''}`, [olderThanMs]);
|
|
151
|
+
return deleted;
|
|
152
|
+
};
|
|
153
|
+
const clear = async () => {
|
|
154
|
+
await db.execute(`DELETE FROM ${TABLE_ENTRIES}`, []);
|
|
155
|
+
};
|
|
156
|
+
const getMonitoring = async () => {
|
|
157
|
+
const rows = (await db.query(`SELECT tag FROM ${TABLE_MONITORING}`, []));
|
|
158
|
+
return rows.map((row) => row.tag);
|
|
159
|
+
};
|
|
160
|
+
const addMonitoring = async (tag) => {
|
|
161
|
+
await db.execute(`INSERT OR IGNORE INTO ${TABLE_MONITORING} (tag) VALUES (?)`, [tag]);
|
|
162
|
+
};
|
|
163
|
+
const removeMonitoring = async (tag) => {
|
|
164
|
+
await db.execute(`DELETE FROM ${TABLE_MONITORING} WHERE tag = ?`, [tag]);
|
|
165
|
+
};
|
|
166
|
+
const stats = async () => {
|
|
167
|
+
const rows = (await db.query(`SELECT type, COUNT(*) as cnt FROM ${TABLE_ENTRIES} GROUP BY type`, []));
|
|
168
|
+
const output = {};
|
|
169
|
+
for (const row of rows) {
|
|
170
|
+
output[row.type] = row.cnt;
|
|
171
|
+
}
|
|
172
|
+
return output;
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
writeEntry,
|
|
176
|
+
updateEntry,
|
|
177
|
+
markFamilyStale,
|
|
178
|
+
queryEntries,
|
|
179
|
+
getEntry,
|
|
180
|
+
getBatch,
|
|
181
|
+
prune,
|
|
182
|
+
clear,
|
|
183
|
+
getMonitoring,
|
|
184
|
+
addMonitoring,
|
|
185
|
+
removeMonitoring,
|
|
186
|
+
stats,
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const resolveStorage = (db) => {
|
|
190
|
+
return createStorage(db);
|
|
191
|
+
};
|
|
192
|
+
const reset = () => {
|
|
193
|
+
return;
|
|
194
|
+
};
|
|
195
|
+
export const TraceStorage = Object.freeze({ resolveStorage, reset, familyHash });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITraceStorage } from '../types';
|
|
2
|
+
type ProxyTraceStorageSettings = {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
path: string;
|
|
5
|
+
keyId: string;
|
|
6
|
+
secret: string;
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
};
|
|
9
|
+
export declare const ProxyTraceStorage: Readonly<{
|
|
10
|
+
create(settings: ProxyTraceStorageSettings): ITraceStorage;
|
|
11
|
+
}>;
|
|
12
|
+
export default ProxyTraceStorage;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ErrorFactory, RemoteSignedJson } from '@zintrust/core';
|
|
2
|
+
const ensureConfigured = (settings) => {
|
|
3
|
+
if (settings.baseUrl.trim() === '') {
|
|
4
|
+
throw ErrorFactory.createConfigError('TRACE_PROXY_URL is required when TRACE_PROXY=true');
|
|
5
|
+
}
|
|
6
|
+
if (settings.keyId.trim() === '' || settings.secret.trim() === '') {
|
|
7
|
+
throw ErrorFactory.createConfigError('TRACE_PROXY signing credentials are required when TRACE_PROXY=true');
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const normalizePath = (value) => {
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
if (trimmed === '')
|
|
13
|
+
return '/zin/trace/write';
|
|
14
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
15
|
+
};
|
|
16
|
+
const createUnsupportedReadError = () => ErrorFactory.createConfigError('Trace proxy sender storage does not expose dashboard/query operations. Use the trace server for reads.');
|
|
17
|
+
const buildSettings = (settings) => {
|
|
18
|
+
ensureConfigured(settings);
|
|
19
|
+
const normalizedPath = normalizePath(settings.path);
|
|
20
|
+
return {
|
|
21
|
+
baseUrl: settings.baseUrl,
|
|
22
|
+
keyId: settings.keyId,
|
|
23
|
+
secret: settings.secret,
|
|
24
|
+
timeoutMs: settings.timeoutMs,
|
|
25
|
+
signaturePathPrefixToStrip: new URL(settings.baseUrl).pathname,
|
|
26
|
+
missingUrlMessage: 'TRACE_PROXY_URL is required when TRACE_PROXY=true',
|
|
27
|
+
missingCredentialsMessage: 'TRACE_PROXY signing credentials are required when TRACE_PROXY=true',
|
|
28
|
+
messages: {
|
|
29
|
+
unauthorized: 'Trace proxy rejected the request credentials',
|
|
30
|
+
forbidden: 'Trace proxy rejected the request signature',
|
|
31
|
+
rateLimited: 'Trace proxy rate-limited the request',
|
|
32
|
+
rejected: 'Trace proxy rejected the request payload',
|
|
33
|
+
error: 'Trace proxy request failed',
|
|
34
|
+
timedOut: 'Trace proxy request timed out',
|
|
35
|
+
},
|
|
36
|
+
normalizedPath,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const appendSuffix = (path, suffix) => {
|
|
40
|
+
const base = normalizePath(path).replace(/\/+$/, '');
|
|
41
|
+
const tail = suffix.startsWith('/') ? suffix : `/${suffix}`;
|
|
42
|
+
return `${base}${tail}`;
|
|
43
|
+
};
|
|
44
|
+
const unsupportedQueryEntries = async () => {
|
|
45
|
+
throw createUnsupportedReadError();
|
|
46
|
+
};
|
|
47
|
+
const unsupportedGetEntry = async () => {
|
|
48
|
+
throw createUnsupportedReadError();
|
|
49
|
+
};
|
|
50
|
+
const unsupportedGetBatch = async () => {
|
|
51
|
+
throw createUnsupportedReadError();
|
|
52
|
+
};
|
|
53
|
+
const unsupportedQueryBatchEntries = async () => {
|
|
54
|
+
throw createUnsupportedReadError();
|
|
55
|
+
};
|
|
56
|
+
const unsupportedPrune = async () => {
|
|
57
|
+
throw createUnsupportedReadError();
|
|
58
|
+
};
|
|
59
|
+
const unsupportedClear = async () => {
|
|
60
|
+
throw createUnsupportedReadError();
|
|
61
|
+
};
|
|
62
|
+
const unsupportedGetMonitoring = async () => {
|
|
63
|
+
throw createUnsupportedReadError();
|
|
64
|
+
};
|
|
65
|
+
const unsupportedAddMonitoring = async () => {
|
|
66
|
+
throw createUnsupportedReadError();
|
|
67
|
+
};
|
|
68
|
+
const unsupportedRemoveMonitoring = async () => {
|
|
69
|
+
throw createUnsupportedReadError();
|
|
70
|
+
};
|
|
71
|
+
const unsupportedStats = async () => {
|
|
72
|
+
throw createUnsupportedReadError();
|
|
73
|
+
};
|
|
74
|
+
export const ProxyTraceStorage = Object.freeze({
|
|
75
|
+
create(settings) {
|
|
76
|
+
const normalized = buildSettings(settings);
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
async writeEntry(entry) {
|
|
79
|
+
await RemoteSignedJson.request(normalized, normalized.normalizedPath, {
|
|
80
|
+
entry,
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
async updateEntry(uuid, patch) {
|
|
84
|
+
await RemoteSignedJson.request(normalized, appendSuffix(normalized.normalizedPath, '/update'), { uuid, patch });
|
|
85
|
+
},
|
|
86
|
+
async markFamilyStale(familyHash, exceptUuid) {
|
|
87
|
+
await RemoteSignedJson.request(normalized, appendSuffix(normalized.normalizedPath, '/mark-family-stale'), { familyHash, exceptUuid });
|
|
88
|
+
},
|
|
89
|
+
queryEntries: unsupportedQueryEntries,
|
|
90
|
+
getEntry: unsupportedGetEntry,
|
|
91
|
+
getBatch: unsupportedGetBatch,
|
|
92
|
+
queryBatchEntries: unsupportedQueryBatchEntries,
|
|
93
|
+
prune: unsupportedPrune,
|
|
94
|
+
clear: unsupportedClear,
|
|
95
|
+
getMonitoring: unsupportedGetMonitoring,
|
|
96
|
+
addMonitoring: unsupportedAddMonitoring,
|
|
97
|
+
removeMonitoring: unsupportedRemoveMonitoring,
|
|
98
|
+
stats: unsupportedStats,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
export default ProxyTraceStorage;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ErrorFactory } from '@zintrust/core';
|
|
2
|
+
const appendServiceTag = (entry, serviceTag) => {
|
|
3
|
+
const normalizedTag = serviceTag?.trim() ?? '';
|
|
4
|
+
if (normalizedTag === '' || entry.tags.includes(normalizedTag)) {
|
|
5
|
+
return entry;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
...entry,
|
|
9
|
+
tags: [...entry.tags, normalizedTag],
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const unsupportedRead = async () => {
|
|
13
|
+
throw ErrorFactory.createConfigError('Trace proxy mode only supports runtime persistence on the sender. Query the trace server database or dashboard directly.');
|
|
14
|
+
};
|
|
15
|
+
const bindOrUnsupported = (method) => {
|
|
16
|
+
if (method === undefined) {
|
|
17
|
+
return unsupportedRead;
|
|
18
|
+
}
|
|
19
|
+
return method;
|
|
20
|
+
};
|
|
21
|
+
export const TraceServiceTag = Object.freeze({
|
|
22
|
+
wrapStorage(storage, config) {
|
|
23
|
+
const writeEntry = async (entry) => {
|
|
24
|
+
await storage.writeEntry(appendServiceTag(entry, config.serviceTag));
|
|
25
|
+
};
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
writeEntry,
|
|
28
|
+
updateEntry: storage.updateEntry.bind(storage),
|
|
29
|
+
markFamilyStale: storage.markFamilyStale.bind(storage),
|
|
30
|
+
queryEntries: bindOrUnsupported(storage.queryEntries?.bind(storage)),
|
|
31
|
+
getEntry: bindOrUnsupported(storage.getEntry?.bind(storage)),
|
|
32
|
+
getBatch: bindOrUnsupported(storage.getBatch?.bind(storage)),
|
|
33
|
+
queryBatchEntries: bindOrUnsupported(storage.queryBatchEntries?.bind(storage)),
|
|
34
|
+
prune: bindOrUnsupported(storage.prune?.bind(storage)),
|
|
35
|
+
clear: bindOrUnsupported(storage.clear?.bind(storage)),
|
|
36
|
+
getMonitoring: bindOrUnsupported(storage.getMonitoring?.bind(storage)),
|
|
37
|
+
addMonitoring: bindOrUnsupported(storage.addMonitoring?.bind(storage)),
|
|
38
|
+
removeMonitoring: bindOrUnsupported(storage.removeMonitoring?.bind(storage)),
|
|
39
|
+
stats: bindOrUnsupported(storage.stats?.bind(storage)),
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
export default TraceServiceTag;
|
package/dist/storage/index.d.ts
CHANGED
package/dist/storage/index.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -316,6 +316,14 @@ export type TraceContentDispatchConfig = {
|
|
|
316
316
|
enqueueTimeoutMs: number;
|
|
317
317
|
worker: TraceContentDispatchWorkerConfig;
|
|
318
318
|
};
|
|
319
|
+
export type TraceProxyConfig = {
|
|
320
|
+
enabled: boolean;
|
|
321
|
+
url?: string;
|
|
322
|
+
path: string;
|
|
323
|
+
keyId?: string;
|
|
324
|
+
secret?: string;
|
|
325
|
+
timeoutMs: number;
|
|
326
|
+
};
|
|
319
327
|
export type TraceWatcherToggle = boolean | TraceFilterRule;
|
|
320
328
|
export type TraceRequestWatcherToggle = boolean | TraceRequestWatcherConfig;
|
|
321
329
|
export type TraceClientRequestWatcherToggle = boolean | TraceClientRequestWatcherConfig;
|
|
@@ -345,6 +353,8 @@ export interface ITraceConfig {
|
|
|
345
353
|
enabled: boolean;
|
|
346
354
|
connection?: string;
|
|
347
355
|
observeConnection?: string;
|
|
356
|
+
serviceTag?: string;
|
|
357
|
+
proxy: TraceProxyConfig;
|
|
348
358
|
pruneAfterHours: number;
|
|
349
359
|
ignoreRoutes: string[];
|
|
350
360
|
ignorePaths: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/trace",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=20.0.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@zintrust/core": "^0.9.
|
|
43
|
+
"@zintrust/core": "^0.9.4"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
package/src/config.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
TraceConfigOverrides,
|
|
9
9
|
TraceContentDispatchConfig,
|
|
10
10
|
TraceFilterRule,
|
|
11
|
+
TraceProxyConfig,
|
|
11
12
|
TraceRequestWatcherConfig,
|
|
12
13
|
TraceWatcherToggle,
|
|
13
14
|
} from './types';
|
|
@@ -253,10 +254,31 @@ const mergeContentDispatch = (
|
|
|
253
254
|
};
|
|
254
255
|
};
|
|
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
|
+
|
|
256
269
|
const DEFAULTS: ITraceConfig = Object.freeze({
|
|
257
270
|
enabled: false,
|
|
258
271
|
connection: undefined,
|
|
259
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
|
+
},
|
|
260
282
|
pruneAfterHours: 24,
|
|
261
283
|
ignoreRoutes: ['/trace', '/health', '/ping'],
|
|
262
284
|
ignorePaths: [],
|
|
@@ -342,6 +364,7 @@ export const TraceConfig = Object.freeze({
|
|
|
342
364
|
return Object.freeze({
|
|
343
365
|
...DEFAULTS,
|
|
344
366
|
...overrides,
|
|
367
|
+
proxy: mergeProxyConfig(DEFAULTS.proxy, overrides.proxy),
|
|
345
368
|
contentDispatch: mergeContentDispatch(DEFAULTS.contentDispatch, overrides.contentDispatch),
|
|
346
369
|
watchers: mergeWatchers(DEFAULTS.watchers, overrides.watchers),
|
|
347
370
|
redaction: {
|
package/src/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ export { TraceContext } from './context';
|
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
export { registerTraceDashboard, registerTraceRoutes } from './dashboard/routes';
|
|
33
33
|
export type { TraceDashboardOptions, TraceDashboardRegistrationOptions } from './dashboard/routes';
|
|
34
|
+
export { registerTraceIngestGateway, TraceIngestGateway } from './ingest/TraceIngestGateway';
|
|
34
35
|
|
|
35
36
|
// ---------------------------------------------------------------------------
|
|
36
37
|
// Watchers (named re-exports for use with custom wiring)
|