@deeptracer/node 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 +494 -0
- package/dist/index.cjs +141 -0
- package/dist/index.d.cts +108 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.js +110 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
# @deeptracer/node
|
|
2
|
+
|
|
3
|
+
DeepTracer SDK for **Node.js and Bun** applications. Provides automatic global error capture, console interception, and HTTP middleware for Hono and Express -- on top of the full core logging, tracing, and error tracking API.
|
|
4
|
+
|
|
5
|
+
This is the **recommended entry point** for any Node.js or Bun server. It re-exports everything from [`@deeptracer/core`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/core), so you only need to import from `@deeptracer/node`.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick Start](#quick-start)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [init(config)](#initconfig)
|
|
13
|
+
- [captureGlobalErrors(logger)](#captureglobalerrors)
|
|
14
|
+
- [captureConsole(logger)](#captureconsole)
|
|
15
|
+
- [honoMiddleware(logger, options?)](#honomiddleware)
|
|
16
|
+
- [expressMiddleware(logger, options?)](#expressmiddleware)
|
|
17
|
+
- [MiddlewareOptions](#middlewareoptions)
|
|
18
|
+
- [Re-exported from @deeptracer/core](#re-exported-from-deeptracercore)
|
|
19
|
+
- [Full Examples](#full-examples)
|
|
20
|
+
- [Hono + Bun Server](#hono--bun-server)
|
|
21
|
+
- [Express Server](#express-server)
|
|
22
|
+
- [Background Worker](#background-worker)
|
|
23
|
+
- [Monorepo](#monorepo)
|
|
24
|
+
- [License](#license)
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @deeptracer/node
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`@deeptracer/core` is included as a dependency and does not need to be installed separately.
|
|
33
|
+
|
|
34
|
+
The package ships as both ESM and CJS with full TypeScript declarations.
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { init, honoMiddleware, captureConsole } from "@deeptracer/node"
|
|
40
|
+
import { Hono } from "hono"
|
|
41
|
+
|
|
42
|
+
// 1. Initialize -- creates a logger and captures uncaught errors automatically
|
|
43
|
+
const logger = init({
|
|
44
|
+
product: "my-app",
|
|
45
|
+
service: "api",
|
|
46
|
+
environment: "production",
|
|
47
|
+
endpoint: "https://your-deeptracer.example.com",
|
|
48
|
+
apiKey: "dt_live_xxx",
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// 2. (Optional) Forward all console.* calls to DeepTracer
|
|
52
|
+
captureConsole(logger)
|
|
53
|
+
|
|
54
|
+
// 3. Add middleware for automatic request tracing
|
|
55
|
+
const app = new Hono()
|
|
56
|
+
app.use(honoMiddleware(logger))
|
|
57
|
+
|
|
58
|
+
app.get("/", (c) => c.text("Hello!"))
|
|
59
|
+
|
|
60
|
+
export default app
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Reference
|
|
64
|
+
|
|
65
|
+
### init(config)
|
|
66
|
+
|
|
67
|
+
Initialize DeepTracer for Node.js/Bun with sensible defaults. Creates a `Logger` instance and automatically sets up global error capture via `captureGlobalErrors()`.
|
|
68
|
+
|
|
69
|
+
**This is the recommended way to set up DeepTracer.** It is equivalent to calling `createLogger(config)` followed by `captureGlobalErrors(logger)`.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { init } from "@deeptracer/node"
|
|
73
|
+
|
|
74
|
+
const logger = init({
|
|
75
|
+
product: "my-app",
|
|
76
|
+
service: "api",
|
|
77
|
+
environment: "production",
|
|
78
|
+
endpoint: "https://your-deeptracer.example.com",
|
|
79
|
+
apiKey: "dt_live_xxx",
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Parameters:**
|
|
84
|
+
- `config: LoggerConfig` -- Logger configuration. See [`@deeptracer/core` Configuration](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/core#configuration) for the full reference.
|
|
85
|
+
|
|
86
|
+
**Returns:** `Logger` -- A fully configured logger instance with global error capture active.
|
|
87
|
+
|
|
88
|
+
**Config quick reference:**
|
|
89
|
+
|
|
90
|
+
| Field | Type | Required | Default | Description |
|
|
91
|
+
|-------|------|----------|---------|-------------|
|
|
92
|
+
| `product` | `string` | Yes | -- | Product name (e.g., `"spotbeam"`) |
|
|
93
|
+
| `service` | `string` | Yes | -- | Service name (e.g., `"api"`) |
|
|
94
|
+
| `environment` | `"production" \| "staging"` | Yes | -- | Deployment environment |
|
|
95
|
+
| `endpoint` | `string` | Yes | -- | DeepTracer ingestion endpoint URL |
|
|
96
|
+
| `apiKey` | `string` | Yes | -- | DeepTracer API key |
|
|
97
|
+
| `batchSize` | `number` | No | `50` | Log entries to buffer before flushing |
|
|
98
|
+
| `flushIntervalMs` | `number` | No | `5000` | Milliseconds between automatic flushes |
|
|
99
|
+
| `debug` | `boolean` | No | `false` | Mirror all logs to local console |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### captureGlobalErrors(logger)
|
|
104
|
+
|
|
105
|
+
Automatically capture all uncaught exceptions and unhandled promise rejections via Node.js/Bun `process` events. Call once at application startup.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { createLogger, captureGlobalErrors } from "@deeptracer/node"
|
|
109
|
+
|
|
110
|
+
const logger = createLogger({ /* ... */ })
|
|
111
|
+
captureGlobalErrors(logger)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Parameters:**
|
|
115
|
+
- `logger: Logger` -- A DeepTracer logger instance.
|
|
116
|
+
|
|
117
|
+
**Returns:** `void`
|
|
118
|
+
|
|
119
|
+
**Behavior:**
|
|
120
|
+
- `process.on("uncaughtException")` -- Reports the error with severity `"critical"` and immediately flushes.
|
|
121
|
+
- `process.on("unhandledRejection")` -- Reports the error with severity `"high"` and immediately flushes.
|
|
122
|
+
|
|
123
|
+
Errors are sent immediately via `captureError()` (not batched) and `flush()` is called after each to ensure delivery before a potential process exit.
|
|
124
|
+
|
|
125
|
+
> **Note:** `init()` calls this automatically. You only need to call `captureGlobalErrors()` directly if you are using `createLogger()` instead of `init()`.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### captureConsole(logger)
|
|
130
|
+
|
|
131
|
+
Intercept all `console.log`, `console.info`, `console.warn`, `console.error`, and `console.debug` calls and forward them to DeepTracer as log entries. **Original console output is preserved** -- messages still appear in stdout/stderr as normal.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { init, captureConsole } from "@deeptracer/node"
|
|
135
|
+
|
|
136
|
+
const logger = init({ /* ... */ })
|
|
137
|
+
captureConsole(logger)
|
|
138
|
+
|
|
139
|
+
// All of these now go to BOTH the console AND DeepTracer:
|
|
140
|
+
console.log("Server started on port 3000")
|
|
141
|
+
console.error("Something went wrong")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Parameters:**
|
|
145
|
+
- `logger: Logger` -- A DeepTracer logger instance.
|
|
146
|
+
|
|
147
|
+
**Returns:** `void`
|
|
148
|
+
|
|
149
|
+
**Console method to log level mapping:**
|
|
150
|
+
|
|
151
|
+
| Console Method | DeepTracer Level |
|
|
152
|
+
|----------------|------------------|
|
|
153
|
+
| `console.log()` | `info` |
|
|
154
|
+
| `console.info()` | `info` |
|
|
155
|
+
| `console.warn()` | `warn` |
|
|
156
|
+
| `console.error()` | `error` |
|
|
157
|
+
| `console.debug()` | `debug` |
|
|
158
|
+
|
|
159
|
+
Multiple arguments are joined with spaces (e.g., `console.log("a", "b")` becomes `"a b"`).
|
|
160
|
+
|
|
161
|
+
> **Implementation note:** The original console methods are preserved internally before interception. When the logger's `debug: true` option is active, it uses the preserved originals to avoid infinite recursion.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### honoMiddleware(logger, options?)
|
|
166
|
+
|
|
167
|
+
Create Hono-compatible middleware that automatically instruments every HTTP request with:
|
|
168
|
+
|
|
169
|
+
- **Distributed tracing** -- creates a span per request, propagates `x-trace-id` and `x-span-id` response headers.
|
|
170
|
+
- **Duration tracking** -- span records total request time.
|
|
171
|
+
- **Trace context extraction** -- reads `x-trace-id`, `x-span-id`, `x-request-id`, and `x-vercel-id` from incoming request headers.
|
|
172
|
+
- **Automatic error capture** -- if the handler throws, the span ends with `status: "error"`.
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { Hono } from "hono"
|
|
176
|
+
import { init, honoMiddleware } from "@deeptracer/node"
|
|
177
|
+
|
|
178
|
+
const logger = init({ /* ... */ })
|
|
179
|
+
const app = new Hono()
|
|
180
|
+
|
|
181
|
+
// Basic usage -- traces all requests
|
|
182
|
+
app.use(honoMiddleware(logger))
|
|
183
|
+
|
|
184
|
+
// With options
|
|
185
|
+
app.use(honoMiddleware(logger, {
|
|
186
|
+
ignorePaths: ["/health", "/ready", "/metrics"],
|
|
187
|
+
operationName: (method, path) => `HTTP ${method} ${path}`,
|
|
188
|
+
}))
|
|
189
|
+
|
|
190
|
+
app.get("/api/users", async (c) => {
|
|
191
|
+
// The request is already being traced by the middleware
|
|
192
|
+
return c.json({ users: [] })
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Parameters:**
|
|
197
|
+
- `logger: Logger` -- A DeepTracer logger instance.
|
|
198
|
+
- `options?: MiddlewareOptions` -- Optional configuration (see [MiddlewareOptions](#middlewareoptions)).
|
|
199
|
+
|
|
200
|
+
**Returns:** A Hono middleware function `(c, next) => Promise<void>`. Pass directly to `app.use()`.
|
|
201
|
+
|
|
202
|
+
**Default span operation name:** `"{METHOD} {path}"` (e.g., `"GET /api/users"`).
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### expressMiddleware(logger, options?)
|
|
207
|
+
|
|
208
|
+
Create Express-compatible middleware that automatically instruments every HTTP request. Same capabilities as `honoMiddleware` but for Express.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import express from "express"
|
|
212
|
+
import { init, expressMiddleware } from "@deeptracer/node"
|
|
213
|
+
|
|
214
|
+
const logger = init({ /* ... */ })
|
|
215
|
+
const app = express()
|
|
216
|
+
|
|
217
|
+
// Basic usage
|
|
218
|
+
app.use(expressMiddleware(logger))
|
|
219
|
+
|
|
220
|
+
// With options
|
|
221
|
+
app.use(expressMiddleware(logger, {
|
|
222
|
+
ignorePaths: ["/health"],
|
|
223
|
+
}))
|
|
224
|
+
|
|
225
|
+
app.get("/api/users", (req, res) => {
|
|
226
|
+
res.json({ users: [] })
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
app.listen(3000)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Parameters:**
|
|
233
|
+
- `logger: Logger` -- A DeepTracer logger instance.
|
|
234
|
+
- `options?: MiddlewareOptions` -- Optional configuration (see [MiddlewareOptions](#middlewareoptions)).
|
|
235
|
+
|
|
236
|
+
**Returns:** An Express middleware function `(req, res, next) => void`. Pass directly to `app.use()`.
|
|
237
|
+
|
|
238
|
+
**Behavior details:**
|
|
239
|
+
- Reads trace context from incoming headers (`x-trace-id`, `x-span-id`, `x-request-id`, `x-vercel-id`).
|
|
240
|
+
- Sets `x-trace-id` and `x-span-id` response headers.
|
|
241
|
+
- Listens on the `res.on("finish")` event to end the span with the final HTTP status code.
|
|
242
|
+
- Status codes >= 400 result in `status: "error"` on the span.
|
|
243
|
+
- Span metadata includes `status_code`, `method`, and `path`.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### MiddlewareOptions
|
|
248
|
+
|
|
249
|
+
Configuration options shared by both `honoMiddleware` and `expressMiddleware`.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
interface MiddlewareOptions {
|
|
253
|
+
/** Custom function to generate the span operation name. Default: "{METHOD} {path}" */
|
|
254
|
+
operationName?: (method: string, path: string) => string
|
|
255
|
+
/** Paths to exclude from tracing (e.g., ["/health", "/ready"]) */
|
|
256
|
+
ignorePaths?: string[]
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Field | Type | Default | Description |
|
|
261
|
+
|-------|------|---------|-------------|
|
|
262
|
+
| `operationName` | `(method: string, path: string) => string` | `` `${method} ${path}` `` | Custom operation name for the request span |
|
|
263
|
+
| `ignorePaths` | `string[]` | `[]` | Paths to skip tracing. Uses `startsWith` matching. |
|
|
264
|
+
|
|
265
|
+
**Examples:**
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
// Skip health checks and static assets
|
|
269
|
+
honoMiddleware(logger, {
|
|
270
|
+
ignorePaths: ["/health", "/ready", "/_next/static"],
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
// Custom operation naming
|
|
274
|
+
honoMiddleware(logger, {
|
|
275
|
+
operationName: (method, path) => {
|
|
276
|
+
// Group dynamic routes: /api/users/123 -> "GET /api/users/:id"
|
|
277
|
+
const normalized = path.replace(/\/[a-f0-9-]{36}/g, "/:id")
|
|
278
|
+
return `${method} ${normalized}`
|
|
279
|
+
},
|
|
280
|
+
})
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Re-exported from @deeptracer/core
|
|
284
|
+
|
|
285
|
+
`@deeptracer/node` re-exports the entire public API from `@deeptracer/core`. You do **not** need to install or import from `@deeptracer/core` separately.
|
|
286
|
+
|
|
287
|
+
**Functions:**
|
|
288
|
+
- `createLogger(config)` -- Create a logger instance (use `init()` instead for automatic global error capture)
|
|
289
|
+
|
|
290
|
+
**Logger methods** (available on the `Logger` instance returned by `init()` or `createLogger()`):
|
|
291
|
+
- `logger.debug(message, metadata?, error?)` -- Log a debug message
|
|
292
|
+
- `logger.info(message, metadata?, error?)` -- Log an info message
|
|
293
|
+
- `logger.warn(message, metadata?, error?)` -- Log a warning
|
|
294
|
+
- `logger.error(message, metadata?, error?)` -- Log an error
|
|
295
|
+
- `logger.captureError(error, options?)` -- Report an error immediately
|
|
296
|
+
- `logger.startSpan(operation, fn)` -- Callback-based tracing (auto-ends)
|
|
297
|
+
- `logger.startInactiveSpan(operation)` -- Manual tracing (call `.end()`)
|
|
298
|
+
- `logger.wrap(operation, fn)` -- Wrap a function with automatic tracing
|
|
299
|
+
- `logger.llmUsage(report)` -- Report LLM usage
|
|
300
|
+
- `logger.forRequest(request)` -- Create a request-scoped logger
|
|
301
|
+
- `logger.withContext(name)` -- Create a context-scoped logger
|
|
302
|
+
- `logger.flush()` -- Immediately flush buffered logs
|
|
303
|
+
- `logger.destroy()` -- Stop the batch timer and flush
|
|
304
|
+
|
|
305
|
+
**Types:**
|
|
306
|
+
- `LoggerConfig`, `Logger`, `LogLevel`, `LogEntry`, `ErrorReport`, `LLMUsageReport`, `Span`, `InactiveSpan`, `SpanData`, `MiddlewareOptions`
|
|
307
|
+
|
|
308
|
+
See the [`@deeptracer/core` README](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/core) for full documentation of these APIs.
|
|
309
|
+
|
|
310
|
+
## Full Examples
|
|
311
|
+
|
|
312
|
+
### Hono + Bun Server
|
|
313
|
+
|
|
314
|
+
A complete Hono server running on Bun with full DeepTracer instrumentation:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { Hono } from "hono"
|
|
318
|
+
import { init, honoMiddleware, captureConsole } from "@deeptracer/node"
|
|
319
|
+
import { wrapVercelAI } from "@deeptracer/ai"
|
|
320
|
+
import { generateText } from "ai"
|
|
321
|
+
import { openai } from "@ai-sdk/openai"
|
|
322
|
+
|
|
323
|
+
// Initialize DeepTracer
|
|
324
|
+
const logger = init({
|
|
325
|
+
product: "my-saas",
|
|
326
|
+
service: "api",
|
|
327
|
+
environment: "production",
|
|
328
|
+
endpoint: process.env.DEEPTRACER_ENDPOINT!,
|
|
329
|
+
apiKey: process.env.DEEPTRACER_API_KEY!,
|
|
330
|
+
debug: process.env.NODE_ENV !== "production",
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
// Capture all console output
|
|
334
|
+
captureConsole(logger)
|
|
335
|
+
|
|
336
|
+
// Wrap AI SDK
|
|
337
|
+
const ai = wrapVercelAI(logger, { generateText })
|
|
338
|
+
|
|
339
|
+
// Create Hono app with middleware
|
|
340
|
+
const app = new Hono()
|
|
341
|
+
app.use(honoMiddleware(logger, {
|
|
342
|
+
ignorePaths: ["/health"],
|
|
343
|
+
}))
|
|
344
|
+
|
|
345
|
+
// Health check (excluded from tracing)
|
|
346
|
+
app.get("/health", (c) => c.text("ok"))
|
|
347
|
+
|
|
348
|
+
// API routes
|
|
349
|
+
app.get("/api/summarize", async (c) => {
|
|
350
|
+
const reqLogger = logger.forRequest(c.req.raw)
|
|
351
|
+
const url = c.req.query("url")
|
|
352
|
+
|
|
353
|
+
reqLogger.info("Summarization requested", { url })
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
const { text } = await ai.generateText({
|
|
357
|
+
model: openai("gpt-4o"),
|
|
358
|
+
prompt: `Summarize: ${url}`,
|
|
359
|
+
})
|
|
360
|
+
return c.json({ summary: text })
|
|
361
|
+
} catch (err) {
|
|
362
|
+
reqLogger.captureError(err, { severity: "high", context: { url } })
|
|
363
|
+
return c.json({ error: "Failed to summarize" }, 500)
|
|
364
|
+
}
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
// Graceful shutdown
|
|
368
|
+
process.on("SIGTERM", () => {
|
|
369
|
+
logger.destroy()
|
|
370
|
+
process.exit(0)
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
export default {
|
|
374
|
+
port: 3001,
|
|
375
|
+
fetch: app.fetch,
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Express Server
|
|
380
|
+
|
|
381
|
+
A complete Express server with DeepTracer:
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
import express from "express"
|
|
385
|
+
import { init, expressMiddleware, captureConsole } from "@deeptracer/node"
|
|
386
|
+
|
|
387
|
+
const logger = init({
|
|
388
|
+
product: "my-saas",
|
|
389
|
+
service: "web-api",
|
|
390
|
+
environment: "production",
|
|
391
|
+
endpoint: process.env.DEEPTRACER_ENDPOINT!,
|
|
392
|
+
apiKey: process.env.DEEPTRACER_API_KEY!,
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
captureConsole(logger)
|
|
396
|
+
|
|
397
|
+
const app = express()
|
|
398
|
+
app.use(express.json())
|
|
399
|
+
app.use(expressMiddleware(logger, {
|
|
400
|
+
ignorePaths: ["/health", "/ready"],
|
|
401
|
+
}))
|
|
402
|
+
|
|
403
|
+
app.get("/health", (req, res) => res.send("ok"))
|
|
404
|
+
|
|
405
|
+
app.post("/api/orders", async (req, res) => {
|
|
406
|
+
const orderLogger = logger.withContext("orders")
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
const order = await logger.startSpan("create-order", async () => {
|
|
410
|
+
orderLogger.info("Creating order", { items: req.body.items?.length })
|
|
411
|
+
return createOrder(req.body)
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
res.json(order)
|
|
415
|
+
} catch (err) {
|
|
416
|
+
orderLogger.captureError(err, { severity: "high" })
|
|
417
|
+
res.status(500).json({ error: "Order creation failed" })
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
const server = app.listen(3000, () => {
|
|
422
|
+
logger.info("Server started", { port: 3000 })
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
process.on("SIGTERM", () => {
|
|
426
|
+
logger.destroy()
|
|
427
|
+
server.close()
|
|
428
|
+
})
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Background Worker
|
|
432
|
+
|
|
433
|
+
A background job processor with tracing:
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
import { init } from "@deeptracer/node"
|
|
437
|
+
|
|
438
|
+
const logger = init({
|
|
439
|
+
product: "my-saas",
|
|
440
|
+
service: "worker",
|
|
441
|
+
environment: "production",
|
|
442
|
+
endpoint: process.env.DEEPTRACER_ENDPOINT!,
|
|
443
|
+
apiKey: process.env.DEEPTRACER_API_KEY!,
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
const workerLogger = logger.withContext("job-processor")
|
|
447
|
+
|
|
448
|
+
async function processJob(job: Job) {
|
|
449
|
+
await workerLogger.startSpan(`job:${job.type}`, async (span) => {
|
|
450
|
+
workerLogger.info("Processing job", { jobId: job.id, type: job.type })
|
|
451
|
+
|
|
452
|
+
// Nested span for a specific step
|
|
453
|
+
await workerLogger.startSpan("send-email", async (childSpan) => {
|
|
454
|
+
await sendEmail(job.payload)
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
workerLogger.info("Job completed", { jobId: job.id })
|
|
458
|
+
})
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Process jobs in a loop
|
|
462
|
+
async function main() {
|
|
463
|
+
workerLogger.info("Worker started")
|
|
464
|
+
|
|
465
|
+
while (true) {
|
|
466
|
+
try {
|
|
467
|
+
const job = await getNextJob()
|
|
468
|
+
if (job) await processJob(job)
|
|
469
|
+
else await sleep(1000)
|
|
470
|
+
} catch (err) {
|
|
471
|
+
workerLogger.captureError(err, { severity: "high" })
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
main()
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Monorepo
|
|
480
|
+
|
|
481
|
+
This package is part of the [DeepTracer JavaScript SDK](https://github.com/getdeeptracer/deeptracer-js) monorepo:
|
|
482
|
+
|
|
483
|
+
| Package | Description |
|
|
484
|
+
|---------|-------------|
|
|
485
|
+
| [`@deeptracer/core`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/core) | Zero-dependency shared core |
|
|
486
|
+
| **`@deeptracer/node`** | Node.js/Bun SDK (this package) |
|
|
487
|
+
| [`@deeptracer/ai`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/ai) | AI SDK wrappers -- Vercel AI, OpenAI, Anthropic |
|
|
488
|
+
| [`@deeptracer/browser`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/browser) | Browser SDK (preview) |
|
|
489
|
+
| [`@deeptracer/react`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/react) | React integration (coming soon) |
|
|
490
|
+
| [`@deeptracer/nextjs`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/nextjs) | Next.js integration (coming soon) |
|
|
491
|
+
|
|
492
|
+
## License
|
|
493
|
+
|
|
494
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
captureConsole: () => captureConsole,
|
|
25
|
+
captureGlobalErrors: () => captureGlobalErrors,
|
|
26
|
+
expressMiddleware: () => expressMiddleware,
|
|
27
|
+
honoMiddleware: () => honoMiddleware,
|
|
28
|
+
init: () => init
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
__reExport(index_exports, require("@deeptracer/core"), module.exports);
|
|
32
|
+
|
|
33
|
+
// src/global-errors.ts
|
|
34
|
+
function captureGlobalErrors(logger) {
|
|
35
|
+
process.on("uncaughtException", (error) => {
|
|
36
|
+
logger.captureError(error, { severity: "critical" });
|
|
37
|
+
logger.flush();
|
|
38
|
+
});
|
|
39
|
+
process.on("unhandledRejection", (reason) => {
|
|
40
|
+
logger.captureError(
|
|
41
|
+
reason instanceof Error ? reason : new Error(String(reason)),
|
|
42
|
+
{ severity: "high" }
|
|
43
|
+
);
|
|
44
|
+
logger.flush();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/console.ts
|
|
49
|
+
var import_internal = require("@deeptracer/core/internal");
|
|
50
|
+
function captureConsole(logger) {
|
|
51
|
+
console.log = (...args) => {
|
|
52
|
+
logger.info(args.map(String).join(" "));
|
|
53
|
+
import_internal._originalConsole.log(...args);
|
|
54
|
+
};
|
|
55
|
+
console.info = (...args) => {
|
|
56
|
+
logger.info(args.map(String).join(" "));
|
|
57
|
+
import_internal._originalConsole.info(...args);
|
|
58
|
+
};
|
|
59
|
+
console.warn = (...args) => {
|
|
60
|
+
logger.warn(args.map(String).join(" "));
|
|
61
|
+
import_internal._originalConsole.warn(...args);
|
|
62
|
+
};
|
|
63
|
+
console.error = (...args) => {
|
|
64
|
+
logger.error(args.map(String).join(" "));
|
|
65
|
+
import_internal._originalConsole.error(...args);
|
|
66
|
+
};
|
|
67
|
+
console.debug = (...args) => {
|
|
68
|
+
logger.debug(args.map(String).join(" "));
|
|
69
|
+
import_internal._originalConsole.debug(...args);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/middleware.ts
|
|
74
|
+
function honoMiddleware(logger, options) {
|
|
75
|
+
return async (c, next) => {
|
|
76
|
+
const method = c.req.method;
|
|
77
|
+
const path = c.req.path;
|
|
78
|
+
if (options?.ignorePaths?.some((p) => path.startsWith(p))) {
|
|
79
|
+
return next();
|
|
80
|
+
}
|
|
81
|
+
const opName = options?.operationName ? options.operationName(method, path) : `${method} ${path}`;
|
|
82
|
+
const reqLogger = logger.forRequest(c.req.raw);
|
|
83
|
+
return reqLogger.startSpan(opName, async (span) => {
|
|
84
|
+
c.header("x-trace-id", span.traceId);
|
|
85
|
+
c.header("x-span-id", span.spanId);
|
|
86
|
+
await next();
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function expressMiddleware(logger, options) {
|
|
91
|
+
return (req, res, next) => {
|
|
92
|
+
const method = req.method;
|
|
93
|
+
const path = req.path || req.url;
|
|
94
|
+
if (options?.ignorePaths?.some((p) => path.startsWith(p))) {
|
|
95
|
+
return next();
|
|
96
|
+
}
|
|
97
|
+
const opName = options?.operationName ? options.operationName(method, path) : `${method} ${path}`;
|
|
98
|
+
const traceId = req.headers["x-trace-id"] || void 0;
|
|
99
|
+
const spanId = req.headers["x-span-id"] || void 0;
|
|
100
|
+
const requestId = req.headers["x-request-id"] || void 0;
|
|
101
|
+
const vercelId = req.headers["x-vercel-id"] || void 0;
|
|
102
|
+
const reqLogger = new logger.constructor(
|
|
103
|
+
logger.config,
|
|
104
|
+
logger.contextName,
|
|
105
|
+
{
|
|
106
|
+
trace_id: traceId,
|
|
107
|
+
span_id: spanId,
|
|
108
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
109
|
+
vercel_id: vercelId
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
const span = reqLogger.startInactiveSpan(opName);
|
|
113
|
+
res.setHeader("x-trace-id", span.traceId);
|
|
114
|
+
res.setHeader("x-span-id", span.spanId);
|
|
115
|
+
res.on("finish", () => {
|
|
116
|
+
const status = res.statusCode >= 400 ? "error" : "ok";
|
|
117
|
+
span.end({
|
|
118
|
+
status,
|
|
119
|
+
metadata: { status_code: res.statusCode, method, path }
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
next();
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/init.ts
|
|
127
|
+
var import_core = require("@deeptracer/core");
|
|
128
|
+
function init(config) {
|
|
129
|
+
const logger = (0, import_core.createLogger)(config);
|
|
130
|
+
captureGlobalErrors(logger);
|
|
131
|
+
return logger;
|
|
132
|
+
}
|
|
133
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
134
|
+
0 && (module.exports = {
|
|
135
|
+
captureConsole,
|
|
136
|
+
captureGlobalErrors,
|
|
137
|
+
expressMiddleware,
|
|
138
|
+
honoMiddleware,
|
|
139
|
+
init,
|
|
140
|
+
...require("@deeptracer/core")
|
|
141
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Logger, MiddlewareOptions, LoggerConfig } from '@deeptracer/core';
|
|
2
|
+
export * from '@deeptracer/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Automatically capture all uncaught exceptions and unhandled promise rejections
|
|
6
|
+
* via Node.js/Bun process events. Call once at application startup.
|
|
7
|
+
*
|
|
8
|
+
* Uncaught exceptions are reported with severity "critical".
|
|
9
|
+
* Unhandled rejections are reported with severity "high".
|
|
10
|
+
* Errors are flushed immediately to ensure delivery before process exit.
|
|
11
|
+
*
|
|
12
|
+
* @param logger - DeepTracer logger instance
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { createLogger, captureGlobalErrors } from "@deeptracer/node"
|
|
17
|
+
*
|
|
18
|
+
* const logger = createLogger({ ... })
|
|
19
|
+
* captureGlobalErrors(logger)
|
|
20
|
+
* // All uncaught errors now automatically sent to DeepTracer
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function captureGlobalErrors(logger: Logger): void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Intercept all console.log/info/warn/error/debug calls and forward them
|
|
27
|
+
* to DeepTracer as log entries. Original console output is preserved.
|
|
28
|
+
*
|
|
29
|
+
* @param logger - DeepTracer logger instance
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { createLogger, captureConsole } from "@deeptracer/node"
|
|
34
|
+
*
|
|
35
|
+
* const logger = createLogger({ ... })
|
|
36
|
+
* captureConsole(logger)
|
|
37
|
+
* // console.log("hello") now goes to BOTH console AND DeepTracer
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function captureConsole(logger: Logger): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create Hono-compatible middleware that auto-instruments every request with:
|
|
44
|
+
* - Distributed tracing (creates a span per request)
|
|
45
|
+
* - Duration tracking
|
|
46
|
+
* - HTTP status code capture
|
|
47
|
+
* - Automatic error capture
|
|
48
|
+
*
|
|
49
|
+
* @param logger - DeepTracer logger instance
|
|
50
|
+
* @param options - Optional middleware configuration
|
|
51
|
+
* @returns A Hono middleware function — pass directly to `app.use()`
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Hono } from "hono"
|
|
56
|
+
* import { createLogger, honoMiddleware } from "@deeptracer/node"
|
|
57
|
+
*
|
|
58
|
+
* const logger = createLogger({ ... })
|
|
59
|
+
* const app = new Hono()
|
|
60
|
+
* app.use(honoMiddleware(logger))
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function honoMiddleware(logger: Logger, options?: MiddlewareOptions): (c: any, next: () => Promise<void>) => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Create Express-compatible middleware that auto-instruments every request.
|
|
66
|
+
*
|
|
67
|
+
* @param logger - DeepTracer logger instance
|
|
68
|
+
* @param options - Optional middleware configuration
|
|
69
|
+
* @returns An Express middleware function — pass directly to `app.use()`
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* import express from "express"
|
|
74
|
+
* import { createLogger, expressMiddleware } from "@deeptracer/node"
|
|
75
|
+
*
|
|
76
|
+
* const logger = createLogger({ ... })
|
|
77
|
+
* const app = express()
|
|
78
|
+
* app.use(expressMiddleware(logger))
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function expressMiddleware(logger: Logger, options?: MiddlewareOptions): (req: any, res: any, next: () => void) => void;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initialize DeepTracer for Node.js/Bun with sensible defaults.
|
|
85
|
+
* Creates a logger and automatically sets up global error capture.
|
|
86
|
+
*
|
|
87
|
+
* This is the recommended way to set up DeepTracer in a Node.js/Bun application.
|
|
88
|
+
*
|
|
89
|
+
* @param config - Logger configuration
|
|
90
|
+
* @returns A Logger instance with global error capture enabled
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { init } from "@deeptracer/node"
|
|
95
|
+
*
|
|
96
|
+
* const logger = init({
|
|
97
|
+
* product: "my-app",
|
|
98
|
+
* service: "api",
|
|
99
|
+
* environment: "production",
|
|
100
|
+
* endpoint: "https://deeptracer.example.com",
|
|
101
|
+
* apiKey: "dt_live_xxx",
|
|
102
|
+
* })
|
|
103
|
+
* // Global error capture is already active!
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare function init(config: LoggerConfig): Logger;
|
|
107
|
+
|
|
108
|
+
export { captureConsole, captureGlobalErrors, expressMiddleware, honoMiddleware, init };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Logger, MiddlewareOptions, LoggerConfig } from '@deeptracer/core';
|
|
2
|
+
export * from '@deeptracer/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Automatically capture all uncaught exceptions and unhandled promise rejections
|
|
6
|
+
* via Node.js/Bun process events. Call once at application startup.
|
|
7
|
+
*
|
|
8
|
+
* Uncaught exceptions are reported with severity "critical".
|
|
9
|
+
* Unhandled rejections are reported with severity "high".
|
|
10
|
+
* Errors are flushed immediately to ensure delivery before process exit.
|
|
11
|
+
*
|
|
12
|
+
* @param logger - DeepTracer logger instance
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { createLogger, captureGlobalErrors } from "@deeptracer/node"
|
|
17
|
+
*
|
|
18
|
+
* const logger = createLogger({ ... })
|
|
19
|
+
* captureGlobalErrors(logger)
|
|
20
|
+
* // All uncaught errors now automatically sent to DeepTracer
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function captureGlobalErrors(logger: Logger): void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Intercept all console.log/info/warn/error/debug calls and forward them
|
|
27
|
+
* to DeepTracer as log entries. Original console output is preserved.
|
|
28
|
+
*
|
|
29
|
+
* @param logger - DeepTracer logger instance
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { createLogger, captureConsole } from "@deeptracer/node"
|
|
34
|
+
*
|
|
35
|
+
* const logger = createLogger({ ... })
|
|
36
|
+
* captureConsole(logger)
|
|
37
|
+
* // console.log("hello") now goes to BOTH console AND DeepTracer
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function captureConsole(logger: Logger): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create Hono-compatible middleware that auto-instruments every request with:
|
|
44
|
+
* - Distributed tracing (creates a span per request)
|
|
45
|
+
* - Duration tracking
|
|
46
|
+
* - HTTP status code capture
|
|
47
|
+
* - Automatic error capture
|
|
48
|
+
*
|
|
49
|
+
* @param logger - DeepTracer logger instance
|
|
50
|
+
* @param options - Optional middleware configuration
|
|
51
|
+
* @returns A Hono middleware function — pass directly to `app.use()`
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Hono } from "hono"
|
|
56
|
+
* import { createLogger, honoMiddleware } from "@deeptracer/node"
|
|
57
|
+
*
|
|
58
|
+
* const logger = createLogger({ ... })
|
|
59
|
+
* const app = new Hono()
|
|
60
|
+
* app.use(honoMiddleware(logger))
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function honoMiddleware(logger: Logger, options?: MiddlewareOptions): (c: any, next: () => Promise<void>) => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Create Express-compatible middleware that auto-instruments every request.
|
|
66
|
+
*
|
|
67
|
+
* @param logger - DeepTracer logger instance
|
|
68
|
+
* @param options - Optional middleware configuration
|
|
69
|
+
* @returns An Express middleware function — pass directly to `app.use()`
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* import express from "express"
|
|
74
|
+
* import { createLogger, expressMiddleware } from "@deeptracer/node"
|
|
75
|
+
*
|
|
76
|
+
* const logger = createLogger({ ... })
|
|
77
|
+
* const app = express()
|
|
78
|
+
* app.use(expressMiddleware(logger))
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function expressMiddleware(logger: Logger, options?: MiddlewareOptions): (req: any, res: any, next: () => void) => void;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initialize DeepTracer for Node.js/Bun with sensible defaults.
|
|
85
|
+
* Creates a logger and automatically sets up global error capture.
|
|
86
|
+
*
|
|
87
|
+
* This is the recommended way to set up DeepTracer in a Node.js/Bun application.
|
|
88
|
+
*
|
|
89
|
+
* @param config - Logger configuration
|
|
90
|
+
* @returns A Logger instance with global error capture enabled
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { init } from "@deeptracer/node"
|
|
95
|
+
*
|
|
96
|
+
* const logger = init({
|
|
97
|
+
* product: "my-app",
|
|
98
|
+
* service: "api",
|
|
99
|
+
* environment: "production",
|
|
100
|
+
* endpoint: "https://deeptracer.example.com",
|
|
101
|
+
* apiKey: "dt_live_xxx",
|
|
102
|
+
* })
|
|
103
|
+
* // Global error capture is already active!
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare function init(config: LoggerConfig): Logger;
|
|
107
|
+
|
|
108
|
+
export { captureConsole, captureGlobalErrors, expressMiddleware, honoMiddleware, init };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
export * from "@deeptracer/core";
|
|
3
|
+
|
|
4
|
+
// src/global-errors.ts
|
|
5
|
+
function captureGlobalErrors(logger) {
|
|
6
|
+
process.on("uncaughtException", (error) => {
|
|
7
|
+
logger.captureError(error, { severity: "critical" });
|
|
8
|
+
logger.flush();
|
|
9
|
+
});
|
|
10
|
+
process.on("unhandledRejection", (reason) => {
|
|
11
|
+
logger.captureError(
|
|
12
|
+
reason instanceof Error ? reason : new Error(String(reason)),
|
|
13
|
+
{ severity: "high" }
|
|
14
|
+
);
|
|
15
|
+
logger.flush();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/console.ts
|
|
20
|
+
import { _originalConsole } from "@deeptracer/core/internal";
|
|
21
|
+
function captureConsole(logger) {
|
|
22
|
+
console.log = (...args) => {
|
|
23
|
+
logger.info(args.map(String).join(" "));
|
|
24
|
+
_originalConsole.log(...args);
|
|
25
|
+
};
|
|
26
|
+
console.info = (...args) => {
|
|
27
|
+
logger.info(args.map(String).join(" "));
|
|
28
|
+
_originalConsole.info(...args);
|
|
29
|
+
};
|
|
30
|
+
console.warn = (...args) => {
|
|
31
|
+
logger.warn(args.map(String).join(" "));
|
|
32
|
+
_originalConsole.warn(...args);
|
|
33
|
+
};
|
|
34
|
+
console.error = (...args) => {
|
|
35
|
+
logger.error(args.map(String).join(" "));
|
|
36
|
+
_originalConsole.error(...args);
|
|
37
|
+
};
|
|
38
|
+
console.debug = (...args) => {
|
|
39
|
+
logger.debug(args.map(String).join(" "));
|
|
40
|
+
_originalConsole.debug(...args);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/middleware.ts
|
|
45
|
+
function honoMiddleware(logger, options) {
|
|
46
|
+
return async (c, next) => {
|
|
47
|
+
const method = c.req.method;
|
|
48
|
+
const path = c.req.path;
|
|
49
|
+
if (options?.ignorePaths?.some((p) => path.startsWith(p))) {
|
|
50
|
+
return next();
|
|
51
|
+
}
|
|
52
|
+
const opName = options?.operationName ? options.operationName(method, path) : `${method} ${path}`;
|
|
53
|
+
const reqLogger = logger.forRequest(c.req.raw);
|
|
54
|
+
return reqLogger.startSpan(opName, async (span) => {
|
|
55
|
+
c.header("x-trace-id", span.traceId);
|
|
56
|
+
c.header("x-span-id", span.spanId);
|
|
57
|
+
await next();
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function expressMiddleware(logger, options) {
|
|
62
|
+
return (req, res, next) => {
|
|
63
|
+
const method = req.method;
|
|
64
|
+
const path = req.path || req.url;
|
|
65
|
+
if (options?.ignorePaths?.some((p) => path.startsWith(p))) {
|
|
66
|
+
return next();
|
|
67
|
+
}
|
|
68
|
+
const opName = options?.operationName ? options.operationName(method, path) : `${method} ${path}`;
|
|
69
|
+
const traceId = req.headers["x-trace-id"] || void 0;
|
|
70
|
+
const spanId = req.headers["x-span-id"] || void 0;
|
|
71
|
+
const requestId = req.headers["x-request-id"] || void 0;
|
|
72
|
+
const vercelId = req.headers["x-vercel-id"] || void 0;
|
|
73
|
+
const reqLogger = new logger.constructor(
|
|
74
|
+
logger.config,
|
|
75
|
+
logger.contextName,
|
|
76
|
+
{
|
|
77
|
+
trace_id: traceId,
|
|
78
|
+
span_id: spanId,
|
|
79
|
+
request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
|
|
80
|
+
vercel_id: vercelId
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
const span = reqLogger.startInactiveSpan(opName);
|
|
84
|
+
res.setHeader("x-trace-id", span.traceId);
|
|
85
|
+
res.setHeader("x-span-id", span.spanId);
|
|
86
|
+
res.on("finish", () => {
|
|
87
|
+
const status = res.statusCode >= 400 ? "error" : "ok";
|
|
88
|
+
span.end({
|
|
89
|
+
status,
|
|
90
|
+
metadata: { status_code: res.statusCode, method, path }
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
next();
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/init.ts
|
|
98
|
+
import { createLogger } from "@deeptracer/core";
|
|
99
|
+
function init(config) {
|
|
100
|
+
const logger = createLogger(config);
|
|
101
|
+
captureGlobalErrors(logger);
|
|
102
|
+
return logger;
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
captureConsole,
|
|
106
|
+
captureGlobalErrors,
|
|
107
|
+
expressMiddleware,
|
|
108
|
+
honoMiddleware,
|
|
109
|
+
init
|
|
110
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deeptracer/node",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "DeepTracer SDK for Node.js and Bun — global error capture, console capture, Express & Hono middleware",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist", "README.md"],
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"keywords": ["logging", "observability", "tracing", "deeptracer", "nodejs", "bun", "hono", "express"],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/getdeeptracer/deeptracer-js.git",
|
|
22
|
+
"directory": "packages/node"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@deeptracer/core": "0.2.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"dev": "tsup --watch"
|
|
34
|
+
}
|
|
35
|
+
}
|