UNPKG

autotel

Version:
160 lines (114 loc) 5.26 kB
--- name: autotel-core description: > When to use trace vs span vs request logger vs events in Autotel. Init once at startup, package exports (autotel, autotel/event, autotel/testing). Use for setup and choosing the right API. --- # Autotel — Core OpenTelemetry instrumentation for Node.js and edge. Instrument once; stream to any OTLP backend. Use `trace()`/`span()` for spans, `getRequestLogger()` for one snapshot per request, `createStructuredError`/`parseError` for errors, `track()` for product events. Event guidance: for new instrumentation, emit events as correlated logs (via request logger or logging pipeline bridged to OTel Logs API). Do not introduce new direct span-event dependencies for business/exception events. ## When to Use What | Need | API | Import | | ------------------------------------- | ---------------------------------------------------------------- | -------------------------------------- | | Wrap a function with a span | `trace(fn)`, `span('Name', fn)` | `autotel` | | Request-scoped attributes + emit once | `getRequestLogger(ctx?)``.set()`, `.emitNow()` | `autotel` | | Throw with why/fix/link | `createStructuredError({ message, why?, fix?, link?, status? })` | `autotel` | | Parse API errors (client) | `parseError(err)``message`, `why`, `fix`, `link` | `autotel` | | Product/analytics events | `track(name, attrs)` or `Event` from `autotel/event` | `autotel`, `autotel/event` | | Init (once at startup) | `init({ service, ... })` | `autotel` or `autotel/instrumentation` | | Testing | `createTraceCollector()`, `InMemorySpanExporter` | `autotel/testing`, `autotel/exporters` | Request logger requires an active span. Wrap HTTP handlers with `trace()` or framework middleware that creates a span, then call `getRequestLogger()` inside. Backend config rule of thumb: use `endpoint` for one OTLP destination, `destinations` for explicit OTLP fan-out, and `spanProcessors` / `spanExporters` only when you need full manual control. ## Setup ```typescript import { init, trace, getRequestLogger } from 'autotel'; init({ service: 'my-app' }); const handler = trace((ctx) => async (req: Request) => { const log = getRequestLogger(ctx); log.set({ path: req.url }); const result = await doWork(req); log.emitNow(); return result; }); ``` ## Core Patterns **Factory pattern when you need context (attributes, request logger):** ```typescript const createUser = trace((ctx) => async (data: UserInput) => { ctx.setAttribute('user.id', data.id); const log = getRequestLogger(ctx); log.set({ user: { id: data.id } }); return db.users.create(data); }); ``` **Direct pattern when you don't need context:** ```typescript const getUser = trace(async (id: string) => { return db.users.findById(id); }); ``` **Structured errors in API routes:** ```typescript import { createStructuredError } from 'autotel'; throw createStructuredError({ message: 'Not found', status: 404, why: `No user "${id}"`, fix: 'Check the ID and try again', }); ``` **Client: parseError for UI:** ```typescript import { parseError } from 'autotel'; const e = parseError(err); toast.error(e.message, { description: e.why }); ``` ## Common Mistakes ### HIGH Call getRequestLogger() without active span Wrong: ```typescript app.get('/api/x', () => { const log = getRequestLogger(); log.set({ route: 'x' }); }); ``` Correct: ```typescript app.use(autotelMiddleware()); // or wrap route with trace() app.get('/api/x', () => { const log = getRequestLogger(); log.set({ route: 'x' }); }); ``` getRequestLogger() requires an active span. Register middleware that creates a span per request, or wrap the handler with `trace()`. Source: packages/autotel/src/request-logger.ts ### HIGH Use await import() for init-time optional deps Wrong: ```typescript const pkg = await import('optional-dep'); ``` Correct: ```typescript import { safeRequire } from 'autotel'; const pkg = safeRequire('optional-dep'); ``` init() must stay synchronous. Use node-require helpers for optional dependencies. Source: packages/autotel/CLAUDE.md ### MEDIUM Use trace() without ctx when you need attributes or request logger Wrong: ```typescript const handler = trace(async (req) => { const log = getRequestLogger(); // may throw if span not set up for request logger }); ``` Correct: ```typescript const handler = trace((ctx) => async (req) => { const log = getRequestLogger(ctx); log.set({ route: req.url }); }); ``` Use the factory pattern `(ctx) => async (...)` when you need to set attributes or use the request logger. Source: docs/AGENT-GUIDE.md ## Version Targets autotel v2.23.x. See also: autotel-instrumentation/SKILL.md — init and trace/span in depth. autotel-request-logging/SKILL.md — request logger usage.