@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/internal.cjs
CHANGED
|
@@ -21,7 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var internal_exports = {};
|
|
22
22
|
__export(internal_exports, {
|
|
23
23
|
Logger: () => Logger,
|
|
24
|
-
|
|
24
|
+
Transport: () => Transport,
|
|
25
|
+
_originalConsole: () => _originalConsole,
|
|
26
|
+
parseConsoleArgs: () => parseConsoleArgs,
|
|
27
|
+
parseTraceparent: () => parseTraceparent
|
|
25
28
|
});
|
|
26
29
|
module.exports = __toCommonJS(internal_exports);
|
|
27
30
|
|
|
@@ -60,21 +63,51 @@ var Batcher = class {
|
|
|
60
63
|
};
|
|
61
64
|
|
|
62
65
|
// src/version.ts
|
|
63
|
-
var SDK_VERSION = "0.
|
|
66
|
+
var SDK_VERSION = "0.4.2";
|
|
64
67
|
var SDK_NAME = "core";
|
|
65
68
|
|
|
66
69
|
// src/transport.ts
|
|
67
70
|
var Transport = class {
|
|
68
71
|
constructor(config) {
|
|
69
72
|
this.config = config;
|
|
73
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
74
|
+
const hasEndpoint = !!config.endpoint;
|
|
75
|
+
this.disabled = !hasKey || !hasEndpoint;
|
|
76
|
+
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
77
|
+
console.error(
|
|
78
|
+
"[@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."
|
|
79
|
+
);
|
|
80
|
+
}
|
|
70
81
|
}
|
|
71
82
|
inFlightRequests = /* @__PURE__ */ new Set();
|
|
83
|
+
/**
|
|
84
|
+
* When true, all send methods become silent no-ops.
|
|
85
|
+
* Set automatically when no auth key or no endpoint is configured.
|
|
86
|
+
* This prevents pointless network requests and console noise during
|
|
87
|
+
* local development without API keys.
|
|
88
|
+
*/
|
|
89
|
+
disabled;
|
|
90
|
+
/**
|
|
91
|
+
* Tracks which send types (logs, error, trace, LLM usage) have already
|
|
92
|
+
* logged a failure warning. After the first failure for a given type,
|
|
93
|
+
* subsequent failures are silently dropped to prevent console spam
|
|
94
|
+
* (e.g., when the ingestion endpoint is unreachable during development).
|
|
95
|
+
*/
|
|
96
|
+
warnedLabels = /* @__PURE__ */ new Set();
|
|
97
|
+
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
98
|
+
get authKey() {
|
|
99
|
+
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
100
|
+
}
|
|
72
101
|
/**
|
|
73
102
|
* Send a request with automatic retry and exponential backoff.
|
|
74
103
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
75
104
|
* Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
|
|
105
|
+
*
|
|
106
|
+
* After the first total failure for a given label, subsequent failures
|
|
107
|
+
* are silently dropped (no more console warnings).
|
|
76
108
|
*/
|
|
77
109
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
110
|
+
if (this.disabled) return;
|
|
78
111
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
79
112
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
80
113
|
try {
|
|
@@ -82,33 +115,45 @@ var Transport = class {
|
|
|
82
115
|
method: "POST",
|
|
83
116
|
headers: {
|
|
84
117
|
"Content-Type": "application/json",
|
|
85
|
-
Authorization: `Bearer ${this.
|
|
118
|
+
Authorization: `Bearer ${this.authKey}`,
|
|
86
119
|
"x-deeptracer-sdk": `${SDK_NAME}/${SDK_VERSION}`
|
|
87
120
|
},
|
|
88
121
|
body: JSON.stringify(body)
|
|
89
122
|
});
|
|
90
|
-
if (res.ok)
|
|
123
|
+
if (res.ok) {
|
|
124
|
+
this.warnedLabels.delete(label);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
91
127
|
if (res.status >= 400 && res.status < 500) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
128
|
+
if (!this.warnedLabels.has(label)) {
|
|
129
|
+
this.warnedLabels.add(label);
|
|
130
|
+
console.warn(
|
|
131
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText}`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
95
134
|
return;
|
|
96
135
|
}
|
|
97
136
|
if (attempt < maxRetries) {
|
|
98
137
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
99
138
|
continue;
|
|
100
139
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
140
|
+
if (!this.warnedLabels.has(label)) {
|
|
141
|
+
this.warnedLabels.add(label);
|
|
142
|
+
console.warn(
|
|
143
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
104
146
|
} catch {
|
|
105
147
|
if (attempt < maxRetries) {
|
|
106
148
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
107
149
|
continue;
|
|
108
150
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
151
|
+
if (!this.warnedLabels.has(label)) {
|
|
152
|
+
this.warnedLabels.add(label);
|
|
153
|
+
console.warn(
|
|
154
|
+
`[@deeptracer/core] Failed to send ${label} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
112
157
|
}
|
|
113
158
|
}
|
|
114
159
|
}
|
|
@@ -129,7 +174,6 @@ var Transport = class {
|
|
|
129
174
|
const p = this.sendWithRetry(
|
|
130
175
|
`${this.config.endpoint}/ingest/logs`,
|
|
131
176
|
{
|
|
132
|
-
product: this.config.product,
|
|
133
177
|
service: this.config.service,
|
|
134
178
|
environment: this.config.environment,
|
|
135
179
|
logs
|
|
@@ -144,7 +188,6 @@ var Transport = class {
|
|
|
144
188
|
`${this.config.endpoint}/ingest/errors`,
|
|
145
189
|
{
|
|
146
190
|
...error,
|
|
147
|
-
product: this.config.product,
|
|
148
191
|
service: this.config.service,
|
|
149
192
|
environment: this.config.environment
|
|
150
193
|
},
|
|
@@ -158,7 +201,6 @@ var Transport = class {
|
|
|
158
201
|
`${this.config.endpoint}/ingest/traces`,
|
|
159
202
|
{
|
|
160
203
|
...span,
|
|
161
|
-
product: this.config.product,
|
|
162
204
|
service: this.config.service,
|
|
163
205
|
environment: this.config.environment
|
|
164
206
|
},
|
|
@@ -172,7 +214,6 @@ var Transport = class {
|
|
|
172
214
|
`${this.config.endpoint}/ingest/llm`,
|
|
173
215
|
{
|
|
174
216
|
...report,
|
|
175
|
-
product: this.config.product,
|
|
176
217
|
service: this.config.service,
|
|
177
218
|
environment: this.config.environment
|
|
178
219
|
},
|
|
@@ -206,6 +247,15 @@ function createLoggerState(maxBreadcrumbs) {
|
|
|
206
247
|
maxBreadcrumbs
|
|
207
248
|
};
|
|
208
249
|
}
|
|
250
|
+
function cloneState(state) {
|
|
251
|
+
return {
|
|
252
|
+
user: state.user ? { ...state.user } : null,
|
|
253
|
+
tags: { ...state.tags },
|
|
254
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
255
|
+
breadcrumbs: [...state.breadcrumbs],
|
|
256
|
+
maxBreadcrumbs: state.maxBreadcrumbs
|
|
257
|
+
};
|
|
258
|
+
}
|
|
209
259
|
function addBreadcrumb(state, breadcrumb) {
|
|
210
260
|
state.breadcrumbs.push(breadcrumb);
|
|
211
261
|
if (state.breadcrumbs.length > state.maxBreadcrumbs) {
|
|
@@ -214,11 +264,33 @@ function addBreadcrumb(state, breadcrumb) {
|
|
|
214
264
|
}
|
|
215
265
|
|
|
216
266
|
// src/logger.ts
|
|
267
|
+
var LOG_LEVEL_VALUES = {
|
|
268
|
+
debug: 0,
|
|
269
|
+
info: 1,
|
|
270
|
+
warn: 2,
|
|
271
|
+
error: 3
|
|
272
|
+
};
|
|
217
273
|
function generateId() {
|
|
218
274
|
const bytes = new Uint8Array(8);
|
|
219
275
|
crypto.getRandomValues(bytes);
|
|
220
276
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
221
277
|
}
|
|
278
|
+
function generateTraceId() {
|
|
279
|
+
const bytes = new Uint8Array(16);
|
|
280
|
+
crypto.getRandomValues(bytes);
|
|
281
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
282
|
+
}
|
|
283
|
+
function parseTraceparent(header) {
|
|
284
|
+
const parts = header.trim().split("-");
|
|
285
|
+
if (parts.length !== 4) return null;
|
|
286
|
+
const [version, traceId, parentId, flags] = parts;
|
|
287
|
+
if (version !== "00") return null;
|
|
288
|
+
if (traceId.length !== 32 || !/^[0-9a-f]{32}$/.test(traceId)) return null;
|
|
289
|
+
if (parentId.length !== 16 || !/^[0-9a-f]{16}$/.test(parentId)) return null;
|
|
290
|
+
if (flags.length !== 2 || !/^[0-9a-f]{2}$/.test(flags)) return null;
|
|
291
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentId)) return null;
|
|
292
|
+
return { traceId, parentId, flags };
|
|
293
|
+
}
|
|
222
294
|
var _originalConsole = {
|
|
223
295
|
log: console.log,
|
|
224
296
|
info: console.info,
|
|
@@ -229,6 +301,7 @@ var _originalConsole = {
|
|
|
229
301
|
var Logger = class _Logger {
|
|
230
302
|
batcher;
|
|
231
303
|
transport;
|
|
304
|
+
effectiveLevel;
|
|
232
305
|
contextName;
|
|
233
306
|
config;
|
|
234
307
|
state;
|
|
@@ -238,6 +311,20 @@ var Logger = class _Logger {
|
|
|
238
311
|
this.contextName = contextName;
|
|
239
312
|
this.requestMeta = requestMeta;
|
|
240
313
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
314
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
315
|
+
const hasEndpoint = !!config.endpoint;
|
|
316
|
+
if (!hasKey && !hasEndpoint) {
|
|
317
|
+
_originalConsole.warn(
|
|
318
|
+
"[@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."
|
|
319
|
+
);
|
|
320
|
+
} else if (!hasKey) {
|
|
321
|
+
_originalConsole.warn(
|
|
322
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
323
|
+
);
|
|
324
|
+
} else if (!hasEndpoint) {
|
|
325
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
326
|
+
}
|
|
327
|
+
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
241
328
|
this.transport = new Transport(config);
|
|
242
329
|
this.batcher = new Batcher(
|
|
243
330
|
{ batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
|
|
@@ -251,7 +338,8 @@ var Logger = class _Logger {
|
|
|
251
338
|
// ---------------------------------------------------------------------------
|
|
252
339
|
/**
|
|
253
340
|
* Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
|
|
254
|
-
*
|
|
341
|
+
* Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
|
|
342
|
+
* have their own independent state.
|
|
255
343
|
*
|
|
256
344
|
* @example
|
|
257
345
|
* ```ts
|
|
@@ -373,26 +461,13 @@ var Logger = class _Logger {
|
|
|
373
461
|
};
|
|
374
462
|
}
|
|
375
463
|
metadata = this.mergeStateMetadata(metadata);
|
|
376
|
-
const
|
|
377
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
378
|
-
level,
|
|
379
|
-
message,
|
|
380
|
-
metadata,
|
|
381
|
-
context: this.contextName,
|
|
382
|
-
trace_id: this.requestMeta?.trace_id,
|
|
383
|
-
span_id: this.requestMeta?.span_id,
|
|
384
|
-
request_id: this.requestMeta?.request_id,
|
|
385
|
-
vercel_id: this.requestMeta?.vercel_id
|
|
386
|
-
};
|
|
387
|
-
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
388
|
-
if (hookResult === null) return;
|
|
389
|
-
const finalEntry = hookResult.data;
|
|
464
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
390
465
|
if (this.config.debug) {
|
|
391
466
|
const prefix = this.contextName ? `[${this.contextName}]` : "";
|
|
392
467
|
const lvl = level.toUpperCase().padEnd(5);
|
|
393
468
|
const consoleFn = level === "error" ? _originalConsole.error : level === "warn" ? _originalConsole.warn : level === "debug" ? _originalConsole.debug : _originalConsole.log;
|
|
394
|
-
if (
|
|
395
|
-
consoleFn(`${lvl} ${prefix} ${message}`,
|
|
469
|
+
if (metadata) {
|
|
470
|
+
consoleFn(`${lvl} ${prefix} ${message}`, metadata);
|
|
396
471
|
} else {
|
|
397
472
|
consoleFn(`${lvl} ${prefix} ${message}`);
|
|
398
473
|
}
|
|
@@ -400,9 +475,23 @@ var Logger = class _Logger {
|
|
|
400
475
|
addBreadcrumb(this.state, {
|
|
401
476
|
type: "log",
|
|
402
477
|
message: `[${level}] ${message}`,
|
|
403
|
-
timestamp
|
|
478
|
+
timestamp
|
|
404
479
|
});
|
|
405
|
-
this.
|
|
480
|
+
if (LOG_LEVEL_VALUES[level] < this.effectiveLevel) return;
|
|
481
|
+
const entry = {
|
|
482
|
+
timestamp,
|
|
483
|
+
level,
|
|
484
|
+
message,
|
|
485
|
+
metadata,
|
|
486
|
+
context: this.contextName,
|
|
487
|
+
trace_id: this.requestMeta?.trace_id,
|
|
488
|
+
span_id: this.requestMeta?.span_id,
|
|
489
|
+
request_id: this.requestMeta?.request_id,
|
|
490
|
+
vercel_id: this.requestMeta?.vercel_id
|
|
491
|
+
};
|
|
492
|
+
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
493
|
+
if (hookResult === null) return;
|
|
494
|
+
this.batcher.add(hookResult.data);
|
|
406
495
|
}
|
|
407
496
|
/** Log a debug message. */
|
|
408
497
|
debug(message, dataOrError, error) {
|
|
@@ -423,22 +512,37 @@ var Logger = class _Logger {
|
|
|
423
512
|
// ---------------------------------------------------------------------------
|
|
424
513
|
// Child loggers
|
|
425
514
|
// ---------------------------------------------------------------------------
|
|
426
|
-
/** Create a context-scoped logger. All logs include the context name.
|
|
515
|
+
/** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
|
|
427
516
|
withContext(name) {
|
|
428
|
-
return new _Logger(this.config, name, this.requestMeta, this.state);
|
|
517
|
+
return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
|
|
429
518
|
}
|
|
430
|
-
/** Create a request-scoped logger that extracts trace context from headers.
|
|
519
|
+
/** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
|
|
431
520
|
forRequest(request) {
|
|
432
|
-
|
|
521
|
+
let traceId;
|
|
522
|
+
let spanId;
|
|
523
|
+
const traceparent = request.headers.get("traceparent");
|
|
524
|
+
if (traceparent) {
|
|
525
|
+
const parsed = parseTraceparent(traceparent);
|
|
526
|
+
if (parsed) {
|
|
527
|
+
traceId = parsed.traceId;
|
|
528
|
+
spanId = parsed.parentId;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
traceId = traceId || request.headers.get("x-trace-id") || void 0;
|
|
532
|
+
spanId = spanId || request.headers.get("x-span-id") || void 0;
|
|
433
533
|
const requestId = request.headers.get("x-request-id") || void 0;
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
534
|
+
const vercelId = request.headers.get("x-vercel-id") || void 0;
|
|
535
|
+
return new _Logger(
|
|
536
|
+
this.config,
|
|
537
|
+
this.contextName,
|
|
538
|
+
{
|
|
539
|
+
trace_id: traceId,
|
|
540
|
+
span_id: spanId,
|
|
541
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
542
|
+
vercel_id: vercelId
|
|
543
|
+
},
|
|
544
|
+
cloneState(this.state)
|
|
545
|
+
);
|
|
442
546
|
}
|
|
443
547
|
// ---------------------------------------------------------------------------
|
|
444
548
|
// Error capture
|
|
@@ -457,7 +561,8 @@ var Logger = class _Logger {
|
|
|
457
561
|
const enrichedContext = { ...context?.context };
|
|
458
562
|
if (this.state.user) enrichedContext.user = this.state.user;
|
|
459
563
|
if (Object.keys(this.state.tags).length > 0) enrichedContext._tags = { ...this.state.tags };
|
|
460
|
-
if (Object.keys(this.state.contexts).length > 0)
|
|
564
|
+
if (Object.keys(this.state.contexts).length > 0)
|
|
565
|
+
enrichedContext._contexts = { ...this.state.contexts };
|
|
461
566
|
const report = {
|
|
462
567
|
error_message: err.message,
|
|
463
568
|
stack_trace: err.stack || "",
|
|
@@ -538,7 +643,7 @@ var Logger = class _Logger {
|
|
|
538
643
|
}
|
|
539
644
|
/** Start a span with manual lifecycle. You must call span.end(). */
|
|
540
645
|
startInactiveSpan(operation) {
|
|
541
|
-
const traceId = this.requestMeta?.trace_id ||
|
|
646
|
+
const traceId = this.requestMeta?.trace_id || generateTraceId();
|
|
542
647
|
const parentSpanId = this.requestMeta?.span_id || "";
|
|
543
648
|
const spanId = generateId();
|
|
544
649
|
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -578,10 +683,16 @@ var Logger = class _Logger {
|
|
|
578
683
|
const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
|
|
579
684
|
return childLogger.startInactiveSpan(childOp);
|
|
580
685
|
},
|
|
581
|
-
getHeaders: () =>
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
686
|
+
getHeaders: () => {
|
|
687
|
+
const headers = {
|
|
688
|
+
"x-trace-id": traceId,
|
|
689
|
+
"x-span-id": spanId
|
|
690
|
+
};
|
|
691
|
+
if (/^[0-9a-f]{32}$/.test(traceId)) {
|
|
692
|
+
headers.traceparent = `00-${traceId}-${spanId}-01`;
|
|
693
|
+
}
|
|
694
|
+
return headers;
|
|
695
|
+
}
|
|
585
696
|
};
|
|
586
697
|
return span;
|
|
587
698
|
}
|
|
@@ -615,8 +726,71 @@ var Logger = class _Logger {
|
|
|
615
726
|
await this.transport.drain(timeoutMs);
|
|
616
727
|
}
|
|
617
728
|
};
|
|
729
|
+
|
|
730
|
+
// src/internal.ts
|
|
731
|
+
function safeStringify(value) {
|
|
732
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
733
|
+
return JSON.stringify(value, (_key, val) => {
|
|
734
|
+
if (val instanceof Error) {
|
|
735
|
+
return { name: val.name, message: val.message, stack: val.stack };
|
|
736
|
+
}
|
|
737
|
+
if (typeof val === "bigint") return val.toString();
|
|
738
|
+
if (typeof val === "symbol") return val.toString();
|
|
739
|
+
if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
|
|
740
|
+
if (val !== null && typeof val === "object") {
|
|
741
|
+
if (seen.has(val)) return "[Circular]";
|
|
742
|
+
seen.add(val);
|
|
743
|
+
}
|
|
744
|
+
return val;
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
function parseConsoleArgs(args) {
|
|
748
|
+
if (args.length === 0) return { message: "" };
|
|
749
|
+
const first = args[0];
|
|
750
|
+
if (typeof first === "string" && /%[sdifoc%]/.test(first)) {
|
|
751
|
+
return { message: args.map(String).join(" ") };
|
|
752
|
+
}
|
|
753
|
+
if (typeof first === "string") {
|
|
754
|
+
const messageParts = [first];
|
|
755
|
+
const metadata = {};
|
|
756
|
+
let metadataCount = 0;
|
|
757
|
+
for (let i = 1; i < args.length; i++) {
|
|
758
|
+
const arg = args[i];
|
|
759
|
+
if (arg instanceof Error) {
|
|
760
|
+
metadata[`error${metadataCount > 0 ? `_${metadataCount}` : ""}`] = {
|
|
761
|
+
name: arg.name,
|
|
762
|
+
message: arg.message,
|
|
763
|
+
stack: arg.stack
|
|
764
|
+
};
|
|
765
|
+
metadataCount++;
|
|
766
|
+
} else if (arg !== null && typeof arg === "object") {
|
|
767
|
+
Object.assign(metadata, arg);
|
|
768
|
+
metadataCount++;
|
|
769
|
+
} else if (arg !== void 0) {
|
|
770
|
+
messageParts.push(String(arg));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
message: messageParts.join(" "),
|
|
775
|
+
metadata: metadataCount > 0 ? metadata : void 0
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
if (first instanceof Error) {
|
|
779
|
+
return {
|
|
780
|
+
message: first.message,
|
|
781
|
+
metadata: { error: { name: first.name, message: first.message, stack: first.stack } }
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
if (first !== null && typeof first === "object") {
|
|
785
|
+
return { message: safeStringify(first) };
|
|
786
|
+
}
|
|
787
|
+
return { message: String(first) };
|
|
788
|
+
}
|
|
618
789
|
// Annotate the CommonJS export names for ESM import in node:
|
|
619
790
|
0 && (module.exports = {
|
|
620
791
|
Logger,
|
|
621
|
-
|
|
792
|
+
Transport,
|
|
793
|
+
_originalConsole,
|
|
794
|
+
parseConsoleArgs,
|
|
795
|
+
parseTraceparent
|
|
622
796
|
});
|
package/dist/internal.d.cts
CHANGED
|
@@ -1 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
import { e as LoggerConfig, b as LogEntry, E as ErrorReport, f as SpanData } from './logger-BDTEt7Gi.cjs';
|
|
2
|
+
export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-BDTEt7Gi.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTTP transport for sending data to the DeepTracer ingestion API.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
|
|
9
|
+
* - Only retries on network errors and 5xx (not 4xx client errors)
|
|
10
|
+
* - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
|
|
11
|
+
* - In-flight request tracking for graceful shutdown via `drain()`
|
|
12
|
+
* - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
|
|
13
|
+
* - Warn-once per failure type — first failure for each send type (logs, error, trace)
|
|
14
|
+
* logs a warning, subsequent identical failures are silently dropped
|
|
15
|
+
*/
|
|
16
|
+
declare class Transport {
|
|
17
|
+
private config;
|
|
18
|
+
private inFlightRequests;
|
|
19
|
+
/**
|
|
20
|
+
* When true, all send methods become silent no-ops.
|
|
21
|
+
* Set automatically when no auth key or no endpoint is configured.
|
|
22
|
+
* This prevents pointless network requests and console noise during
|
|
23
|
+
* local development without API keys.
|
|
24
|
+
*/
|
|
25
|
+
private readonly disabled;
|
|
26
|
+
/**
|
|
27
|
+
* Tracks which send types (logs, error, trace, LLM usage) have already
|
|
28
|
+
* logged a failure warning. After the first failure for a given type,
|
|
29
|
+
* subsequent failures are silently dropped to prevent console spam
|
|
30
|
+
* (e.g., when the ingestion endpoint is unreachable during development).
|
|
31
|
+
*/
|
|
32
|
+
private warnedLabels;
|
|
33
|
+
constructor(config: Pick<LoggerConfig, "endpoint" | "secretKey" | "publicKey" | "service" | "environment">);
|
|
34
|
+
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
35
|
+
private get authKey();
|
|
36
|
+
/**
|
|
37
|
+
* Send a request with automatic retry and exponential backoff.
|
|
38
|
+
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
39
|
+
* Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
|
|
40
|
+
*
|
|
41
|
+
* After the first total failure for a given label, subsequent failures
|
|
42
|
+
* are silently dropped (no more console warnings).
|
|
43
|
+
*/
|
|
44
|
+
private sendWithRetry;
|
|
45
|
+
/** Add +/- 20% jitter to a delay to prevent thundering herd. */
|
|
46
|
+
private jitter;
|
|
47
|
+
private sleep;
|
|
48
|
+
/** Track an in-flight request and remove it when done. */
|
|
49
|
+
private track;
|
|
50
|
+
sendLogs(logs: LogEntry[]): Promise<void>;
|
|
51
|
+
sendError(error: ErrorReport): Promise<void>;
|
|
52
|
+
sendTrace(span: SpanData): Promise<void>;
|
|
53
|
+
sendLLMUsage(report: {
|
|
54
|
+
model: string;
|
|
55
|
+
provider: string;
|
|
56
|
+
operation: string;
|
|
57
|
+
input_tokens: number;
|
|
58
|
+
output_tokens: number;
|
|
59
|
+
cost_usd: number;
|
|
60
|
+
latency_ms: number;
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Wait for all in-flight requests to complete, with a timeout.
|
|
65
|
+
* Used by `logger.destroy()` to ensure data is sent before process exit.
|
|
66
|
+
*
|
|
67
|
+
* @param timeoutMs - Maximum time to wait (default: 2000ms)
|
|
68
|
+
*/
|
|
69
|
+
drain(timeoutMs?: number): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
|
|
74
|
+
*
|
|
75
|
+
* - First string arg → message; remaining objects → merged into metadata
|
|
76
|
+
* - If first string has printf patterns (`%s`, `%d`, `%o`, etc.) → join all as string, no metadata
|
|
77
|
+
* - First non-string arg → `safeStringify` it for message
|
|
78
|
+
* - Error objects → serialize `{ name, message, stack }` into metadata
|
|
79
|
+
* - Remaining primitives → append to message string
|
|
80
|
+
*/
|
|
81
|
+
declare function parseConsoleArgs(args: unknown[]): {
|
|
82
|
+
message: string;
|
|
83
|
+
metadata?: Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export { LoggerConfig, Transport, parseConsoleArgs };
|
package/dist/internal.d.ts
CHANGED
|
@@ -1 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
import { e as LoggerConfig, b as LogEntry, E as ErrorReport, f as SpanData } from './logger-BDTEt7Gi.js';
|
|
2
|
+
export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-BDTEt7Gi.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTTP transport for sending data to the DeepTracer ingestion API.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
|
|
9
|
+
* - Only retries on network errors and 5xx (not 4xx client errors)
|
|
10
|
+
* - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
|
|
11
|
+
* - In-flight request tracking for graceful shutdown via `drain()`
|
|
12
|
+
* - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
|
|
13
|
+
* - Warn-once per failure type — first failure for each send type (logs, error, trace)
|
|
14
|
+
* logs a warning, subsequent identical failures are silently dropped
|
|
15
|
+
*/
|
|
16
|
+
declare class Transport {
|
|
17
|
+
private config;
|
|
18
|
+
private inFlightRequests;
|
|
19
|
+
/**
|
|
20
|
+
* When true, all send methods become silent no-ops.
|
|
21
|
+
* Set automatically when no auth key or no endpoint is configured.
|
|
22
|
+
* This prevents pointless network requests and console noise during
|
|
23
|
+
* local development without API keys.
|
|
24
|
+
*/
|
|
25
|
+
private readonly disabled;
|
|
26
|
+
/**
|
|
27
|
+
* Tracks which send types (logs, error, trace, LLM usage) have already
|
|
28
|
+
* logged a failure warning. After the first failure for a given type,
|
|
29
|
+
* subsequent failures are silently dropped to prevent console spam
|
|
30
|
+
* (e.g., when the ingestion endpoint is unreachable during development).
|
|
31
|
+
*/
|
|
32
|
+
private warnedLabels;
|
|
33
|
+
constructor(config: Pick<LoggerConfig, "endpoint" | "secretKey" | "publicKey" | "service" | "environment">);
|
|
34
|
+
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
35
|
+
private get authKey();
|
|
36
|
+
/**
|
|
37
|
+
* Send a request with automatic retry and exponential backoff.
|
|
38
|
+
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
39
|
+
* Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
|
|
40
|
+
*
|
|
41
|
+
* After the first total failure for a given label, subsequent failures
|
|
42
|
+
* are silently dropped (no more console warnings).
|
|
43
|
+
*/
|
|
44
|
+
private sendWithRetry;
|
|
45
|
+
/** Add +/- 20% jitter to a delay to prevent thundering herd. */
|
|
46
|
+
private jitter;
|
|
47
|
+
private sleep;
|
|
48
|
+
/** Track an in-flight request and remove it when done. */
|
|
49
|
+
private track;
|
|
50
|
+
sendLogs(logs: LogEntry[]): Promise<void>;
|
|
51
|
+
sendError(error: ErrorReport): Promise<void>;
|
|
52
|
+
sendTrace(span: SpanData): Promise<void>;
|
|
53
|
+
sendLLMUsage(report: {
|
|
54
|
+
model: string;
|
|
55
|
+
provider: string;
|
|
56
|
+
operation: string;
|
|
57
|
+
input_tokens: number;
|
|
58
|
+
output_tokens: number;
|
|
59
|
+
cost_usd: number;
|
|
60
|
+
latency_ms: number;
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Wait for all in-flight requests to complete, with a timeout.
|
|
65
|
+
* Used by `logger.destroy()` to ensure data is sent before process exit.
|
|
66
|
+
*
|
|
67
|
+
* @param timeoutMs - Maximum time to wait (default: 2000ms)
|
|
68
|
+
*/
|
|
69
|
+
drain(timeoutMs?: number): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
|
|
74
|
+
*
|
|
75
|
+
* - First string arg → message; remaining objects → merged into metadata
|
|
76
|
+
* - If first string has printf patterns (`%s`, `%d`, `%o`, etc.) → join all as string, no metadata
|
|
77
|
+
* - First non-string arg → `safeStringify` it for message
|
|
78
|
+
* - Error objects → serialize `{ name, message, stack }` into metadata
|
|
79
|
+
* - Remaining primitives → append to message string
|
|
80
|
+
*/
|
|
81
|
+
declare function parseConsoleArgs(args: unknown[]): {
|
|
82
|
+
message: string;
|
|
83
|
+
metadata?: Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export { LoggerConfig, Transport, parseConsoleArgs };
|