@tracewayapp/backend 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 +368 -0
- package/dist/index.d.mts +232 -0
- package/dist/index.d.ts +232 -0
- package/dist/index.js +742 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +681 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# @tracewayapp/backend
|
|
2
|
+
|
|
3
|
+
Traceway SDK for Node.js backends. Core telemetry collection library.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import * as traceway from "@tracewayapp/backend";
|
|
9
|
+
|
|
10
|
+
traceway.init("your-token@https://your-traceway-server.com/api/report", {
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
debug: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Capture an error
|
|
16
|
+
traceway.captureException(new Error("something broke"));
|
|
17
|
+
|
|
18
|
+
// Capture a message
|
|
19
|
+
traceway.captureMessage("Deployment completed");
|
|
20
|
+
|
|
21
|
+
// Capture a custom metric
|
|
22
|
+
traceway.captureMetric("queue.length", 42);
|
|
23
|
+
|
|
24
|
+
// Graceful shutdown
|
|
25
|
+
await traceway.shutdown();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
### Two Modes of Operation
|
|
31
|
+
|
|
32
|
+
The SDK supports both **manual** and **automatic** context propagation:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
36
|
+
│ Your Application │
|
|
37
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
38
|
+
│ │
|
|
39
|
+
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
40
|
+
│ │ AsyncLocalStorage │ │
|
|
41
|
+
│ │ ┌─────────────────────────────────────────────────────┐ │ │
|
|
42
|
+
│ │ │ TraceContext (per request/task) │ │ │
|
|
43
|
+
│ │ │ - traceId: string │ │ │
|
|
44
|
+
│ │ │ - spans: Span[] │ │ │
|
|
45
|
+
│ │ │ - attributes: Record<string, string> │ │ │
|
|
46
|
+
│ │ │ - startedAt: Date │ │ │
|
|
47
|
+
│ │ │ - statusCode, bodySize, clientIP, endpoint │ │ │
|
|
48
|
+
│ │ └─────────────────────────────────────────────────────┘ │ │
|
|
49
|
+
│ └─────────────────────────────────────────────────────────────┘ │
|
|
50
|
+
│ │ │
|
|
51
|
+
│ withTraceContext() ───────┘ │
|
|
52
|
+
│ │
|
|
53
|
+
│ captureException() ──────► auto-detects context ──────┐ │
|
|
54
|
+
│ captureMessage() ────────► auto-detects context ──────┤ │
|
|
55
|
+
│ endSpan() ───────────────► auto-adds to context ──────┤ │
|
|
56
|
+
│ captureCurrentTrace() ───► reads from context ────────┤ │
|
|
57
|
+
│ ▼ │
|
|
58
|
+
│ ┌────────────────────┐ │
|
|
59
|
+
│ │ CollectionFrameStore│ │
|
|
60
|
+
│ │ (global singleton) │ │
|
|
61
|
+
│ └────────────────────┘ │
|
|
62
|
+
│ │ │
|
|
63
|
+
│ gzip + POST │
|
|
64
|
+
│ ▼ │
|
|
65
|
+
│ Traceway API │
|
|
66
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Automatic Context Propagation (Recommended)
|
|
70
|
+
|
|
71
|
+
The SDK uses Node.js `AsyncLocalStorage` to automatically propagate trace context through async operations:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import * as traceway from "@tracewayapp/backend";
|
|
75
|
+
|
|
76
|
+
traceway.init("token@https://api.traceway.io/api/report");
|
|
77
|
+
|
|
78
|
+
// Wrap your request handler
|
|
79
|
+
app.get("/api/users", (req, res) => {
|
|
80
|
+
traceway.withTraceContext(
|
|
81
|
+
{ endpoint: `${req.method} ${req.path}`, clientIP: req.ip },
|
|
82
|
+
async () => {
|
|
83
|
+
// All operations inside automatically belong to this trace
|
|
84
|
+
|
|
85
|
+
const span = traceway.startSpan("db-query");
|
|
86
|
+
const users = await db.query("SELECT * FROM users");
|
|
87
|
+
traceway.endSpan(span); // Auto-added to trace context
|
|
88
|
+
|
|
89
|
+
// Exceptions auto-link to trace
|
|
90
|
+
if (!users.length) {
|
|
91
|
+
traceway.captureMessage("No users found");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
res.json(users);
|
|
95
|
+
|
|
96
|
+
// Capture the trace at the end
|
|
97
|
+
traceway.setTraceResponseInfo(200, JSON.stringify(users).length);
|
|
98
|
+
traceway.captureCurrentTrace();
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Context API
|
|
105
|
+
|
|
106
|
+
| Function | Description |
|
|
107
|
+
|----------|-------------|
|
|
108
|
+
| `withTraceContext(options, fn)` | Run function within a new trace context |
|
|
109
|
+
| `getTraceContext()` | Get current context (or undefined) |
|
|
110
|
+
| `getTraceId()` | Get current trace ID (or undefined) |
|
|
111
|
+
| `hasTraceContext()` | Check if inside a trace context |
|
|
112
|
+
| `setTraceAttribute(key, value)` | Set attribute on current trace |
|
|
113
|
+
| `setTraceAttributes(attrs)` | Set multiple attributes |
|
|
114
|
+
| `setTraceResponseInfo(status, size?)` | Set HTTP response info |
|
|
115
|
+
| `addSpanToContext(span)` | Manually add a span |
|
|
116
|
+
| `getTraceSpans()` | Get all spans in current trace |
|
|
117
|
+
| `getTraceDuration()` | Get elapsed time in ms |
|
|
118
|
+
| `forkTraceContext(fn)` | Fork context for parallel ops |
|
|
119
|
+
| `captureCurrentTrace()` | Capture trace from context |
|
|
120
|
+
|
|
121
|
+
### Building Framework Middleware
|
|
122
|
+
|
|
123
|
+
The context API makes it easy to build framework-specific middleware:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// Express middleware
|
|
127
|
+
import * as traceway from "@tracewayapp/backend";
|
|
128
|
+
|
|
129
|
+
export function tracewayMiddleware() {
|
|
130
|
+
return (req, res, next) => {
|
|
131
|
+
traceway.withTraceContext(
|
|
132
|
+
{
|
|
133
|
+
endpoint: `${req.method} ${req.path}`,
|
|
134
|
+
clientIP: req.ip,
|
|
135
|
+
attributes: { userAgent: req.get("User-Agent") || "" },
|
|
136
|
+
},
|
|
137
|
+
() => {
|
|
138
|
+
// Intercept response to capture trace
|
|
139
|
+
const originalEnd = res.end;
|
|
140
|
+
res.end = function (...args) {
|
|
141
|
+
traceway.setTraceResponseInfo(
|
|
142
|
+
res.statusCode,
|
|
143
|
+
res.get("Content-Length") ? parseInt(res.get("Content-Length")) : 0
|
|
144
|
+
);
|
|
145
|
+
traceway.captureCurrentTrace();
|
|
146
|
+
return originalEnd.apply(this, args);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
next();
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Usage
|
|
156
|
+
app.use(tracewayMiddleware());
|
|
157
|
+
app.get("/api/users", async (req, res) => {
|
|
158
|
+
// Context is already set up - just use the SDK
|
|
159
|
+
const span = traceway.startSpan("fetch-users");
|
|
160
|
+
try {
|
|
161
|
+
const users = await getUsers();
|
|
162
|
+
traceway.endSpan(span);
|
|
163
|
+
res.json(users);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
traceway.endSpan(span);
|
|
166
|
+
traceway.captureException(err); // Auto-linked to request trace
|
|
167
|
+
res.status(500).json({ error: "Internal error" });
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// Fastify plugin
|
|
174
|
+
import * as traceway from "@tracewayapp/backend";
|
|
175
|
+
|
|
176
|
+
export const tracewayPlugin = (fastify, opts, done) => {
|
|
177
|
+
fastify.addHook("onRequest", (request, reply, done) => {
|
|
178
|
+
traceway.withTraceContext(
|
|
179
|
+
{
|
|
180
|
+
endpoint: `${request.method} ${request.url}`,
|
|
181
|
+
clientIP: request.ip,
|
|
182
|
+
},
|
|
183
|
+
() => done()
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
fastify.addHook("onResponse", (request, reply, done) => {
|
|
188
|
+
traceway.setTraceResponseInfo(reply.statusCode);
|
|
189
|
+
traceway.captureCurrentTrace();
|
|
190
|
+
done();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
done();
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Manual Mode (Legacy)
|
|
198
|
+
|
|
199
|
+
You can still use explicit parameter passing if preferred:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import * as traceway from "@tracewayapp/backend";
|
|
203
|
+
import { generateUUID } from "@tracewayapp/core";
|
|
204
|
+
|
|
205
|
+
const traceId = generateUUID();
|
|
206
|
+
const spans: Span[] = [];
|
|
207
|
+
|
|
208
|
+
const span = traceway.startSpan("operation");
|
|
209
|
+
// ... do work ...
|
|
210
|
+
spans.push(traceway.endSpan(span, false)); // false = don't auto-add to context
|
|
211
|
+
|
|
212
|
+
traceway.captureTrace(traceId, "GET /api", 150, new Date(), 200, 1024, "127.0.0.1", {}, spans);
|
|
213
|
+
traceway.captureExceptionWithAttributes(err, {}, traceId);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Public API
|
|
217
|
+
|
|
218
|
+
### Core Functions
|
|
219
|
+
|
|
220
|
+
| Function | Description |
|
|
221
|
+
|----------|-------------|
|
|
222
|
+
| `init(connectionString, options?)` | Initialize the SDK (throws if already initialized) |
|
|
223
|
+
| `shutdown()` | Stop timers, flush remaining data, and await final upload |
|
|
224
|
+
|
|
225
|
+
### Capture Functions
|
|
226
|
+
|
|
227
|
+
| Function | Description |
|
|
228
|
+
|----------|-------------|
|
|
229
|
+
| `captureException(error)` | Capture error (auto-detects trace context) |
|
|
230
|
+
| `captureExceptionWithAttributes(error, attrs?, traceId?)` | Capture with explicit context |
|
|
231
|
+
| `captureMessage(msg, attrs?)` | Capture message (auto-detects trace context) |
|
|
232
|
+
| `captureMetric(name, value)` | Capture a custom metric |
|
|
233
|
+
| `captureTrace(...)` | Capture HTTP trace (manual mode) |
|
|
234
|
+
| `captureTask(...)` | Capture background task (manual mode) |
|
|
235
|
+
| `captureCurrentTrace()` | Capture trace from current context |
|
|
236
|
+
|
|
237
|
+
### Span Functions
|
|
238
|
+
|
|
239
|
+
| Function | Description |
|
|
240
|
+
|----------|-------------|
|
|
241
|
+
| `startSpan(name)` | Start a span (returns `SpanHandle`) |
|
|
242
|
+
| `endSpan(span, addToContext?)` | End span (auto-adds to context by default) |
|
|
243
|
+
|
|
244
|
+
### Utility Functions
|
|
245
|
+
|
|
246
|
+
| Function | Description |
|
|
247
|
+
|----------|-------------|
|
|
248
|
+
| `shouldSample(isError)` | Check if trace should be recorded |
|
|
249
|
+
| `measureTask(title, fn)` | Execute function as auto-captured task |
|
|
250
|
+
|
|
251
|
+
### Span Handle vs Span Object
|
|
252
|
+
|
|
253
|
+
`startSpan()` returns a **span handle** for tracking:
|
|
254
|
+
```ts
|
|
255
|
+
interface SpanHandle {
|
|
256
|
+
id: string; // UUID
|
|
257
|
+
name: string; // Operation name
|
|
258
|
+
startTime: string; // ISO timestamp
|
|
259
|
+
startedAt: number; // Unix ms (for duration calc)
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`endSpan()` returns a **Span object** for the trace:
|
|
264
|
+
```ts
|
|
265
|
+
interface Span {
|
|
266
|
+
id: string; // Same UUID
|
|
267
|
+
name: string; // Operation name
|
|
268
|
+
startTime: string; // ISO timestamp
|
|
269
|
+
duration: number; // Nanoseconds
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Configuration Options
|
|
274
|
+
|
|
275
|
+
| Option | Type | Default | Description |
|
|
276
|
+
|--------|------|---------|-------------|
|
|
277
|
+
| `debug` | `boolean` | `false` | Enable debug logging to console |
|
|
278
|
+
| `maxCollectionFrames` | `number` | `12` | Ring buffer capacity for pending frames |
|
|
279
|
+
| `collectionInterval` | `number` | `5000` | Frame rotation interval (ms) |
|
|
280
|
+
| `uploadThrottle` | `number` | `2000` | Minimum gap between uploads (ms) |
|
|
281
|
+
| `metricsInterval` | `number` | `30000` | System metrics collection interval (ms) |
|
|
282
|
+
| `version` | `string` | `""` | Application version sent with reports |
|
|
283
|
+
| `serverName` | `string` | hostname | Server identifier sent with reports |
|
|
284
|
+
| `sampleRate` | `number` | `1.0` | Normal trace sampling rate (0.0-1.0) |
|
|
285
|
+
| `errorSampleRate` | `number` | `1.0` | Error trace sampling rate (0.0-1.0) |
|
|
286
|
+
|
|
287
|
+
## Collection Frame Lifecycle
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
291
|
+
│ 1. COLLECT │
|
|
292
|
+
│ captureException/Trace/Metric ──► Current CollectionFrame │
|
|
293
|
+
│ │
|
|
294
|
+
│ 2. ROTATE (every collectionInterval ms) │
|
|
295
|
+
│ Current frame ──► Send Queue (ring buffer, max 12 frames) │
|
|
296
|
+
│ │
|
|
297
|
+
│ 3. UPLOAD (respects uploadThrottle) │
|
|
298
|
+
│ Send Queue ──► gzip ──► POST /api/report │
|
|
299
|
+
│ Headers: Authorization: Bearer {token} │
|
|
300
|
+
│ Content-Type: application/json │
|
|
301
|
+
│ Content-Encoding: gzip │
|
|
302
|
+
│ │
|
|
303
|
+
│ 4. CLEANUP │
|
|
304
|
+
│ 200 OK ──► Remove frames from queue │
|
|
305
|
+
│ Failure ──► Retain frames for retry │
|
|
306
|
+
│ │
|
|
307
|
+
│ 5. SHUTDOWN │
|
|
308
|
+
│ shutdown() ──► Rotate current ──► Upload all ──► Stop timers │
|
|
309
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Auto-Collected Metrics
|
|
313
|
+
|
|
314
|
+
Every `metricsInterval` ms (default: 30s), these metrics are automatically captured:
|
|
315
|
+
|
|
316
|
+
| Name | Description | Unit |
|
|
317
|
+
|------|-------------|------|
|
|
318
|
+
| `mem.used` | Process RSS memory | MB |
|
|
319
|
+
| `mem.total` | Total system memory | MB |
|
|
320
|
+
| `cpu.used_pcnt` | CPU usage (delta-based) | % (0-100) |
|
|
321
|
+
|
|
322
|
+
## Sampling
|
|
323
|
+
|
|
324
|
+
Use sampling to reduce data volume in high-traffic applications:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
traceway.init(connectionString, {
|
|
328
|
+
sampleRate: 0.1, // Record 10% of normal traces
|
|
329
|
+
errorSampleRate: 1.0, // Record 100% of error traces
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// In your code, check before capturing:
|
|
333
|
+
if (traceway.shouldSample(isError)) {
|
|
334
|
+
traceway.captureTrace(...);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The `measureTask()` function automatically respects sampling rates.
|
|
339
|
+
|
|
340
|
+
## Comparison with Go Client
|
|
341
|
+
|
|
342
|
+
| Go Client Feature | JS Backend Equivalent |
|
|
343
|
+
|-------------------|----------------------|
|
|
344
|
+
| `Init(connectionString, opts...)` | `init(connectionString, options)` |
|
|
345
|
+
| `StartTrace(ctx) context.Context` | `withTraceContext(options, fn)` |
|
|
346
|
+
| `GetTraceFromContext(ctx)` | `getTraceContext()` |
|
|
347
|
+
| `GetTraceIdFromContext(ctx)` | `getTraceId()` |
|
|
348
|
+
| `GetAttributesFromContext(ctx)` | `getTraceContext()?.attributes` |
|
|
349
|
+
| `WithAttributes(ctx, fn)` | `setTraceAttribute()` / `setTraceAttributes()` |
|
|
350
|
+
| `StartSpan(ctx, name)` | `startSpan(name)` (auto-adds on `endSpan()`) |
|
|
351
|
+
| `CaptureException(err)` | `captureException(err)` (auto-detects context) |
|
|
352
|
+
| `CaptureExceptionWithContext(ctx, err)` | `captureException(err)` inside `withTraceContext()` |
|
|
353
|
+
| `CaptureTrace(tc, ...)` | `captureCurrentTrace()` or `captureTrace(...)` |
|
|
354
|
+
| `CaptureTask(tc, ...)` | `captureCurrentTrace()` with `isTask: true` |
|
|
355
|
+
| `MeasureTask(title, fn)` | `measureTask(title, fn)` |
|
|
356
|
+
| `Recover()` / `RecoverWithContext(ctx)` | Use try/catch with `captureException()` |
|
|
357
|
+
| `tracewayhttp.New(...)` | Build with `withTraceContext()` (see examples) |
|
|
358
|
+
| `tracewaygin.New(...)` | Build with `withTraceContext()` (see examples) |
|
|
359
|
+
| `tracewaydb.NewTwDB(...)` | Wrap DB calls with `startSpan()`/`endSpan()` |
|
|
360
|
+
|
|
361
|
+
## Thread Safety
|
|
362
|
+
|
|
363
|
+
The SDK is designed for concurrent use in Node.js:
|
|
364
|
+
- `AsyncLocalStorage` provides request isolation automatically
|
|
365
|
+
- `CollectionFrameStore` uses synchronous operations (Node.js event loop)
|
|
366
|
+
- Timer callbacks are non-blocking via `unref()`
|
|
367
|
+
- `shutdown()` is async and awaits the final upload
|
|
368
|
+
- Parallel requests each get their own isolated trace context
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { Span, TracewayOptions, MetricRecord, ExceptionStackTrace, Trace } from '@tracewayapp/core';
|
|
2
|
+
export { CollectionFrame, ExceptionStackTrace, MetricRecord, ReportRequest, Span, Trace, TracewayOptions } from '@tracewayapp/core';
|
|
3
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
4
|
+
|
|
5
|
+
declare function init(connectionString: string, options?: TracewayOptions): void;
|
|
6
|
+
declare function captureException(error: Error): void;
|
|
7
|
+
declare function captureExceptionWithAttributes(error: Error, attributes?: Record<string, string>, traceId?: string): void;
|
|
8
|
+
declare function captureMessage(msg: string, attributes?: Record<string, string>): void;
|
|
9
|
+
declare function captureMetric(name: string, value: number): void;
|
|
10
|
+
declare function captureTrace(traceId: string, endpoint: string, durationMs: number, startedAt: Date, statusCode: number, bodySize: number, clientIP: string, attributes?: Record<string, string>, spans?: Span[]): void;
|
|
11
|
+
declare function captureTask(traceId: string, taskName: string, durationMs: number, startedAt: Date, attributes?: Record<string, string>, spans?: Span[]): void;
|
|
12
|
+
/** Handle returned by startSpan for tracking span timing */
|
|
13
|
+
interface SpanHandle {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
startTime: string;
|
|
17
|
+
startedAt: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start a new span. If within a trace context, the span will be
|
|
21
|
+
* automatically added to the trace when ended.
|
|
22
|
+
*/
|
|
23
|
+
declare function startSpan(name: string): SpanHandle;
|
|
24
|
+
/**
|
|
25
|
+
* End a span and get the completed Span object.
|
|
26
|
+
* If within a trace context, automatically adds the span to the trace.
|
|
27
|
+
*
|
|
28
|
+
* @param addToContext - If true (default), adds span to current trace context
|
|
29
|
+
*/
|
|
30
|
+
declare function endSpan(span: SpanHandle, addToContext?: boolean): Span;
|
|
31
|
+
/**
|
|
32
|
+
* Capture the current trace context as a trace.
|
|
33
|
+
* Call this at the end of a request/task to record the trace.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // In Express middleware (after response)
|
|
38
|
+
* withTraceContext({ endpoint: `${req.method} ${req.path}` }, async () => {
|
|
39
|
+
* await handleRequest(req, res);
|
|
40
|
+
* setTraceResponseInfo(res.statusCode, contentLength);
|
|
41
|
+
* captureCurrentTrace(); // Records the trace with all spans
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function captureCurrentTrace(): void;
|
|
46
|
+
declare function shouldSample(isError: boolean): boolean;
|
|
47
|
+
declare function measureTask(title: string, fn: () => void | Promise<void>): void;
|
|
48
|
+
declare function shutdown(): Promise<void>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Trace context stored in AsyncLocalStorage.
|
|
52
|
+
* Automatically propagates through async operations.
|
|
53
|
+
*/
|
|
54
|
+
interface TraceContext {
|
|
55
|
+
/** Unique trace identifier (UUID v4) */
|
|
56
|
+
traceId: string;
|
|
57
|
+
/** Whether this is a background task (vs HTTP request) */
|
|
58
|
+
isTask: boolean;
|
|
59
|
+
/** When the trace started */
|
|
60
|
+
startedAt: Date;
|
|
61
|
+
/** Collected spans within this trace */
|
|
62
|
+
spans: Span[];
|
|
63
|
+
/** Key-value attributes for this trace */
|
|
64
|
+
attributes: Record<string, string>;
|
|
65
|
+
/** For HTTP traces: endpoint like "GET /api/users" */
|
|
66
|
+
endpoint?: string;
|
|
67
|
+
/** For HTTP traces: response status code */
|
|
68
|
+
statusCode?: number;
|
|
69
|
+
/** For HTTP traces: response body size */
|
|
70
|
+
bodySize?: number;
|
|
71
|
+
/** For HTTP traces: client IP address */
|
|
72
|
+
clientIP?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Options for creating a new trace context.
|
|
76
|
+
*/
|
|
77
|
+
interface TraceContextOptions {
|
|
78
|
+
/** Custom trace ID (auto-generated if not provided) */
|
|
79
|
+
traceId?: string;
|
|
80
|
+
/** Mark as background task instead of HTTP trace */
|
|
81
|
+
isTask?: boolean;
|
|
82
|
+
/** Initial attributes */
|
|
83
|
+
attributes?: Record<string, string>;
|
|
84
|
+
/** HTTP endpoint (e.g., "GET /api/users") */
|
|
85
|
+
endpoint?: string;
|
|
86
|
+
/** Client IP address */
|
|
87
|
+
clientIP?: string;
|
|
88
|
+
}
|
|
89
|
+
declare const asyncLocalStorage: AsyncLocalStorage<TraceContext>;
|
|
90
|
+
/**
|
|
91
|
+
* Get the current trace context, if any.
|
|
92
|
+
* Returns undefined if not within a trace context.
|
|
93
|
+
*/
|
|
94
|
+
declare function getTraceContext(): TraceContext | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Get the current trace ID, if within a trace context.
|
|
97
|
+
*/
|
|
98
|
+
declare function getTraceId(): string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Check if currently within a trace context.
|
|
101
|
+
*/
|
|
102
|
+
declare function hasTraceContext(): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Run a function within a new trace context.
|
|
105
|
+
* All async operations within will have access to this context.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* // HTTP request handler
|
|
110
|
+
* withTraceContext({ endpoint: "GET /api/users", clientIP: req.ip }, async () => {
|
|
111
|
+
* const users = await db.query("SELECT * FROM users");
|
|
112
|
+
* captureException(new Error("oops")); // Auto-linked to trace
|
|
113
|
+
* return users;
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* // Background task
|
|
117
|
+
* withTraceContext({ isTask: true, endpoint: "process-emails" }, async () => {
|
|
118
|
+
* await processEmails();
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare function withTraceContext<T>(options: TraceContextOptions, fn: () => T): T;
|
|
123
|
+
/**
|
|
124
|
+
* Run a function within a trace context, automatically capturing the trace on completion.
|
|
125
|
+
* This is a convenience wrapper that handles timing and capture automatically.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* // In Express middleware
|
|
130
|
+
* app.use((req, res, next) => {
|
|
131
|
+
* runWithTraceContext(
|
|
132
|
+
* {
|
|
133
|
+
* endpoint: `${req.method} ${req.path}`,
|
|
134
|
+
* clientIP: req.ip,
|
|
135
|
+
* attributes: { userId: req.user?.id },
|
|
136
|
+
* },
|
|
137
|
+
* async () => {
|
|
138
|
+
* await next();
|
|
139
|
+
* // Status code and body size set via setTraceResponseInfo()
|
|
140
|
+
* },
|
|
141
|
+
* { captureOnEnd: true }
|
|
142
|
+
* );
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare function runWithTraceContext<T>(options: TraceContextOptions, fn: () => T | Promise<T>): T | Promise<T>;
|
|
147
|
+
/**
|
|
148
|
+
* Add a completed span to the current trace context.
|
|
149
|
+
* No-op if not within a trace context.
|
|
150
|
+
*/
|
|
151
|
+
declare function addSpanToContext(span: Span): void;
|
|
152
|
+
/**
|
|
153
|
+
* Set an attribute on the current trace context.
|
|
154
|
+
* No-op if not within a trace context.
|
|
155
|
+
*/
|
|
156
|
+
declare function setTraceAttribute(key: string, value: string): void;
|
|
157
|
+
/**
|
|
158
|
+
* Set multiple attributes on the current trace context.
|
|
159
|
+
* No-op if not within a trace context.
|
|
160
|
+
*/
|
|
161
|
+
declare function setTraceAttributes(attributes: Record<string, string>): void;
|
|
162
|
+
/**
|
|
163
|
+
* Set HTTP response info on the current trace context.
|
|
164
|
+
* Used by framework adapters after the response is sent.
|
|
165
|
+
*/
|
|
166
|
+
declare function setTraceResponseInfo(statusCode: number, bodySize?: number): void;
|
|
167
|
+
/**
|
|
168
|
+
* Get all spans from the current trace context.
|
|
169
|
+
* Returns empty array if not within a trace context.
|
|
170
|
+
*/
|
|
171
|
+
declare function getTraceSpans(): Span[];
|
|
172
|
+
/**
|
|
173
|
+
* Get the duration in milliseconds since the trace started.
|
|
174
|
+
* Returns 0 if not within a trace context.
|
|
175
|
+
*/
|
|
176
|
+
declare function getTraceDuration(): number;
|
|
177
|
+
/**
|
|
178
|
+
* Fork the current trace context for a sub-operation.
|
|
179
|
+
* Useful for parallel operations that should have isolated spans.
|
|
180
|
+
* Returns undefined if not within a trace context.
|
|
181
|
+
*/
|
|
182
|
+
declare function forkTraceContext<T>(fn: () => T): T | undefined;
|
|
183
|
+
|
|
184
|
+
declare function formatErrorStackTrace(error: Error): string;
|
|
185
|
+
|
|
186
|
+
declare function collectMetrics(): MetricRecord[];
|
|
187
|
+
declare function resetCpuTracking(): void;
|
|
188
|
+
|
|
189
|
+
interface CollectionFrameStoreOptions {
|
|
190
|
+
apiUrl: string;
|
|
191
|
+
token: string;
|
|
192
|
+
debug: boolean;
|
|
193
|
+
maxCollectionFrames: number;
|
|
194
|
+
collectionInterval: number;
|
|
195
|
+
uploadThrottle: number;
|
|
196
|
+
metricsInterval: number;
|
|
197
|
+
version: string;
|
|
198
|
+
serverName: string;
|
|
199
|
+
sampleRate: number;
|
|
200
|
+
errorSampleRate: number;
|
|
201
|
+
}
|
|
202
|
+
declare class CollectionFrameStore {
|
|
203
|
+
private current;
|
|
204
|
+
private currentSetAt;
|
|
205
|
+
private sendQueue;
|
|
206
|
+
private lastUploadStarted;
|
|
207
|
+
private collectionTimer;
|
|
208
|
+
private metricsTimer;
|
|
209
|
+
private readonly apiUrl;
|
|
210
|
+
private readonly token;
|
|
211
|
+
private readonly debug;
|
|
212
|
+
private readonly collectionInterval;
|
|
213
|
+
private readonly uploadThrottle;
|
|
214
|
+
private readonly metricsInterval;
|
|
215
|
+
private readonly version;
|
|
216
|
+
private readonly serverName;
|
|
217
|
+
readonly sampleRate: number;
|
|
218
|
+
readonly errorSampleRate: number;
|
|
219
|
+
constructor(options: CollectionFrameStoreOptions);
|
|
220
|
+
private tick;
|
|
221
|
+
private ensureCurrent;
|
|
222
|
+
addException(exception: ExceptionStackTrace): void;
|
|
223
|
+
addMetric(metric: MetricRecord): void;
|
|
224
|
+
addTrace(trace: Trace): void;
|
|
225
|
+
private rotateCurrentCollectionFrame;
|
|
226
|
+
private processSendQueue;
|
|
227
|
+
private triggerUpload;
|
|
228
|
+
private collectSystemMetrics;
|
|
229
|
+
shutdown(): Promise<void>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export { CollectionFrameStore, type CollectionFrameStoreOptions, type SpanHandle, type TraceContext, type TraceContextOptions, addSpanToContext, captureCurrentTrace, captureException, captureExceptionWithAttributes, captureMessage, captureMetric, captureTask, captureTrace, collectMetrics, endSpan, forkTraceContext, formatErrorStackTrace, getTraceContext, getTraceDuration, getTraceId, getTraceSpans, hasTraceContext, init, measureTask, resetCpuTracking, runWithTraceContext, setTraceAttribute, setTraceAttributes, setTraceResponseInfo, shouldSample, shutdown, startSpan, asyncLocalStorage as traceContextStorage, withTraceContext };
|