@deeptracer/core 0.2.0
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 +611 -0
- package/dist/chunk-LSMMIS4A.js +382 -0
- package/dist/index.cjs +408 -0
- package/dist/index.d.cts +221 -0
- package/dist/index.d.ts +221 -0
- package/dist/index.js +8 -0
- package/dist/internal.cjs +405 -0
- package/dist/internal.d.cts +1 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +8 -0
- package/package.json +34 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Logger: () => Logger,
|
|
24
|
+
createLogger: () => createLogger
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/batcher.ts
|
|
29
|
+
var Batcher = class {
|
|
30
|
+
constructor(config, onFlush) {
|
|
31
|
+
this.onFlush = onFlush;
|
|
32
|
+
this.batchSize = config.batchSize ?? 50;
|
|
33
|
+
this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
|
|
34
|
+
this.startTimer();
|
|
35
|
+
}
|
|
36
|
+
buffer = [];
|
|
37
|
+
timer = null;
|
|
38
|
+
batchSize;
|
|
39
|
+
flushIntervalMs;
|
|
40
|
+
add(entry) {
|
|
41
|
+
this.buffer.push(entry);
|
|
42
|
+
if (this.buffer.length >= this.batchSize) {
|
|
43
|
+
this.flush();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
flush() {
|
|
47
|
+
if (this.buffer.length === 0) return;
|
|
48
|
+
const entries = [...this.buffer];
|
|
49
|
+
this.buffer = [];
|
|
50
|
+
this.onFlush(entries);
|
|
51
|
+
}
|
|
52
|
+
startTimer() {
|
|
53
|
+
this.timer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
54
|
+
}
|
|
55
|
+
destroy() {
|
|
56
|
+
if (this.timer) clearInterval(this.timer);
|
|
57
|
+
this.flush();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/transport.ts
|
|
62
|
+
var Transport = class {
|
|
63
|
+
constructor(config) {
|
|
64
|
+
this.config = config;
|
|
65
|
+
}
|
|
66
|
+
async sendLogs(logs) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(`${this.config.endpoint}/ingest/logs`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Type": "application/json",
|
|
72
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
product: this.config.product,
|
|
76
|
+
service: this.config.service,
|
|
77
|
+
environment: this.config.environment,
|
|
78
|
+
logs
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
console.warn(
|
|
83
|
+
`[@deeptracer/core] Failed to send logs: ${res.status} ${res.statusText}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
console.warn(
|
|
88
|
+
"[@deeptracer/core] Failed to send logs, falling back to console"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async sendError(error) {
|
|
93
|
+
try {
|
|
94
|
+
const res = await fetch(`${this.config.endpoint}/ingest/errors`, {
|
|
95
|
+
method: "POST",
|
|
96
|
+
headers: {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
...error,
|
|
102
|
+
product: this.config.product,
|
|
103
|
+
service: this.config.service,
|
|
104
|
+
environment: this.config.environment
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
console.warn(
|
|
109
|
+
`[@deeptracer/core] Failed to send error: ${res.status} ${res.statusText}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
console.warn("[@deeptracer/core] Failed to send error report");
|
|
114
|
+
console.error(error.error_message);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async sendTrace(span) {
|
|
118
|
+
try {
|
|
119
|
+
const res = await fetch(`${this.config.endpoint}/ingest/traces`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: {
|
|
122
|
+
"Content-Type": "application/json",
|
|
123
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
...span,
|
|
127
|
+
product: this.config.product,
|
|
128
|
+
service: this.config.service,
|
|
129
|
+
environment: this.config.environment
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
console.warn(
|
|
134
|
+
`[@deeptracer/core] Failed to send trace: ${res.status} ${res.statusText}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
console.warn("[@deeptracer/core] Failed to send trace span");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async sendLLMUsage(report) {
|
|
142
|
+
try {
|
|
143
|
+
const res = await fetch(`${this.config.endpoint}/ingest/llm`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: {
|
|
146
|
+
"Content-Type": "application/json",
|
|
147
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
148
|
+
},
|
|
149
|
+
body: JSON.stringify({
|
|
150
|
+
...report,
|
|
151
|
+
product: this.config.product,
|
|
152
|
+
service: this.config.service,
|
|
153
|
+
environment: this.config.environment
|
|
154
|
+
})
|
|
155
|
+
});
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
console.warn(
|
|
158
|
+
`[@deeptracer/core] Failed to send LLM usage: ${res.status} ${res.statusText}`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
console.warn("[@deeptracer/core] Failed to send LLM usage report");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/logger.ts
|
|
168
|
+
function generateId() {
|
|
169
|
+
const bytes = new Uint8Array(8);
|
|
170
|
+
crypto.getRandomValues(bytes);
|
|
171
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
172
|
+
}
|
|
173
|
+
var _originalConsole = {
|
|
174
|
+
log: console.log,
|
|
175
|
+
info: console.info,
|
|
176
|
+
warn: console.warn,
|
|
177
|
+
error: console.error,
|
|
178
|
+
debug: console.debug
|
|
179
|
+
};
|
|
180
|
+
var Logger = class _Logger {
|
|
181
|
+
batcher;
|
|
182
|
+
transport;
|
|
183
|
+
contextName;
|
|
184
|
+
config;
|
|
185
|
+
requestMeta;
|
|
186
|
+
constructor(config, contextName, requestMeta) {
|
|
187
|
+
this.config = config;
|
|
188
|
+
this.contextName = contextName;
|
|
189
|
+
this.requestMeta = requestMeta;
|
|
190
|
+
this.transport = new Transport(config);
|
|
191
|
+
this.batcher = new Batcher(
|
|
192
|
+
{ batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
|
|
193
|
+
(entries) => {
|
|
194
|
+
this.transport.sendLogs(entries);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
log(level, message, dataOrError, maybeError) {
|
|
199
|
+
let metadata;
|
|
200
|
+
let error;
|
|
201
|
+
if (dataOrError instanceof Error) {
|
|
202
|
+
error = dataOrError;
|
|
203
|
+
} else if (dataOrError && typeof dataOrError === "object" && !Array.isArray(dataOrError)) {
|
|
204
|
+
metadata = dataOrError;
|
|
205
|
+
error = maybeError;
|
|
206
|
+
} else if (dataOrError !== void 0) {
|
|
207
|
+
error = dataOrError;
|
|
208
|
+
}
|
|
209
|
+
if (error instanceof Error) {
|
|
210
|
+
metadata = {
|
|
211
|
+
...metadata,
|
|
212
|
+
error: {
|
|
213
|
+
message: error.message,
|
|
214
|
+
name: error.name,
|
|
215
|
+
stack: error.stack
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const entry = {
|
|
220
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
221
|
+
level,
|
|
222
|
+
message,
|
|
223
|
+
metadata,
|
|
224
|
+
context: this.contextName,
|
|
225
|
+
trace_id: this.requestMeta?.trace_id,
|
|
226
|
+
span_id: this.requestMeta?.span_id,
|
|
227
|
+
request_id: this.requestMeta?.request_id,
|
|
228
|
+
vercel_id: this.requestMeta?.vercel_id
|
|
229
|
+
};
|
|
230
|
+
if (this.config.debug) {
|
|
231
|
+
const prefix = this.contextName ? `[${this.contextName}]` : "";
|
|
232
|
+
const lvl = level.toUpperCase().padEnd(5);
|
|
233
|
+
const consoleFn = level === "error" ? _originalConsole.error : level === "warn" ? _originalConsole.warn : level === "debug" ? _originalConsole.debug : _originalConsole.log;
|
|
234
|
+
if (metadata) {
|
|
235
|
+
consoleFn(`${lvl} ${prefix} ${message}`, metadata);
|
|
236
|
+
} else {
|
|
237
|
+
consoleFn(`${lvl} ${prefix} ${message}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
this.batcher.add(entry);
|
|
241
|
+
}
|
|
242
|
+
/** Log a debug message. */
|
|
243
|
+
debug(message, dataOrError, error) {
|
|
244
|
+
this.log("debug", message, dataOrError, error);
|
|
245
|
+
}
|
|
246
|
+
/** Log an informational message. */
|
|
247
|
+
info(message, dataOrError, error) {
|
|
248
|
+
this.log("info", message, dataOrError, error);
|
|
249
|
+
}
|
|
250
|
+
/** Log a warning. */
|
|
251
|
+
warn(message, dataOrError, error) {
|
|
252
|
+
this.log("warn", message, dataOrError, error);
|
|
253
|
+
}
|
|
254
|
+
/** Log an error. */
|
|
255
|
+
error(message, dataOrError, error) {
|
|
256
|
+
this.log("error", message, dataOrError, error);
|
|
257
|
+
}
|
|
258
|
+
/** Create a context-scoped logger. All logs include the context name. */
|
|
259
|
+
withContext(name) {
|
|
260
|
+
return new _Logger(this.config, name, this.requestMeta);
|
|
261
|
+
}
|
|
262
|
+
/** Create a request-scoped logger that extracts trace context from headers. */
|
|
263
|
+
forRequest(request) {
|
|
264
|
+
const vercelId = request.headers.get("x-vercel-id") || void 0;
|
|
265
|
+
const requestId = request.headers.get("x-request-id") || void 0;
|
|
266
|
+
const traceId = request.headers.get("x-trace-id") || void 0;
|
|
267
|
+
const spanId = request.headers.get("x-span-id") || void 0;
|
|
268
|
+
return new _Logger(this.config, this.contextName, {
|
|
269
|
+
trace_id: traceId,
|
|
270
|
+
span_id: spanId,
|
|
271
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
272
|
+
vercel_id: vercelId
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/** Capture and report an error immediately (not batched). */
|
|
276
|
+
captureError(error, context) {
|
|
277
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
278
|
+
const report = {
|
|
279
|
+
error_message: err.message,
|
|
280
|
+
stack_trace: err.stack || "",
|
|
281
|
+
severity: context?.severity || "medium",
|
|
282
|
+
context: context?.context,
|
|
283
|
+
trace_id: this.requestMeta?.trace_id,
|
|
284
|
+
user_id: context?.userId,
|
|
285
|
+
breadcrumbs: context?.breadcrumbs
|
|
286
|
+
};
|
|
287
|
+
this.transport.sendError(report);
|
|
288
|
+
}
|
|
289
|
+
/** Track LLM usage. Sends to /ingest/llm and logs for visibility. */
|
|
290
|
+
llmUsage(report) {
|
|
291
|
+
this.transport.sendLLMUsage({
|
|
292
|
+
model: report.model,
|
|
293
|
+
provider: report.provider,
|
|
294
|
+
operation: report.operation,
|
|
295
|
+
input_tokens: report.inputTokens,
|
|
296
|
+
output_tokens: report.outputTokens,
|
|
297
|
+
cost_usd: report.costUsd || 0,
|
|
298
|
+
latency_ms: report.latencyMs,
|
|
299
|
+
metadata: report.metadata
|
|
300
|
+
});
|
|
301
|
+
this.log("info", `LLM call: ${report.model} (${report.operation})`, {
|
|
302
|
+
llm_usage: {
|
|
303
|
+
model: report.model,
|
|
304
|
+
provider: report.provider,
|
|
305
|
+
operation: report.operation,
|
|
306
|
+
input_tokens: report.inputTokens,
|
|
307
|
+
output_tokens: report.outputTokens,
|
|
308
|
+
latency_ms: report.latencyMs
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/** Start a span with automatic lifecycle (callback-based, recommended). */
|
|
313
|
+
startSpan(operation, fn) {
|
|
314
|
+
const inactive = this.startInactiveSpan(operation);
|
|
315
|
+
const span = {
|
|
316
|
+
traceId: inactive.traceId,
|
|
317
|
+
spanId: inactive.spanId,
|
|
318
|
+
parentSpanId: inactive.parentSpanId,
|
|
319
|
+
operation: inactive.operation,
|
|
320
|
+
getHeaders: () => inactive.getHeaders()
|
|
321
|
+
};
|
|
322
|
+
let result;
|
|
323
|
+
try {
|
|
324
|
+
result = fn(span);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
inactive.end({ status: "error" });
|
|
327
|
+
throw err;
|
|
328
|
+
}
|
|
329
|
+
if (result instanceof Promise) {
|
|
330
|
+
return result.then(
|
|
331
|
+
(value) => {
|
|
332
|
+
inactive.end({ status: "ok" });
|
|
333
|
+
return value;
|
|
334
|
+
},
|
|
335
|
+
(err) => {
|
|
336
|
+
inactive.end({ status: "error" });
|
|
337
|
+
throw err;
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
inactive.end({ status: "ok" });
|
|
342
|
+
return result;
|
|
343
|
+
}
|
|
344
|
+
/** Start a span with manual lifecycle. You must call span.end(). */
|
|
345
|
+
startInactiveSpan(operation) {
|
|
346
|
+
const traceId = this.requestMeta?.trace_id || generateId();
|
|
347
|
+
const parentSpanId = this.requestMeta?.span_id || "";
|
|
348
|
+
const spanId = generateId();
|
|
349
|
+
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
350
|
+
const startMs = Date.now();
|
|
351
|
+
const childMeta = { ...this.requestMeta, trace_id: traceId, span_id: spanId };
|
|
352
|
+
const span = {
|
|
353
|
+
traceId,
|
|
354
|
+
spanId,
|
|
355
|
+
parentSpanId,
|
|
356
|
+
operation,
|
|
357
|
+
end: (options) => {
|
|
358
|
+
const durationMs = Date.now() - startMs;
|
|
359
|
+
const spanData = {
|
|
360
|
+
trace_id: traceId,
|
|
361
|
+
span_id: spanId,
|
|
362
|
+
parent_span_id: parentSpanId,
|
|
363
|
+
operation,
|
|
364
|
+
start_time: startTime,
|
|
365
|
+
duration_ms: durationMs,
|
|
366
|
+
status: options?.status || "ok",
|
|
367
|
+
metadata: options?.metadata
|
|
368
|
+
};
|
|
369
|
+
this.transport.sendTrace(spanData);
|
|
370
|
+
},
|
|
371
|
+
startSpan: (childOp, fn) => {
|
|
372
|
+
const childLogger = new _Logger(this.config, this.contextName, childMeta);
|
|
373
|
+
return childLogger.startSpan(childOp, fn);
|
|
374
|
+
},
|
|
375
|
+
startInactiveSpan: (childOp) => {
|
|
376
|
+
const childLogger = new _Logger(this.config, this.contextName, childMeta);
|
|
377
|
+
return childLogger.startInactiveSpan(childOp);
|
|
378
|
+
},
|
|
379
|
+
getHeaders: () => ({
|
|
380
|
+
"x-trace-id": traceId,
|
|
381
|
+
"x-span-id": spanId
|
|
382
|
+
})
|
|
383
|
+
};
|
|
384
|
+
return span;
|
|
385
|
+
}
|
|
386
|
+
/** Wrap a function with automatic tracing and error capture. */
|
|
387
|
+
wrap(operation, fn) {
|
|
388
|
+
return (...args) => {
|
|
389
|
+
return this.startSpan(operation, () => fn(...args));
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/** Immediately flush all batched log entries. */
|
|
393
|
+
flush() {
|
|
394
|
+
this.batcher.flush();
|
|
395
|
+
}
|
|
396
|
+
/** Stop the batch timer and flush remaining logs. */
|
|
397
|
+
destroy() {
|
|
398
|
+
this.batcher.destroy();
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
function createLogger(config) {
|
|
402
|
+
return new Logger(config);
|
|
403
|
+
}
|
|
404
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
405
|
+
0 && (module.exports = {
|
|
406
|
+
Logger,
|
|
407
|
+
createLogger
|
|
408
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for creating a DeepTracer logger instance.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const config: LoggerConfig = {
|
|
7
|
+
* product: "my-app",
|
|
8
|
+
* service: "api-server",
|
|
9
|
+
* environment: "production",
|
|
10
|
+
* endpoint: "https://deeptracer.example.com",
|
|
11
|
+
* apiKey: "dt_live_xxx",
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
interface LoggerConfig {
|
|
16
|
+
/** Product name (e.g., "spotbeam", "macro") */
|
|
17
|
+
product: string;
|
|
18
|
+
/** Service name (e.g., "api", "worker", "web") */
|
|
19
|
+
service: string;
|
|
20
|
+
/** Deployment environment */
|
|
21
|
+
environment: "production" | "staging";
|
|
22
|
+
/** DeepTracer ingestion endpoint URL */
|
|
23
|
+
endpoint: string;
|
|
24
|
+
/** DeepTracer API key for authentication */
|
|
25
|
+
apiKey: string;
|
|
26
|
+
/** Number of log entries to batch before sending. Default: 50 */
|
|
27
|
+
batchSize?: number;
|
|
28
|
+
/** Milliseconds between automatic batch flushes. Default: 5000 */
|
|
29
|
+
flushIntervalMs?: number;
|
|
30
|
+
/** Enable console output for all log calls (useful for local development) */
|
|
31
|
+
debug?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** Log severity level */
|
|
34
|
+
type LogLevel = "debug" | "info" | "warn" | "error";
|
|
35
|
+
/**
|
|
36
|
+
* A single log entry sent to the DeepTracer backend.
|
|
37
|
+
* Created internally by the Logger — you don't construct these manually.
|
|
38
|
+
*/
|
|
39
|
+
interface LogEntry {
|
|
40
|
+
timestamp: string;
|
|
41
|
+
level: LogLevel;
|
|
42
|
+
message: string;
|
|
43
|
+
metadata?: Record<string, unknown>;
|
|
44
|
+
trace_id?: string;
|
|
45
|
+
span_id?: string;
|
|
46
|
+
request_id?: string;
|
|
47
|
+
vercel_id?: string;
|
|
48
|
+
context?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Error report sent to DeepTracer for tracking and alerting.
|
|
52
|
+
*/
|
|
53
|
+
interface ErrorReport {
|
|
54
|
+
error_message: string;
|
|
55
|
+
stack_trace: string;
|
|
56
|
+
severity: "low" | "medium" | "high" | "critical";
|
|
57
|
+
context?: Record<string, unknown>;
|
|
58
|
+
trace_id?: string;
|
|
59
|
+
user_id?: string;
|
|
60
|
+
breadcrumbs?: Array<{
|
|
61
|
+
type: string;
|
|
62
|
+
message: string;
|
|
63
|
+
timestamp: string;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* LLM usage report for tracking AI costs and performance.
|
|
68
|
+
*/
|
|
69
|
+
interface LLMUsageReport {
|
|
70
|
+
model: string;
|
|
71
|
+
provider: string;
|
|
72
|
+
operation: string;
|
|
73
|
+
inputTokens: number;
|
|
74
|
+
outputTokens: number;
|
|
75
|
+
latencyMs: number;
|
|
76
|
+
costUsd?: number;
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Raw span data sent to the DeepTracer backend.
|
|
81
|
+
*/
|
|
82
|
+
interface SpanData {
|
|
83
|
+
trace_id: string;
|
|
84
|
+
span_id: string;
|
|
85
|
+
parent_span_id: string;
|
|
86
|
+
operation: string;
|
|
87
|
+
start_time: string;
|
|
88
|
+
duration_ms: number;
|
|
89
|
+
status: "ok" | "error";
|
|
90
|
+
metadata?: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* A span representing a unit of work within a trace.
|
|
94
|
+
* Returned by the callback-based `startSpan()` — lifecycle is managed automatically.
|
|
95
|
+
*/
|
|
96
|
+
interface Span {
|
|
97
|
+
/** Trace ID linking all spans in a distributed trace */
|
|
98
|
+
traceId: string;
|
|
99
|
+
/** Unique ID for this span */
|
|
100
|
+
spanId: string;
|
|
101
|
+
/** ID of the parent span (empty string if root span) */
|
|
102
|
+
parentSpanId: string;
|
|
103
|
+
/** Operation name (e.g., "db-query", "fetch-user") */
|
|
104
|
+
operation: string;
|
|
105
|
+
/** Returns headers for propagating trace context to downstream services */
|
|
106
|
+
getHeaders(): Record<string, string>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A span with manual lifecycle control. You must call `.end()` when done.
|
|
110
|
+
*/
|
|
111
|
+
interface InactiveSpan extends Span {
|
|
112
|
+
/** End the span and send timing data to DeepTracer */
|
|
113
|
+
end(options?: {
|
|
114
|
+
status?: "ok" | "error";
|
|
115
|
+
metadata?: Record<string, unknown>;
|
|
116
|
+
}): void;
|
|
117
|
+
/** Create a child span with callback-based lifecycle (auto-ends) */
|
|
118
|
+
startSpan<T>(operation: string, fn: (span: Span) => T): T;
|
|
119
|
+
/** Create a child span with manual lifecycle (you must call .end()) */
|
|
120
|
+
startInactiveSpan(operation: string): InactiveSpan;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Options for HTTP middleware (Hono, Express).
|
|
124
|
+
*/
|
|
125
|
+
interface MiddlewareOptions {
|
|
126
|
+
/** Custom function to generate the span operation name. Default: "{METHOD} {path}" */
|
|
127
|
+
operationName?: (method: string, path: string) => string;
|
|
128
|
+
/** Paths to exclude from tracing (e.g., ["/health", "/ready"]) */
|
|
129
|
+
ignorePaths?: string[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Original console methods, preserved before any interception.
|
|
134
|
+
* Used internally by the Logger's debug output to avoid infinite loops
|
|
135
|
+
* when captureConsole() is active.
|
|
136
|
+
*
|
|
137
|
+
* @internal Exported for use by @deeptracer/node and @deeptracer/browser.
|
|
138
|
+
*/
|
|
139
|
+
declare const _originalConsole: {
|
|
140
|
+
log: (...data: any[]) => void;
|
|
141
|
+
info: (...data: any[]) => void;
|
|
142
|
+
warn: (...data: any[]) => void;
|
|
143
|
+
error: (...data: any[]) => void;
|
|
144
|
+
debug: (...data: any[]) => void;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* DeepTracer Logger — lightweight observability SDK for logging, errors, tracing, and LLM usage.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* import { createLogger } from "@deeptracer/core"
|
|
152
|
+
*
|
|
153
|
+
* const logger = createLogger({
|
|
154
|
+
* product: "my-app",
|
|
155
|
+
* service: "api",
|
|
156
|
+
* environment: "production",
|
|
157
|
+
* endpoint: "https://deeptracer.example.com",
|
|
158
|
+
* apiKey: "dt_live_xxx",
|
|
159
|
+
* })
|
|
160
|
+
*
|
|
161
|
+
* logger.info("Server started", { port: 3000 })
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare class Logger {
|
|
165
|
+
private batcher;
|
|
166
|
+
private transport;
|
|
167
|
+
protected contextName?: string;
|
|
168
|
+
protected config: LoggerConfig;
|
|
169
|
+
protected requestMeta?: {
|
|
170
|
+
trace_id?: string;
|
|
171
|
+
span_id?: string;
|
|
172
|
+
request_id?: string;
|
|
173
|
+
vercel_id?: string;
|
|
174
|
+
};
|
|
175
|
+
constructor(config: LoggerConfig, contextName?: string, requestMeta?: {
|
|
176
|
+
trace_id?: string;
|
|
177
|
+
span_id?: string;
|
|
178
|
+
request_id?: string;
|
|
179
|
+
vercel_id?: string;
|
|
180
|
+
});
|
|
181
|
+
private log;
|
|
182
|
+
/** Log a debug message. */
|
|
183
|
+
debug(message: string, dataOrError?: Record<string, unknown> | unknown, error?: unknown): void;
|
|
184
|
+
/** Log an informational message. */
|
|
185
|
+
info(message: string, dataOrError?: Record<string, unknown> | unknown, error?: unknown): void;
|
|
186
|
+
/** Log a warning. */
|
|
187
|
+
warn(message: string, dataOrError?: Record<string, unknown> | unknown, error?: unknown): void;
|
|
188
|
+
/** Log an error. */
|
|
189
|
+
error(message: string, dataOrError?: Record<string, unknown> | unknown, error?: unknown): void;
|
|
190
|
+
/** Create a context-scoped logger. All logs include the context name. */
|
|
191
|
+
withContext(name: string): Logger;
|
|
192
|
+
/** Create a request-scoped logger that extracts trace context from headers. */
|
|
193
|
+
forRequest(request: Request): Logger;
|
|
194
|
+
/** Capture and report an error immediately (not batched). */
|
|
195
|
+
captureError(error: Error | unknown, context?: {
|
|
196
|
+
severity?: "low" | "medium" | "high" | "critical";
|
|
197
|
+
userId?: string;
|
|
198
|
+
context?: Record<string, unknown>;
|
|
199
|
+
breadcrumbs?: Array<{
|
|
200
|
+
type: string;
|
|
201
|
+
message: string;
|
|
202
|
+
timestamp: string;
|
|
203
|
+
}>;
|
|
204
|
+
}): void;
|
|
205
|
+
/** Track LLM usage. Sends to /ingest/llm and logs for visibility. */
|
|
206
|
+
llmUsage(report: LLMUsageReport): void;
|
|
207
|
+
/** Start a span with automatic lifecycle (callback-based, recommended). */
|
|
208
|
+
startSpan<T>(operation: string, fn: (span: Span) => T): T;
|
|
209
|
+
/** Start a span with manual lifecycle. You must call span.end(). */
|
|
210
|
+
startInactiveSpan(operation: string): InactiveSpan;
|
|
211
|
+
/** Wrap a function with automatic tracing and error capture. */
|
|
212
|
+
wrap<TArgs extends unknown[], TReturn>(operation: string, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
|
|
213
|
+
/** Immediately flush all batched log entries. */
|
|
214
|
+
flush(): void;
|
|
215
|
+
/** Stop the batch timer and flush remaining logs. */
|
|
216
|
+
destroy(): void;
|
|
217
|
+
}
|
|
218
|
+
/** Create a new DeepTracer logger instance. */
|
|
219
|
+
declare function createLogger(config: LoggerConfig): Logger;
|
|
220
|
+
|
|
221
|
+
export { type ErrorReport, type InactiveSpan, type LLMUsageReport, type LogEntry, type LogLevel, Logger, type LoggerConfig, type MiddlewareOptions, type Span, type SpanData, _originalConsole as _, createLogger };
|