Feature Req: Otel middleware
Since Otel Telemetry is becoming the standard, it would be good to have a middleware that also plays well with Hono logger
any updates on this @yusukebe ?
resemble? https://github.com/honojs/hono/pull/3025
Hi @DawnImpulse
There is no update. We (at least I) don't plan to create it right now, so I hope someone works on it.
Here is a simple solution. It needs a test as well. Do you have any suggestion about coding?
@kevbook @DawnImpulse @yusukebe
import otelapi, { type Tracer } from "@opentelemetry/api";
import {
context,
propagation,
SpanKind,
SpanStatusCode,
trace,
} from "@opentelemetry/api";
import type { MiddlewareHandler } from "hono";
import type { Env } from "../../env.ts";
import type { PortLogger } from "../logger/logger.ts";
let otel: typeof otelapi | undefined;
let rawTracer: Tracer | undefined;
export const opentelemetryMiddleware =
(logger: PortLogger): MiddlewareHandler<Env> =>
async (ctx, next) => {
if (!otel) {
try {
await next();
if (ctx.error) {
logger.error({ error: ctx.error.message });
}
} catch (error) {
logger.error({
error: error instanceof Error ? error.message : "unknown error",
});
throw error;
}
return;
}
if (!rawTracer) {
rawTracer = otel.trace.getTracer("hono-poc", "0.0.0");
}
const span = rawTracer.startSpan(
"opentelemetry.infrastructure.middleware",
{
attributes: {
"http.method": ctx.req.method,
"http.url": ctx.req.url,
},
kind: SpanKind.SERVER,
},
propagation.extract(context.active(), ctx.req.raw.headers),
);
try {
await context.with(trace.setSpan(context.active(), span), async () => {
await next();
});
if (ctx.error) {
logger.error({ error: ctx.error.message });
span.recordException(ctx.error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: ctx.error.message,
});
} else {
span.setStatus({ code: SpanStatusCode.OK });
}
} catch (error) {
logger.error({
error: error instanceof Error ? error.message : "unknown error",
});
span.recordException(error as Error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: error instanceof Error ? error.message : "unknown error",
});
throw error;
}
span.end();
};
Hi mates! How is this coming along? Actively worked on?
Is there anything that needs to be done for this aside from
- Turning @smhmayboudi code snippet into PR-ready code
- Adding tests
For the latter, afaik the 2 main options for automated tests are to do the usually kind of mocking/spying on the @opentelemetry/api, but there's also a way to setup an in-memory exporter to capture the telemetry output and assert about it there (https://github.com/open-telemetry/opentelemetry-js/issues/4969 has more discussion around this and which to use)
For manual tests, there's a ConsoleSpanExporter you can use in the SDK that will write the telemetry data to stdout. There are also several local GUI options (e.g. the Aspire Dashboard docker image, OTEL Desktop Viewer binary, Seq docker image, Grafana all-in-one, Jaeger all-in-one) and 1 TUI option (OTEL-TUI) afaik.
New to Hono so apologies if I'm missing a lot.