autotel 5.0.0 → 6.1.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 +14 -1
- package/dist/auto.cjs +1 -1
- package/dist/auto.js +1 -1
- package/dist/correlation-id.cjs +9 -9
- package/dist/correlation-id.js +1 -1
- package/dist/decorators.cjs +2 -2
- package/dist/decorators.cjs.map +1 -1
- package/dist/decorators.js +1 -1
- package/dist/drain-pipeline.cjs +10 -1
- package/dist/drain-pipeline.cjs.map +1 -1
- package/dist/drain-pipeline.d.cts +5 -0
- package/dist/drain-pipeline.d.cts.map +1 -1
- package/dist/drain-pipeline.d.ts +5 -0
- package/dist/drain-pipeline.d.ts.map +1 -1
- package/dist/drain-pipeline.js +10 -1
- package/dist/drain-pipeline.js.map +1 -1
- package/dist/event.cjs +4 -4
- package/dist/event.js +1 -1
- package/dist/{functional-Bit6noRu.js → functional-BnDUxnSl.js} +2 -4
- package/dist/{functional-Bit6noRu.js.map → functional-BnDUxnSl.js.map} +1 -1
- package/dist/{functional-Cj7PSItS.cjs → functional-DcLBuCPz.cjs} +12 -14
- package/dist/{functional-Cj7PSItS.cjs.map → functional-DcLBuCPz.cjs.map} +1 -1
- package/dist/functional.cjs +1 -1
- package/dist/functional.js +1 -1
- package/dist/http.cjs +2 -2
- package/dist/http.cjs.map +1 -1
- package/dist/http.js +1 -1
- package/dist/index.cjs +33 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -147
- package/dist/index.js.map +1 -1
- package/dist/init-C3RApHKJ.cjs +3371 -0
- package/dist/init-C3RApHKJ.cjs.map +1 -0
- package/dist/{init-CTyqG9qR.d.ts → init-D6n2diBy.d.ts} +21 -2
- package/dist/init-D6n2diBy.d.ts.map +1 -0
- package/dist/init-R-gSEXkJ.js +3190 -0
- package/dist/init-R-gSEXkJ.js.map +1 -0
- package/dist/{init-a4yPDYqC.d.cts → init-XzXzrarP.d.cts} +21 -2
- package/dist/init-XzXzrarP.d.cts.map +1 -0
- package/dist/instrumentation.cjs +1 -1
- package/dist/instrumentation.js +1 -1
- package/dist/messaging.cjs +1 -1
- package/dist/messaging.js +1 -1
- package/dist/semantic-helpers.cjs +1 -1
- package/dist/semantic-helpers.js +1 -1
- package/dist/webhook.cjs +1 -1
- package/dist/webhook.js +1 -1
- package/dist/workflow-distributed.cjs +1 -1
- package/dist/workflow-distributed.js +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.js +1 -1
- package/dist/yaml-config.d.cts +1 -1
- package/dist/yaml-config.d.ts +1 -1
- package/package.json +2 -3
- package/dist/event-CwIpFdoY.cjs +0 -778
- package/dist/event-CwIpFdoY.cjs.map +0 -1
- package/dist/event-pLMF5b3d.js +0 -761
- package/dist/event-pLMF5b3d.js.map +0 -1
- package/dist/init-B2uvZReD.cjs +0 -1120
- package/dist/init-B2uvZReD.cjs.map +0 -1
- package/dist/init-CTyqG9qR.d.ts.map +0 -1
- package/dist/init-CdEWjhvl.js +0 -1043
- package/dist/init-CdEWjhvl.js.map +0 -1
- package/dist/init-a4yPDYqC.d.cts.map +0 -1
- package/dist/operation-context-CKBoA4Qy.js +0 -59
- package/dist/operation-context-CKBoA4Qy.js.map +0 -1
- package/dist/operation-context-hzKbTKnt.cjs +0 -72
- package/dist/operation-context-hzKbTKnt.cjs.map +0 -1
- package/dist/track-BBcxEJEC.js +0 -1110
- package/dist/track-BBcxEJEC.js.map +0 -1
- package/dist/track-BI6dmZ2X.cjs +0 -1207
- package/dist/track-BI6dmZ2X.cjs.map +0 -1
- package/skills/analyze-traces/SKILL.md +0 -209
- package/skills/autotel-core/SKILL.md +0 -166
- package/skills/autotel-events/SKILL.md +0 -84
- package/skills/autotel-frameworks/SKILL.md +0 -125
- package/skills/autotel-instrumentation/SKILL.md +0 -150
- package/skills/autotel-request-logging/SKILL.md +0 -99
- package/skills/autotel-structured-errors/SKILL.md +0 -125
- package/skills/build-audit-trails/SKILL.md +0 -460
- package/skills/build-audit-trails/references/audit-queries.md +0 -73
- package/skills/build-audit-trails/references/framework-wiring.md +0 -196
- package/skills/debug-missing-spans/SKILL.md +0 -250
- package/skills/migrate-to-autotel/SKILL.md +0 -269
- package/skills/review-otel-patterns/SKILL.md +0 -540
- package/skills/review-otel-patterns/references/code-review.md +0 -76
- package/skills/review-otel-patterns/references/processor-pipeline.md +0 -205
- package/skills/review-otel-patterns/references/structured-errors.md +0 -102
- package/skills/review-otel-patterns/references/wide-spans.md +0 -85
- package/skills/tune-sampling/SKILL.md +0 -290
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autotel-frameworks
|
|
3
|
-
description: >
|
|
4
|
-
Hono, Fastify, TanStack Start, Cloudflare Workers, NestJS, SvelteKit, Elysia, Nuxt. Middleware and init; getRequestLogger() in handlers. Load when adding Autotel to a web framework.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Autotel: Framework Integration
|
|
8
|
-
|
|
9
|
-
This skill builds on autotel-instrumentation. Read it first for init() and span creation.
|
|
10
|
-
|
|
11
|
-
Use framework-specific middleware or wrappers to create a span per request; then call `getRequestLogger()` inside handlers. Most frameworks use `autotel-adapters` subpaths (or a thin wrapper package like `autotel-hono`, `autotel-tanstack`, `autotel-cloudflare`, `autotel-nuxt`).
|
|
12
|
-
|
|
13
|
-
When adding new request/exception events in framework handlers, prefer correlated logs (`getRequestLogger().info/warn/error`) instead of introducing new `span.addEvent()` usage.
|
|
14
|
-
|
|
15
|
-
For custom HTTP frameworks, start from `autotel-adapters/toolkit` (`defineFrameworkIntegration`, `createMiddlewareLogger`, `finishResponse` for streaming, `waitUntil` on edge runtimes).
|
|
16
|
-
|
|
17
|
-
## Setup
|
|
18
|
-
|
|
19
|
-
### Hono
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
import { Hono } from 'hono';
|
|
23
|
-
import { init, getRequestLogger } from 'autotel';
|
|
24
|
-
import { otel } from 'autotel-hono';
|
|
25
|
-
|
|
26
|
-
init({ service: 'my-api' });
|
|
27
|
-
|
|
28
|
-
const app = new Hono();
|
|
29
|
-
app.use('*', otel({ serviceName: 'my-api' }));
|
|
30
|
-
|
|
31
|
-
app.post('/api/checkout', async (c) => {
|
|
32
|
-
const log = getRequestLogger();
|
|
33
|
-
log.set({ route: 'checkout' });
|
|
34
|
-
const body = await c.req.json();
|
|
35
|
-
log.set({ cart: { items: body.items?.length } });
|
|
36
|
-
log.emitNow();
|
|
37
|
-
return c.json({ ok: true });
|
|
38
|
-
});
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Fastify
|
|
42
|
-
|
|
43
|
-
Use middleware or a wrapper that creates a span per request (see apps/example-fastify). Inside the route, wrap with `trace()` or ensure a span is active, then `getRequestLogger(ctx)` or `getRequestLogger()`.
|
|
44
|
-
|
|
45
|
-
### TanStack Start
|
|
46
|
-
|
|
47
|
-
See packages/autotel-tanstack and apps/example-tanstack-start: middleware and env config. Use `getRequestLogger()` inside server handlers when a span is active.
|
|
48
|
-
|
|
49
|
-
### Cloudflare Workers
|
|
50
|
-
|
|
51
|
-
See packages/autotel-cloudflare: init at top level, wrap the fetch handler so each request gets a span. Use `getRequestLogger()` or trace context inside the handler. Pass `ctx.waitUntil` through adapter options so emit/drain completes after the response.
|
|
52
|
-
|
|
53
|
-
### NestJS
|
|
54
|
-
|
|
55
|
-
Use `AutotelInterceptor` from `autotel-adapters/nestjs` and `useLogger()` in controllers/services (see apps/example-nestjs):
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
59
|
-
import { AutotelInterceptor } from 'autotel-adapters/nestjs';
|
|
60
|
-
|
|
61
|
-
@Module({
|
|
62
|
-
providers: [{ provide: APP_INTERCEPTOR, useClass: AutotelInterceptor }],
|
|
63
|
-
})
|
|
64
|
-
export class AppModule {}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### SvelteKit
|
|
68
|
-
|
|
69
|
-
Add `autotelHandle()` in `hooks.server.ts` from `autotel-adapters/sveltekit`; call `useLogger()` in `+server.ts` / server loads. Use `finishResponse` semantics for streaming routes (see toolkit `stream-response`).
|
|
70
|
-
|
|
71
|
-
### Elysia
|
|
72
|
-
|
|
73
|
-
Wrap handlers with `withAutotelHandler()` from `autotel-adapters/elysia` (or the `autotel` alias); use `useLogger()` inside handlers (see apps/example-elysia).
|
|
74
|
-
|
|
75
|
-
### Nuxt
|
|
76
|
-
|
|
77
|
-
Add the `autotel-nuxt` module for zero-config Nitro wiring; server code can use `useLogger()` via `autotel-adapters/nitro` re-exports from `autotel-nuxt/runtime/nitro`.
|
|
78
|
-
|
|
79
|
-
## Core Patterns
|
|
80
|
-
|
|
81
|
-
**Register middleware before routes:** Middleware creates the span; getRequestLogger() needs that active span.
|
|
82
|
-
|
|
83
|
-
**Framework-specific packages:** autotel-hono, autotel-tanstack, autotel-cloudflare, autotel-nuxt. Adapter subpaths: autotel-adapters/{express,fastify,next,nitro,nestjs,sveltekit,elysia,...}. Install the package for your framework and follow its README or CLAUDE.md.
|
|
84
|
-
|
|
85
|
-
**Streaming responses:** defer `emitNow` until the body finishes via adapter `finishResponse` / toolkit `bindStreamingResponseLifecycle`.
|
|
86
|
-
|
|
87
|
-
**Edge drain:** pass `waitUntil` (Cloudflare `ExecutionContext`, etc.) so async emit/drain does not block the response.
|
|
88
|
-
|
|
89
|
-
## Common Mistakes
|
|
90
|
-
|
|
91
|
-
### HIGH Use getRequestLogger() in Hono without registering middleware first
|
|
92
|
-
|
|
93
|
-
Wrong:
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
const app = new Hono();
|
|
97
|
-
app.get('/api/x', (c) => {
|
|
98
|
-
const log = getRequestLogger();
|
|
99
|
-
return c.json({});
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Correct:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const app = new Hono();
|
|
107
|
-
app.use('*', otel());
|
|
108
|
-
app.get('/api/x', (c) => {
|
|
109
|
-
const log = getRequestLogger();
|
|
110
|
-
return c.json({});
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Middleware creates the span per request. Without it, getRequestLogger() has no active span and will throw.
|
|
115
|
-
|
|
116
|
-
Source: packages/autotel-hono, docs/AGENT-GUIDE.md
|
|
117
|
-
|
|
118
|
-
## Version
|
|
119
|
-
|
|
120
|
-
Targets autotel v2.23.x.
|
|
121
|
-
|
|
122
|
-
See also:
|
|
123
|
-
|
|
124
|
-
- `autotel-instrumentation/SKILL.md` for init and spans
|
|
125
|
-
- `autotel-request-logging/SKILL.md` for request logger usage
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autotel-instrumentation
|
|
3
|
-
description: >
|
|
4
|
-
trace(), span(), instrument(), init(). Factory vs direct pattern, name inference. Sync init; use node-require for optional deps. Load when wrapping handlers or functions with spans.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Autotel: Instrumentation
|
|
8
|
-
|
|
9
|
-
Wrap functions and handlers with `trace()`, `span()`, or `instrument()`. Call `init()` once at app startup. Keep init synchronous; use `safeRequire`/`requireModule` for optional dependencies.
|
|
10
|
-
|
|
11
|
-
For new event emission, prefer correlated logs (OTel Logs API path) over adding new direct span-event calls.
|
|
12
|
-
|
|
13
|
-
## Setup
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { init, trace, withTracing } from 'autotel';
|
|
17
|
-
|
|
18
|
-
init({ service: 'my-app' });
|
|
19
|
-
|
|
20
|
-
const handler = trace(async (req: Request) => {
|
|
21
|
-
return processRequest(req);
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
With span context (attributes, request logger):
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
const handler = withTracing({ name: 'http.request' })(
|
|
29
|
-
(ctx) => async (req: Request) => {
|
|
30
|
-
ctx.setAttribute('http.route', '/api/checkout');
|
|
31
|
-
const log = getRequestLogger(ctx);
|
|
32
|
-
log.set({ path: req.url });
|
|
33
|
-
return processRequest(req);
|
|
34
|
-
},
|
|
35
|
-
);
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Core Patterns
|
|
39
|
-
|
|
40
|
-
**Explicit span name:**
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
const checkout = trace('checkout', async (body) => {
|
|
44
|
-
return processCheckout(body);
|
|
45
|
-
});
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**instrument() with key:**
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
import { instrument } from 'autotel';
|
|
52
|
-
const fn = instrument({
|
|
53
|
-
key: 'processOrder',
|
|
54
|
-
fn: async (id) => db.orders.get(id),
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**span() for a child span:**
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { span } from 'autotel';
|
|
62
|
-
const result = await span('db.query', async () => db.query(sql));
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Init with optional config:**
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
init({
|
|
69
|
-
service: 'my-api',
|
|
70
|
-
// see docs/CONFIGURATION.md for full options
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**Single backend vs multi-backend OTLP:**
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
init({
|
|
78
|
-
service: 'my-api',
|
|
79
|
-
endpoint: 'https://otlp-gateway-prod.grafana.net/otlp', // single destination
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
init({
|
|
83
|
-
service: 'my-api',
|
|
84
|
-
logs: true,
|
|
85
|
-
destinations: [
|
|
86
|
-
{
|
|
87
|
-
endpoint: 'https://otlp-gateway-prod.grafana.net/otlp',
|
|
88
|
-
headers: 'Authorization=Basic ...',
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
endpoint: 'https://api.honeycomb.io',
|
|
92
|
-
headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY! },
|
|
93
|
-
signals: ['traces'],
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
});
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Common Mistakes
|
|
100
|
-
|
|
101
|
-
### HIGH Forget to call init() before using trace/span
|
|
102
|
-
|
|
103
|
-
Wrong:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
import { trace } from 'autotel';
|
|
107
|
-
export const fn = trace(async () => {});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Correct:
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
import { init, trace } from 'autotel';
|
|
114
|
-
init({ service: 'my-app' });
|
|
115
|
-
export const fn = trace(async () => {});
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
SDK must be initialized; trace() and span() rely on the global tracer.
|
|
119
|
-
|
|
120
|
-
Source: packages/autotel/CLAUDE.md
|
|
121
|
-
|
|
122
|
-
### MEDIUM Wrong export path for submodules
|
|
123
|
-
|
|
124
|
-
Wrong:
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
import { Event } from 'autotel'; // Event is on autotel/event
|
|
128
|
-
import { createTraceCollector } from 'autotel'; // testing subpath
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Correct:
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
import { trace, init, getRequestLogger } from 'autotel';
|
|
135
|
-
import { Event } from 'autotel/event';
|
|
136
|
-
import { createTraceCollector } from 'autotel/testing';
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Use the exact export paths from package.json (autotel/event, autotel/testing, autotel/attributes, etc.).
|
|
140
|
-
|
|
141
|
-
Source: packages/autotel/package.json exports
|
|
142
|
-
|
|
143
|
-
## Version
|
|
144
|
-
|
|
145
|
-
Targets autotel v2.23.x.
|
|
146
|
-
|
|
147
|
-
See also:
|
|
148
|
-
|
|
149
|
-
- `autotel-core/SKILL.md` for when to use what
|
|
150
|
-
- `autotel-request-logging/SKILL.md`, since `getRequestLogger` requires an active span
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autotel-request-logging
|
|
3
|
-
description: >
|
|
4
|
-
getRequestLogger(), set(), info/warn/error, emitNow(). One snapshot per request; requires active span. Use when adding request-scoped context or replacing scattered console.log.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Autotel: Request Logging
|
|
8
|
-
|
|
9
|
-
This skill builds on autotel-instrumentation. Read it first for init and span creation.
|
|
10
|
-
|
|
11
|
-
Accumulate context with `getRequestLogger(ctx)`, `.set()`, and `.info()`/`.warn()`/`.error()`. Call `.emitNow()` (or rely on middleware) to emit one snapshot per request. Request logger requires an active span. Use inside `trace()` or framework middleware.
|
|
12
|
-
|
|
13
|
-
Preferred event model: treat request logger emissions as the default way to capture request-correlated events in new code. If a backend still expects span-event rendering, keep compatibility at export/processor level rather than adding new `span.addEvent()` calls in application code.
|
|
14
|
-
|
|
15
|
-
## Setup
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
import { init, withTracing, getRequestLogger } from 'autotel';
|
|
19
|
-
|
|
20
|
-
init({ service: 'my-app' });
|
|
21
|
-
|
|
22
|
-
const handler = withTracing({ name: 'http.request' })(
|
|
23
|
-
(ctx) => async (req: Request, res: Response) => {
|
|
24
|
-
const log = getRequestLogger(ctx);
|
|
25
|
-
log.set({ method: req.method, path: req.url });
|
|
26
|
-
|
|
27
|
-
const user = await getAuth(req);
|
|
28
|
-
log.set({ user: { id: user.id } });
|
|
29
|
-
|
|
30
|
-
const result = await doWork(req);
|
|
31
|
-
log.set({ result: { id: result.id } });
|
|
32
|
-
log.emitNow();
|
|
33
|
-
return res.json(result);
|
|
34
|
-
},
|
|
35
|
-
);
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
When the framework creates the span (e.g. Hono middleware), call `getRequestLogger()` with no args:
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
app.use(autotelMiddleware());
|
|
42
|
-
app.get('/api/users', (c) => {
|
|
43
|
-
const log = getRequestLogger();
|
|
44
|
-
log.set({ route: 'users' });
|
|
45
|
-
return c.json({ users: [] });
|
|
46
|
-
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Core Patterns
|
|
50
|
-
|
|
51
|
-
**Accumulate then emit:**
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
const log = getRequestLogger(ctx);
|
|
55
|
-
log.set({ cart: { items: body.items.length } });
|
|
56
|
-
log.set({ payment: { method: body.method } });
|
|
57
|
-
log.error(err, { step: 'payment' });
|
|
58
|
-
log.emitNow();
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**RequestLogSnapshot:** `emitNow()` returns `{ timestamp, traceId, spanId, correlationId, context }`. You can pass `onEmit` in options to forward it.
|
|
62
|
-
|
|
63
|
-
**Options:** `getRequestLogger(ctx?, { onEmit?: (snapshot) => void })` for custom fan-out on emit.
|
|
64
|
-
|
|
65
|
-
## Common Mistakes
|
|
66
|
-
|
|
67
|
-
### HIGH Call getRequestLogger() outside a span
|
|
68
|
-
|
|
69
|
-
Wrong:
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
function helper() {
|
|
73
|
-
const log = getRequestLogger();
|
|
74
|
-
log.set({ step: 'helper' });
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Correct:
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
// Ensure helper runs inside trace() or middleware-created span
|
|
82
|
-
function helper(ctx?: TraceContext) {
|
|
83
|
-
const log = getRequestLogger(ctx);
|
|
84
|
-
log.set({ step: 'helper' });
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Request logger attaches to the active span. If there is no active span, it throws. Wrap the call path with `trace()` or register middleware that creates a span per request.
|
|
89
|
-
|
|
90
|
-
Source: packages/autotel/src/request-logger.ts
|
|
91
|
-
|
|
92
|
-
## Version
|
|
93
|
-
|
|
94
|
-
Targets autotel v2.23.x.
|
|
95
|
-
|
|
96
|
-
See also:
|
|
97
|
-
|
|
98
|
-
- `autotel-instrumentation/SKILL.md` for creating the span
|
|
99
|
-
- `autotel-structured-errors/SKILL.md`, which uses `.error()` to record errors in the snapshot
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autotel-structured-errors
|
|
3
|
-
description: >
|
|
4
|
-
createStructuredError, parseError, recordStructuredError. API errors with message, why, fix, link; client parsing for UI. Use in API routes and client catch blocks.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Autotel: Structured Errors
|
|
8
|
-
|
|
9
|
-
Throw errors with `createStructuredError({ message, why?, fix?, link?, status?, cause? })` in API routes and services. On the client, use `parseError(caught)` to get `message`, `status`, `why`, `fix`, `link` for toasts and UI.
|
|
10
|
-
|
|
11
|
-
## Setup
|
|
12
|
-
|
|
13
|
-
**Server (API route or service):**
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { createStructuredError } from 'autotel';
|
|
17
|
-
|
|
18
|
-
if (!user) {
|
|
19
|
-
throw createStructuredError({
|
|
20
|
-
message: 'User not found',
|
|
21
|
-
status: 404,
|
|
22
|
-
why: `No user with ID "${userId}"`,
|
|
23
|
-
fix: 'Check the user ID and try again',
|
|
24
|
-
link: 'https://docs.example.com/errors/user-not-found',
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Client:**
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
import { parseError } from 'autotel';
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await fetch('/api/checkout', { method: 'POST', body: JSON.stringify(data) });
|
|
36
|
-
} catch (err) {
|
|
37
|
-
const e = parseError(err);
|
|
38
|
-
toast.error(e.message, { description: e.why });
|
|
39
|
-
if (e.fix) setHelp(e.fix);
|
|
40
|
-
if (e.link) setDocLink(e.link);
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Core Patterns
|
|
45
|
-
|
|
46
|
-
**Wrap a caught error (preserve cause):**
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
try {
|
|
50
|
-
await stripe.charges.create(data);
|
|
51
|
-
} catch (err) {
|
|
52
|
-
throw createStructuredError({
|
|
53
|
-
message: 'Payment failed',
|
|
54
|
-
status: 402,
|
|
55
|
-
why: err instanceof Error ? err.message : 'Unknown error',
|
|
56
|
-
fix: 'Try a different payment method or contact support',
|
|
57
|
-
link: 'https://docs.stripe.com/declines',
|
|
58
|
-
cause: err,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**Record on current span:** Use `recordStructuredError(ctx, error)` or the request logger's `.error(error, fields)` so the span gets error attributes and status.
|
|
64
|
-
|
|
65
|
-
For new exception event flows, prefer request-logger/log-based correlation and keep span-event compatibility as an implementation detail (processors/export path), not a new app-level dependency.
|
|
66
|
-
|
|
67
|
-
**parseError** handles FetchError (ofetch), nested `data.data`, and plain Error. Returns `{ message, status, why?, fix?, link?, raw }`.
|
|
68
|
-
|
|
69
|
-
## Common Mistakes
|
|
70
|
-
|
|
71
|
-
### HIGH Throw new Error() in API routes instead of createStructuredError
|
|
72
|
-
|
|
73
|
-
Wrong:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
throw new Error('Payment failed');
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Correct:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
throw createStructuredError({
|
|
83
|
-
message: 'Payment failed',
|
|
84
|
-
status: 402,
|
|
85
|
-
why: 'Card declined by issuer',
|
|
86
|
-
fix: 'Try a different payment method',
|
|
87
|
-
link: 'https://docs.example.com/payments',
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Clients and agents need structured fields (why, fix, link) for actionable errors. parseError() reads these from API responses.
|
|
92
|
-
|
|
93
|
-
Source: docs/AGENT-GUIDE.md, AGENTS.md
|
|
94
|
-
|
|
95
|
-
### MEDIUM Client only shows error.message and ignores why/fix/link
|
|
96
|
-
|
|
97
|
-
Wrong:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
catch (err) {
|
|
101
|
-
toast.error(err.message);
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Correct:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import { parseError } from 'autotel';
|
|
109
|
-
catch (err) {
|
|
110
|
-
const e = parseError(err);
|
|
111
|
-
toast.error(e.message, { description: e.why });
|
|
112
|
-
if (e.fix) showFix(e.fix);
|
|
113
|
-
if (e.link) setDocLink(e.link);
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
parseError() extracts status, why, fix, and link from API error responses and FetchError so the UI can show them.
|
|
118
|
-
|
|
119
|
-
Source: docs/AGENT-GUIDE.md
|
|
120
|
-
|
|
121
|
-
## Version
|
|
122
|
-
|
|
123
|
-
Targets autotel v2.23.x.
|
|
124
|
-
|
|
125
|
-
See also: autotel-request-logging/SKILL.md. Use .error() to record errors in the request snapshot.
|