Skip to content

Adapters

autotel-adapters provides easy-to-use ergonomics (withAutotel(), useLogger(), parseError()) while keeping one trace-native stack.

Adapter Import
Hono autotel-adapters/hono
TanStack autotel-tanstack
Next.js autotel-adapters/next
Nitro autotel-adapters/nitro
Cloudflare autotel-adapters/cloudflare
Custom autotel-adapters/core

[!NOTE] For TanStack Start, reach for the autotel-tanstack package: it gives you tracing middleware, server-function and loader wrappers, and context propagation. A lighter autotel-adapters/tanstack subpath also exists, exporting useLogger for custom glue when you do not want the full integration.

withAutotel(). Use when you have NO existing autotel middleware. Creates a span and injects a request logger:

import { withAutotel, useLogger } from 'autotel-adapters/next';
export const POST = withAutotel(async (request) => {
const log = useLogger(request);
log.set({ feature: 'checkout' });
return Response.json({ ok: true });
});

useLogger() alone. Use when middleware already creates the span (avoids duplicate spans):

import { otel } from 'autotel-hono';
import { useLogger } from 'autotel-adapters/hono';
app.use('*', otel());
app.get('/orders/:id', (c) => {
const log = useLogger(c);
log.set({ route: c.req.path });
return c.json({ ok: true });
});
import { withAutotel, useLogger, parseError } from 'autotel-adapters/next';
export const POST = withAutotel(async (request: Request) => {
const log = useLogger(request);
log.set({ feature: 'checkout' });
try {
return Response.json({ ok: true });
} catch (error) {
const parsed = parseError(error);
log.set({ error_status: parsed.status, error_why: parsed.why });
throw error;
}
});

Serving Hono from a Next.js catch-all? Keep autotel-adapters and hono on the same side of serverExternalPackages: bundle both with the app, or list both. If they resolve different copies, the Hono adapter names the route from the request and warns once.

Request spans follow the OpenTelemetry HTTP conventions. http.route holds the matched route template (/users/:id), the span is named {METHOD} {route} (or {METHOD} when no route matched), and url.path holds the raw path. A 5xx response ends the span with status ERROR.

Next.js and Cloudflare Workers set only url.path. Pass http.route through enrichRequest and a name through spanName:

export const GET = withAutotel(handler, {
spanName: 'GET /api/orders/[id]',
enrichRequest: () => ({ 'http.route': '/api/orders/[id]' }),
});

With autoEmit: false, call markOutcome({ status, error }) to record the outcome on the span without emitting the snapshot. finishResponse(response, { error }) records an error the framework caught on the way to the response.

import { createUseLogger } from 'autotel-adapters/core';
const useLogger = createUseLogger<{ requestId?: string }>({
adapterName: 'custom-framework',
enrich: (ctx) => ({ request_id: ctx.requestId }),
});
  • example-nextjs: Next.js with autotel-adapters/next and parseError() for client-side error handling.
  • example-nestjs: NestJS with auto-instrumentation and manual trace() in services.
  • example-fastify: Fastify with HTTP and Fastify auto-instrumentation.