Hono
The autotel-hono package provides an otel() middleware for automatic request tracing and HTTP metrics in Hono applications.
Installation
Section titled “Installation”npm install autotel-hono autotelQuick Start
Section titled “Quick Start”import { Hono } from 'hono';import { init, getRequestLogger } from 'autotel';import { otel } from 'autotel-hono';
init({ service: 'my-api' });
const app = new Hono();app.use('*', otel());
app.get('/api/users', async (c) => { const log = getRequestLogger(); log.set({ route: '/api/users' }); const users = await db.users.findAll(); log.emitNow(); return c.json(users);});With Adapters
Section titled “With Adapters”Use useLogger() from autotel-adapters/hono when the otel() middleware already creates a 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 });});Streaming responses
Section titled “Streaming responses”A handler returning an SSE, NDJSON, or AI stream returns before the work finishes. Emit the request snapshot at that moment and you capture a request that has barely started, while everything the stream adds later lands nowhere.
autotelMiddleware() from autotel-adapters/hono waits for the body. Use it in
place of otel() when you stream: it creates the span, the request logger, and
emits the snapshot once the stream closes, errors, or gets cancelled.
import { autotelMiddleware, useLogger } from 'autotel-adapters/hono';
app.use('*', autotelMiddleware());
app.get('/chat', (c) => { const log = useLogger(c); return streamSSE(c, async (stream) => { for await (const token of model.stream(prompt)) { await stream.writeSSE({ data: token }); } log.set({ 'chat.tokens': tokenCount }); // still lands in the snapshot });});A client that disconnects mid-stream still produces a snapshot, so an abandoned generation reads as a cancelled stream rather than a request that never finished. The middleware wraps the response without locking the original body, so the client receives exactly what it would have without it.
Pass autoEmit: false when you want to call .emitNow() yourself.
Options
Section titled “Options”The otel() middleware accepts options for customizing tracing behavior:
| Option | Description |
|---|---|
tracer |
Custom tracer instance |
tracerProvider |
Custom tracer provider |
meter |
Custom meter instance |
spanNameFactory |
Custom span name from request |
captureRequestHeaders |
Headers to capture as span attributes |
captureResponseHeaders |
Response headers to capture |
captureActiveRequests |
Track active request gauge |
captureRequestDuration |
Track request duration histogram |
serviceName |
Override service name |
serviceVersion |
Override service version |
disableTracing |
Disable span creation (metrics only) |
Span Attributes
Section titled “Span Attributes”HTTP request spans include:
http.request.method: GET, POST, etc.url.path: Request pathhttp.response.status_code: Response statushttp.request.duration_ms: Request duration
Examples
Section titled “Examples”example-hono: Hono withotel()middleware,useLogger()request-scoped logging, and manualtrace()in handlers.
Related
Section titled “Related”- autotel-adapters: DX helpers (
useLogger,withAutotel) - Agent Guide: Framework setup snippets