@tracewayapp/backend 0.2.0 → 1.0.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 +62 -304
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +36 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,225 +1,67 @@
|
|
|
1
1
|
# @tracewayapp/backend
|
|
2
2
|
|
|
3
|
-
Traceway SDK for Node.js backends.
|
|
3
|
+
Traceway SDK for Node.js backends. Provides error tracking, distributed tracing, span management, and metrics collection.
|
|
4
4
|
|
|
5
|
-
##
|
|
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
|
|
5
|
+
## Installation
|
|
31
6
|
|
|
32
|
-
|
|
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
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
7
|
+
```bash
|
|
8
|
+
npm install @tracewayapp/backend
|
|
67
9
|
```
|
|
68
10
|
|
|
69
|
-
|
|
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");
|
|
11
|
+
## Quick Start
|
|
77
12
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
init,
|
|
16
|
+
captureException,
|
|
17
|
+
withTraceContext,
|
|
18
|
+
startSpan,
|
|
19
|
+
endSpan,
|
|
20
|
+
captureCurrentTrace,
|
|
21
|
+
shutdown,
|
|
22
|
+
} from "@tracewayapp/backend";
|
|
23
|
+
|
|
24
|
+
// Initialize once at startup
|
|
25
|
+
init("your-token@https://traceway.example.com/api/report");
|
|
26
|
+
|
|
27
|
+
// Use trace context for HTTP requests
|
|
28
|
+
async function handleRequest(req, res) {
|
|
29
|
+
await withTraceContext(
|
|
30
|
+
{
|
|
31
|
+
endpoint: `${req.method} ${req.path}`,
|
|
32
|
+
clientIP: req.ip,
|
|
33
|
+
},
|
|
82
34
|
async () => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
35
|
+
try {
|
|
36
|
+
const dbSpan = startSpan("database-query");
|
|
37
|
+
const users = await db.query("SELECT * FROM users");
|
|
38
|
+
endSpan(dbSpan);
|
|
39
|
+
|
|
40
|
+
res.json(users);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
captureException(error);
|
|
43
|
+
res.status(500).json({ error: "Internal error" });
|
|
44
|
+
} finally {
|
|
45
|
+
captureCurrentTrace();
|
|
92
46
|
}
|
|
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
47
|
}
|
|
100
48
|
);
|
|
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
49
|
}
|
|
154
50
|
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
}
|
|
51
|
+
// Graceful shutdown
|
|
52
|
+
process.on("SIGTERM", async () => {
|
|
53
|
+
await shutdown();
|
|
54
|
+
process.exit(0);
|
|
169
55
|
});
|
|
170
56
|
```
|
|
171
57
|
|
|
172
|
-
|
|
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
|
|
58
|
+
## API
|
|
217
59
|
|
|
218
60
|
### Core Functions
|
|
219
61
|
|
|
220
62
|
| Function | Description |
|
|
221
63
|
|----------|-------------|
|
|
222
|
-
| `init(connectionString, options?)` | Initialize the SDK
|
|
64
|
+
| `init(connectionString, options?)` | Initialize the SDK |
|
|
223
65
|
| `shutdown()` | Stop timers, flush remaining data, and await final upload |
|
|
224
66
|
|
|
225
67
|
### Capture Functions
|
|
@@ -241,6 +83,23 @@ traceway.captureExceptionWithAttributes(err, {}, traceId);
|
|
|
241
83
|
| `startSpan(name)` | Start a span (returns `SpanHandle`) |
|
|
242
84
|
| `endSpan(span, addToContext?)` | End span (auto-adds to context by default) |
|
|
243
85
|
|
|
86
|
+
### Context API
|
|
87
|
+
|
|
88
|
+
| Function | Description |
|
|
89
|
+
|----------|-------------|
|
|
90
|
+
| `withTraceContext(options, fn)` | Run function within a new trace context |
|
|
91
|
+
| `runWithTraceContext(options, fn)` | Run function within a new trace context (alternative) |
|
|
92
|
+
| `getTraceContext()` | Get current context (or `undefined`) |
|
|
93
|
+
| `getTraceId()` | Get current trace ID (or `undefined`) |
|
|
94
|
+
| `hasTraceContext()` | Check if inside a trace context |
|
|
95
|
+
| `setTraceAttribute(key, value)` | Set attribute on current trace |
|
|
96
|
+
| `setTraceAttributes(attrs)` | Set multiple attributes |
|
|
97
|
+
| `setTraceResponseInfo(status, size?)` | Set HTTP response info |
|
|
98
|
+
| `addSpanToContext(span)` | Manually add a span |
|
|
99
|
+
| `getTraceSpans()` | Get all spans in current trace |
|
|
100
|
+
| `getTraceDuration()` | Get elapsed time in ms |
|
|
101
|
+
| `forkTraceContext(fn)` | Fork context for parallel ops |
|
|
102
|
+
|
|
244
103
|
### Utility Functions
|
|
245
104
|
|
|
246
105
|
| Function | Description |
|
|
@@ -248,28 +107,6 @@ traceway.captureExceptionWithAttributes(err, {}, traceId);
|
|
|
248
107
|
| `shouldSample(isError)` | Check if trace should be recorded |
|
|
249
108
|
| `measureTask(title, fn)` | Execute function as auto-captured task |
|
|
250
109
|
|
|
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
110
|
## Configuration Options
|
|
274
111
|
|
|
275
112
|
| Option | Type | Default | Description |
|
|
@@ -284,85 +121,6 @@ interface Span {
|
|
|
284
121
|
| `sampleRate` | `number` | `1.0` | Normal trace sampling rate (0.0-1.0) |
|
|
285
122
|
| `errorSampleRate` | `number` | `1.0` | Error trace sampling rate (0.0-1.0) |
|
|
286
123
|
|
|
287
|
-
##
|
|
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
|
|
124
|
+
## Requirements
|
|
362
125
|
|
|
363
|
-
|
|
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
|
|
126
|
+
- Node.js >= 18
|
package/dist/index.d.mts
CHANGED
|
@@ -45,7 +45,7 @@ declare function endSpan(span: SpanHandle, addToContext?: boolean): Span;
|
|
|
45
45
|
declare function captureCurrentTrace(): void;
|
|
46
46
|
declare function shouldSample(isError: boolean): boolean;
|
|
47
47
|
declare function measureTask(title: string, fn: () => void | Promise<void>): void;
|
|
48
|
-
declare function shutdown(): Promise<void>;
|
|
48
|
+
declare function shutdown(timeoutMs?: number): Promise<void>;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Trace context stored in AsyncLocalStorage.
|
|
@@ -226,7 +226,7 @@ declare class CollectionFrameStore {
|
|
|
226
226
|
private processSendQueue;
|
|
227
227
|
private triggerUpload;
|
|
228
228
|
private collectSystemMetrics;
|
|
229
|
-
shutdown(): Promise<void>;
|
|
229
|
+
shutdown(timeoutMs?: number): Promise<void>;
|
|
230
230
|
}
|
|
231
231
|
|
|
232
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ declare function endSpan(span: SpanHandle, addToContext?: boolean): Span;
|
|
|
45
45
|
declare function captureCurrentTrace(): void;
|
|
46
46
|
declare function shouldSample(isError: boolean): boolean;
|
|
47
47
|
declare function measureTask(title: string, fn: () => void | Promise<void>): void;
|
|
48
|
-
declare function shutdown(): Promise<void>;
|
|
48
|
+
declare function shutdown(timeoutMs?: number): Promise<void>;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Trace context stored in AsyncLocalStorage.
|
|
@@ -226,7 +226,7 @@ declare class CollectionFrameStore {
|
|
|
226
226
|
private processSendQueue;
|
|
227
227
|
private triggerUpload;
|
|
228
228
|
private collectSystemMetrics;
|
|
229
|
-
shutdown(): Promise<void>;
|
|
229
|
+
shutdown(timeoutMs?: number): Promise<void>;
|
|
230
230
|
}
|
|
231
231
|
|
|
232
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 };
|
package/dist/index.js
CHANGED
|
@@ -323,7 +323,7 @@ var CollectionFrameStore = class {
|
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
-
async shutdown() {
|
|
326
|
+
async shutdown(timeoutMs) {
|
|
327
327
|
if (this.collectionTimer !== null) {
|
|
328
328
|
clearInterval(this.collectionTimer);
|
|
329
329
|
this.collectionTimer = null;
|
|
@@ -335,30 +335,40 @@ var CollectionFrameStore = class {
|
|
|
335
335
|
this.rotateCurrentCollectionFrame();
|
|
336
336
|
const frames = this.sendQueue.readAll();
|
|
337
337
|
if (frames.length === 0) return;
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
338
|
+
const uploadPromise = (async () => {
|
|
339
|
+
const payload = {
|
|
340
|
+
collectionFrames: frames,
|
|
341
|
+
appVersion: this.version,
|
|
342
|
+
serverName: this.serverName
|
|
343
|
+
};
|
|
344
|
+
try {
|
|
345
|
+
const jsonData = JSON.stringify(payload);
|
|
346
|
+
const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));
|
|
347
|
+
const resp = await fetch(this.apiUrl, {
|
|
348
|
+
method: "POST",
|
|
349
|
+
headers: {
|
|
350
|
+
"Content-Type": "application/json",
|
|
351
|
+
"Content-Encoding": "gzip",
|
|
352
|
+
Authorization: `Bearer ${this.token}`
|
|
353
|
+
},
|
|
354
|
+
body: gzipped
|
|
355
|
+
});
|
|
356
|
+
if (resp.status === 200) {
|
|
357
|
+
this.sendQueue.remove(frames);
|
|
358
|
+
}
|
|
359
|
+
} catch (err) {
|
|
360
|
+
if (this.debug) {
|
|
361
|
+
console.error("Traceway: shutdown upload failed:", err);
|
|
362
|
+
}
|
|
361
363
|
}
|
|
364
|
+
})();
|
|
365
|
+
if (timeoutMs !== void 0) {
|
|
366
|
+
await Promise.race([
|
|
367
|
+
uploadPromise,
|
|
368
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs))
|
|
369
|
+
]);
|
|
370
|
+
} else {
|
|
371
|
+
await uploadPromise;
|
|
362
372
|
}
|
|
363
373
|
}
|
|
364
374
|
};
|
|
@@ -700,11 +710,11 @@ function measureTask(title, fn) {
|
|
|
700
710
|
throw err;
|
|
701
711
|
}
|
|
702
712
|
}
|
|
703
|
-
async function shutdown() {
|
|
713
|
+
async function shutdown(timeoutMs) {
|
|
704
714
|
if (!store) return;
|
|
705
715
|
const s = store;
|
|
706
716
|
store = null;
|
|
707
|
-
await s.shutdown();
|
|
717
|
+
await s.shutdown(timeoutMs);
|
|
708
718
|
}
|
|
709
719
|
// Annotate the CommonJS export names for ESM import in node:
|
|
710
720
|
0 && (module.exports = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/traceway.ts","../src/collection-frame-store.ts","../src/typed-ring.ts","../src/metrics.ts","../src/stack-trace.ts","../src/context.ts"],"sourcesContent":["export {\n init,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n captureMetric,\n captureTrace,\n captureTask,\n captureCurrentTrace,\n startSpan,\n endSpan,\n shouldSample,\n measureTask,\n shutdown,\n} from \"./traceway.js\";\nexport type { SpanHandle } from \"./traceway.js\";\n\n// Context propagation (AsyncLocalStorage-based)\nexport {\n withTraceContext,\n runWithTraceContext,\n getTraceContext,\n getTraceId,\n hasTraceContext,\n addSpanToContext,\n setTraceAttribute,\n setTraceAttributes,\n setTraceResponseInfo,\n getTraceSpans,\n getTraceDuration,\n forkTraceContext,\n traceContextStorage,\n} from \"./context.js\";\nexport type { TraceContext, TraceContextOptions } from \"./context.js\";\n\nexport { formatErrorStackTrace } from \"./stack-trace.js\";\nexport { collectMetrics, resetCpuTracking } from \"./metrics.js\";\nexport { CollectionFrameStore } from \"./collection-frame-store.js\";\nexport type { CollectionFrameStoreOptions } from \"./collection-frame-store.js\";\n\nexport type {\n ExceptionStackTrace,\n MetricRecord,\n Span,\n Trace,\n CollectionFrame,\n ReportRequest,\n TracewayOptions,\n} from \"@tracewayapp/core\";\n","import {\n generateUUID,\n parseConnectionString,\n nowISO,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport type {\n TracewayOptions,\n ExceptionStackTrace,\n Trace,\n Span,\n} from \"@tracewayapp/core\";\nimport { CollectionFrameStore } from \"./collection-frame-store.js\";\nimport { formatErrorStackTrace } from \"./stack-trace.js\";\nimport {\n getTraceContext,\n getTraceId,\n addSpanToContext,\n type TraceContext,\n} from \"./context.js\";\nimport * as os from \"os\";\n\nlet store: CollectionFrameStore | null = null;\n\nfunction getHostname(): string {\n try {\n const hostname = os.hostname();\n const dotIdx = hostname.indexOf(\".\");\n return dotIdx >= 0 ? hostname.slice(0, dotIdx) : hostname;\n } catch {\n return \"unknown\";\n }\n}\n\nexport function init(\n connectionString: string,\n options: TracewayOptions = {},\n): void {\n if (store !== null) {\n throw new Error(\"Traceway: already initialized. Call shutdown() first.\");\n }\n\n const { token, apiUrl } = parseConnectionString(connectionString);\n\n store = new CollectionFrameStore({\n apiUrl,\n token,\n debug: options.debug ?? false,\n maxCollectionFrames: options.maxCollectionFrames ?? 12,\n collectionInterval: options.collectionInterval ?? 5000,\n uploadThrottle: options.uploadThrottle ?? 2000,\n metricsInterval: options.metricsInterval ?? 30000,\n version: options.version ?? \"\",\n serverName: options.serverName ?? getHostname(),\n sampleRate: options.sampleRate ?? 1,\n errorSampleRate: options.errorSampleRate ?? 1,\n });\n}\n\nexport function captureException(error: Error): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n captureExceptionWithAttributes(\n error,\n ctx?.attributes,\n ctx?.traceId,\n );\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n): void {\n if (!store) return;\n // Auto-detect trace context if not explicitly provided\n const ctx = getTraceContext();\n const resolvedTraceId = traceId ?? ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: formatErrorStackTrace(error),\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: false,\n });\n}\n\nexport function captureMessage(\n msg: string,\n attributes?: Record<string, string>,\n): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n const resolvedTraceId = ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: msg,\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: true,\n });\n}\n\nexport function captureMetric(name: string, value: number): void {\n if (!store) return;\n store.addMetric({\n name,\n value,\n recordedAt: nowISO(),\n });\n}\n\nexport function captureTrace(\n traceId: string,\n endpoint: string,\n durationMs: number,\n startedAt: Date,\n statusCode: number,\n bodySize: number,\n clientIP: string,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode,\n bodySize,\n clientIP,\n attributes,\n spans,\n });\n}\n\nexport function captureTask(\n traceId: string,\n taskName: string,\n durationMs: number,\n startedAt: Date,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint: taskName,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes,\n spans,\n isTask: true,\n });\n}\n\n/** Handle returned by startSpan for tracking span timing */\nexport interface SpanHandle {\n id: string;\n name: string;\n startTime: string;\n startedAt: number;\n}\n\n/**\n * Start a new span. If within a trace context, the span will be\n * automatically added to the trace when ended.\n */\nexport function startSpan(name: string): SpanHandle {\n const now = Date.now();\n return {\n id: generateUUID(),\n name,\n startTime: new Date(now).toISOString(),\n startedAt: now,\n };\n}\n\n/**\n * End a span and get the completed Span object.\n * If within a trace context, automatically adds the span to the trace.\n *\n * @param addToContext - If true (default), adds span to current trace context\n */\nexport function endSpan(span: SpanHandle, addToContext: boolean = true): Span {\n const durationMs = Date.now() - span.startedAt;\n const completedSpan: Span = {\n id: span.id,\n name: span.name,\n startTime: span.startTime,\n duration: msToNanoseconds(durationMs),\n };\n\n // Auto-add to trace context if available\n if (addToContext) {\n addSpanToContext(completedSpan);\n }\n\n return completedSpan;\n}\n\n/**\n * Capture the current trace context as a trace.\n * Call this at the end of a request/task to record the trace.\n *\n * @example\n * ```ts\n * // In Express middleware (after response)\n * withTraceContext({ endpoint: `${req.method} ${req.path}` }, async () => {\n * await handleRequest(req, res);\n * setTraceResponseInfo(res.statusCode, contentLength);\n * captureCurrentTrace(); // Records the trace with all spans\n * });\n * ```\n */\nexport function captureCurrentTrace(): void {\n if (!store) return;\n\n const ctx = getTraceContext();\n if (!ctx) return;\n\n const durationMs = Date.now() - ctx.startedAt.getTime();\n const isError = (ctx.statusCode ?? 0) >= 500;\n\n if (!shouldSample(isError)) return;\n\n if (ctx.isTask) {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown-task\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n isTask: true,\n });\n } else {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: ctx.statusCode ?? 0,\n bodySize: ctx.bodySize ?? 0,\n clientIP: ctx.clientIP ?? \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n });\n }\n}\n\nexport function shouldSample(isError: boolean): boolean {\n if (!store) return false;\n const rate = isError ? store.errorSampleRate : store.sampleRate;\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n return Math.random() < rate;\n}\n\nexport function measureTask(\n title: string,\n fn: () => void | Promise<void>,\n): void {\n const traceId = generateUUID();\n const start = Date.now();\n const startDate = new Date(start);\n\n try {\n const result = fn();\n if (result && typeof (result as Promise<void>).then === \"function\") {\n (result as Promise<void>)\n .then(() => {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n })\n .catch((err: unknown) => {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n });\n } else {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n }\n } catch (err) {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n }\n}\n\nexport async function shutdown(): Promise<void> {\n if (!store) return;\n const s = store;\n store = null;\n await s.shutdown();\n}\n","import * as zlib from \"zlib\";\nimport {\n nowISO,\n generateUUID,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport { TypedRing } from \"./typed-ring.js\";\nimport type {\n CollectionFrame,\n ExceptionStackTrace,\n MetricRecord,\n Trace,\n Span,\n ReportRequest,\n} from \"@tracewayapp/core\";\nimport { collectMetrics } from \"./metrics.js\";\n\nexport interface CollectionFrameStoreOptions {\n apiUrl: string;\n token: string;\n debug: boolean;\n maxCollectionFrames: number;\n collectionInterval: number;\n uploadThrottle: number;\n metricsInterval: number;\n version: string;\n serverName: string;\n sampleRate: number;\n errorSampleRate: number;\n}\n\nexport class CollectionFrameStore {\n private current: CollectionFrame | null = null;\n private currentSetAt: number = Date.now();\n private sendQueue: TypedRing<CollectionFrame>;\n private lastUploadStarted: number | null = null;\n\n private collectionTimer: ReturnType<typeof setInterval> | null = null;\n private metricsTimer: ReturnType<typeof setInterval> | null = null;\n\n private readonly apiUrl: string;\n private readonly token: string;\n private readonly debug: boolean;\n private readonly collectionInterval: number;\n private readonly uploadThrottle: number;\n private readonly metricsInterval: number;\n private readonly version: string;\n private readonly serverName: string;\n\n readonly sampleRate: number;\n readonly errorSampleRate: number;\n\n constructor(options: CollectionFrameStoreOptions) {\n this.apiUrl = options.apiUrl;\n this.token = options.token;\n this.debug = options.debug;\n this.collectionInterval = options.collectionInterval;\n this.uploadThrottle = options.uploadThrottle;\n this.metricsInterval = options.metricsInterval;\n this.version = options.version;\n this.serverName = options.serverName;\n this.sampleRate = options.sampleRate;\n this.errorSampleRate = options.errorSampleRate;\n this.sendQueue = new TypedRing<CollectionFrame>(\n options.maxCollectionFrames,\n );\n\n this.collectionTimer = setInterval(() => {\n this.tick();\n }, this.collectionInterval);\n if (this.collectionTimer && typeof this.collectionTimer.unref === \"function\") {\n this.collectionTimer.unref();\n }\n\n this.metricsTimer = setInterval(() => {\n this.collectSystemMetrics();\n }, this.metricsInterval);\n if (this.metricsTimer && typeof this.metricsTimer.unref === \"function\") {\n this.metricsTimer.unref();\n }\n }\n\n private tick(): void {\n if (this.current !== null) {\n if (this.currentSetAt < Date.now() - this.collectionInterval) {\n this.rotateCurrentCollectionFrame();\n this.processSendQueue();\n }\n } else if (this.sendQueue.length > 0) {\n this.processSendQueue();\n }\n }\n\n private ensureCurrent(): CollectionFrame {\n if (this.current === null) {\n this.current = { stackTraces: [], metrics: [], traces: [] };\n this.currentSetAt = Date.now();\n }\n return this.current;\n }\n\n addException(exception: ExceptionStackTrace): void {\n this.ensureCurrent().stackTraces.push(exception);\n }\n\n addMetric(metric: MetricRecord): void {\n this.ensureCurrent().metrics.push(metric);\n }\n\n addTrace(trace: Trace): void {\n this.ensureCurrent().traces.push(trace);\n }\n\n private rotateCurrentCollectionFrame(): void {\n if (this.current !== null) {\n this.sendQueue.push(this.current);\n this.current = null;\n }\n }\n\n private processSendQueue(): void {\n if (\n this.lastUploadStarted === null ||\n this.lastUploadStarted < Date.now() - this.uploadThrottle\n ) {\n this.lastUploadStarted = Date.now();\n const frames = this.sendQueue.readAll();\n if (frames.length > 0) {\n this.triggerUpload(frames);\n }\n }\n }\n\n private triggerUpload(framesToSend: CollectionFrame[]): void {\n const payload: ReportRequest = {\n collectionFrames: framesToSend,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n let jsonData: string;\n try {\n jsonData = JSON.stringify(payload);\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to serialize frames:\", err);\n }\n return;\n }\n\n let gzipped: Uint8Array;\n try {\n gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to gzip:\", err);\n }\n return;\n }\n\n fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n })\n .then((resp) => {\n if (resp.status === 200) {\n this.sendQueue.remove(framesToSend);\n } else if (this.debug) {\n console.error(`Traceway: upload returned status ${resp.status}`);\n }\n })\n .catch((err) => {\n if (this.debug) {\n console.error(\"Traceway: upload failed:\", err);\n }\n });\n }\n\n private collectSystemMetrics(): void {\n try {\n const metrics = collectMetrics();\n for (const metric of metrics) {\n this.addMetric(metric);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to collect metrics:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.collectionTimer !== null) {\n clearInterval(this.collectionTimer);\n this.collectionTimer = null;\n }\n if (this.metricsTimer !== null) {\n clearInterval(this.metricsTimer);\n this.metricsTimer = null;\n }\n\n this.rotateCurrentCollectionFrame();\n\n const frames = this.sendQueue.readAll();\n if (frames.length === 0) return;\n\n const payload: ReportRequest = {\n collectionFrames: frames,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n try {\n const jsonData = JSON.stringify(payload);\n const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n\n const resp = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n });\n\n if (resp.status === 200) {\n this.sendQueue.remove(frames);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: shutdown upload failed:\", err);\n }\n }\n }\n}\n","export class TypedRing<T> {\n private arr: (T | null)[];\n private head: number = 0;\n private _capacity: number;\n private _len: number = 0;\n\n constructor(capacity: number) {\n this._capacity = capacity;\n this.arr = new Array<T | null>(capacity).fill(null);\n }\n\n get length(): number {\n return this._len;\n }\n\n get capacity(): number {\n return this._capacity;\n }\n\n push(val: T): void {\n this.arr[this.head] = val;\n this.head = (this.head + 1) % this._capacity;\n if (this._len < this._capacity) {\n this._len += 1;\n }\n }\n\n readAll(): T[] {\n const result: T[] = [];\n for (let i = 0; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n result.push(this.arr[idx] as T);\n }\n return result;\n }\n\n clear(): void {\n for (let i = 0; i < this.arr.length; i++) {\n this.arr[i] = null;\n }\n this.head = 0;\n this._len = 0;\n }\n\n remove(vals: T[]): number {\n if (vals.length === 0) return 0;\n\n const toRemove = new Set<T>(vals);\n let writeIdx = 0;\n let removed = 0;\n\n for (let i = 0; i < this._len; i++) {\n const readIdx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n if (toRemove.has(this.arr[readIdx] as T)) {\n removed++;\n } else {\n if (writeIdx !== i) {\n const destIdx =\n (this.head - this._len + writeIdx + this._capacity) %\n this._capacity;\n this.arr[destIdx] = this.arr[readIdx];\n }\n writeIdx++;\n }\n }\n\n for (let i = writeIdx; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n this.arr[idx] = null;\n }\n\n this._len = writeIdx;\n this.head = (this.head - removed + this._capacity) % this._capacity;\n\n return removed;\n }\n}\n","import * as os from \"os\";\nimport { METRIC_MEM_USED, METRIC_MEM_TOTAL, METRIC_CPU_USED_PCNT } from \"@tracewayapp/core\";\nimport type { MetricRecord } from \"@tracewayapp/core\";\nimport { nowISO } from \"@tracewayapp/core\";\n\nlet prevCpuUsage: NodeJS.CpuUsage | null = null;\nlet prevCpuTime: number | null = null;\n\nexport function collectMetrics(): MetricRecord[] {\n const metrics: MetricRecord[] = [];\n const recordedAt = nowISO();\n\n const mem = process.memoryUsage();\n metrics.push({\n name: METRIC_MEM_USED,\n value: Math.round((mem.rss / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const totalMem = os.totalmem();\n metrics.push({\n name: METRIC_MEM_TOTAL,\n value: Math.round((totalMem / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const currentCpuUsage = process.cpuUsage();\n const currentTime = Date.now();\n if (prevCpuUsage !== null && prevCpuTime !== null) {\n const elapsedMs = currentTime - prevCpuTime;\n if (elapsedMs > 0) {\n const userDelta = currentCpuUsage.user - prevCpuUsage.user;\n const systemDelta = currentCpuUsage.system - prevCpuUsage.system;\n const totalDeltaMs = (userDelta + systemDelta) / 1000;\n const cpuCount = os.cpus().length || 1;\n const cpuPercent = (totalDeltaMs / elapsedMs / cpuCount) * 100;\n metrics.push({\n name: METRIC_CPU_USED_PCNT,\n value: Math.round(cpuPercent * 100) / 100,\n recordedAt,\n });\n }\n }\n prevCpuUsage = currentCpuUsage;\n prevCpuTime = currentTime;\n\n return metrics;\n}\n\nexport function resetCpuTracking(): void {\n prevCpuUsage = null;\n prevCpuTime = null;\n}\n","export function formatErrorStackTrace(error: Error): string {\n const lines: string[] = [];\n\n const typeName = error.constructor.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n const match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):\\d+\\)$/);\n if (match) {\n const funcName = shortenFunctionName(match[1]);\n const file = shortenFilePath(match[2]);\n const lineNum = match[3];\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchNoParens = line.match(/^\\s+at\\s+(.+):(\\d+):\\d+$/);\n if (matchNoParens) {\n const file = shortenFilePath(matchNoParens[1]);\n const lineNum = matchNoParens[2];\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchFnOnly = line.match(/^\\s+at\\s+(.+)$/);\n if (matchFnOnly) {\n const funcName = shortenFunctionName(matchFnOnly[1]);\n lines.push(`${funcName}()`);\n lines.push(` <unknown>:0`);\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import { AsyncLocalStorage } from \"async_hooks\";\nimport { generateUUID } from \"@tracewayapp/core\";\nimport type { Span } from \"@tracewayapp/core\";\n\n/**\n * Trace context stored in AsyncLocalStorage.\n * Automatically propagates through async operations.\n */\nexport interface TraceContext {\n /** Unique trace identifier (UUID v4) */\n traceId: string;\n /** Whether this is a background task (vs HTTP request) */\n isTask: boolean;\n /** When the trace started */\n startedAt: Date;\n /** Collected spans within this trace */\n spans: Span[];\n /** Key-value attributes for this trace */\n attributes: Record<string, string>;\n /** For HTTP traces: endpoint like \"GET /api/users\" */\n endpoint?: string;\n /** For HTTP traces: response status code */\n statusCode?: number;\n /** For HTTP traces: response body size */\n bodySize?: number;\n /** For HTTP traces: client IP address */\n clientIP?: string;\n}\n\n/**\n * Options for creating a new trace context.\n */\nexport interface TraceContextOptions {\n /** Custom trace ID (auto-generated if not provided) */\n traceId?: string;\n /** Mark as background task instead of HTTP trace */\n isTask?: boolean;\n /** Initial attributes */\n attributes?: Record<string, string>;\n /** HTTP endpoint (e.g., \"GET /api/users\") */\n endpoint?: string;\n /** Client IP address */\n clientIP?: string;\n}\n\n// The AsyncLocalStorage instance for trace context\nconst asyncLocalStorage = new AsyncLocalStorage<TraceContext>();\n\n/**\n * Get the current trace context, if any.\n * Returns undefined if not within a trace context.\n */\nexport function getTraceContext(): TraceContext | undefined {\n return asyncLocalStorage.getStore();\n}\n\n/**\n * Get the current trace ID, if within a trace context.\n */\nexport function getTraceId(): string | undefined {\n return asyncLocalStorage.getStore()?.traceId;\n}\n\n/**\n * Check if currently within a trace context.\n */\nexport function hasTraceContext(): boolean {\n return asyncLocalStorage.getStore() !== undefined;\n}\n\n/**\n * Run a function within a new trace context.\n * All async operations within will have access to this context.\n *\n * @example\n * ```ts\n * // HTTP request handler\n * withTraceContext({ endpoint: \"GET /api/users\", clientIP: req.ip }, async () => {\n * const users = await db.query(\"SELECT * FROM users\");\n * captureException(new Error(\"oops\")); // Auto-linked to trace\n * return users;\n * });\n *\n * // Background task\n * withTraceContext({ isTask: true, endpoint: \"process-emails\" }, async () => {\n * await processEmails();\n * });\n * ```\n */\nexport function withTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T,\n): T {\n const context: TraceContext = {\n traceId: options.traceId ?? generateUUID(),\n isTask: options.isTask ?? false,\n startedAt: new Date(),\n spans: [],\n attributes: options.attributes ?? {},\n endpoint: options.endpoint,\n clientIP: options.clientIP,\n };\n return asyncLocalStorage.run(context, fn);\n}\n\n/**\n * Run a function within a trace context, automatically capturing the trace on completion.\n * This is a convenience wrapper that handles timing and capture automatically.\n *\n * @example\n * ```ts\n * // In Express middleware\n * app.use((req, res, next) => {\n * runWithTraceContext(\n * {\n * endpoint: `${req.method} ${req.path}`,\n * clientIP: req.ip,\n * attributes: { userId: req.user?.id },\n * },\n * async () => {\n * await next();\n * // Status code and body size set via setTraceResponseInfo()\n * },\n * { captureOnEnd: true }\n * );\n * });\n * ```\n */\nexport function runWithTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return withTraceContext(options, fn);\n}\n\n/**\n * Add a completed span to the current trace context.\n * No-op if not within a trace context.\n */\nexport function addSpanToContext(span: Span): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.spans.push(span);\n }\n}\n\n/**\n * Set an attribute on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttribute(key: string, value: string): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.attributes[key] = value;\n }\n}\n\n/**\n * Set multiple attributes on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttributes(attributes: Record<string, string>): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n Object.assign(ctx.attributes, attributes);\n }\n}\n\n/**\n * Set HTTP response info on the current trace context.\n * Used by framework adapters after the response is sent.\n */\nexport function setTraceResponseInfo(\n statusCode: number,\n bodySize?: number,\n): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.statusCode = statusCode;\n ctx.bodySize = bodySize;\n }\n}\n\n/**\n * Get all spans from the current trace context.\n * Returns empty array if not within a trace context.\n */\nexport function getTraceSpans(): Span[] {\n return asyncLocalStorage.getStore()?.spans ?? [];\n}\n\n/**\n * Get the duration in milliseconds since the trace started.\n * Returns 0 if not within a trace context.\n */\nexport function getTraceDuration(): number {\n const ctx = asyncLocalStorage.getStore();\n if (!ctx) return 0;\n return Date.now() - ctx.startedAt.getTime();\n}\n\n/**\n * Fork the current trace context for a sub-operation.\n * Useful for parallel operations that should have isolated spans.\n * Returns undefined if not within a trace context.\n */\nexport function forkTraceContext<T>(fn: () => T): T | undefined {\n const parentCtx = asyncLocalStorage.getStore();\n if (!parentCtx) return undefined;\n\n const forkedContext: TraceContext = {\n ...parentCtx,\n spans: [], // Forked context gets its own spans\n attributes: { ...parentCtx.attributes },\n };\n\n return asyncLocalStorage.run(forkedContext, () => {\n const result = fn();\n // Merge spans back to parent after completion\n parentCtx.spans.push(...forkedContext.spans);\n return result;\n });\n}\n\n// Export the AsyncLocalStorage instance for advanced use cases\nexport { asyncLocalStorage as traceContextStorage };\n"],"mappings":"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","names":["import_core","import_core","import_core","os","hostname"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/traceway.ts","../src/collection-frame-store.ts","../src/typed-ring.ts","../src/metrics.ts","../src/stack-trace.ts","../src/context.ts"],"sourcesContent":["export {\n init,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n captureMetric,\n captureTrace,\n captureTask,\n captureCurrentTrace,\n startSpan,\n endSpan,\n shouldSample,\n measureTask,\n shutdown,\n} from \"./traceway.js\";\nexport type { SpanHandle } from \"./traceway.js\";\n\n// Context propagation (AsyncLocalStorage-based)\nexport {\n withTraceContext,\n runWithTraceContext,\n getTraceContext,\n getTraceId,\n hasTraceContext,\n addSpanToContext,\n setTraceAttribute,\n setTraceAttributes,\n setTraceResponseInfo,\n getTraceSpans,\n getTraceDuration,\n forkTraceContext,\n traceContextStorage,\n} from \"./context.js\";\nexport type { TraceContext, TraceContextOptions } from \"./context.js\";\n\nexport { formatErrorStackTrace } from \"./stack-trace.js\";\nexport { collectMetrics, resetCpuTracking } from \"./metrics.js\";\nexport { CollectionFrameStore } from \"./collection-frame-store.js\";\nexport type { CollectionFrameStoreOptions } from \"./collection-frame-store.js\";\n\nexport type {\n ExceptionStackTrace,\n MetricRecord,\n Span,\n Trace,\n CollectionFrame,\n ReportRequest,\n TracewayOptions,\n} from \"@tracewayapp/core\";\n","import {\n generateUUID,\n parseConnectionString,\n nowISO,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport type {\n TracewayOptions,\n ExceptionStackTrace,\n Trace,\n Span,\n} from \"@tracewayapp/core\";\nimport { CollectionFrameStore } from \"./collection-frame-store.js\";\nimport { formatErrorStackTrace } from \"./stack-trace.js\";\nimport {\n getTraceContext,\n getTraceId,\n addSpanToContext,\n type TraceContext,\n} from \"./context.js\";\nimport * as os from \"os\";\n\nlet store: CollectionFrameStore | null = null;\n\nfunction getHostname(): string {\n try {\n const hostname = os.hostname();\n const dotIdx = hostname.indexOf(\".\");\n return dotIdx >= 0 ? hostname.slice(0, dotIdx) : hostname;\n } catch {\n return \"unknown\";\n }\n}\n\nexport function init(\n connectionString: string,\n options: TracewayOptions = {},\n): void {\n if (store !== null) {\n throw new Error(\"Traceway: already initialized. Call shutdown() first.\");\n }\n\n const { token, apiUrl } = parseConnectionString(connectionString);\n\n store = new CollectionFrameStore({\n apiUrl,\n token,\n debug: options.debug ?? false,\n maxCollectionFrames: options.maxCollectionFrames ?? 12,\n collectionInterval: options.collectionInterval ?? 5000,\n uploadThrottle: options.uploadThrottle ?? 2000,\n metricsInterval: options.metricsInterval ?? 30000,\n version: options.version ?? \"\",\n serverName: options.serverName ?? getHostname(),\n sampleRate: options.sampleRate ?? 1,\n errorSampleRate: options.errorSampleRate ?? 1,\n });\n}\n\nexport function captureException(error: Error): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n captureExceptionWithAttributes(\n error,\n ctx?.attributes,\n ctx?.traceId,\n );\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n): void {\n if (!store) return;\n // Auto-detect trace context if not explicitly provided\n const ctx = getTraceContext();\n const resolvedTraceId = traceId ?? ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: formatErrorStackTrace(error),\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: false,\n });\n}\n\nexport function captureMessage(\n msg: string,\n attributes?: Record<string, string>,\n): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n const resolvedTraceId = ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: msg,\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: true,\n });\n}\n\nexport function captureMetric(name: string, value: number): void {\n if (!store) return;\n store.addMetric({\n name,\n value,\n recordedAt: nowISO(),\n });\n}\n\nexport function captureTrace(\n traceId: string,\n endpoint: string,\n durationMs: number,\n startedAt: Date,\n statusCode: number,\n bodySize: number,\n clientIP: string,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode,\n bodySize,\n clientIP,\n attributes,\n spans,\n });\n}\n\nexport function captureTask(\n traceId: string,\n taskName: string,\n durationMs: number,\n startedAt: Date,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint: taskName,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes,\n spans,\n isTask: true,\n });\n}\n\n/** Handle returned by startSpan for tracking span timing */\nexport interface SpanHandle {\n id: string;\n name: string;\n startTime: string;\n startedAt: number;\n}\n\n/**\n * Start a new span. If within a trace context, the span will be\n * automatically added to the trace when ended.\n */\nexport function startSpan(name: string): SpanHandle {\n const now = Date.now();\n return {\n id: generateUUID(),\n name,\n startTime: new Date(now).toISOString(),\n startedAt: now,\n };\n}\n\n/**\n * End a span and get the completed Span object.\n * If within a trace context, automatically adds the span to the trace.\n *\n * @param addToContext - If true (default), adds span to current trace context\n */\nexport function endSpan(span: SpanHandle, addToContext: boolean = true): Span {\n const durationMs = Date.now() - span.startedAt;\n const completedSpan: Span = {\n id: span.id,\n name: span.name,\n startTime: span.startTime,\n duration: msToNanoseconds(durationMs),\n };\n\n // Auto-add to trace context if available\n if (addToContext) {\n addSpanToContext(completedSpan);\n }\n\n return completedSpan;\n}\n\n/**\n * Capture the current trace context as a trace.\n * Call this at the end of a request/task to record the trace.\n *\n * @example\n * ```ts\n * // In Express middleware (after response)\n * withTraceContext({ endpoint: `${req.method} ${req.path}` }, async () => {\n * await handleRequest(req, res);\n * setTraceResponseInfo(res.statusCode, contentLength);\n * captureCurrentTrace(); // Records the trace with all spans\n * });\n * ```\n */\nexport function captureCurrentTrace(): void {\n if (!store) return;\n\n const ctx = getTraceContext();\n if (!ctx) return;\n\n const durationMs = Date.now() - ctx.startedAt.getTime();\n const isError = (ctx.statusCode ?? 0) >= 500;\n\n if (!shouldSample(isError)) return;\n\n if (ctx.isTask) {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown-task\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n isTask: true,\n });\n } else {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: ctx.statusCode ?? 0,\n bodySize: ctx.bodySize ?? 0,\n clientIP: ctx.clientIP ?? \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n });\n }\n}\n\nexport function shouldSample(isError: boolean): boolean {\n if (!store) return false;\n const rate = isError ? store.errorSampleRate : store.sampleRate;\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n return Math.random() < rate;\n}\n\nexport function measureTask(\n title: string,\n fn: () => void | Promise<void>,\n): void {\n const traceId = generateUUID();\n const start = Date.now();\n const startDate = new Date(start);\n\n try {\n const result = fn();\n if (result && typeof (result as Promise<void>).then === \"function\") {\n (result as Promise<void>)\n .then(() => {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n })\n .catch((err: unknown) => {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n });\n } else {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n }\n } catch (err) {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n }\n}\n\nexport async function shutdown(timeoutMs?: number): Promise<void> {\n if (!store) return;\n const s = store;\n store = null;\n await s.shutdown(timeoutMs);\n}\n","import * as zlib from \"zlib\";\nimport {\n nowISO,\n generateUUID,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport { TypedRing } from \"./typed-ring.js\";\nimport type {\n CollectionFrame,\n ExceptionStackTrace,\n MetricRecord,\n Trace,\n Span,\n ReportRequest,\n} from \"@tracewayapp/core\";\nimport { collectMetrics } from \"./metrics.js\";\n\nexport interface CollectionFrameStoreOptions {\n apiUrl: string;\n token: string;\n debug: boolean;\n maxCollectionFrames: number;\n collectionInterval: number;\n uploadThrottle: number;\n metricsInterval: number;\n version: string;\n serverName: string;\n sampleRate: number;\n errorSampleRate: number;\n}\n\nexport class CollectionFrameStore {\n private current: CollectionFrame | null = null;\n private currentSetAt: number = Date.now();\n private sendQueue: TypedRing<CollectionFrame>;\n private lastUploadStarted: number | null = null;\n\n private collectionTimer: ReturnType<typeof setInterval> | null = null;\n private metricsTimer: ReturnType<typeof setInterval> | null = null;\n\n private readonly apiUrl: string;\n private readonly token: string;\n private readonly debug: boolean;\n private readonly collectionInterval: number;\n private readonly uploadThrottle: number;\n private readonly metricsInterval: number;\n private readonly version: string;\n private readonly serverName: string;\n\n readonly sampleRate: number;\n readonly errorSampleRate: number;\n\n constructor(options: CollectionFrameStoreOptions) {\n this.apiUrl = options.apiUrl;\n this.token = options.token;\n this.debug = options.debug;\n this.collectionInterval = options.collectionInterval;\n this.uploadThrottle = options.uploadThrottle;\n this.metricsInterval = options.metricsInterval;\n this.version = options.version;\n this.serverName = options.serverName;\n this.sampleRate = options.sampleRate;\n this.errorSampleRate = options.errorSampleRate;\n this.sendQueue = new TypedRing<CollectionFrame>(\n options.maxCollectionFrames,\n );\n\n this.collectionTimer = setInterval(() => {\n this.tick();\n }, this.collectionInterval);\n if (this.collectionTimer && typeof this.collectionTimer.unref === \"function\") {\n this.collectionTimer.unref();\n }\n\n this.metricsTimer = setInterval(() => {\n this.collectSystemMetrics();\n }, this.metricsInterval);\n if (this.metricsTimer && typeof this.metricsTimer.unref === \"function\") {\n this.metricsTimer.unref();\n }\n }\n\n private tick(): void {\n if (this.current !== null) {\n if (this.currentSetAt < Date.now() - this.collectionInterval) {\n this.rotateCurrentCollectionFrame();\n this.processSendQueue();\n }\n } else if (this.sendQueue.length > 0) {\n this.processSendQueue();\n }\n }\n\n private ensureCurrent(): CollectionFrame {\n if (this.current === null) {\n this.current = { stackTraces: [], metrics: [], traces: [] };\n this.currentSetAt = Date.now();\n }\n return this.current;\n }\n\n addException(exception: ExceptionStackTrace): void {\n this.ensureCurrent().stackTraces.push(exception);\n }\n\n addMetric(metric: MetricRecord): void {\n this.ensureCurrent().metrics.push(metric);\n }\n\n addTrace(trace: Trace): void {\n this.ensureCurrent().traces.push(trace);\n }\n\n private rotateCurrentCollectionFrame(): void {\n if (this.current !== null) {\n this.sendQueue.push(this.current);\n this.current = null;\n }\n }\n\n private processSendQueue(): void {\n if (\n this.lastUploadStarted === null ||\n this.lastUploadStarted < Date.now() - this.uploadThrottle\n ) {\n this.lastUploadStarted = Date.now();\n const frames = this.sendQueue.readAll();\n if (frames.length > 0) {\n this.triggerUpload(frames);\n }\n }\n }\n\n private triggerUpload(framesToSend: CollectionFrame[]): void {\n const payload: ReportRequest = {\n collectionFrames: framesToSend,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n let jsonData: string;\n try {\n jsonData = JSON.stringify(payload);\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to serialize frames:\", err);\n }\n return;\n }\n\n let gzipped: Uint8Array;\n try {\n gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to gzip:\", err);\n }\n return;\n }\n\n fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n })\n .then((resp) => {\n if (resp.status === 200) {\n this.sendQueue.remove(framesToSend);\n } else if (this.debug) {\n console.error(`Traceway: upload returned status ${resp.status}`);\n }\n })\n .catch((err) => {\n if (this.debug) {\n console.error(\"Traceway: upload failed:\", err);\n }\n });\n }\n\n private collectSystemMetrics(): void {\n try {\n const metrics = collectMetrics();\n for (const metric of metrics) {\n this.addMetric(metric);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to collect metrics:\", err);\n }\n }\n }\n\n async shutdown(timeoutMs?: number): Promise<void> {\n if (this.collectionTimer !== null) {\n clearInterval(this.collectionTimer);\n this.collectionTimer = null;\n }\n if (this.metricsTimer !== null) {\n clearInterval(this.metricsTimer);\n this.metricsTimer = null;\n }\n\n this.rotateCurrentCollectionFrame();\n\n const frames = this.sendQueue.readAll();\n if (frames.length === 0) return;\n\n const uploadPromise = (async () => {\n const payload: ReportRequest = {\n collectionFrames: frames,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n try {\n const jsonData = JSON.stringify(payload);\n const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n\n const resp = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n });\n\n if (resp.status === 200) {\n this.sendQueue.remove(frames);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: shutdown upload failed:\", err);\n }\n }\n })();\n\n if (timeoutMs !== undefined) {\n await Promise.race([\n uploadPromise,\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\n ]);\n } else {\n await uploadPromise;\n }\n }\n}\n","export class TypedRing<T> {\n private arr: (T | null)[];\n private head: number = 0;\n private _capacity: number;\n private _len: number = 0;\n\n constructor(capacity: number) {\n this._capacity = capacity;\n this.arr = new Array<T | null>(capacity).fill(null);\n }\n\n get length(): number {\n return this._len;\n }\n\n get capacity(): number {\n return this._capacity;\n }\n\n push(val: T): void {\n this.arr[this.head] = val;\n this.head = (this.head + 1) % this._capacity;\n if (this._len < this._capacity) {\n this._len += 1;\n }\n }\n\n readAll(): T[] {\n const result: T[] = [];\n for (let i = 0; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n result.push(this.arr[idx] as T);\n }\n return result;\n }\n\n clear(): void {\n for (let i = 0; i < this.arr.length; i++) {\n this.arr[i] = null;\n }\n this.head = 0;\n this._len = 0;\n }\n\n remove(vals: T[]): number {\n if (vals.length === 0) return 0;\n\n const toRemove = new Set<T>(vals);\n let writeIdx = 0;\n let removed = 0;\n\n for (let i = 0; i < this._len; i++) {\n const readIdx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n if (toRemove.has(this.arr[readIdx] as T)) {\n removed++;\n } else {\n if (writeIdx !== i) {\n const destIdx =\n (this.head - this._len + writeIdx + this._capacity) %\n this._capacity;\n this.arr[destIdx] = this.arr[readIdx];\n }\n writeIdx++;\n }\n }\n\n for (let i = writeIdx; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n this.arr[idx] = null;\n }\n\n this._len = writeIdx;\n this.head = (this.head - removed + this._capacity) % this._capacity;\n\n return removed;\n }\n}\n","import * as os from \"os\";\nimport { METRIC_MEM_USED, METRIC_MEM_TOTAL, METRIC_CPU_USED_PCNT } from \"@tracewayapp/core\";\nimport type { MetricRecord } from \"@tracewayapp/core\";\nimport { nowISO } from \"@tracewayapp/core\";\n\nlet prevCpuUsage: NodeJS.CpuUsage | null = null;\nlet prevCpuTime: number | null = null;\n\nexport function collectMetrics(): MetricRecord[] {\n const metrics: MetricRecord[] = [];\n const recordedAt = nowISO();\n\n const mem = process.memoryUsage();\n metrics.push({\n name: METRIC_MEM_USED,\n value: Math.round((mem.rss / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const totalMem = os.totalmem();\n metrics.push({\n name: METRIC_MEM_TOTAL,\n value: Math.round((totalMem / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const currentCpuUsage = process.cpuUsage();\n const currentTime = Date.now();\n if (prevCpuUsage !== null && prevCpuTime !== null) {\n const elapsedMs = currentTime - prevCpuTime;\n if (elapsedMs > 0) {\n const userDelta = currentCpuUsage.user - prevCpuUsage.user;\n const systemDelta = currentCpuUsage.system - prevCpuUsage.system;\n const totalDeltaMs = (userDelta + systemDelta) / 1000;\n const cpuCount = os.cpus().length || 1;\n const cpuPercent = (totalDeltaMs / elapsedMs / cpuCount) * 100;\n metrics.push({\n name: METRIC_CPU_USED_PCNT,\n value: Math.round(cpuPercent * 100) / 100,\n recordedAt,\n });\n }\n }\n prevCpuUsage = currentCpuUsage;\n prevCpuTime = currentTime;\n\n return metrics;\n}\n\nexport function resetCpuTracking(): void {\n prevCpuUsage = null;\n prevCpuTime = null;\n}\n","export function formatErrorStackTrace(error: Error): string {\n const lines: string[] = [];\n\n const typeName = error.constructor.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n const match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):\\d+\\)$/);\n if (match) {\n const funcName = shortenFunctionName(match[1]);\n const file = shortenFilePath(match[2]);\n const lineNum = match[3];\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchNoParens = line.match(/^\\s+at\\s+(.+):(\\d+):\\d+$/);\n if (matchNoParens) {\n const file = shortenFilePath(matchNoParens[1]);\n const lineNum = matchNoParens[2];\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchFnOnly = line.match(/^\\s+at\\s+(.+)$/);\n if (matchFnOnly) {\n const funcName = shortenFunctionName(matchFnOnly[1]);\n lines.push(`${funcName}()`);\n lines.push(` <unknown>:0`);\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import { AsyncLocalStorage } from \"async_hooks\";\nimport { generateUUID } from \"@tracewayapp/core\";\nimport type { Span } from \"@tracewayapp/core\";\n\n/**\n * Trace context stored in AsyncLocalStorage.\n * Automatically propagates through async operations.\n */\nexport interface TraceContext {\n /** Unique trace identifier (UUID v4) */\n traceId: string;\n /** Whether this is a background task (vs HTTP request) */\n isTask: boolean;\n /** When the trace started */\n startedAt: Date;\n /** Collected spans within this trace */\n spans: Span[];\n /** Key-value attributes for this trace */\n attributes: Record<string, string>;\n /** For HTTP traces: endpoint like \"GET /api/users\" */\n endpoint?: string;\n /** For HTTP traces: response status code */\n statusCode?: number;\n /** For HTTP traces: response body size */\n bodySize?: number;\n /** For HTTP traces: client IP address */\n clientIP?: string;\n}\n\n/**\n * Options for creating a new trace context.\n */\nexport interface TraceContextOptions {\n /** Custom trace ID (auto-generated if not provided) */\n traceId?: string;\n /** Mark as background task instead of HTTP trace */\n isTask?: boolean;\n /** Initial attributes */\n attributes?: Record<string, string>;\n /** HTTP endpoint (e.g., \"GET /api/users\") */\n endpoint?: string;\n /** Client IP address */\n clientIP?: string;\n}\n\n// The AsyncLocalStorage instance for trace context\nconst asyncLocalStorage = new AsyncLocalStorage<TraceContext>();\n\n/**\n * Get the current trace context, if any.\n * Returns undefined if not within a trace context.\n */\nexport function getTraceContext(): TraceContext | undefined {\n return asyncLocalStorage.getStore();\n}\n\n/**\n * Get the current trace ID, if within a trace context.\n */\nexport function getTraceId(): string | undefined {\n return asyncLocalStorage.getStore()?.traceId;\n}\n\n/**\n * Check if currently within a trace context.\n */\nexport function hasTraceContext(): boolean {\n return asyncLocalStorage.getStore() !== undefined;\n}\n\n/**\n * Run a function within a new trace context.\n * All async operations within will have access to this context.\n *\n * @example\n * ```ts\n * // HTTP request handler\n * withTraceContext({ endpoint: \"GET /api/users\", clientIP: req.ip }, async () => {\n * const users = await db.query(\"SELECT * FROM users\");\n * captureException(new Error(\"oops\")); // Auto-linked to trace\n * return users;\n * });\n *\n * // Background task\n * withTraceContext({ isTask: true, endpoint: \"process-emails\" }, async () => {\n * await processEmails();\n * });\n * ```\n */\nexport function withTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T,\n): T {\n const context: TraceContext = {\n traceId: options.traceId ?? generateUUID(),\n isTask: options.isTask ?? false,\n startedAt: new Date(),\n spans: [],\n attributes: options.attributes ?? {},\n endpoint: options.endpoint,\n clientIP: options.clientIP,\n };\n return asyncLocalStorage.run(context, fn);\n}\n\n/**\n * Run a function within a trace context, automatically capturing the trace on completion.\n * This is a convenience wrapper that handles timing and capture automatically.\n *\n * @example\n * ```ts\n * // In Express middleware\n * app.use((req, res, next) => {\n * runWithTraceContext(\n * {\n * endpoint: `${req.method} ${req.path}`,\n * clientIP: req.ip,\n * attributes: { userId: req.user?.id },\n * },\n * async () => {\n * await next();\n * // Status code and body size set via setTraceResponseInfo()\n * },\n * { captureOnEnd: true }\n * );\n * });\n * ```\n */\nexport function runWithTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return withTraceContext(options, fn);\n}\n\n/**\n * Add a completed span to the current trace context.\n * No-op if not within a trace context.\n */\nexport function addSpanToContext(span: Span): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.spans.push(span);\n }\n}\n\n/**\n * Set an attribute on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttribute(key: string, value: string): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.attributes[key] = value;\n }\n}\n\n/**\n * Set multiple attributes on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttributes(attributes: Record<string, string>): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n Object.assign(ctx.attributes, attributes);\n }\n}\n\n/**\n * Set HTTP response info on the current trace context.\n * Used by framework adapters after the response is sent.\n */\nexport function setTraceResponseInfo(\n statusCode: number,\n bodySize?: number,\n): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.statusCode = statusCode;\n ctx.bodySize = bodySize;\n }\n}\n\n/**\n * Get all spans from the current trace context.\n * Returns empty array if not within a trace context.\n */\nexport function getTraceSpans(): Span[] {\n return asyncLocalStorage.getStore()?.spans ?? [];\n}\n\n/**\n * Get the duration in milliseconds since the trace started.\n * Returns 0 if not within a trace context.\n */\nexport function getTraceDuration(): number {\n const ctx = asyncLocalStorage.getStore();\n if (!ctx) return 0;\n return Date.now() - ctx.startedAt.getTime();\n}\n\n/**\n * Fork the current trace context for a sub-operation.\n * Useful for parallel operations that should have isolated spans.\n * Returns undefined if not within a trace context.\n */\nexport function forkTraceContext<T>(fn: () => T): T | undefined {\n const parentCtx = asyncLocalStorage.getStore();\n if (!parentCtx) return undefined;\n\n const forkedContext: TraceContext = {\n ...parentCtx,\n spans: [], // Forked context gets its own spans\n attributes: { ...parentCtx.attributes },\n };\n\n return asyncLocalStorage.run(forkedContext, () => {\n const result = fn();\n // Merge spans back to parent after completion\n parentCtx.spans.push(...forkedContext.spans);\n return result;\n });\n}\n\n// Export the AsyncLocalStorage instance for advanced use cases\nexport { asyncLocalStorage as traceContextStorage };\n"],"mappings":"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","names":["import_core","import_core","import_core","os","hostname"]}
|
package/dist/index.mjs
CHANGED
|
@@ -263,7 +263,7 @@ var CollectionFrameStore = class {
|
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
-
async shutdown() {
|
|
266
|
+
async shutdown(timeoutMs) {
|
|
267
267
|
if (this.collectionTimer !== null) {
|
|
268
268
|
clearInterval(this.collectionTimer);
|
|
269
269
|
this.collectionTimer = null;
|
|
@@ -275,30 +275,40 @@ var CollectionFrameStore = class {
|
|
|
275
275
|
this.rotateCurrentCollectionFrame();
|
|
276
276
|
const frames = this.sendQueue.readAll();
|
|
277
277
|
if (frames.length === 0) return;
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
278
|
+
const uploadPromise = (async () => {
|
|
279
|
+
const payload = {
|
|
280
|
+
collectionFrames: frames,
|
|
281
|
+
appVersion: this.version,
|
|
282
|
+
serverName: this.serverName
|
|
283
|
+
};
|
|
284
|
+
try {
|
|
285
|
+
const jsonData = JSON.stringify(payload);
|
|
286
|
+
const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));
|
|
287
|
+
const resp = await fetch(this.apiUrl, {
|
|
288
|
+
method: "POST",
|
|
289
|
+
headers: {
|
|
290
|
+
"Content-Type": "application/json",
|
|
291
|
+
"Content-Encoding": "gzip",
|
|
292
|
+
Authorization: `Bearer ${this.token}`
|
|
293
|
+
},
|
|
294
|
+
body: gzipped
|
|
295
|
+
});
|
|
296
|
+
if (resp.status === 200) {
|
|
297
|
+
this.sendQueue.remove(frames);
|
|
298
|
+
}
|
|
299
|
+
} catch (err) {
|
|
300
|
+
if (this.debug) {
|
|
301
|
+
console.error("Traceway: shutdown upload failed:", err);
|
|
302
|
+
}
|
|
301
303
|
}
|
|
304
|
+
})();
|
|
305
|
+
if (timeoutMs !== void 0) {
|
|
306
|
+
await Promise.race([
|
|
307
|
+
uploadPromise,
|
|
308
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs))
|
|
309
|
+
]);
|
|
310
|
+
} else {
|
|
311
|
+
await uploadPromise;
|
|
302
312
|
}
|
|
303
313
|
}
|
|
304
314
|
};
|
|
@@ -640,11 +650,11 @@ function measureTask(title, fn) {
|
|
|
640
650
|
throw err;
|
|
641
651
|
}
|
|
642
652
|
}
|
|
643
|
-
async function shutdown() {
|
|
653
|
+
async function shutdown(timeoutMs) {
|
|
644
654
|
if (!store) return;
|
|
645
655
|
const s = store;
|
|
646
656
|
store = null;
|
|
647
|
-
await s.shutdown();
|
|
657
|
+
await s.shutdown(timeoutMs);
|
|
648
658
|
}
|
|
649
659
|
export {
|
|
650
660
|
CollectionFrameStore,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/traceway.ts","../src/collection-frame-store.ts","../src/typed-ring.ts","../src/metrics.ts","../src/stack-trace.ts","../src/context.ts"],"sourcesContent":["import {\n generateUUID,\n parseConnectionString,\n nowISO,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport type {\n TracewayOptions,\n ExceptionStackTrace,\n Trace,\n Span,\n} from \"@tracewayapp/core\";\nimport { CollectionFrameStore } from \"./collection-frame-store.js\";\nimport { formatErrorStackTrace } from \"./stack-trace.js\";\nimport {\n getTraceContext,\n getTraceId,\n addSpanToContext,\n type TraceContext,\n} from \"./context.js\";\nimport * as os from \"os\";\n\nlet store: CollectionFrameStore | null = null;\n\nfunction getHostname(): string {\n try {\n const hostname = os.hostname();\n const dotIdx = hostname.indexOf(\".\");\n return dotIdx >= 0 ? hostname.slice(0, dotIdx) : hostname;\n } catch {\n return \"unknown\";\n }\n}\n\nexport function init(\n connectionString: string,\n options: TracewayOptions = {},\n): void {\n if (store !== null) {\n throw new Error(\"Traceway: already initialized. Call shutdown() first.\");\n }\n\n const { token, apiUrl } = parseConnectionString(connectionString);\n\n store = new CollectionFrameStore({\n apiUrl,\n token,\n debug: options.debug ?? false,\n maxCollectionFrames: options.maxCollectionFrames ?? 12,\n collectionInterval: options.collectionInterval ?? 5000,\n uploadThrottle: options.uploadThrottle ?? 2000,\n metricsInterval: options.metricsInterval ?? 30000,\n version: options.version ?? \"\",\n serverName: options.serverName ?? getHostname(),\n sampleRate: options.sampleRate ?? 1,\n errorSampleRate: options.errorSampleRate ?? 1,\n });\n}\n\nexport function captureException(error: Error): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n captureExceptionWithAttributes(\n error,\n ctx?.attributes,\n ctx?.traceId,\n );\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n): void {\n if (!store) return;\n // Auto-detect trace context if not explicitly provided\n const ctx = getTraceContext();\n const resolvedTraceId = traceId ?? ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: formatErrorStackTrace(error),\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: false,\n });\n}\n\nexport function captureMessage(\n msg: string,\n attributes?: Record<string, string>,\n): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n const resolvedTraceId = ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: msg,\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: true,\n });\n}\n\nexport function captureMetric(name: string, value: number): void {\n if (!store) return;\n store.addMetric({\n name,\n value,\n recordedAt: nowISO(),\n });\n}\n\nexport function captureTrace(\n traceId: string,\n endpoint: string,\n durationMs: number,\n startedAt: Date,\n statusCode: number,\n bodySize: number,\n clientIP: string,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode,\n bodySize,\n clientIP,\n attributes,\n spans,\n });\n}\n\nexport function captureTask(\n traceId: string,\n taskName: string,\n durationMs: number,\n startedAt: Date,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint: taskName,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes,\n spans,\n isTask: true,\n });\n}\n\n/** Handle returned by startSpan for tracking span timing */\nexport interface SpanHandle {\n id: string;\n name: string;\n startTime: string;\n startedAt: number;\n}\n\n/**\n * Start a new span. If within a trace context, the span will be\n * automatically added to the trace when ended.\n */\nexport function startSpan(name: string): SpanHandle {\n const now = Date.now();\n return {\n id: generateUUID(),\n name,\n startTime: new Date(now).toISOString(),\n startedAt: now,\n };\n}\n\n/**\n * End a span and get the completed Span object.\n * If within a trace context, automatically adds the span to the trace.\n *\n * @param addToContext - If true (default), adds span to current trace context\n */\nexport function endSpan(span: SpanHandle, addToContext: boolean = true): Span {\n const durationMs = Date.now() - span.startedAt;\n const completedSpan: Span = {\n id: span.id,\n name: span.name,\n startTime: span.startTime,\n duration: msToNanoseconds(durationMs),\n };\n\n // Auto-add to trace context if available\n if (addToContext) {\n addSpanToContext(completedSpan);\n }\n\n return completedSpan;\n}\n\n/**\n * Capture the current trace context as a trace.\n * Call this at the end of a request/task to record the trace.\n *\n * @example\n * ```ts\n * // In Express middleware (after response)\n * withTraceContext({ endpoint: `${req.method} ${req.path}` }, async () => {\n * await handleRequest(req, res);\n * setTraceResponseInfo(res.statusCode, contentLength);\n * captureCurrentTrace(); // Records the trace with all spans\n * });\n * ```\n */\nexport function captureCurrentTrace(): void {\n if (!store) return;\n\n const ctx = getTraceContext();\n if (!ctx) return;\n\n const durationMs = Date.now() - ctx.startedAt.getTime();\n const isError = (ctx.statusCode ?? 0) >= 500;\n\n if (!shouldSample(isError)) return;\n\n if (ctx.isTask) {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown-task\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n isTask: true,\n });\n } else {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: ctx.statusCode ?? 0,\n bodySize: ctx.bodySize ?? 0,\n clientIP: ctx.clientIP ?? \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n });\n }\n}\n\nexport function shouldSample(isError: boolean): boolean {\n if (!store) return false;\n const rate = isError ? store.errorSampleRate : store.sampleRate;\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n return Math.random() < rate;\n}\n\nexport function measureTask(\n title: string,\n fn: () => void | Promise<void>,\n): void {\n const traceId = generateUUID();\n const start = Date.now();\n const startDate = new Date(start);\n\n try {\n const result = fn();\n if (result && typeof (result as Promise<void>).then === \"function\") {\n (result as Promise<void>)\n .then(() => {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n })\n .catch((err: unknown) => {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n });\n } else {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n }\n } catch (err) {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n }\n}\n\nexport async function shutdown(): Promise<void> {\n if (!store) return;\n const s = store;\n store = null;\n await s.shutdown();\n}\n","import * as zlib from \"zlib\";\nimport {\n nowISO,\n generateUUID,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport { TypedRing } from \"./typed-ring.js\";\nimport type {\n CollectionFrame,\n ExceptionStackTrace,\n MetricRecord,\n Trace,\n Span,\n ReportRequest,\n} from \"@tracewayapp/core\";\nimport { collectMetrics } from \"./metrics.js\";\n\nexport interface CollectionFrameStoreOptions {\n apiUrl: string;\n token: string;\n debug: boolean;\n maxCollectionFrames: number;\n collectionInterval: number;\n uploadThrottle: number;\n metricsInterval: number;\n version: string;\n serverName: string;\n sampleRate: number;\n errorSampleRate: number;\n}\n\nexport class CollectionFrameStore {\n private current: CollectionFrame | null = null;\n private currentSetAt: number = Date.now();\n private sendQueue: TypedRing<CollectionFrame>;\n private lastUploadStarted: number | null = null;\n\n private collectionTimer: ReturnType<typeof setInterval> | null = null;\n private metricsTimer: ReturnType<typeof setInterval> | null = null;\n\n private readonly apiUrl: string;\n private readonly token: string;\n private readonly debug: boolean;\n private readonly collectionInterval: number;\n private readonly uploadThrottle: number;\n private readonly metricsInterval: number;\n private readonly version: string;\n private readonly serverName: string;\n\n readonly sampleRate: number;\n readonly errorSampleRate: number;\n\n constructor(options: CollectionFrameStoreOptions) {\n this.apiUrl = options.apiUrl;\n this.token = options.token;\n this.debug = options.debug;\n this.collectionInterval = options.collectionInterval;\n this.uploadThrottle = options.uploadThrottle;\n this.metricsInterval = options.metricsInterval;\n this.version = options.version;\n this.serverName = options.serverName;\n this.sampleRate = options.sampleRate;\n this.errorSampleRate = options.errorSampleRate;\n this.sendQueue = new TypedRing<CollectionFrame>(\n options.maxCollectionFrames,\n );\n\n this.collectionTimer = setInterval(() => {\n this.tick();\n }, this.collectionInterval);\n if (this.collectionTimer && typeof this.collectionTimer.unref === \"function\") {\n this.collectionTimer.unref();\n }\n\n this.metricsTimer = setInterval(() => {\n this.collectSystemMetrics();\n }, this.metricsInterval);\n if (this.metricsTimer && typeof this.metricsTimer.unref === \"function\") {\n this.metricsTimer.unref();\n }\n }\n\n private tick(): void {\n if (this.current !== null) {\n if (this.currentSetAt < Date.now() - this.collectionInterval) {\n this.rotateCurrentCollectionFrame();\n this.processSendQueue();\n }\n } else if (this.sendQueue.length > 0) {\n this.processSendQueue();\n }\n }\n\n private ensureCurrent(): CollectionFrame {\n if (this.current === null) {\n this.current = { stackTraces: [], metrics: [], traces: [] };\n this.currentSetAt = Date.now();\n }\n return this.current;\n }\n\n addException(exception: ExceptionStackTrace): void {\n this.ensureCurrent().stackTraces.push(exception);\n }\n\n addMetric(metric: MetricRecord): void {\n this.ensureCurrent().metrics.push(metric);\n }\n\n addTrace(trace: Trace): void {\n this.ensureCurrent().traces.push(trace);\n }\n\n private rotateCurrentCollectionFrame(): void {\n if (this.current !== null) {\n this.sendQueue.push(this.current);\n this.current = null;\n }\n }\n\n private processSendQueue(): void {\n if (\n this.lastUploadStarted === null ||\n this.lastUploadStarted < Date.now() - this.uploadThrottle\n ) {\n this.lastUploadStarted = Date.now();\n const frames = this.sendQueue.readAll();\n if (frames.length > 0) {\n this.triggerUpload(frames);\n }\n }\n }\n\n private triggerUpload(framesToSend: CollectionFrame[]): void {\n const payload: ReportRequest = {\n collectionFrames: framesToSend,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n let jsonData: string;\n try {\n jsonData = JSON.stringify(payload);\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to serialize frames:\", err);\n }\n return;\n }\n\n let gzipped: Uint8Array;\n try {\n gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to gzip:\", err);\n }\n return;\n }\n\n fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n })\n .then((resp) => {\n if (resp.status === 200) {\n this.sendQueue.remove(framesToSend);\n } else if (this.debug) {\n console.error(`Traceway: upload returned status ${resp.status}`);\n }\n })\n .catch((err) => {\n if (this.debug) {\n console.error(\"Traceway: upload failed:\", err);\n }\n });\n }\n\n private collectSystemMetrics(): void {\n try {\n const metrics = collectMetrics();\n for (const metric of metrics) {\n this.addMetric(metric);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to collect metrics:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.collectionTimer !== null) {\n clearInterval(this.collectionTimer);\n this.collectionTimer = null;\n }\n if (this.metricsTimer !== null) {\n clearInterval(this.metricsTimer);\n this.metricsTimer = null;\n }\n\n this.rotateCurrentCollectionFrame();\n\n const frames = this.sendQueue.readAll();\n if (frames.length === 0) return;\n\n const payload: ReportRequest = {\n collectionFrames: frames,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n try {\n const jsonData = JSON.stringify(payload);\n const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n\n const resp = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n });\n\n if (resp.status === 200) {\n this.sendQueue.remove(frames);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: shutdown upload failed:\", err);\n }\n }\n }\n}\n","export class TypedRing<T> {\n private arr: (T | null)[];\n private head: number = 0;\n private _capacity: number;\n private _len: number = 0;\n\n constructor(capacity: number) {\n this._capacity = capacity;\n this.arr = new Array<T | null>(capacity).fill(null);\n }\n\n get length(): number {\n return this._len;\n }\n\n get capacity(): number {\n return this._capacity;\n }\n\n push(val: T): void {\n this.arr[this.head] = val;\n this.head = (this.head + 1) % this._capacity;\n if (this._len < this._capacity) {\n this._len += 1;\n }\n }\n\n readAll(): T[] {\n const result: T[] = [];\n for (let i = 0; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n result.push(this.arr[idx] as T);\n }\n return result;\n }\n\n clear(): void {\n for (let i = 0; i < this.arr.length; i++) {\n this.arr[i] = null;\n }\n this.head = 0;\n this._len = 0;\n }\n\n remove(vals: T[]): number {\n if (vals.length === 0) return 0;\n\n const toRemove = new Set<T>(vals);\n let writeIdx = 0;\n let removed = 0;\n\n for (let i = 0; i < this._len; i++) {\n const readIdx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n if (toRemove.has(this.arr[readIdx] as T)) {\n removed++;\n } else {\n if (writeIdx !== i) {\n const destIdx =\n (this.head - this._len + writeIdx + this._capacity) %\n this._capacity;\n this.arr[destIdx] = this.arr[readIdx];\n }\n writeIdx++;\n }\n }\n\n for (let i = writeIdx; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n this.arr[idx] = null;\n }\n\n this._len = writeIdx;\n this.head = (this.head - removed + this._capacity) % this._capacity;\n\n return removed;\n }\n}\n","import * as os from \"os\";\nimport { METRIC_MEM_USED, METRIC_MEM_TOTAL, METRIC_CPU_USED_PCNT } from \"@tracewayapp/core\";\nimport type { MetricRecord } from \"@tracewayapp/core\";\nimport { nowISO } from \"@tracewayapp/core\";\n\nlet prevCpuUsage: NodeJS.CpuUsage | null = null;\nlet prevCpuTime: number | null = null;\n\nexport function collectMetrics(): MetricRecord[] {\n const metrics: MetricRecord[] = [];\n const recordedAt = nowISO();\n\n const mem = process.memoryUsage();\n metrics.push({\n name: METRIC_MEM_USED,\n value: Math.round((mem.rss / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const totalMem = os.totalmem();\n metrics.push({\n name: METRIC_MEM_TOTAL,\n value: Math.round((totalMem / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const currentCpuUsage = process.cpuUsage();\n const currentTime = Date.now();\n if (prevCpuUsage !== null && prevCpuTime !== null) {\n const elapsedMs = currentTime - prevCpuTime;\n if (elapsedMs > 0) {\n const userDelta = currentCpuUsage.user - prevCpuUsage.user;\n const systemDelta = currentCpuUsage.system - prevCpuUsage.system;\n const totalDeltaMs = (userDelta + systemDelta) / 1000;\n const cpuCount = os.cpus().length || 1;\n const cpuPercent = (totalDeltaMs / elapsedMs / cpuCount) * 100;\n metrics.push({\n name: METRIC_CPU_USED_PCNT,\n value: Math.round(cpuPercent * 100) / 100,\n recordedAt,\n });\n }\n }\n prevCpuUsage = currentCpuUsage;\n prevCpuTime = currentTime;\n\n return metrics;\n}\n\nexport function resetCpuTracking(): void {\n prevCpuUsage = null;\n prevCpuTime = null;\n}\n","export function formatErrorStackTrace(error: Error): string {\n const lines: string[] = [];\n\n const typeName = error.constructor.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n const match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):\\d+\\)$/);\n if (match) {\n const funcName = shortenFunctionName(match[1]);\n const file = shortenFilePath(match[2]);\n const lineNum = match[3];\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchNoParens = line.match(/^\\s+at\\s+(.+):(\\d+):\\d+$/);\n if (matchNoParens) {\n const file = shortenFilePath(matchNoParens[1]);\n const lineNum = matchNoParens[2];\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchFnOnly = line.match(/^\\s+at\\s+(.+)$/);\n if (matchFnOnly) {\n const funcName = shortenFunctionName(matchFnOnly[1]);\n lines.push(`${funcName}()`);\n lines.push(` <unknown>:0`);\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import { AsyncLocalStorage } from \"async_hooks\";\nimport { generateUUID } from \"@tracewayapp/core\";\nimport type { Span } from \"@tracewayapp/core\";\n\n/**\n * Trace context stored in AsyncLocalStorage.\n * Automatically propagates through async operations.\n */\nexport interface TraceContext {\n /** Unique trace identifier (UUID v4) */\n traceId: string;\n /** Whether this is a background task (vs HTTP request) */\n isTask: boolean;\n /** When the trace started */\n startedAt: Date;\n /** Collected spans within this trace */\n spans: Span[];\n /** Key-value attributes for this trace */\n attributes: Record<string, string>;\n /** For HTTP traces: endpoint like \"GET /api/users\" */\n endpoint?: string;\n /** For HTTP traces: response status code */\n statusCode?: number;\n /** For HTTP traces: response body size */\n bodySize?: number;\n /** For HTTP traces: client IP address */\n clientIP?: string;\n}\n\n/**\n * Options for creating a new trace context.\n */\nexport interface TraceContextOptions {\n /** Custom trace ID (auto-generated if not provided) */\n traceId?: string;\n /** Mark as background task instead of HTTP trace */\n isTask?: boolean;\n /** Initial attributes */\n attributes?: Record<string, string>;\n /** HTTP endpoint (e.g., \"GET /api/users\") */\n endpoint?: string;\n /** Client IP address */\n clientIP?: string;\n}\n\n// The AsyncLocalStorage instance for trace context\nconst asyncLocalStorage = new AsyncLocalStorage<TraceContext>();\n\n/**\n * Get the current trace context, if any.\n * Returns undefined if not within a trace context.\n */\nexport function getTraceContext(): TraceContext | undefined {\n return asyncLocalStorage.getStore();\n}\n\n/**\n * Get the current trace ID, if within a trace context.\n */\nexport function getTraceId(): string | undefined {\n return asyncLocalStorage.getStore()?.traceId;\n}\n\n/**\n * Check if currently within a trace context.\n */\nexport function hasTraceContext(): boolean {\n return asyncLocalStorage.getStore() !== undefined;\n}\n\n/**\n * Run a function within a new trace context.\n * All async operations within will have access to this context.\n *\n * @example\n * ```ts\n * // HTTP request handler\n * withTraceContext({ endpoint: \"GET /api/users\", clientIP: req.ip }, async () => {\n * const users = await db.query(\"SELECT * FROM users\");\n * captureException(new Error(\"oops\")); // Auto-linked to trace\n * return users;\n * });\n *\n * // Background task\n * withTraceContext({ isTask: true, endpoint: \"process-emails\" }, async () => {\n * await processEmails();\n * });\n * ```\n */\nexport function withTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T,\n): T {\n const context: TraceContext = {\n traceId: options.traceId ?? generateUUID(),\n isTask: options.isTask ?? false,\n startedAt: new Date(),\n spans: [],\n attributes: options.attributes ?? {},\n endpoint: options.endpoint,\n clientIP: options.clientIP,\n };\n return asyncLocalStorage.run(context, fn);\n}\n\n/**\n * Run a function within a trace context, automatically capturing the trace on completion.\n * This is a convenience wrapper that handles timing and capture automatically.\n *\n * @example\n * ```ts\n * // In Express middleware\n * app.use((req, res, next) => {\n * runWithTraceContext(\n * {\n * endpoint: `${req.method} ${req.path}`,\n * clientIP: req.ip,\n * attributes: { userId: req.user?.id },\n * },\n * async () => {\n * await next();\n * // Status code and body size set via setTraceResponseInfo()\n * },\n * { captureOnEnd: true }\n * );\n * });\n * ```\n */\nexport function runWithTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return withTraceContext(options, fn);\n}\n\n/**\n * Add a completed span to the current trace context.\n * No-op if not within a trace context.\n */\nexport function addSpanToContext(span: Span): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.spans.push(span);\n }\n}\n\n/**\n * Set an attribute on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttribute(key: string, value: string): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.attributes[key] = value;\n }\n}\n\n/**\n * Set multiple attributes on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttributes(attributes: Record<string, string>): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n Object.assign(ctx.attributes, attributes);\n }\n}\n\n/**\n * Set HTTP response info on the current trace context.\n * Used by framework adapters after the response is sent.\n */\nexport function setTraceResponseInfo(\n statusCode: number,\n bodySize?: number,\n): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.statusCode = statusCode;\n ctx.bodySize = bodySize;\n }\n}\n\n/**\n * Get all spans from the current trace context.\n * Returns empty array if not within a trace context.\n */\nexport function getTraceSpans(): Span[] {\n return asyncLocalStorage.getStore()?.spans ?? [];\n}\n\n/**\n * Get the duration in milliseconds since the trace started.\n * Returns 0 if not within a trace context.\n */\nexport function getTraceDuration(): number {\n const ctx = asyncLocalStorage.getStore();\n if (!ctx) return 0;\n return Date.now() - ctx.startedAt.getTime();\n}\n\n/**\n * Fork the current trace context for a sub-operation.\n * Useful for parallel operations that should have isolated spans.\n * Returns undefined if not within a trace context.\n */\nexport function forkTraceContext<T>(fn: () => T): T | undefined {\n const parentCtx = asyncLocalStorage.getStore();\n if (!parentCtx) return undefined;\n\n const forkedContext: TraceContext = {\n ...parentCtx,\n spans: [], // Forked context gets its own spans\n attributes: { ...parentCtx.attributes },\n };\n\n return asyncLocalStorage.run(forkedContext, () => {\n const result = fn();\n // Merge spans back to parent after completion\n parentCtx.spans.push(...forkedContext.spans);\n return result;\n });\n}\n\n// Export the AsyncLocalStorage instance for advanced use cases\nexport { asyncLocalStorage as traceContextStorage };\n"],"mappings":"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","names":["generateUUID","nowISO","os","hostname","nowISO","generateUUID"]}
|
|
1
|
+
{"version":3,"sources":["../src/traceway.ts","../src/collection-frame-store.ts","../src/typed-ring.ts","../src/metrics.ts","../src/stack-trace.ts","../src/context.ts"],"sourcesContent":["import {\n generateUUID,\n parseConnectionString,\n nowISO,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport type {\n TracewayOptions,\n ExceptionStackTrace,\n Trace,\n Span,\n} from \"@tracewayapp/core\";\nimport { CollectionFrameStore } from \"./collection-frame-store.js\";\nimport { formatErrorStackTrace } from \"./stack-trace.js\";\nimport {\n getTraceContext,\n getTraceId,\n addSpanToContext,\n type TraceContext,\n} from \"./context.js\";\nimport * as os from \"os\";\n\nlet store: CollectionFrameStore | null = null;\n\nfunction getHostname(): string {\n try {\n const hostname = os.hostname();\n const dotIdx = hostname.indexOf(\".\");\n return dotIdx >= 0 ? hostname.slice(0, dotIdx) : hostname;\n } catch {\n return \"unknown\";\n }\n}\n\nexport function init(\n connectionString: string,\n options: TracewayOptions = {},\n): void {\n if (store !== null) {\n throw new Error(\"Traceway: already initialized. Call shutdown() first.\");\n }\n\n const { token, apiUrl } = parseConnectionString(connectionString);\n\n store = new CollectionFrameStore({\n apiUrl,\n token,\n debug: options.debug ?? false,\n maxCollectionFrames: options.maxCollectionFrames ?? 12,\n collectionInterval: options.collectionInterval ?? 5000,\n uploadThrottle: options.uploadThrottle ?? 2000,\n metricsInterval: options.metricsInterval ?? 30000,\n version: options.version ?? \"\",\n serverName: options.serverName ?? getHostname(),\n sampleRate: options.sampleRate ?? 1,\n errorSampleRate: options.errorSampleRate ?? 1,\n });\n}\n\nexport function captureException(error: Error): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n captureExceptionWithAttributes(\n error,\n ctx?.attributes,\n ctx?.traceId,\n );\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n): void {\n if (!store) return;\n // Auto-detect trace context if not explicitly provided\n const ctx = getTraceContext();\n const resolvedTraceId = traceId ?? ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: formatErrorStackTrace(error),\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: false,\n });\n}\n\nexport function captureMessage(\n msg: string,\n attributes?: Record<string, string>,\n): void {\n if (!store) return;\n // Auto-detect trace context\n const ctx = getTraceContext();\n const resolvedTraceId = ctx?.traceId ?? null;\n const resolvedAttrs = attributes ?? ctx?.attributes;\n const isTask = ctx?.isTask ?? false;\n\n store.addException({\n traceId: resolvedTraceId,\n isTask: isTask || undefined,\n stackTrace: msg,\n recordedAt: nowISO(),\n attributes: resolvedAttrs,\n isMessage: true,\n });\n}\n\nexport function captureMetric(name: string, value: number): void {\n if (!store) return;\n store.addMetric({\n name,\n value,\n recordedAt: nowISO(),\n });\n}\n\nexport function captureTrace(\n traceId: string,\n endpoint: string,\n durationMs: number,\n startedAt: Date,\n statusCode: number,\n bodySize: number,\n clientIP: string,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode,\n bodySize,\n clientIP,\n attributes,\n spans,\n });\n}\n\nexport function captureTask(\n traceId: string,\n taskName: string,\n durationMs: number,\n startedAt: Date,\n attributes?: Record<string, string>,\n spans?: Span[],\n): void {\n if (!store) return;\n store.addTrace({\n id: traceId,\n endpoint: taskName,\n duration: msToNanoseconds(durationMs),\n recordedAt: startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes,\n spans,\n isTask: true,\n });\n}\n\n/** Handle returned by startSpan for tracking span timing */\nexport interface SpanHandle {\n id: string;\n name: string;\n startTime: string;\n startedAt: number;\n}\n\n/**\n * Start a new span. If within a trace context, the span will be\n * automatically added to the trace when ended.\n */\nexport function startSpan(name: string): SpanHandle {\n const now = Date.now();\n return {\n id: generateUUID(),\n name,\n startTime: new Date(now).toISOString(),\n startedAt: now,\n };\n}\n\n/**\n * End a span and get the completed Span object.\n * If within a trace context, automatically adds the span to the trace.\n *\n * @param addToContext - If true (default), adds span to current trace context\n */\nexport function endSpan(span: SpanHandle, addToContext: boolean = true): Span {\n const durationMs = Date.now() - span.startedAt;\n const completedSpan: Span = {\n id: span.id,\n name: span.name,\n startTime: span.startTime,\n duration: msToNanoseconds(durationMs),\n };\n\n // Auto-add to trace context if available\n if (addToContext) {\n addSpanToContext(completedSpan);\n }\n\n return completedSpan;\n}\n\n/**\n * Capture the current trace context as a trace.\n * Call this at the end of a request/task to record the trace.\n *\n * @example\n * ```ts\n * // In Express middleware (after response)\n * withTraceContext({ endpoint: `${req.method} ${req.path}` }, async () => {\n * await handleRequest(req, res);\n * setTraceResponseInfo(res.statusCode, contentLength);\n * captureCurrentTrace(); // Records the trace with all spans\n * });\n * ```\n */\nexport function captureCurrentTrace(): void {\n if (!store) return;\n\n const ctx = getTraceContext();\n if (!ctx) return;\n\n const durationMs = Date.now() - ctx.startedAt.getTime();\n const isError = (ctx.statusCode ?? 0) >= 500;\n\n if (!shouldSample(isError)) return;\n\n if (ctx.isTask) {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown-task\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: 0,\n bodySize: 0,\n clientIP: \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n isTask: true,\n });\n } else {\n store.addTrace({\n id: ctx.traceId,\n endpoint: ctx.endpoint ?? \"unknown\",\n duration: msToNanoseconds(durationMs),\n recordedAt: ctx.startedAt.toISOString(),\n statusCode: ctx.statusCode ?? 0,\n bodySize: ctx.bodySize ?? 0,\n clientIP: ctx.clientIP ?? \"\",\n attributes: Object.keys(ctx.attributes).length > 0 ? ctx.attributes : undefined,\n spans: ctx.spans.length > 0 ? ctx.spans : undefined,\n });\n }\n}\n\nexport function shouldSample(isError: boolean): boolean {\n if (!store) return false;\n const rate = isError ? store.errorSampleRate : store.sampleRate;\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n return Math.random() < rate;\n}\n\nexport function measureTask(\n title: string,\n fn: () => void | Promise<void>,\n): void {\n const traceId = generateUUID();\n const start = Date.now();\n const startDate = new Date(start);\n\n try {\n const result = fn();\n if (result && typeof (result as Promise<void>).then === \"function\") {\n (result as Promise<void>)\n .then(() => {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n })\n .catch((err: unknown) => {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n });\n } else {\n const durationMs = Date.now() - start;\n if (shouldSample(false)) {\n captureTask(traceId, title, durationMs, startDate);\n }\n }\n } catch (err) {\n const durationMs = Date.now() - start;\n if (shouldSample(true)) {\n captureTask(traceId, title, durationMs, startDate);\n if (err instanceof Error) {\n captureExceptionWithAttributes(err, undefined, traceId);\n }\n }\n throw err;\n }\n}\n\nexport async function shutdown(timeoutMs?: number): Promise<void> {\n if (!store) return;\n const s = store;\n store = null;\n await s.shutdown(timeoutMs);\n}\n","import * as zlib from \"zlib\";\nimport {\n nowISO,\n generateUUID,\n msToNanoseconds,\n} from \"@tracewayapp/core\";\nimport { TypedRing } from \"./typed-ring.js\";\nimport type {\n CollectionFrame,\n ExceptionStackTrace,\n MetricRecord,\n Trace,\n Span,\n ReportRequest,\n} from \"@tracewayapp/core\";\nimport { collectMetrics } from \"./metrics.js\";\n\nexport interface CollectionFrameStoreOptions {\n apiUrl: string;\n token: string;\n debug: boolean;\n maxCollectionFrames: number;\n collectionInterval: number;\n uploadThrottle: number;\n metricsInterval: number;\n version: string;\n serverName: string;\n sampleRate: number;\n errorSampleRate: number;\n}\n\nexport class CollectionFrameStore {\n private current: CollectionFrame | null = null;\n private currentSetAt: number = Date.now();\n private sendQueue: TypedRing<CollectionFrame>;\n private lastUploadStarted: number | null = null;\n\n private collectionTimer: ReturnType<typeof setInterval> | null = null;\n private metricsTimer: ReturnType<typeof setInterval> | null = null;\n\n private readonly apiUrl: string;\n private readonly token: string;\n private readonly debug: boolean;\n private readonly collectionInterval: number;\n private readonly uploadThrottle: number;\n private readonly metricsInterval: number;\n private readonly version: string;\n private readonly serverName: string;\n\n readonly sampleRate: number;\n readonly errorSampleRate: number;\n\n constructor(options: CollectionFrameStoreOptions) {\n this.apiUrl = options.apiUrl;\n this.token = options.token;\n this.debug = options.debug;\n this.collectionInterval = options.collectionInterval;\n this.uploadThrottle = options.uploadThrottle;\n this.metricsInterval = options.metricsInterval;\n this.version = options.version;\n this.serverName = options.serverName;\n this.sampleRate = options.sampleRate;\n this.errorSampleRate = options.errorSampleRate;\n this.sendQueue = new TypedRing<CollectionFrame>(\n options.maxCollectionFrames,\n );\n\n this.collectionTimer = setInterval(() => {\n this.tick();\n }, this.collectionInterval);\n if (this.collectionTimer && typeof this.collectionTimer.unref === \"function\") {\n this.collectionTimer.unref();\n }\n\n this.metricsTimer = setInterval(() => {\n this.collectSystemMetrics();\n }, this.metricsInterval);\n if (this.metricsTimer && typeof this.metricsTimer.unref === \"function\") {\n this.metricsTimer.unref();\n }\n }\n\n private tick(): void {\n if (this.current !== null) {\n if (this.currentSetAt < Date.now() - this.collectionInterval) {\n this.rotateCurrentCollectionFrame();\n this.processSendQueue();\n }\n } else if (this.sendQueue.length > 0) {\n this.processSendQueue();\n }\n }\n\n private ensureCurrent(): CollectionFrame {\n if (this.current === null) {\n this.current = { stackTraces: [], metrics: [], traces: [] };\n this.currentSetAt = Date.now();\n }\n return this.current;\n }\n\n addException(exception: ExceptionStackTrace): void {\n this.ensureCurrent().stackTraces.push(exception);\n }\n\n addMetric(metric: MetricRecord): void {\n this.ensureCurrent().metrics.push(metric);\n }\n\n addTrace(trace: Trace): void {\n this.ensureCurrent().traces.push(trace);\n }\n\n private rotateCurrentCollectionFrame(): void {\n if (this.current !== null) {\n this.sendQueue.push(this.current);\n this.current = null;\n }\n }\n\n private processSendQueue(): void {\n if (\n this.lastUploadStarted === null ||\n this.lastUploadStarted < Date.now() - this.uploadThrottle\n ) {\n this.lastUploadStarted = Date.now();\n const frames = this.sendQueue.readAll();\n if (frames.length > 0) {\n this.triggerUpload(frames);\n }\n }\n }\n\n private triggerUpload(framesToSend: CollectionFrame[]): void {\n const payload: ReportRequest = {\n collectionFrames: framesToSend,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n let jsonData: string;\n try {\n jsonData = JSON.stringify(payload);\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to serialize frames:\", err);\n }\n return;\n }\n\n let gzipped: Uint8Array;\n try {\n gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to gzip:\", err);\n }\n return;\n }\n\n fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n })\n .then((resp) => {\n if (resp.status === 200) {\n this.sendQueue.remove(framesToSend);\n } else if (this.debug) {\n console.error(`Traceway: upload returned status ${resp.status}`);\n }\n })\n .catch((err) => {\n if (this.debug) {\n console.error(\"Traceway: upload failed:\", err);\n }\n });\n }\n\n private collectSystemMetrics(): void {\n try {\n const metrics = collectMetrics();\n for (const metric of metrics) {\n this.addMetric(metric);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: failed to collect metrics:\", err);\n }\n }\n }\n\n async shutdown(timeoutMs?: number): Promise<void> {\n if (this.collectionTimer !== null) {\n clearInterval(this.collectionTimer);\n this.collectionTimer = null;\n }\n if (this.metricsTimer !== null) {\n clearInterval(this.metricsTimer);\n this.metricsTimer = null;\n }\n\n this.rotateCurrentCollectionFrame();\n\n const frames = this.sendQueue.readAll();\n if (frames.length === 0) return;\n\n const uploadPromise = (async () => {\n const payload: ReportRequest = {\n collectionFrames: frames,\n appVersion: this.version,\n serverName: this.serverName,\n };\n\n try {\n const jsonData = JSON.stringify(payload);\n const gzipped = new Uint8Array(zlib.gzipSync(Buffer.from(jsonData)));\n\n const resp = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${this.token}`,\n },\n body: gzipped as unknown as BodyInit,\n });\n\n if (resp.status === 200) {\n this.sendQueue.remove(frames);\n }\n } catch (err) {\n if (this.debug) {\n console.error(\"Traceway: shutdown upload failed:\", err);\n }\n }\n })();\n\n if (timeoutMs !== undefined) {\n await Promise.race([\n uploadPromise,\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\n ]);\n } else {\n await uploadPromise;\n }\n }\n}\n","export class TypedRing<T> {\n private arr: (T | null)[];\n private head: number = 0;\n private _capacity: number;\n private _len: number = 0;\n\n constructor(capacity: number) {\n this._capacity = capacity;\n this.arr = new Array<T | null>(capacity).fill(null);\n }\n\n get length(): number {\n return this._len;\n }\n\n get capacity(): number {\n return this._capacity;\n }\n\n push(val: T): void {\n this.arr[this.head] = val;\n this.head = (this.head + 1) % this._capacity;\n if (this._len < this._capacity) {\n this._len += 1;\n }\n }\n\n readAll(): T[] {\n const result: T[] = [];\n for (let i = 0; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n result.push(this.arr[idx] as T);\n }\n return result;\n }\n\n clear(): void {\n for (let i = 0; i < this.arr.length; i++) {\n this.arr[i] = null;\n }\n this.head = 0;\n this._len = 0;\n }\n\n remove(vals: T[]): number {\n if (vals.length === 0) return 0;\n\n const toRemove = new Set<T>(vals);\n let writeIdx = 0;\n let removed = 0;\n\n for (let i = 0; i < this._len; i++) {\n const readIdx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n if (toRemove.has(this.arr[readIdx] as T)) {\n removed++;\n } else {\n if (writeIdx !== i) {\n const destIdx =\n (this.head - this._len + writeIdx + this._capacity) %\n this._capacity;\n this.arr[destIdx] = this.arr[readIdx];\n }\n writeIdx++;\n }\n }\n\n for (let i = writeIdx; i < this._len; i++) {\n const idx =\n (this.head - this._len + i + this._capacity) % this._capacity;\n this.arr[idx] = null;\n }\n\n this._len = writeIdx;\n this.head = (this.head - removed + this._capacity) % this._capacity;\n\n return removed;\n }\n}\n","import * as os from \"os\";\nimport { METRIC_MEM_USED, METRIC_MEM_TOTAL, METRIC_CPU_USED_PCNT } from \"@tracewayapp/core\";\nimport type { MetricRecord } from \"@tracewayapp/core\";\nimport { nowISO } from \"@tracewayapp/core\";\n\nlet prevCpuUsage: NodeJS.CpuUsage | null = null;\nlet prevCpuTime: number | null = null;\n\nexport function collectMetrics(): MetricRecord[] {\n const metrics: MetricRecord[] = [];\n const recordedAt = nowISO();\n\n const mem = process.memoryUsage();\n metrics.push({\n name: METRIC_MEM_USED,\n value: Math.round((mem.rss / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const totalMem = os.totalmem();\n metrics.push({\n name: METRIC_MEM_TOTAL,\n value: Math.round((totalMem / 1024 / 1024) * 100) / 100,\n recordedAt,\n });\n\n const currentCpuUsage = process.cpuUsage();\n const currentTime = Date.now();\n if (prevCpuUsage !== null && prevCpuTime !== null) {\n const elapsedMs = currentTime - prevCpuTime;\n if (elapsedMs > 0) {\n const userDelta = currentCpuUsage.user - prevCpuUsage.user;\n const systemDelta = currentCpuUsage.system - prevCpuUsage.system;\n const totalDeltaMs = (userDelta + systemDelta) / 1000;\n const cpuCount = os.cpus().length || 1;\n const cpuPercent = (totalDeltaMs / elapsedMs / cpuCount) * 100;\n metrics.push({\n name: METRIC_CPU_USED_PCNT,\n value: Math.round(cpuPercent * 100) / 100,\n recordedAt,\n });\n }\n }\n prevCpuUsage = currentCpuUsage;\n prevCpuTime = currentTime;\n\n return metrics;\n}\n\nexport function resetCpuTracking(): void {\n prevCpuUsage = null;\n prevCpuTime = null;\n}\n","export function formatErrorStackTrace(error: Error): string {\n const lines: string[] = [];\n\n const typeName = error.constructor.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n const match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):\\d+\\)$/);\n if (match) {\n const funcName = shortenFunctionName(match[1]);\n const file = shortenFilePath(match[2]);\n const lineNum = match[3];\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchNoParens = line.match(/^\\s+at\\s+(.+):(\\d+):\\d+$/);\n if (matchNoParens) {\n const file = shortenFilePath(matchNoParens[1]);\n const lineNum = matchNoParens[2];\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${lineNum}`);\n continue;\n }\n\n const matchFnOnly = line.match(/^\\s+at\\s+(.+)$/);\n if (matchFnOnly) {\n const funcName = shortenFunctionName(matchFnOnly[1]);\n lines.push(`${funcName}()`);\n lines.push(` <unknown>:0`);\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import { AsyncLocalStorage } from \"async_hooks\";\nimport { generateUUID } from \"@tracewayapp/core\";\nimport type { Span } from \"@tracewayapp/core\";\n\n/**\n * Trace context stored in AsyncLocalStorage.\n * Automatically propagates through async operations.\n */\nexport interface TraceContext {\n /** Unique trace identifier (UUID v4) */\n traceId: string;\n /** Whether this is a background task (vs HTTP request) */\n isTask: boolean;\n /** When the trace started */\n startedAt: Date;\n /** Collected spans within this trace */\n spans: Span[];\n /** Key-value attributes for this trace */\n attributes: Record<string, string>;\n /** For HTTP traces: endpoint like \"GET /api/users\" */\n endpoint?: string;\n /** For HTTP traces: response status code */\n statusCode?: number;\n /** For HTTP traces: response body size */\n bodySize?: number;\n /** For HTTP traces: client IP address */\n clientIP?: string;\n}\n\n/**\n * Options for creating a new trace context.\n */\nexport interface TraceContextOptions {\n /** Custom trace ID (auto-generated if not provided) */\n traceId?: string;\n /** Mark as background task instead of HTTP trace */\n isTask?: boolean;\n /** Initial attributes */\n attributes?: Record<string, string>;\n /** HTTP endpoint (e.g., \"GET /api/users\") */\n endpoint?: string;\n /** Client IP address */\n clientIP?: string;\n}\n\n// The AsyncLocalStorage instance for trace context\nconst asyncLocalStorage = new AsyncLocalStorage<TraceContext>();\n\n/**\n * Get the current trace context, if any.\n * Returns undefined if not within a trace context.\n */\nexport function getTraceContext(): TraceContext | undefined {\n return asyncLocalStorage.getStore();\n}\n\n/**\n * Get the current trace ID, if within a trace context.\n */\nexport function getTraceId(): string | undefined {\n return asyncLocalStorage.getStore()?.traceId;\n}\n\n/**\n * Check if currently within a trace context.\n */\nexport function hasTraceContext(): boolean {\n return asyncLocalStorage.getStore() !== undefined;\n}\n\n/**\n * Run a function within a new trace context.\n * All async operations within will have access to this context.\n *\n * @example\n * ```ts\n * // HTTP request handler\n * withTraceContext({ endpoint: \"GET /api/users\", clientIP: req.ip }, async () => {\n * const users = await db.query(\"SELECT * FROM users\");\n * captureException(new Error(\"oops\")); // Auto-linked to trace\n * return users;\n * });\n *\n * // Background task\n * withTraceContext({ isTask: true, endpoint: \"process-emails\" }, async () => {\n * await processEmails();\n * });\n * ```\n */\nexport function withTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T,\n): T {\n const context: TraceContext = {\n traceId: options.traceId ?? generateUUID(),\n isTask: options.isTask ?? false,\n startedAt: new Date(),\n spans: [],\n attributes: options.attributes ?? {},\n endpoint: options.endpoint,\n clientIP: options.clientIP,\n };\n return asyncLocalStorage.run(context, fn);\n}\n\n/**\n * Run a function within a trace context, automatically capturing the trace on completion.\n * This is a convenience wrapper that handles timing and capture automatically.\n *\n * @example\n * ```ts\n * // In Express middleware\n * app.use((req, res, next) => {\n * runWithTraceContext(\n * {\n * endpoint: `${req.method} ${req.path}`,\n * clientIP: req.ip,\n * attributes: { userId: req.user?.id },\n * },\n * async () => {\n * await next();\n * // Status code and body size set via setTraceResponseInfo()\n * },\n * { captureOnEnd: true }\n * );\n * });\n * ```\n */\nexport function runWithTraceContext<T>(\n options: TraceContextOptions,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return withTraceContext(options, fn);\n}\n\n/**\n * Add a completed span to the current trace context.\n * No-op if not within a trace context.\n */\nexport function addSpanToContext(span: Span): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.spans.push(span);\n }\n}\n\n/**\n * Set an attribute on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttribute(key: string, value: string): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.attributes[key] = value;\n }\n}\n\n/**\n * Set multiple attributes on the current trace context.\n * No-op if not within a trace context.\n */\nexport function setTraceAttributes(attributes: Record<string, string>): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n Object.assign(ctx.attributes, attributes);\n }\n}\n\n/**\n * Set HTTP response info on the current trace context.\n * Used by framework adapters after the response is sent.\n */\nexport function setTraceResponseInfo(\n statusCode: number,\n bodySize?: number,\n): void {\n const ctx = asyncLocalStorage.getStore();\n if (ctx) {\n ctx.statusCode = statusCode;\n ctx.bodySize = bodySize;\n }\n}\n\n/**\n * Get all spans from the current trace context.\n * Returns empty array if not within a trace context.\n */\nexport function getTraceSpans(): Span[] {\n return asyncLocalStorage.getStore()?.spans ?? [];\n}\n\n/**\n * Get the duration in milliseconds since the trace started.\n * Returns 0 if not within a trace context.\n */\nexport function getTraceDuration(): number {\n const ctx = asyncLocalStorage.getStore();\n if (!ctx) return 0;\n return Date.now() - ctx.startedAt.getTime();\n}\n\n/**\n * Fork the current trace context for a sub-operation.\n * Useful for parallel operations that should have isolated spans.\n * Returns undefined if not within a trace context.\n */\nexport function forkTraceContext<T>(fn: () => T): T | undefined {\n const parentCtx = asyncLocalStorage.getStore();\n if (!parentCtx) return undefined;\n\n const forkedContext: TraceContext = {\n ...parentCtx,\n spans: [], // Forked context gets its own spans\n attributes: { ...parentCtx.attributes },\n };\n\n return asyncLocalStorage.run(forkedContext, () => {\n const result = fn();\n // Merge spans back to parent after completion\n parentCtx.spans.push(...forkedContext.spans);\n return result;\n });\n}\n\n// Export the AsyncLocalStorage instance for advanced use cases\nexport { asyncLocalStorage as traceContextStorage };\n"],"mappings":"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","names":["generateUUID","nowISO","os","hostname","nowISO","generateUUID"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracewayapp/backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Traceway SDK for Node.js backends",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
"dev": "tsup --watch"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tracewayapp/core": "0.
|
|
26
|
+
"@tracewayapp/core": "1.0.0"
|
|
27
27
|
}
|
|
28
28
|
}
|