@deeptracer/core 0.3.1 → 0.4.2
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 +9 -12
- package/dist/{chunk-XVDM75HZ.js → chunk-IWPXOBZV.js} +197 -87
- package/dist/index.cjs +161 -53
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/internal.cjs +229 -55
- package/dist/internal.d.cts +86 -1
- package/dist/internal.d.ts +86 -1
- package/dist/internal.js +68 -3
- package/dist/{internal-DdKQRgCs.d.cts → logger-BDTEt7Gi.d.cts} +60 -23
- package/dist/{internal-DdKQRgCs.d.ts → logger-BDTEt7Gi.d.ts} +60 -23
- package/package.json +14 -3
package/dist/index.cjs
CHANGED
|
@@ -62,21 +62,51 @@ var Batcher = class {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// src/version.ts
|
|
65
|
-
var SDK_VERSION = "0.
|
|
65
|
+
var SDK_VERSION = "0.4.2";
|
|
66
66
|
var SDK_NAME = "core";
|
|
67
67
|
|
|
68
68
|
// src/transport.ts
|
|
69
69
|
var Transport = class {
|
|
70
70
|
constructor(config) {
|
|
71
71
|
this.config = config;
|
|
72
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
73
|
+
const hasEndpoint = !!config.endpoint;
|
|
74
|
+
this.disabled = !hasKey || !hasEndpoint;
|
|
75
|
+
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
76
|
+
console.error(
|
|
77
|
+
"[@deeptracer/core] WARNING: `secretKey` (dt_secret_...) detected in a browser bundle. This exposes your server key to end users. Use `publicKey` (dt_public_...) for client-side code."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
72
80
|
}
|
|
73
81
|
inFlightRequests = /* @__PURE__ */ new Set();
|
|
82
|
+
/**
|
|
83
|
+
* When true, all send methods become silent no-ops.
|
|
84
|
+
* Set automatically when no auth key or no endpoint is configured.
|
|
85
|
+
* This prevents pointless network requests and console noise during
|
|
86
|
+
* local development without API keys.
|
|
87
|
+
*/
|
|
88
|
+
disabled;
|
|
89
|
+
/**
|
|
90
|
+
* Tracks which send types (logs, error, trace, LLM usage) have already
|
|
91
|
+
* logged a failure warning. After the first failure for a given type,
|
|
92
|
+
* subsequent failures are silently dropped to prevent console spam
|
|
93
|
+
* (e.g., when the ingestion endpoint is unreachable during development).
|
|
94
|
+
*/
|
|
95
|
+
warnedLabels = /* @__PURE__ */ new Set();
|
|
96
|
+
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
97
|
+
get authKey() {
|
|
98
|
+
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
99
|
+
}
|
|
74
100
|
/**
|
|
75
101
|
* Send a request with automatic retry and exponential backoff.
|
|
76
102
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
77
103
|
* Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
|
|
104
|
+
*
|
|
105
|
+
* After the first total failure for a given label, subsequent failures
|
|
106
|
+
* are silently dropped (no more console warnings).
|
|
78
107
|
*/
|
|
79
108
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
109
|
+
if (this.disabled) return;
|
|
80
110
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
81
111
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
82
112
|
try {
|
|
@@ -84,33 +114,45 @@ var Transport = class {
|
|
|
84
114
|
method: "POST",
|
|
85
115
|
headers: {
|
|
86
116
|
"Content-Type": "application/json",
|
|
87
|
-
Authorization: `Bearer ${this.
|
|
117
|
+
Authorization: `Bearer ${this.authKey}`,
|
|
88
118
|
"x-deeptracer-sdk": `${SDK_NAME}/${SDK_VERSION}`
|
|
89
119
|
},
|
|
90
120
|
body: JSON.stringify(body)
|
|
91
121
|
});
|
|
92
|
-
if (res.ok)
|
|
122
|
+
if (res.ok) {
|
|
123
|
+
this.warnedLabels.delete(label);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
93
126
|
if (res.status >= 400 && res.status < 500) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
127
|
+
if (!this.warnedLabels.has(label)) {
|
|
128
|
+
this.warnedLabels.add(label);
|
|
129
|
+
console.warn(
|
|
130
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
97
133
|
return;
|
|
98
134
|
}
|
|
99
135
|
if (attempt < maxRetries) {
|
|
100
136
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
101
137
|
continue;
|
|
102
138
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
139
|
+
if (!this.warnedLabels.has(label)) {
|
|
140
|
+
this.warnedLabels.add(label);
|
|
141
|
+
console.warn(
|
|
142
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
106
145
|
} catch {
|
|
107
146
|
if (attempt < maxRetries) {
|
|
108
147
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
109
148
|
continue;
|
|
110
149
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
150
|
+
if (!this.warnedLabels.has(label)) {
|
|
151
|
+
this.warnedLabels.add(label);
|
|
152
|
+
console.warn(
|
|
153
|
+
`[@deeptracer/core] Failed to send ${label} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
114
156
|
}
|
|
115
157
|
}
|
|
116
158
|
}
|
|
@@ -131,7 +173,6 @@ var Transport = class {
|
|
|
131
173
|
const p = this.sendWithRetry(
|
|
132
174
|
`${this.config.endpoint}/ingest/logs`,
|
|
133
175
|
{
|
|
134
|
-
product: this.config.product,
|
|
135
176
|
service: this.config.service,
|
|
136
177
|
environment: this.config.environment,
|
|
137
178
|
logs
|
|
@@ -146,7 +187,6 @@ var Transport = class {
|
|
|
146
187
|
`${this.config.endpoint}/ingest/errors`,
|
|
147
188
|
{
|
|
148
189
|
...error,
|
|
149
|
-
product: this.config.product,
|
|
150
190
|
service: this.config.service,
|
|
151
191
|
environment: this.config.environment
|
|
152
192
|
},
|
|
@@ -160,7 +200,6 @@ var Transport = class {
|
|
|
160
200
|
`${this.config.endpoint}/ingest/traces`,
|
|
161
201
|
{
|
|
162
202
|
...span,
|
|
163
|
-
product: this.config.product,
|
|
164
203
|
service: this.config.service,
|
|
165
204
|
environment: this.config.environment
|
|
166
205
|
},
|
|
@@ -174,7 +213,6 @@ var Transport = class {
|
|
|
174
213
|
`${this.config.endpoint}/ingest/llm`,
|
|
175
214
|
{
|
|
176
215
|
...report,
|
|
177
|
-
product: this.config.product,
|
|
178
216
|
service: this.config.service,
|
|
179
217
|
environment: this.config.environment
|
|
180
218
|
},
|
|
@@ -208,6 +246,15 @@ function createLoggerState(maxBreadcrumbs) {
|
|
|
208
246
|
maxBreadcrumbs
|
|
209
247
|
};
|
|
210
248
|
}
|
|
249
|
+
function cloneState(state) {
|
|
250
|
+
return {
|
|
251
|
+
user: state.user ? { ...state.user } : null,
|
|
252
|
+
tags: { ...state.tags },
|
|
253
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
254
|
+
breadcrumbs: [...state.breadcrumbs],
|
|
255
|
+
maxBreadcrumbs: state.maxBreadcrumbs
|
|
256
|
+
};
|
|
257
|
+
}
|
|
211
258
|
function addBreadcrumb(state, breadcrumb) {
|
|
212
259
|
state.breadcrumbs.push(breadcrumb);
|
|
213
260
|
if (state.breadcrumbs.length > state.maxBreadcrumbs) {
|
|
@@ -216,11 +263,33 @@ function addBreadcrumb(state, breadcrumb) {
|
|
|
216
263
|
}
|
|
217
264
|
|
|
218
265
|
// src/logger.ts
|
|
266
|
+
var LOG_LEVEL_VALUES = {
|
|
267
|
+
debug: 0,
|
|
268
|
+
info: 1,
|
|
269
|
+
warn: 2,
|
|
270
|
+
error: 3
|
|
271
|
+
};
|
|
219
272
|
function generateId() {
|
|
220
273
|
const bytes = new Uint8Array(8);
|
|
221
274
|
crypto.getRandomValues(bytes);
|
|
222
275
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
223
276
|
}
|
|
277
|
+
function generateTraceId() {
|
|
278
|
+
const bytes = new Uint8Array(16);
|
|
279
|
+
crypto.getRandomValues(bytes);
|
|
280
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
281
|
+
}
|
|
282
|
+
function parseTraceparent(header) {
|
|
283
|
+
const parts = header.trim().split("-");
|
|
284
|
+
if (parts.length !== 4) return null;
|
|
285
|
+
const [version, traceId, parentId, flags] = parts;
|
|
286
|
+
if (version !== "00") return null;
|
|
287
|
+
if (traceId.length !== 32 || !/^[0-9a-f]{32}$/.test(traceId)) return null;
|
|
288
|
+
if (parentId.length !== 16 || !/^[0-9a-f]{16}$/.test(parentId)) return null;
|
|
289
|
+
if (flags.length !== 2 || !/^[0-9a-f]{2}$/.test(flags)) return null;
|
|
290
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentId)) return null;
|
|
291
|
+
return { traceId, parentId, flags };
|
|
292
|
+
}
|
|
224
293
|
var _originalConsole = {
|
|
225
294
|
log: console.log,
|
|
226
295
|
info: console.info,
|
|
@@ -231,6 +300,7 @@ var _originalConsole = {
|
|
|
231
300
|
var Logger = class _Logger {
|
|
232
301
|
batcher;
|
|
233
302
|
transport;
|
|
303
|
+
effectiveLevel;
|
|
234
304
|
contextName;
|
|
235
305
|
config;
|
|
236
306
|
state;
|
|
@@ -240,6 +310,20 @@ var Logger = class _Logger {
|
|
|
240
310
|
this.contextName = contextName;
|
|
241
311
|
this.requestMeta = requestMeta;
|
|
242
312
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
313
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
314
|
+
const hasEndpoint = !!config.endpoint;
|
|
315
|
+
if (!hasKey && !hasEndpoint) {
|
|
316
|
+
_originalConsole.warn(
|
|
317
|
+
"[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_SECRET_KEY and DEEPTRACER_ENDPOINT to enable."
|
|
318
|
+
);
|
|
319
|
+
} else if (!hasKey) {
|
|
320
|
+
_originalConsole.warn(
|
|
321
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
322
|
+
);
|
|
323
|
+
} else if (!hasEndpoint) {
|
|
324
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
325
|
+
}
|
|
326
|
+
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
243
327
|
this.transport = new Transport(config);
|
|
244
328
|
this.batcher = new Batcher(
|
|
245
329
|
{ batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
|
|
@@ -253,7 +337,8 @@ var Logger = class _Logger {
|
|
|
253
337
|
// ---------------------------------------------------------------------------
|
|
254
338
|
/**
|
|
255
339
|
* Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
|
|
256
|
-
*
|
|
340
|
+
* Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
|
|
341
|
+
* have their own independent state.
|
|
257
342
|
*
|
|
258
343
|
* @example
|
|
259
344
|
* ```ts
|
|
@@ -375,26 +460,13 @@ var Logger = class _Logger {
|
|
|
375
460
|
};
|
|
376
461
|
}
|
|
377
462
|
metadata = this.mergeStateMetadata(metadata);
|
|
378
|
-
const
|
|
379
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
380
|
-
level,
|
|
381
|
-
message,
|
|
382
|
-
metadata,
|
|
383
|
-
context: this.contextName,
|
|
384
|
-
trace_id: this.requestMeta?.trace_id,
|
|
385
|
-
span_id: this.requestMeta?.span_id,
|
|
386
|
-
request_id: this.requestMeta?.request_id,
|
|
387
|
-
vercel_id: this.requestMeta?.vercel_id
|
|
388
|
-
};
|
|
389
|
-
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
390
|
-
if (hookResult === null) return;
|
|
391
|
-
const finalEntry = hookResult.data;
|
|
463
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
392
464
|
if (this.config.debug) {
|
|
393
465
|
const prefix = this.contextName ? `[${this.contextName}]` : "";
|
|
394
466
|
const lvl = level.toUpperCase().padEnd(5);
|
|
395
467
|
const consoleFn = level === "error" ? _originalConsole.error : level === "warn" ? _originalConsole.warn : level === "debug" ? _originalConsole.debug : _originalConsole.log;
|
|
396
|
-
if (
|
|
397
|
-
consoleFn(`${lvl} ${prefix} ${message}`,
|
|
468
|
+
if (metadata) {
|
|
469
|
+
consoleFn(`${lvl} ${prefix} ${message}`, metadata);
|
|
398
470
|
} else {
|
|
399
471
|
consoleFn(`${lvl} ${prefix} ${message}`);
|
|
400
472
|
}
|
|
@@ -402,9 +474,23 @@ var Logger = class _Logger {
|
|
|
402
474
|
addBreadcrumb(this.state, {
|
|
403
475
|
type: "log",
|
|
404
476
|
message: `[${level}] ${message}`,
|
|
405
|
-
timestamp
|
|
477
|
+
timestamp
|
|
406
478
|
});
|
|
407
|
-
this.
|
|
479
|
+
if (LOG_LEVEL_VALUES[level] < this.effectiveLevel) return;
|
|
480
|
+
const entry = {
|
|
481
|
+
timestamp,
|
|
482
|
+
level,
|
|
483
|
+
message,
|
|
484
|
+
metadata,
|
|
485
|
+
context: this.contextName,
|
|
486
|
+
trace_id: this.requestMeta?.trace_id,
|
|
487
|
+
span_id: this.requestMeta?.span_id,
|
|
488
|
+
request_id: this.requestMeta?.request_id,
|
|
489
|
+
vercel_id: this.requestMeta?.vercel_id
|
|
490
|
+
};
|
|
491
|
+
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
492
|
+
if (hookResult === null) return;
|
|
493
|
+
this.batcher.add(hookResult.data);
|
|
408
494
|
}
|
|
409
495
|
/** Log a debug message. */
|
|
410
496
|
debug(message, dataOrError, error) {
|
|
@@ -425,22 +511,37 @@ var Logger = class _Logger {
|
|
|
425
511
|
// ---------------------------------------------------------------------------
|
|
426
512
|
// Child loggers
|
|
427
513
|
// ---------------------------------------------------------------------------
|
|
428
|
-
/** Create a context-scoped logger. All logs include the context name.
|
|
514
|
+
/** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
|
|
429
515
|
withContext(name) {
|
|
430
|
-
return new _Logger(this.config, name, this.requestMeta, this.state);
|
|
516
|
+
return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
|
|
431
517
|
}
|
|
432
|
-
/** Create a request-scoped logger that extracts trace context from headers.
|
|
518
|
+
/** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
|
|
433
519
|
forRequest(request) {
|
|
434
|
-
|
|
520
|
+
let traceId;
|
|
521
|
+
let spanId;
|
|
522
|
+
const traceparent = request.headers.get("traceparent");
|
|
523
|
+
if (traceparent) {
|
|
524
|
+
const parsed = parseTraceparent(traceparent);
|
|
525
|
+
if (parsed) {
|
|
526
|
+
traceId = parsed.traceId;
|
|
527
|
+
spanId = parsed.parentId;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
traceId = traceId || request.headers.get("x-trace-id") || void 0;
|
|
531
|
+
spanId = spanId || request.headers.get("x-span-id") || void 0;
|
|
435
532
|
const requestId = request.headers.get("x-request-id") || void 0;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
533
|
+
const vercelId = request.headers.get("x-vercel-id") || void 0;
|
|
534
|
+
return new _Logger(
|
|
535
|
+
this.config,
|
|
536
|
+
this.contextName,
|
|
537
|
+
{
|
|
538
|
+
trace_id: traceId,
|
|
539
|
+
span_id: spanId,
|
|
540
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
541
|
+
vercel_id: vercelId
|
|
542
|
+
},
|
|
543
|
+
cloneState(this.state)
|
|
544
|
+
);
|
|
444
545
|
}
|
|
445
546
|
// ---------------------------------------------------------------------------
|
|
446
547
|
// Error capture
|
|
@@ -459,7 +560,8 @@ var Logger = class _Logger {
|
|
|
459
560
|
const enrichedContext = { ...context?.context };
|
|
460
561
|
if (this.state.user) enrichedContext.user = this.state.user;
|
|
461
562
|
if (Object.keys(this.state.tags).length > 0) enrichedContext._tags = { ...this.state.tags };
|
|
462
|
-
if (Object.keys(this.state.contexts).length > 0)
|
|
563
|
+
if (Object.keys(this.state.contexts).length > 0)
|
|
564
|
+
enrichedContext._contexts = { ...this.state.contexts };
|
|
463
565
|
const report = {
|
|
464
566
|
error_message: err.message,
|
|
465
567
|
stack_trace: err.stack || "",
|
|
@@ -540,7 +642,7 @@ var Logger = class _Logger {
|
|
|
540
642
|
}
|
|
541
643
|
/** Start a span with manual lifecycle. You must call span.end(). */
|
|
542
644
|
startInactiveSpan(operation) {
|
|
543
|
-
const traceId = this.requestMeta?.trace_id ||
|
|
645
|
+
const traceId = this.requestMeta?.trace_id || generateTraceId();
|
|
544
646
|
const parentSpanId = this.requestMeta?.span_id || "";
|
|
545
647
|
const spanId = generateId();
|
|
546
648
|
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -580,10 +682,16 @@ var Logger = class _Logger {
|
|
|
580
682
|
const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
|
|
581
683
|
return childLogger.startInactiveSpan(childOp);
|
|
582
684
|
},
|
|
583
|
-
getHeaders: () =>
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
685
|
+
getHeaders: () => {
|
|
686
|
+
const headers = {
|
|
687
|
+
"x-trace-id": traceId,
|
|
688
|
+
"x-span-id": spanId
|
|
689
|
+
};
|
|
690
|
+
if (/^[0-9a-f]{32}$/.test(traceId)) {
|
|
691
|
+
headers.traceparent = `00-${traceId}-${spanId}-01`;
|
|
692
|
+
}
|
|
693
|
+
return headers;
|
|
694
|
+
}
|
|
587
695
|
};
|
|
588
696
|
return span;
|
|
589
697
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, L as LLMUsageReport, b as LogEntry, c as LogLevel, d as Logger, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './
|
|
1
|
+
export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, L as LLMUsageReport, b as LogEntry, c as LogLevel, d as Logger, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-BDTEt7Gi.cjs';
|
|
2
2
|
|
|
3
3
|
/** SDK version. Update on each release. */
|
|
4
|
-
declare const SDK_VERSION = "0.
|
|
4
|
+
declare const SDK_VERSION = "0.4.2";
|
|
5
5
|
declare const SDK_NAME = "core";
|
|
6
6
|
|
|
7
7
|
export { SDK_NAME, SDK_VERSION };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, L as LLMUsageReport, b as LogEntry, c as LogLevel, d as Logger, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './
|
|
1
|
+
export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, L as LLMUsageReport, b as LogEntry, c as LogLevel, d as Logger, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-BDTEt7Gi.js';
|
|
2
2
|
|
|
3
3
|
/** SDK version. Update on each release. */
|
|
4
|
-
declare const SDK_VERSION = "0.
|
|
4
|
+
declare const SDK_VERSION = "0.4.2";
|
|
5
5
|
declare const SDK_NAME = "core";
|
|
6
6
|
|
|
7
7
|
export { SDK_NAME, SDK_VERSION };
|