nitro-opentelemetry
Version:
Opentelemetry module for the server framework nitro. Compatible with Nuxt.
62 lines (61 loc) • 2.67 kB
JavaScript
import * as api from "@opentelemetry/api";
import { ATTR_URL_PATH, ATTR_URL_FULL, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_SCHEME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT } from "@opentelemetry/semantic-conventions";
import { getResponseStatus, getRequestProtocol, getRequestURL, getHeaders } from "h3";
const context = api.context, trace = api.trace;
export default ((nitro) => {
nitro.hooks.hook("request", async (event) => {
const tracer = trace.getTracer("nitro-opentelemetry");
const requestURL = getRequestURL(event);
const currentContext = context.active();
const parentCtx = trace.getSpan(currentContext) ? currentContext : api.propagation.extract(currentContext, getHeaders(event));
const span = tracer.startSpan(await getSpanName(event), {
attributes: {
[]: (await nitro.h3App.resolve(event.path))?.route || event.path,
[]: event.path,
[]: event.method,
[]: getRequestProtocol(event),
[]: requestURL.host,
[]: requestURL.port
},
kind: api.SpanKind.SERVER
}, parentCtx);
const ctx = trace.setSpan(context.active(), span);
event.otel = {
span,
__endTime: void 0,
ctx
};
});
nitro.hooks.hook("beforeResponse", (event) => {
event.otel.__endTime = Date.now();
});
nitro.hooks.hook("afterResponse", async (event) => {
event.otel.span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, getResponseStatus(event));
await nitro.hooks.callHook("otel:span:end", { event, span: event.otel.span });
event.otel.span.end(event.otel.__endTime);
});
nitro.hooks.hook("error", async (error, { event }) => {
const ctx = { event, error, shouldRecord: true };
await nitro.hooks.callHook("otel:recordException:before", ctx);
if (event) {
if (ctx.shouldRecord) {
event.otel.span.recordException(error);
event.otel.span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, getResponseStatus(event));
}
await nitro.hooks.callHook("otel:span:end", { event, span: event.otel.span });
event.otel.span.end();
} else {
await nitro.hooks.callHook("otel:recordException:before", ctx);
if (ctx.shouldRecord) {
const span = trace.getSpan(api.ROOT_CONTEXT);
span?.recordException(error);
span?.end();
}
}
});
async function getSpanName(event) {
const ctx = { event, name: void 0 };
await nitro.hooks.callHook("otel:span:name", ctx);
return ctx.name || (await nitro.h3App.resolve(event.path))?.route || event.path;
}
});