@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/README.md
ADDED
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
# @deeptracer/core
|
|
2
|
+
|
|
3
|
+
Zero-dependency shared core for the [DeepTracer JavaScript SDK](https://github.com/getdeeptracer/deeptracer-js). Provides the `Logger` class with structured logging, error tracking, distributed tracing, and LLM usage monitoring.
|
|
4
|
+
|
|
5
|
+
This package is the foundation that all other `@deeptracer/*` packages build on. **Most users should install `@deeptracer/node` instead**, which re-exports everything from core and adds Node.js/Bun-specific features. Use `@deeptracer/core` directly only if you are building a custom integration or working in a runtime that is not Node.js, Bun, or a browser.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick Start](#quick-start)
|
|
11
|
+
- [Configuration](#configuration)
|
|
12
|
+
- [API Reference](#api-reference)
|
|
13
|
+
- [createLogger(config)](#createloggerconfig)
|
|
14
|
+
- [Logging Methods](#logging-methods)
|
|
15
|
+
- [Error Tracking](#error-tracking)
|
|
16
|
+
- [Distributed Tracing](#distributed-tracing)
|
|
17
|
+
- [LLM Usage Tracking](#llm-usage-tracking)
|
|
18
|
+
- [Request Context](#request-context)
|
|
19
|
+
- [Context Scoping](#context-scoping)
|
|
20
|
+
- [Lifecycle](#lifecycle)
|
|
21
|
+
- [Type Reference](#type-reference)
|
|
22
|
+
- [LoggerConfig](#loggerconfig)
|
|
23
|
+
- [LogLevel](#loglevel)
|
|
24
|
+
- [LogEntry](#logentry)
|
|
25
|
+
- [ErrorReport](#errorreport)
|
|
26
|
+
- [LLMUsageReport](#llmusagereport)
|
|
27
|
+
- [Span](#span)
|
|
28
|
+
- [InactiveSpan](#inactivespan)
|
|
29
|
+
- [SpanData](#spandata)
|
|
30
|
+
- [MiddlewareOptions](#middlewareoptions)
|
|
31
|
+
- [Batching Behavior](#batching-behavior)
|
|
32
|
+
- [Transport](#transport)
|
|
33
|
+
- [Monorepo](#monorepo)
|
|
34
|
+
- [License](#license)
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @deeptracer/core
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The package ships as both ESM and CJS with full TypeScript declarations. Zero runtime dependencies.
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createLogger } from "@deeptracer/core"
|
|
48
|
+
|
|
49
|
+
const logger = createLogger({
|
|
50
|
+
product: "my-app",
|
|
51
|
+
service: "api",
|
|
52
|
+
environment: "production",
|
|
53
|
+
endpoint: "https://your-deeptracer.example.com",
|
|
54
|
+
apiKey: "dt_live_xxx",
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Structured logging (batched -- sent in groups of 50 or every 5 seconds)
|
|
58
|
+
logger.info("Server started", { port: 3000 })
|
|
59
|
+
logger.warn("Slow query", { duration_ms: 1200, query: "SELECT ..." })
|
|
60
|
+
logger.error("Request failed", { path: "/api/users" }, new Error("timeout"))
|
|
61
|
+
|
|
62
|
+
// Error tracking (sent immediately)
|
|
63
|
+
try {
|
|
64
|
+
await riskyOperation()
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.captureError(err, { severity: "high" })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Distributed tracing
|
|
70
|
+
const result = await logger.startSpan("fetch-user", async (span) => {
|
|
71
|
+
const res = await fetch("https://api.example.com/user/1", {
|
|
72
|
+
headers: span.getHeaders(), // propagate trace context
|
|
73
|
+
})
|
|
74
|
+
return res.json()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Flush before shutdown
|
|
78
|
+
logger.destroy()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
Pass a `LoggerConfig` object to `createLogger()`:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const logger = createLogger({
|
|
87
|
+
// Required
|
|
88
|
+
product: "spotbeam", // Product name for grouping in the dashboard
|
|
89
|
+
service: "api", // Service name within the product
|
|
90
|
+
environment: "production", // "production" or "staging"
|
|
91
|
+
endpoint: "https://dt.co", // DeepTracer ingestion endpoint URL
|
|
92
|
+
apiKey: "dt_live_xxx", // API key for authentication
|
|
93
|
+
|
|
94
|
+
// Optional
|
|
95
|
+
batchSize: 50, // Logs to buffer before sending (default: 50)
|
|
96
|
+
flushIntervalMs: 5000, // Max ms between flushes (default: 5000)
|
|
97
|
+
debug: false, // Mirror logs to console (default: false)
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Field | Type | Required | Default | Description |
|
|
102
|
+
|-------|------|----------|---------|-------------|
|
|
103
|
+
| `product` | `string` | Yes | -- | Product name (e.g., `"spotbeam"`, `"macro"`) |
|
|
104
|
+
| `service` | `string` | Yes | -- | Service name (e.g., `"api"`, `"worker"`, `"web"`) |
|
|
105
|
+
| `environment` | `"production" \| "staging"` | Yes | -- | Deployment environment |
|
|
106
|
+
| `endpoint` | `string` | Yes | -- | DeepTracer ingestion endpoint URL |
|
|
107
|
+
| `apiKey` | `string` | Yes | -- | DeepTracer API key |
|
|
108
|
+
| `batchSize` | `number` | No | `50` | Number of log entries to buffer before flushing |
|
|
109
|
+
| `flushIntervalMs` | `number` | No | `5000` | Milliseconds between automatic flushes |
|
|
110
|
+
| `debug` | `boolean` | No | `false` | When `true`, all log calls also print to the console |
|
|
111
|
+
|
|
112
|
+
## API Reference
|
|
113
|
+
|
|
114
|
+
### createLogger(config)
|
|
115
|
+
|
|
116
|
+
Create a new `Logger` instance. This is the main entry point.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { createLogger } from "@deeptracer/core"
|
|
120
|
+
|
|
121
|
+
const logger = createLogger({
|
|
122
|
+
product: "my-app",
|
|
123
|
+
service: "api",
|
|
124
|
+
environment: "production",
|
|
125
|
+
endpoint: "https://your-deeptracer.example.com",
|
|
126
|
+
apiKey: "dt_live_xxx",
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Parameters:**
|
|
131
|
+
- `config: LoggerConfig` -- See [Configuration](#configuration).
|
|
132
|
+
|
|
133
|
+
**Returns:** `Logger`
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Logging Methods
|
|
138
|
+
|
|
139
|
+
All logging methods accept the same signature:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
logger.debug(message: string, metadata?: Record<string, unknown>, error?: unknown): void
|
|
143
|
+
logger.info(message: string, metadata?: Record<string, unknown>, error?: unknown): void
|
|
144
|
+
logger.warn(message: string, metadata?: Record<string, unknown>, error?: unknown): void
|
|
145
|
+
logger.error(message: string, metadata?: Record<string, unknown>, error?: unknown): void
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Logs are **batched** -- they accumulate in an internal buffer and are sent to the DeepTracer backend in bulk (every 50 entries or every 5 seconds by default). This minimizes network overhead.
|
|
149
|
+
|
|
150
|
+
**Flexible argument handling:** The second argument can be either a metadata object or an Error. If it is an Error, the error details (message, name, stack) are automatically extracted into the metadata.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// Just a message
|
|
154
|
+
logger.info("User signed in")
|
|
155
|
+
|
|
156
|
+
// Message with structured metadata
|
|
157
|
+
logger.info("User signed in", { userId: "u_123", method: "oauth" })
|
|
158
|
+
|
|
159
|
+
// Message with an error (error is auto-extracted into metadata)
|
|
160
|
+
logger.error("Payment failed", new Error("Card declined"))
|
|
161
|
+
|
|
162
|
+
// Message with both metadata and an error
|
|
163
|
+
logger.error("Payment failed", { orderId: "ord_456" }, new Error("Card declined"))
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
When `debug: true` is set in the config, all log calls also print to the local console using the appropriate console method (`console.debug`, `console.log`, `console.warn`, `console.error`).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Error Tracking
|
|
171
|
+
|
|
172
|
+
#### `captureError(error, options?)`
|
|
173
|
+
|
|
174
|
+
Capture and report an error **immediately** (not batched). Errors are sent to the `/ingest/errors` endpoint as soon as they occur.
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
logger.captureError(error: Error | unknown, options?: {
|
|
178
|
+
severity?: "low" | "medium" | "high" | "critical", // default: "medium"
|
|
179
|
+
userId?: string,
|
|
180
|
+
context?: Record<string, unknown>,
|
|
181
|
+
breadcrumbs?: Array<{ type: string, message: string, timestamp: string }>,
|
|
182
|
+
}): void
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Examples:**
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
// Basic error capture
|
|
189
|
+
try {
|
|
190
|
+
await processPayment(order)
|
|
191
|
+
} catch (err) {
|
|
192
|
+
logger.captureError(err)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// With severity and context
|
|
196
|
+
logger.captureError(err, {
|
|
197
|
+
severity: "critical",
|
|
198
|
+
userId: "u_123",
|
|
199
|
+
context: { orderId: "ord_456", amount: 99.99 },
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
// With breadcrumbs for debugging
|
|
203
|
+
logger.captureError(err, {
|
|
204
|
+
severity: "high",
|
|
205
|
+
breadcrumbs: [
|
|
206
|
+
{ type: "navigation", message: "Visited /checkout", timestamp: new Date().toISOString() },
|
|
207
|
+
{ type: "action", message: "Clicked 'Pay Now'", timestamp: new Date().toISOString() },
|
|
208
|
+
],
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// Non-Error values are automatically wrapped
|
|
212
|
+
logger.captureError("something went wrong") // converted to Error internally
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
If the logger was created with `forRequest()`, the `trace_id` from the request context is automatically attached to the error report.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### Distributed Tracing
|
|
220
|
+
|
|
221
|
+
Three ways to create spans, from simplest to most flexible:
|
|
222
|
+
|
|
223
|
+
#### `startSpan(operation, fn)` -- Callback-based (recommended)
|
|
224
|
+
|
|
225
|
+
Creates a span, runs your function inside it, and automatically ends the span when the function returns or throws. Works with both sync and async functions.
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const result = await logger.startSpan("fetch-user", async (span) => {
|
|
229
|
+
// span is automatically ended when this function returns
|
|
230
|
+
const res = await fetch("https://api.example.com/user/1", {
|
|
231
|
+
headers: span.getHeaders(), // { "x-trace-id": "...", "x-span-id": "..." }
|
|
232
|
+
})
|
|
233
|
+
return res.json()
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If the callback throws, the span is ended with `status: "error"` and the error re-throws. If it succeeds, the span ends with `status: "ok"`.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
// Sync usage
|
|
241
|
+
const value = logger.startSpan("compute", (span) => {
|
|
242
|
+
return heavyComputation()
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// Async usage
|
|
246
|
+
const data = await logger.startSpan("db-query", async (span) => {
|
|
247
|
+
return db.query("SELECT * FROM users")
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### `startInactiveSpan(operation)` -- Manual lifecycle
|
|
252
|
+
|
|
253
|
+
Creates a span that you must manually end by calling `span.end()`. Useful when the span lifetime does not fit a single function scope.
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
const span = logger.startInactiveSpan("process-job")
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
await step1()
|
|
260
|
+
await step2()
|
|
261
|
+
span.end({ status: "ok", metadata: { steps: 2 } })
|
|
262
|
+
} catch (err) {
|
|
263
|
+
span.end({ status: "error", metadata: { error: err.message } })
|
|
264
|
+
throw err
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**`InactiveSpan` methods:**
|
|
269
|
+
|
|
270
|
+
| Method | Description |
|
|
271
|
+
|--------|-------------|
|
|
272
|
+
| `end(options?)` | End the span. Options: `{ status?: "ok" \| "error", metadata?: Record<string, unknown> }` |
|
|
273
|
+
| `startSpan(op, fn)` | Create a child span with callback-based lifecycle |
|
|
274
|
+
| `startInactiveSpan(op)` | Create a child span with manual lifecycle |
|
|
275
|
+
| `getHeaders()` | Returns `{ "x-trace-id": "...", "x-span-id": "..." }` for propagation |
|
|
276
|
+
|
|
277
|
+
**Nested spans:**
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
const parent = logger.startInactiveSpan("handle-request")
|
|
281
|
+
|
|
282
|
+
// Child spans automatically inherit the parent's trace_id
|
|
283
|
+
await parent.startSpan("validate-input", async (span) => {
|
|
284
|
+
// ...
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
const dbSpan = parent.startInactiveSpan("db-query")
|
|
288
|
+
await db.query("SELECT ...")
|
|
289
|
+
dbSpan.end()
|
|
290
|
+
|
|
291
|
+
parent.end()
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### `wrap(operation, fn)` -- Function decorator
|
|
295
|
+
|
|
296
|
+
Wraps an existing function so that every invocation is automatically traced. Returns a new function with the same signature.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
const fetchUser = logger.wrap("fetch-user", async (id: string) => {
|
|
300
|
+
const res = await fetch(`https://api.example.com/users/${id}`)
|
|
301
|
+
return res.json()
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
// Every call is now traced
|
|
305
|
+
const user = await fetchUser("u_123")
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### Span Properties
|
|
309
|
+
|
|
310
|
+
Every span (both `Span` and `InactiveSpan`) has these read-only properties:
|
|
311
|
+
|
|
312
|
+
| Property | Type | Description |
|
|
313
|
+
|----------|------|-------------|
|
|
314
|
+
| `traceId` | `string` | 16-char hex ID linking all spans in a trace |
|
|
315
|
+
| `spanId` | `string` | 16-char hex ID unique to this span |
|
|
316
|
+
| `parentSpanId` | `string` | Parent span ID (empty string for root spans) |
|
|
317
|
+
| `operation` | `string` | Operation name passed to `startSpan()` |
|
|
318
|
+
|
|
319
|
+
#### Trace Context Propagation
|
|
320
|
+
|
|
321
|
+
Use `span.getHeaders()` to propagate trace context to downstream services:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
await logger.startSpan("call-downstream", async (span) => {
|
|
325
|
+
const res = await fetch("https://other-service.com/api", {
|
|
326
|
+
headers: {
|
|
327
|
+
...span.getHeaders(), // { "x-trace-id": "abc123", "x-span-id": "def456" }
|
|
328
|
+
"Content-Type": "application/json",
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify(data),
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
The downstream service can then pick up the trace context via `logger.forRequest(request)`.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### LLM Usage Tracking
|
|
340
|
+
|
|
341
|
+
#### `llmUsage(report)`
|
|
342
|
+
|
|
343
|
+
Manually report LLM usage data. Sends to the `/ingest/llm` endpoint and also emits an info-level log for visibility.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
logger.llmUsage(report: LLMUsageReport): void
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
logger.llmUsage({
|
|
351
|
+
model: "gpt-4o",
|
|
352
|
+
provider: "openai",
|
|
353
|
+
operation: "chat.completions.create",
|
|
354
|
+
inputTokens: 150,
|
|
355
|
+
outputTokens: 320,
|
|
356
|
+
latencyMs: 1200,
|
|
357
|
+
costUsd: 0.0045, // optional
|
|
358
|
+
metadata: { userId: "u_1" }, // optional
|
|
359
|
+
})
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
> **Tip:** For automatic LLM tracking, use [`@deeptracer/ai`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/ai) which wraps Vercel AI SDK, OpenAI, and Anthropic clients.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### Request Context
|
|
367
|
+
|
|
368
|
+
#### `forRequest(request)`
|
|
369
|
+
|
|
370
|
+
Create a request-scoped logger that extracts distributed trace context from incoming HTTP headers. The returned logger attaches `trace_id`, `span_id`, `request_id`, and `vercel_id` to all subsequent logs, errors, and spans.
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
const reqLogger = logger.forRequest(request: Request): Logger
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Headers read:
|
|
377
|
+
- `x-trace-id` -- distributed trace ID
|
|
378
|
+
- `x-span-id` -- parent span ID
|
|
379
|
+
- `x-request-id` -- request ID
|
|
380
|
+
- `x-vercel-id` -- Vercel deployment ID (also used to derive request ID)
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
// In a Hono route handler
|
|
384
|
+
app.get("/api/users", async (c) => {
|
|
385
|
+
const reqLogger = logger.forRequest(c.req.raw)
|
|
386
|
+
reqLogger.info("Fetching users") // automatically includes trace_id, request_id, etc.
|
|
387
|
+
|
|
388
|
+
const users = await reqLogger.startSpan("db-query", async () => {
|
|
389
|
+
return db.query("SELECT * FROM users")
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
return c.json(users)
|
|
393
|
+
})
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Context Scoping
|
|
399
|
+
|
|
400
|
+
#### `withContext(name)`
|
|
401
|
+
|
|
402
|
+
Create a new logger that includes a context name in every log entry. Useful for distinguishing logs from different modules or subsystems.
|
|
403
|
+
|
|
404
|
+
```ts
|
|
405
|
+
const dbLogger = logger.withContext("database")
|
|
406
|
+
dbLogger.info("Connection pool initialized") // context: "database"
|
|
407
|
+
dbLogger.warn("Slow query detected") // context: "database"
|
|
408
|
+
|
|
409
|
+
const authLogger = logger.withContext("auth")
|
|
410
|
+
authLogger.info("Token refreshed") // context: "auth"
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### Lifecycle
|
|
416
|
+
|
|
417
|
+
#### `flush()`
|
|
418
|
+
|
|
419
|
+
Immediately send all buffered log entries. Call this before your process exits or when you want to ensure logs are delivered.
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
logger.flush()
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
#### `destroy()`
|
|
426
|
+
|
|
427
|
+
Stop the internal batch timer and flush any remaining log entries. Call this during graceful shutdown.
|
|
428
|
+
|
|
429
|
+
```ts
|
|
430
|
+
process.on("SIGTERM", () => {
|
|
431
|
+
logger.destroy()
|
|
432
|
+
process.exit(0)
|
|
433
|
+
})
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Type Reference
|
|
437
|
+
|
|
438
|
+
### LoggerConfig
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
interface LoggerConfig {
|
|
442
|
+
product: string
|
|
443
|
+
service: string
|
|
444
|
+
environment: "production" | "staging"
|
|
445
|
+
endpoint: string
|
|
446
|
+
apiKey: string
|
|
447
|
+
batchSize?: number // default: 50
|
|
448
|
+
flushIntervalMs?: number // default: 5000
|
|
449
|
+
debug?: boolean // default: false
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### LogLevel
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
type LogLevel = "debug" | "info" | "warn" | "error"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### LogEntry
|
|
460
|
+
|
|
461
|
+
Internal type representing a single log entry sent to the backend. You do not construct these manually.
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
interface LogEntry {
|
|
465
|
+
timestamp: string // ISO 8601
|
|
466
|
+
level: LogLevel
|
|
467
|
+
message: string
|
|
468
|
+
metadata?: Record<string, unknown>
|
|
469
|
+
trace_id?: string
|
|
470
|
+
span_id?: string
|
|
471
|
+
request_id?: string
|
|
472
|
+
vercel_id?: string
|
|
473
|
+
context?: string
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### ErrorReport
|
|
478
|
+
|
|
479
|
+
```ts
|
|
480
|
+
interface ErrorReport {
|
|
481
|
+
error_message: string
|
|
482
|
+
stack_trace: string
|
|
483
|
+
severity: "low" | "medium" | "high" | "critical"
|
|
484
|
+
context?: Record<string, unknown>
|
|
485
|
+
trace_id?: string
|
|
486
|
+
user_id?: string
|
|
487
|
+
breadcrumbs?: Array<{
|
|
488
|
+
type: string
|
|
489
|
+
message: string
|
|
490
|
+
timestamp: string
|
|
491
|
+
}>
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### LLMUsageReport
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
interface LLMUsageReport {
|
|
499
|
+
model: string
|
|
500
|
+
provider: string
|
|
501
|
+
operation: string
|
|
502
|
+
inputTokens: number
|
|
503
|
+
outputTokens: number
|
|
504
|
+
latencyMs: number
|
|
505
|
+
costUsd?: number
|
|
506
|
+
metadata?: Record<string, unknown>
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Span
|
|
511
|
+
|
|
512
|
+
Returned by `startSpan()`. Lifecycle is managed automatically by the callback.
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
interface Span {
|
|
516
|
+
traceId: string
|
|
517
|
+
spanId: string
|
|
518
|
+
parentSpanId: string
|
|
519
|
+
operation: string
|
|
520
|
+
getHeaders(): Record<string, string>
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### InactiveSpan
|
|
525
|
+
|
|
526
|
+
Returned by `startInactiveSpan()`. You must call `.end()` manually.
|
|
527
|
+
|
|
528
|
+
```ts
|
|
529
|
+
interface InactiveSpan extends Span {
|
|
530
|
+
end(options?: { status?: "ok" | "error"; metadata?: Record<string, unknown> }): void
|
|
531
|
+
startSpan<T>(operation: string, fn: (span: Span) => T): T
|
|
532
|
+
startInactiveSpan(operation: string): InactiveSpan
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### SpanData
|
|
537
|
+
|
|
538
|
+
Internal type representing the raw span payload sent to the backend.
|
|
539
|
+
|
|
540
|
+
```ts
|
|
541
|
+
interface SpanData {
|
|
542
|
+
trace_id: string
|
|
543
|
+
span_id: string
|
|
544
|
+
parent_span_id: string
|
|
545
|
+
operation: string
|
|
546
|
+
start_time: string // ISO 8601
|
|
547
|
+
duration_ms: number
|
|
548
|
+
status: "ok" | "error"
|
|
549
|
+
metadata?: Record<string, unknown>
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### MiddlewareOptions
|
|
554
|
+
|
|
555
|
+
Used by `honoMiddleware()` and `expressMiddleware()` in `@deeptracer/node`.
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
interface MiddlewareOptions {
|
|
559
|
+
operationName?: (method: string, path: string) => string
|
|
560
|
+
ignorePaths?: string[]
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
## Batching Behavior
|
|
565
|
+
|
|
566
|
+
Log entries are buffered and sent in batches to reduce network overhead:
|
|
567
|
+
|
|
568
|
+
1. Entries accumulate in an internal buffer.
|
|
569
|
+
2. The buffer is flushed when **either** condition is met:
|
|
570
|
+
- The buffer reaches `batchSize` (default: 50 entries).
|
|
571
|
+
- The flush interval timer fires (default: every 5000ms).
|
|
572
|
+
3. On flush, all buffered entries are sent as a single POST to `/ingest/logs`.
|
|
573
|
+
4. Calling `flush()` triggers an immediate flush regardless of buffer size.
|
|
574
|
+
5. Calling `destroy()` clears the interval timer and performs a final flush.
|
|
575
|
+
|
|
576
|
+
Error reports (`captureError`) and span data (`startSpan`, `startInactiveSpan`) are **not batched** -- they are sent immediately.
|
|
577
|
+
|
|
578
|
+
## Transport
|
|
579
|
+
|
|
580
|
+
The transport layer sends data to four DeepTracer ingestion endpoints:
|
|
581
|
+
|
|
582
|
+
| Endpoint | Method | Data |
|
|
583
|
+
|----------|--------|------|
|
|
584
|
+
| `POST /ingest/logs` | Batched | Log entries |
|
|
585
|
+
| `POST /ingest/errors` | Immediate | Error reports |
|
|
586
|
+
| `POST /ingest/traces` | Immediate | Span data |
|
|
587
|
+
| `POST /ingest/llm` | Immediate | LLM usage reports |
|
|
588
|
+
|
|
589
|
+
All requests include:
|
|
590
|
+
- `Authorization: Bearer <apiKey>` header
|
|
591
|
+
- `Content-Type: application/json` header
|
|
592
|
+
- `product`, `service`, and `environment` fields in the JSON body
|
|
593
|
+
|
|
594
|
+
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
|
+
|
|
596
|
+
## Monorepo
|
|
597
|
+
|
|
598
|
+
This package is part of the [DeepTracer JavaScript SDK](https://github.com/getdeeptracer/deeptracer-js) monorepo:
|
|
599
|
+
|
|
600
|
+
| Package | Description |
|
|
601
|
+
|---------|-------------|
|
|
602
|
+
| **`@deeptracer/core`** | Zero-dependency shared core (this package) |
|
|
603
|
+
| [`@deeptracer/node`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/node) | Node.js/Bun SDK -- global errors, console capture, Hono & Express middleware |
|
|
604
|
+
| [`@deeptracer/ai`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/ai) | AI SDK wrappers -- Vercel AI, OpenAI, Anthropic |
|
|
605
|
+
| [`@deeptracer/browser`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/browser) | Browser SDK (preview) |
|
|
606
|
+
| [`@deeptracer/react`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/react) | React integration (coming soon) |
|
|
607
|
+
| [`@deeptracer/nextjs`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/nextjs) | Next.js integration (coming soon) |
|
|
608
|
+
|
|
609
|
+
## License
|
|
610
|
+
|
|
611
|
+
MIT
|