@deeptracer/core 0.4.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-YBQXVNNR.js → chunk-IWPXOBZV.js} +55 -19
- package/dist/index.cjs +55 -19
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.cjs +55 -19
- package/dist/internal.d.cts +20 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.js +1 -1
- package/package.json +4 -1
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,11 +1,14 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var SDK_VERSION = "0.4.
|
|
2
|
+
var SDK_VERSION = "0.4.2";
|
|
3
3
|
var SDK_NAME = "core";
|
|
4
4
|
|
|
5
5
|
// src/transport.ts
|
|
6
6
|
var Transport = class {
|
|
7
7
|
constructor(config) {
|
|
8
8
|
this.config = config;
|
|
9
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
10
|
+
const hasEndpoint = !!config.endpoint;
|
|
11
|
+
this.disabled = !hasKey || !hasEndpoint;
|
|
9
12
|
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
10
13
|
console.error(
|
|
11
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."
|
|
@@ -13,6 +16,20 @@ var Transport = class {
|
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
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();
|
|
16
33
|
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
17
34
|
get authKey() {
|
|
18
35
|
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
@@ -21,8 +38,12 @@ var Transport = class {
|
|
|
21
38
|
* Send a request with automatic retry and exponential backoff.
|
|
22
39
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
23
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).
|
|
24
44
|
*/
|
|
25
45
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
46
|
+
if (this.disabled) return;
|
|
26
47
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
27
48
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
28
49
|
try {
|
|
@@ -35,26 +56,40 @@ var Transport = class {
|
|
|
35
56
|
},
|
|
36
57
|
body: JSON.stringify(body)
|
|
37
58
|
});
|
|
38
|
-
if (res.ok)
|
|
59
|
+
if (res.ok) {
|
|
60
|
+
this.warnedLabels.delete(label);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
39
63
|
if (res.status >= 400 && res.status < 500) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
}
|
|
43
70
|
return;
|
|
44
71
|
}
|
|
45
72
|
if (attempt < maxRetries) {
|
|
46
73
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
47
74
|
continue;
|
|
48
75
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
+
}
|
|
52
82
|
} catch {
|
|
53
83
|
if (attempt < maxRetries) {
|
|
54
84
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
55
85
|
continue;
|
|
56
86
|
}
|
|
57
|
-
|
|
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
|
+
}
|
|
58
93
|
}
|
|
59
94
|
}
|
|
60
95
|
}
|
|
@@ -186,9 +221,7 @@ function cloneState(state) {
|
|
|
186
221
|
return {
|
|
187
222
|
user: state.user ? { ...state.user } : null,
|
|
188
223
|
tags: { ...state.tags },
|
|
189
|
-
contexts: Object.fromEntries(
|
|
190
|
-
Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])
|
|
191
|
-
),
|
|
224
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
192
225
|
breadcrumbs: [...state.breadcrumbs],
|
|
193
226
|
maxBreadcrumbs: state.maxBreadcrumbs
|
|
194
227
|
};
|
|
@@ -248,15 +281,18 @@ var Logger = class _Logger {
|
|
|
248
281
|
this.contextName = contextName;
|
|
249
282
|
this.requestMeta = requestMeta;
|
|
250
283
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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."
|
|
254
289
|
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
"[@deeptracer/core] No `endpoint` provided. Events will not be sent."
|
|
290
|
+
} else if (!hasKey) {
|
|
291
|
+
_originalConsole.warn(
|
|
292
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
259
293
|
);
|
|
294
|
+
} else if (!hasEndpoint) {
|
|
295
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
260
296
|
}
|
|
261
297
|
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
262
298
|
this.transport = new Transport(config);
|
package/dist/index.cjs
CHANGED
|
@@ -62,13 +62,16 @@ var Batcher = class {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// src/version.ts
|
|
65
|
-
var SDK_VERSION = "0.4.
|
|
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;
|
|
72
75
|
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
73
76
|
console.error(
|
|
74
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."
|
|
@@ -76,6 +79,20 @@ var Transport = class {
|
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
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();
|
|
79
96
|
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
80
97
|
get authKey() {
|
|
81
98
|
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
@@ -84,8 +101,12 @@ var Transport = class {
|
|
|
84
101
|
* Send a request with automatic retry and exponential backoff.
|
|
85
102
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
86
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).
|
|
87
107
|
*/
|
|
88
108
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
109
|
+
if (this.disabled) return;
|
|
89
110
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
90
111
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
91
112
|
try {
|
|
@@ -98,26 +119,40 @@ var Transport = class {
|
|
|
98
119
|
},
|
|
99
120
|
body: JSON.stringify(body)
|
|
100
121
|
});
|
|
101
|
-
if (res.ok)
|
|
122
|
+
if (res.ok) {
|
|
123
|
+
this.warnedLabels.delete(label);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
102
126
|
if (res.status >= 400 && res.status < 500) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
+
}
|
|
106
133
|
return;
|
|
107
134
|
}
|
|
108
135
|
if (attempt < maxRetries) {
|
|
109
136
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
110
137
|
continue;
|
|
111
138
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
+
}
|
|
115
145
|
} catch {
|
|
116
146
|
if (attempt < maxRetries) {
|
|
117
147
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
118
148
|
continue;
|
|
119
149
|
}
|
|
120
|
-
|
|
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
|
+
}
|
|
121
156
|
}
|
|
122
157
|
}
|
|
123
158
|
}
|
|
@@ -215,9 +250,7 @@ function cloneState(state) {
|
|
|
215
250
|
return {
|
|
216
251
|
user: state.user ? { ...state.user } : null,
|
|
217
252
|
tags: { ...state.tags },
|
|
218
|
-
contexts: Object.fromEntries(
|
|
219
|
-
Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])
|
|
220
|
-
),
|
|
253
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
221
254
|
breadcrumbs: [...state.breadcrumbs],
|
|
222
255
|
maxBreadcrumbs: state.maxBreadcrumbs
|
|
223
256
|
};
|
|
@@ -277,15 +310,18 @@ var Logger = class _Logger {
|
|
|
277
310
|
this.contextName = contextName;
|
|
278
311
|
this.requestMeta = requestMeta;
|
|
279
312
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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."
|
|
283
318
|
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
"[@deeptracer/core] No `endpoint` provided. Events will not be sent."
|
|
319
|
+
} else if (!hasKey) {
|
|
320
|
+
_originalConsole.warn(
|
|
321
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
288
322
|
);
|
|
323
|
+
} else if (!hasEndpoint) {
|
|
324
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
289
325
|
}
|
|
290
326
|
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
291
327
|
this.transport = new Transport(config);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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.
|
|
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
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.
|
|
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.js
CHANGED
package/dist/internal.cjs
CHANGED
|
@@ -63,13 +63,16 @@ var Batcher = class {
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
// src/version.ts
|
|
66
|
-
var SDK_VERSION = "0.4.
|
|
66
|
+
var SDK_VERSION = "0.4.2";
|
|
67
67
|
var SDK_NAME = "core";
|
|
68
68
|
|
|
69
69
|
// src/transport.ts
|
|
70
70
|
var Transport = class {
|
|
71
71
|
constructor(config) {
|
|
72
72
|
this.config = config;
|
|
73
|
+
const hasKey = !!(config.secretKey || config.publicKey);
|
|
74
|
+
const hasEndpoint = !!config.endpoint;
|
|
75
|
+
this.disabled = !hasKey || !hasEndpoint;
|
|
73
76
|
if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
|
|
74
77
|
console.error(
|
|
75
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."
|
|
@@ -77,6 +80,20 @@ var Transport = class {
|
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
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();
|
|
80
97
|
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
81
98
|
get authKey() {
|
|
82
99
|
return this.config.secretKey ?? this.config.publicKey ?? "";
|
|
@@ -85,8 +102,12 @@ var Transport = class {
|
|
|
85
102
|
* Send a request with automatic retry and exponential backoff.
|
|
86
103
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
87
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).
|
|
88
108
|
*/
|
|
89
109
|
async sendWithRetry(url, body, label, maxRetries = 3) {
|
|
110
|
+
if (this.disabled) return;
|
|
90
111
|
const baseDelays = [1e3, 2e3, 4e3];
|
|
91
112
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
92
113
|
try {
|
|
@@ -99,26 +120,40 @@ var Transport = class {
|
|
|
99
120
|
},
|
|
100
121
|
body: JSON.stringify(body)
|
|
101
122
|
});
|
|
102
|
-
if (res.ok)
|
|
123
|
+
if (res.ok) {
|
|
124
|
+
this.warnedLabels.delete(label);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
103
127
|
if (res.status >= 400 && res.status < 500) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
}
|
|
107
134
|
return;
|
|
108
135
|
}
|
|
109
136
|
if (attempt < maxRetries) {
|
|
110
137
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
111
138
|
continue;
|
|
112
139
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
}
|
|
116
146
|
} catch {
|
|
117
147
|
if (attempt < maxRetries) {
|
|
118
148
|
await this.sleep(this.jitter(baseDelays[attempt]));
|
|
119
149
|
continue;
|
|
120
150
|
}
|
|
121
|
-
|
|
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
|
+
}
|
|
122
157
|
}
|
|
123
158
|
}
|
|
124
159
|
}
|
|
@@ -216,9 +251,7 @@ function cloneState(state) {
|
|
|
216
251
|
return {
|
|
217
252
|
user: state.user ? { ...state.user } : null,
|
|
218
253
|
tags: { ...state.tags },
|
|
219
|
-
contexts: Object.fromEntries(
|
|
220
|
-
Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])
|
|
221
|
-
),
|
|
254
|
+
contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
|
|
222
255
|
breadcrumbs: [...state.breadcrumbs],
|
|
223
256
|
maxBreadcrumbs: state.maxBreadcrumbs
|
|
224
257
|
};
|
|
@@ -278,15 +311,18 @@ var Logger = class _Logger {
|
|
|
278
311
|
this.contextName = contextName;
|
|
279
312
|
this.requestMeta = requestMeta;
|
|
280
313
|
this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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."
|
|
284
319
|
);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"[@deeptracer/core] No `endpoint` provided. Events will not be sent."
|
|
320
|
+
} else if (!hasKey) {
|
|
321
|
+
_originalConsole.warn(
|
|
322
|
+
"[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
|
|
289
323
|
);
|
|
324
|
+
} else if (!hasEndpoint) {
|
|
325
|
+
_originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
|
|
290
326
|
}
|
|
291
327
|
this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
|
|
292
328
|
this.transport = new Transport(config);
|
package/dist/internal.d.cts
CHANGED
|
@@ -9,10 +9,27 @@ export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalCo
|
|
|
9
9
|
* - Only retries on network errors and 5xx (not 4xx client errors)
|
|
10
10
|
* - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
|
|
11
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
|
|
12
15
|
*/
|
|
13
16
|
declare class Transport {
|
|
14
17
|
private config;
|
|
15
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;
|
|
16
33
|
constructor(config: Pick<LoggerConfig, "endpoint" | "secretKey" | "publicKey" | "service" | "environment">);
|
|
17
34
|
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
18
35
|
private get authKey();
|
|
@@ -20,6 +37,9 @@ declare class Transport {
|
|
|
20
37
|
* Send a request with automatic retry and exponential backoff.
|
|
21
38
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
22
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).
|
|
23
43
|
*/
|
|
24
44
|
private sendWithRetry;
|
|
25
45
|
/** Add +/- 20% jitter to a delay to prevent thundering herd. */
|
package/dist/internal.d.ts
CHANGED
|
@@ -9,10 +9,27 @@ export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalCo
|
|
|
9
9
|
* - Only retries on network errors and 5xx (not 4xx client errors)
|
|
10
10
|
* - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
|
|
11
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
|
|
12
15
|
*/
|
|
13
16
|
declare class Transport {
|
|
14
17
|
private config;
|
|
15
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;
|
|
16
33
|
constructor(config: Pick<LoggerConfig, "endpoint" | "secretKey" | "publicKey" | "service" | "environment">);
|
|
17
34
|
/** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
|
|
18
35
|
private get authKey();
|
|
@@ -20,6 +37,9 @@ declare class Transport {
|
|
|
20
37
|
* Send a request with automatic retry and exponential backoff.
|
|
21
38
|
* Retries up to `maxRetries` times on network errors and 5xx responses.
|
|
22
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).
|
|
23
43
|
*/
|
|
24
44
|
private sendWithRetry;
|
|
25
45
|
/** Add +/- 20% jitter to a delay to prevent thundering herd. */
|
package/dist/internal.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeptracer/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Core SDK for DeepTracer — Logger class, types, transport, batcher, tracing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"directory": "packages/core"
|
|
36
36
|
},
|
|
37
37
|
"license": "MIT",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
},
|
|
38
41
|
"scripts": {
|
|
39
42
|
"build": "tsup",
|
|
40
43
|
"dev": "tsup --watch"
|