@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/README.md
CHANGED
|
@@ -47,11 +47,10 @@ The package ships as both ESM and CJS with full TypeScript declarations. Zero ru
|
|
|
47
47
|
import { createLogger } from "@deeptracer/core"
|
|
48
48
|
|
|
49
49
|
const logger = createLogger({
|
|
50
|
-
product: "my-app",
|
|
51
50
|
service: "api",
|
|
52
51
|
environment: "production",
|
|
53
52
|
endpoint: "https://your-deeptracer.example.com",
|
|
54
|
-
|
|
53
|
+
secretKey: "dt_secret_xxx",
|
|
55
54
|
})
|
|
56
55
|
|
|
57
56
|
// Structured logging (batched -- sent in groups of 50 or every 5 seconds)
|
|
@@ -85,11 +84,10 @@ Pass a `LoggerConfig` object to `createLogger()`:
|
|
|
85
84
|
```ts
|
|
86
85
|
const logger = createLogger({
|
|
87
86
|
// Required
|
|
88
|
-
product: "spotbeam", // Product name for grouping in the dashboard
|
|
89
87
|
service: "api", // Service name within the product
|
|
90
88
|
environment: "production", // "production" or "staging"
|
|
91
89
|
endpoint: "https://dt.co", // DeepTracer ingestion endpoint URL
|
|
92
|
-
|
|
90
|
+
secretKey: "dt_secret_xxx", // Server-side API key for authentication
|
|
93
91
|
|
|
94
92
|
// Optional
|
|
95
93
|
batchSize: 50, // Logs to buffer before sending (default: 50)
|
|
@@ -100,11 +98,11 @@ const logger = createLogger({
|
|
|
100
98
|
|
|
101
99
|
| Field | Type | Required | Default | Description |
|
|
102
100
|
|-------|------|----------|---------|-------------|
|
|
103
|
-
| `product` | `string` | Yes | -- | Product name (e.g., `"spotbeam"`, `"macro"`) |
|
|
104
101
|
| `service` | `string` | Yes | -- | Service name (e.g., `"api"`, `"worker"`, `"web"`) |
|
|
105
102
|
| `environment` | `"production" \| "staging"` | Yes | -- | Deployment environment |
|
|
106
103
|
| `endpoint` | `string` | Yes | -- | DeepTracer ingestion endpoint URL |
|
|
107
|
-
| `
|
|
104
|
+
| `secretKey` | `string` | Yes | -- | Server-side API key (prefix: `dt_secret_`) |
|
|
105
|
+
| `publicKey` | `string` | No | -- | Client-side API key (prefix: `dt_public_`) |
|
|
108
106
|
| `batchSize` | `number` | No | `50` | Number of log entries to buffer before flushing |
|
|
109
107
|
| `flushIntervalMs` | `number` | No | `5000` | Milliseconds between automatic flushes |
|
|
110
108
|
| `debug` | `boolean` | No | `false` | When `true`, all log calls also print to the console |
|
|
@@ -119,11 +117,10 @@ Create a new `Logger` instance. This is the main entry point.
|
|
|
119
117
|
import { createLogger } from "@deeptracer/core"
|
|
120
118
|
|
|
121
119
|
const logger = createLogger({
|
|
122
|
-
product: "my-app",
|
|
123
120
|
service: "api",
|
|
124
121
|
environment: "production",
|
|
125
122
|
endpoint: "https://your-deeptracer.example.com",
|
|
126
|
-
|
|
123
|
+
secretKey: "dt_secret_xxx",
|
|
127
124
|
})
|
|
128
125
|
```
|
|
129
126
|
|
|
@@ -439,11 +436,11 @@ process.on("SIGTERM", () => {
|
|
|
439
436
|
|
|
440
437
|
```ts
|
|
441
438
|
interface LoggerConfig {
|
|
442
|
-
product: string
|
|
443
439
|
service: string
|
|
444
440
|
environment: "production" | "staging"
|
|
445
441
|
endpoint: string
|
|
446
|
-
|
|
442
|
+
secretKey: string
|
|
443
|
+
publicKey?: string
|
|
447
444
|
batchSize?: number // default: 50
|
|
448
445
|
flushIntervalMs?: number // default: 5000
|
|
449
446
|
debug?: boolean // default: false
|
|
@@ -587,9 +584,9 @@ The transport layer sends data to four DeepTracer ingestion endpoints:
|
|
|
587
584
|
| `POST /ingest/llm` | Immediate | LLM usage reports |
|
|
588
585
|
|
|
589
586
|
All requests include:
|
|
590
|
-
- `Authorization: Bearer <
|
|
587
|
+
- `Authorization: Bearer <secretKey>` header
|
|
591
588
|
- `Content-Type: application/json` header
|
|
592
|
-
- `
|
|
589
|
+
- `service` and `environment` fields in the JSON body
|
|
593
590
|
|
|
594
591
|
If a request fails, a warning is logged to the console. The SDK does not retry failed requests -- it is designed to be non-blocking and never crash your application.
|
|
595
592
|
|
|
@@ -1,53 +1,49 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var SDK_VERSION = "0.
|
|
2
|
+
var SDK_VERSION = "0.4.2";
|
|
3
3
|
var SDK_NAME = "core";
|
|
4
4
|
|
|
5
|
-
// src/batcher.ts
|
|
6
|
-
var Batcher = class {
|
|
7
|
-
constructor(config, onFlush) {
|
|
8
|
-
this.onFlush = onFlush;
|
|
9
|
-
this.batchSize = config.batchSize ?? 50;
|
|
10
|
-
this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
|
|
11
|
-
this.startTimer();
|
|
12
|
-
}
|
|
13
|
-
buffer = [];
|
|
14
|
-
timer = null;
|
|
15
|
-
batchSize;
|
|
16
|
-
flushIntervalMs;
|
|
17
|
-
add(entry) {
|
|
18
|
-
this.buffer.push(entry);
|
|
19
|
-
if (this.buffer.length >= this.batchSize) {
|
|
20
|
-
this.flush();
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
flush() {
|
|
24
|
-
if (this.buffer.length === 0) return;
|
|
25
|
-
const entries = [...this.buffer];
|
|
26
|
-
this.buffer = [];
|
|
27
|
-
this.onFlush(entries);
|
|
28
|
-
}
|
|
29
|
-
startTimer() {
|
|
30
|
-
this.timer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
31
|
-
}
|
|
32
|
-
async destroy() {
|
|
33
|
-
if (this.timer) clearInterval(this.timer);
|
|
34
|
-
this.timer = null;
|
|
35
|
-
this.flush();
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
5
|
// src/transport.ts
|
|
40
6
|
var Transport = class {
|
|
41
7
|
constructor(config) {
|
|
42
8
|
this.config = config;
|
|
9
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
10
|
+
const hasEndpoint = !!config.endpoint;
|
|
11
|
+
this.disabled = !hasKey || !hasEndpoint;
|
|
12
|
+
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
13
|
+
console.error(
|
|
14
|
+
"[@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."
|
|
15
|
+
);
|
|
16
|
+
}
|
|
43
17
|
}
|
|
44
18
|
inFlightRequests = /* @__PURE__ */ new Set();
|
|
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
|
+
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
|
+
warnedLabels = /* @__PURE__ */ new Set();
|
|
33
|
+
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
34
|
+
get authKey() {
|
|
35
|
+
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
36
|
+
}
|
|
45
37
|
/**
|
|
46
38
|
* Send a request with automatic retry and exponential backoff.
|
|
47
39
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
48
40
|
* Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
|
|
41
|
+
*
|
|
42
|
+
* After the first total failure for a given label, subsequent failures
|
|
43
|
+
* are silently dropped (no more console warnings).
|
|
49
44
|
*/
|
|
50
45
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
46
|
+
if (this.disabled) return;
|
|
51
47
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
52
48
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
53
49
|
try {
|
|
@@ -55,33 +51,45 @@ var Transport = class {
|
|
|
55
51
|
method: "POST",
|
|
56
52
|
headers: {
|
|
57
53
|
"Content-Type": "application/json",
|
|
58
|
-
Authorization: `Bearer ${this.
|
|
54
|
+
Authorization: `Bearer ${this.authKey}`,
|
|
59
55
|
"x-deeptracer-sdk": `${SDK_NAME}/${SDK_VERSION}`
|
|
60
56
|
},
|
|
61
57
|
body: JSON.stringify(body)
|
|
62
58
|
});
|
|
63
|
-
if (res.ok)
|
|
59
|
+
if (res.ok) {
|
|
60
|
+
this.warnedLabels.delete(label);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
64
63
|
if (res.status >= 400 && res.status < 500) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
if (!this.warnedLabels.has(label)) {
|
|
65
|
+
this.warnedLabels.add(label);
|
|
66
|
+
console.warn(
|
|
67
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
if (attempt < maxRetries) {
|
|
71
73
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
72
74
|
continue;
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
if (!this.warnedLabels.has(label)) {
|
|
77
|
+
this.warnedLabels.add(label);
|
|
78
|
+
console.warn(
|
|
79
|
+
`[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
77
82
|
} catch {
|
|
78
83
|
if (attempt < maxRetries) {
|
|
79
84
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
80
85
|
continue;
|
|
81
86
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
if (!this.warnedLabels.has(label)) {
|
|
88
|
+
this.warnedLabels.add(label);
|
|
89
|
+
console.warn(
|
|
90
|
+
`[@deeptracer/core] Failed to send ${label} (exhausted ${maxRetries} retries). Suppressing further warnings.`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
}
|
|
@@ -102,7 +110,6 @@ var Transport = class {
|
|
|
102
110
|
const p = this.sendWithRetry(
|
|
103
111
|
`${this.config.endpoint}/ingest/logs`,
|
|
104
112
|
{
|
|
105
|
-
product: this.config.product,
|
|
106
113
|
service: this.config.service,
|
|
107
114
|
environment: this.config.environment,
|
|
108
115
|
logs
|
|
@@ -117,7 +124,6 @@ var Transport = class {
|
|
|
117
124
|
`${this.config.endpoint}/ingest/errors`,
|
|
118
125
|
{
|
|
119
126
|
...error,
|
|
120
|
-
product: this.config.product,
|
|
121
127
|
service: this.config.service,
|
|
122
128
|
environment: this.config.environment
|
|
123
129
|
},
|
|
@@ -131,7 +137,6 @@ var Transport = class {
|
|
|
131
137
|
`${this.config.endpoint}/ingest/traces`,
|
|
132
138
|
{
|
|
133
139
|
...span,
|
|
134
|
-
product: this.config.product,
|
|
135
140
|
service: this.config.service,
|
|
136
141
|
environment: this.config.environment
|
|
137
142
|
},
|
|
@@ -145,7 +150,6 @@ var Transport = class {
|
|
|
145
150
|
`${this.config.endpoint}/ingest/llm`,
|
|
146
151
|
{
|
|
147
152
|
...report,
|
|
148
|
-
product: this.config.product,
|
|
149
153
|
service: this.config.service,
|
|
150
154
|
environment: this.config.environment
|
|
151
155
|
},
|
|
@@ -169,6 +173,40 @@ var Transport = class {
|
|
|
169
173
|
}
|
|
170
174
|
};
|
|
171
175
|
|
|
176
|
+
// src/batcher.ts
|
|
177
|
+
var Batcher = class {
|
|
178
|
+
constructor(config, onFlush) {
|
|
179
|
+
this.onFlush = onFlush;
|
|
180
|
+
this.batchSize = config.batchSize ?? 50;
|
|
181
|
+
this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
|
|
182
|
+
this.startTimer();
|
|
183
|
+
}
|
|
184
|
+
buffer = [];
|
|
185
|
+
timer = null;
|
|
186
|
+
batchSize;
|
|
187
|
+
flushIntervalMs;
|
|
188
|
+
add(entry) {
|
|
189
|
+
this.buffer.push(entry);
|
|
190
|
+
if (this.buffer.length >= this.batchSize) {
|
|
191
|
+
this.flush();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
flush() {
|
|
195
|
+
if (this.buffer.length === 0) return;
|
|
196
|
+
const entries = [...this.buffer];
|
|
197
|
+
this.buffer = [];
|
|
198
|
+
this.onFlush(entries);
|
|
199
|
+
}
|
|
200
|
+
startTimer() {
|
|
201
|
+
this.timer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
202
|
+
}
|
|
203
|
+
async destroy() {
|
|
204
|
+
if (this.timer) clearInterval(this.timer);
|
|
205
|
+
this.timer = null;
|
|
206
|
+
this.flush();
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
172
210
|
// src/state.ts
|
|
173
211
|
function createLoggerState(maxBreadcrumbs) {
|
|
174
212
|
return {
|
|
@@ -179,6 +217,15 @@ function createLoggerState(maxBreadcrumbs) {
|
|
|
179
217
|
maxBreadcrumbs
|
|
180
218
|
};
|
|
181
219
|
}
|
|
220
|
+
function cloneState(state) {
|
|
221
|
+
return {
|
|
222
|
+
user: state.user ? { ...state.user } : null,
|
|
223
|
+
tags: { ...state.tags },
|
|
224
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
225
|
+
breadcrumbs: [...state.breadcrumbs],
|
|
226
|
+
maxBreadcrumbs: state.maxBreadcrumbs
|
|
227
|
+
};
|
|
228
|
+
}
|
|
182
229
|
function addBreadcrumb(state, breadcrumb) {
|
|
183
230
|
state.breadcrumbs.push(breadcrumb);
|
|
184
231
|
if (state.breadcrumbs.length > state.maxBreadcrumbs) {
|
|
@@ -187,11 +234,33 @@ function addBreadcrumb(state, breadcrumb) {
|
|
|
187
234
|
}
|
|
188
235
|
|
|
189
236
|
// src/logger.ts
|
|
237
|
+
var LOG_LEVEL_VALUES = {
|
|
238
|
+
debug: 0,
|
|
239
|
+
info: 1,
|
|
240
|
+
warn: 2,
|
|
241
|
+
error: 3
|
|
242
|
+
};
|
|
190
243
|
function generateId() {
|
|
191
244
|
const bytes = new Uint8Array(8);
|
|
192
245
|
crypto.getRandomValues(bytes);
|
|
193
246
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
194
247
|
}
|
|
248
|
+
function generateTraceId() {
|
|
249
|
+
const bytes = new Uint8Array(16);
|
|
250
|
+
crypto.getRandomValues(bytes);
|
|
251
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
252
|
+
}
|
|
253
|
+
function parseTraceparent(header) {
|
|
254
|
+
const parts = header.trim().split("-");
|
|
255
|
+
if (parts.length !== 4) return null;
|
|
256
|
+
const [version, traceId, parentId, flags] = parts;
|
|
257
|
+
if (version !== "00") return null;
|
|
258
|
+
if (traceId.length !== 32 || !/^[0-9a-f]{32}$/.test(traceId)) return null;
|
|
259
|
+
if (parentId.length !== 16 || !/^[0-9a-f]{16}$/.test(parentId)) return null;
|
|
260
|
+
if (flags.length !== 2 || !/^[0-9a-f]{2}$/.test(flags)) return null;
|
|
261
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentId)) return null;
|
|
262
|
+
return { traceId, parentId, flags };
|
|
263
|
+
}
|
|
195
264
|
var _originalConsole = {
|
|
196
265
|
log: console.log,
|
|
197
266
|
info: console.info,
|
|
@@ -202,6 +271,7 @@ var _originalConsole = {
|
|
|
202
271
|
var Logger = class _Logger {
|
|
203
272
|
batcher;
|
|
204
273
|
transport;
|
|
274
|
+
effectiveLevel;
|
|
205
275
|
contextName;
|
|
206
276
|
config;
|
|
207
277
|
state;
|
|
@@ -211,6 +281,20 @@ var Logger = class _Logger {
|
|
|
211
281
|
this.contextName = contextName;
|
|
212
282
|
this.requestMeta = requestMeta;
|
|
213
283
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
284
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
285
|
+
const hasEndpoint = !!config.endpoint;
|
|
286
|
+
if (!hasKey && !hasEndpoint) {
|
|
287
|
+
_originalConsole.warn(
|
|
288
|
+
"[@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."
|
|
289
|
+
);
|
|
290
|
+
} else if (!hasKey) {
|
|
291
|
+
_originalConsole.warn(
|
|
292
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
293
|
+
);
|
|
294
|
+
} else if (!hasEndpoint) {
|
|
295
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
296
|
+
}
|
|
297
|
+
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
214
298
|
this.transport = new Transport(config);
|
|
215
299
|
this.batcher = new Batcher(
|
|
216
300
|
{ batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
|
|
@@ -224,7 +308,8 @@ var Logger = class _Logger {
|
|
|
224
308
|
// ---------------------------------------------------------------------------
|
|
225
309
|
/**
|
|
226
310
|
* Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
|
|
227
|
-
*
|
|
311
|
+
* Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
|
|
312
|
+
* have their own independent state.
|
|
228
313
|
*
|
|
229
314
|
* @example
|
|
230
315
|
* ```ts
|
|
@@ -346,26 +431,13 @@ var Logger = class _Logger {
|
|
|
346
431
|
};
|
|
347
432
|
}
|
|
348
433
|
metadata = this.mergeStateMetadata(metadata);
|
|
349
|
-
const
|
|
350
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
351
|
-
level,
|
|
352
|
-
message,
|
|
353
|
-
metadata,
|
|
354
|
-
context: this.contextName,
|
|
355
|
-
trace_id: this.requestMeta?.trace_id,
|
|
356
|
-
span_id: this.requestMeta?.span_id,
|
|
357
|
-
request_id: this.requestMeta?.request_id,
|
|
358
|
-
vercel_id: this.requestMeta?.vercel_id
|
|
359
|
-
};
|
|
360
|
-
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
361
|
-
if (hookResult === null) return;
|
|
362
|
-
const finalEntry = hookResult.data;
|
|
434
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
363
435
|
if (this.config.debug) {
|
|
364
436
|
const prefix = this.contextName ? `[${this.contextName}]` : "";
|
|
365
437
|
const lvl = level.toUpperCase().padEnd(5);
|
|
366
438
|
const consoleFn = level === "error" ? _originalConsole.error : level === "warn" ? _originalConsole.warn : level === "debug" ? _originalConsole.debug : _originalConsole.log;
|
|
367
|
-
if (
|
|
368
|
-
consoleFn(`${lvl} ${prefix} ${message}`,
|
|
439
|
+
if (metadata) {
|
|
440
|
+
consoleFn(`${lvl} ${prefix} ${message}`, metadata);
|
|
369
441
|
} else {
|
|
370
442
|
consoleFn(`${lvl} ${prefix} ${message}`);
|
|
371
443
|
}
|
|
@@ -373,9 +445,23 @@ var Logger = class _Logger {
|
|
|
373
445
|
addBreadcrumb(this.state, {
|
|
374
446
|
type: "log",
|
|
375
447
|
message: `[${level}] ${message}`,
|
|
376
|
-
timestamp
|
|
448
|
+
timestamp
|
|
377
449
|
});
|
|
378
|
-
this.
|
|
450
|
+
if (LOG_LEVEL_VALUES[level] < this.effectiveLevel) return;
|
|
451
|
+
const entry = {
|
|
452
|
+
timestamp,
|
|
453
|
+
level,
|
|
454
|
+
message,
|
|
455
|
+
metadata,
|
|
456
|
+
context: this.contextName,
|
|
457
|
+
trace_id: this.requestMeta?.trace_id,
|
|
458
|
+
span_id: this.requestMeta?.span_id,
|
|
459
|
+
request_id: this.requestMeta?.request_id,
|
|
460
|
+
vercel_id: this.requestMeta?.vercel_id
|
|
461
|
+
};
|
|
462
|
+
const hookResult = this.applyBeforeSend({ type: "log", data: entry });
|
|
463
|
+
if (hookResult === null) return;
|
|
464
|
+
this.batcher.add(hookResult.data);
|
|
379
465
|
}
|
|
380
466
|
/** Log a debug message. */
|
|
381
467
|
debug(message, dataOrError, error) {
|
|
@@ -396,22 +482,37 @@ var Logger = class _Logger {
|
|
|
396
482
|
// ---------------------------------------------------------------------------
|
|
397
483
|
// Child loggers
|
|
398
484
|
// ---------------------------------------------------------------------------
|
|
399
|
-
/** Create a context-scoped logger. All logs include the context name.
|
|
485
|
+
/** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
|
|
400
486
|
withContext(name) {
|
|
401
|
-
return new _Logger(this.config, name, this.requestMeta, this.state);
|
|
487
|
+
return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
|
|
402
488
|
}
|
|
403
|
-
/** Create a request-scoped logger that extracts trace context from headers.
|
|
489
|
+
/** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
|
|
404
490
|
forRequest(request) {
|
|
405
|
-
|
|
491
|
+
let traceId;
|
|
492
|
+
let spanId;
|
|
493
|
+
const traceparent = request.headers.get("traceparent");
|
|
494
|
+
if (traceparent) {
|
|
495
|
+
const parsed = parseTraceparent(traceparent);
|
|
496
|
+
if (parsed) {
|
|
497
|
+
traceId = parsed.traceId;
|
|
498
|
+
spanId = parsed.parentId;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
traceId = traceId || request.headers.get("x-trace-id") || void 0;
|
|
502
|
+
spanId = spanId || request.headers.get("x-span-id") || void 0;
|
|
406
503
|
const requestId = request.headers.get("x-request-id") || void 0;
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
504
|
+
const vercelId = request.headers.get("x-vercel-id") || void 0;
|
|
505
|
+
return new _Logger(
|
|
506
|
+
this.config,
|
|
507
|
+
this.contextName,
|
|
508
|
+
{
|
|
509
|
+
trace_id: traceId,
|
|
510
|
+
span_id: spanId,
|
|
511
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
512
|
+
vercel_id: vercelId
|
|
513
|
+
},
|
|
514
|
+
cloneState(this.state)
|
|
515
|
+
);
|
|
415
516
|
}
|
|
416
517
|
// ---------------------------------------------------------------------------
|
|
417
518
|
// Error capture
|
|
@@ -430,7 +531,8 @@ var Logger = class _Logger {
|
|
|
430
531
|
const enrichedContext = { ...context?.context };
|
|
431
532
|
if (this.state.user) enrichedContext.user = this.state.user;
|
|
432
533
|
if (Object.keys(this.state.tags).length > 0) enrichedContext._tags = { ...this.state.tags };
|
|
433
|
-
if (Object.keys(this.state.contexts).length > 0)
|
|
534
|
+
if (Object.keys(this.state.contexts).length > 0)
|
|
535
|
+
enrichedContext._contexts = { ...this.state.contexts };
|
|
434
536
|
const report = {
|
|
435
537
|
error_message: err.message,
|
|
436
538
|
stack_trace: err.stack || "",
|
|
@@ -511,7 +613,7 @@ var Logger = class _Logger {
|
|
|
511
613
|
}
|
|
512
614
|
/** Start a span with manual lifecycle. You must call span.end(). */
|
|
513
615
|
startInactiveSpan(operation) {
|
|
514
|
-
const traceId = this.requestMeta?.trace_id ||
|
|
616
|
+
const traceId = this.requestMeta?.trace_id || generateTraceId();
|
|
515
617
|
const parentSpanId = this.requestMeta?.span_id || "";
|
|
516
618
|
const spanId = generateId();
|
|
517
619
|
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -551,10 +653,16 @@ var Logger = class _Logger {
|
|
|
551
653
|
const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
|
|
552
654
|
return childLogger.startInactiveSpan(childOp);
|
|
553
655
|
},
|
|
554
|
-
getHeaders: () =>
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
656
|
+
getHeaders: () => {
|
|
657
|
+
const headers = {
|
|
658
|
+
"x-trace-id": traceId,
|
|
659
|
+
"x-span-id": spanId
|
|
660
|
+
};
|
|
661
|
+
if (/^[0-9a-f]{32}$/.test(traceId)) {
|
|
662
|
+
headers.traceparent = `00-${traceId}-${spanId}-01`;
|
|
663
|
+
}
|
|
664
|
+
return headers;
|
|
665
|
+
}
|
|
558
666
|
};
|
|
559
667
|
return span;
|
|
560
668
|
}
|
|
@@ -595,6 +703,8 @@ function createLogger(config) {
|
|
|
595
703
|
export {
|
|
596
704
|
SDK_VERSION,
|
|
597
705
|
SDK_NAME,
|
|
706
|
+
Transport,
|
|
707
|
+
parseTraceparent,
|
|
598
708
|
_originalConsole,
|
|
599
709
|
Logger,
|
|
600
710
|
createLogger
|