added observability support to processor app

This commit is contained in:
user
2026-03-01 08:34:46 +02:00
parent eb2f82247b
commit 17039aa3dd
7 changed files with 170 additions and 0 deletions

View File

@@ -7,6 +7,14 @@
"start": "node dist/index.js"
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.70.1",
"@opentelemetry/exporter-logs-otlp-proto": "^0.212.0",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.212.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.212.0",
"@opentelemetry/sdk-logs": "^0.212.0",
"@opentelemetry/sdk-metrics": "^2.1.0",
"@opentelemetry/sdk-node": "^0.212.0",
"@hono/node-server": "^1.19.9",
"@pkg/db": "workspace:*",
"@pkg/logger": "workspace:*",
@@ -14,6 +22,7 @@
"@pkg/result": "workspace:*",
"@pkg/settings": "workspace:*",
"hono": "^4.11.1",
"import-in-the-middle": "^3.0.0",
"valibot": "^1.2.0"
},
"devDependencies": {

View File

@@ -1,8 +1,12 @@
import "./instrumentation.js";
import { mobileRouter } from "./domains/mobile/router.js";
import { httpTelemetryMiddleware } from "./telemetry/http.middleware.js";
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
app.use("*", httpTelemetryMiddleware);
app.get("/health", (c) => {
return c.json({ ok: true });

View File

@@ -0,0 +1,50 @@
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-proto";
import { createAddHookMessageChannel } from "import-in-the-middle";
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { settings } from "@pkg/settings";
import { register } from "node:module";
const { registerOptions } = createAddHookMessageChannel();
register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions);
const normalizedEndpoint = settings.otelExporterOtlpHttpEndpoint.startsWith(
"http",
)
? settings.otelExporterOtlpHttpEndpoint
: `http://${settings.otelExporterOtlpHttpEndpoint}`;
if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = normalizedEndpoint;
}
const sdk = new NodeSDK({
serviceName: `${settings.otelServiceName}-processor`,
traceExporter: new OTLPTraceExporter(),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter(),
exportIntervalMillis: 10_000,
}),
logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter())],
instrumentations: [
getNodeAutoInstrumentations({
"@opentelemetry/instrumentation-winston": {
// We add OpenTelemetryTransportV3 explicitly in @pkg/logger.
disableLogSending: true,
},
}),
],
});
sdk.start();
const shutdown = () => {
void sdk.shutdown();
};
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);

View File

@@ -0,0 +1,77 @@
import { context, metrics, SpanStatusCode, trace } from "@opentelemetry/api";
import type { MiddlewareHandler } from "hono";
const tracer = trace.getTracer("processor.http");
const meter = metrics.getMeter("processor.http");
const requestCount = meter.createCounter("processor.http.server.requests", {
description: "Total number of processor HTTP requests",
});
const requestDuration = meter.createHistogram(
"processor.http.server.duration",
{
description: "Processor HTTP request duration",
unit: "ms",
},
);
const activeRequests = meter.createUpDownCounter(
"processor.http.server.active_requests",
{
description: "Number of in-flight processor HTTP requests",
},
);
export const httpTelemetryMiddleware: MiddlewareHandler = async (c, next) => {
const startedAt = performance.now();
const method = c.req.method;
const route = c.req.path;
const span = tracer.startSpan(`http ${method} ${route}`, {
attributes: {
"http.request.method": method,
"url.path": route,
},
});
activeRequests.add(1, {
"http.request.method": method,
"url.path": route,
});
try {
await context.with(trace.setSpan(context.active(), span), next);
span.setAttribute("http.response.status_code", c.res.status);
span.setStatus({
code:
c.res.status >= 500
? SpanStatusCode.ERROR
: SpanStatusCode.OK,
});
} catch (error) {
span.recordException(error as Error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: "Unhandled processor request error",
});
throw error;
} finally {
const durationMs = performance.now() - startedAt;
const attrs = {
"http.request.method": method,
"http.response.status_code": c.res.status,
"url.path": route,
};
requestCount.add(1, attrs);
requestDuration.record(durationMs, attrs);
activeRequests.add(-1, {
"http.request.method": method,
"url.path": route,
});
span.end();
}
};

View File

@@ -1,5 +1,6 @@
{
"name": "@pkg/logic",
"type": "module",
"scripts": {
"auth:schemagen": "pnpm dlx @better-auth/cli generate --config ./domains/auth/config.base.ts --output ../../packages/db/schema/better.auth.schema.ts"
},

View File

@@ -1,5 +1,7 @@
{
"name": "@pkg/result",
"module": "index.ts",
"type": "module",
"devDependencies": {
"@types/bun": "latest"
},

27
pnpm-lock.yaml generated
View File

@@ -195,6 +195,30 @@ importers:
'@hono/node-server':
specifier: ^1.19.9
version: 1.19.9(hono@4.12.3)
'@opentelemetry/api':
specifier: ^1.9.0
version: 1.9.0
'@opentelemetry/auto-instrumentations-node':
specifier: ^0.70.1
version: 0.70.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))
'@opentelemetry/exporter-logs-otlp-proto':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-metrics-otlp-proto':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-proto':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-metrics':
specifier: ^2.1.0
version: 2.5.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@pkg/db':
specifier: workspace:*
version: link:../../packages/db
@@ -213,6 +237,9 @@ importers:
hono:
specifier: ^4.11.1
version: 4.12.3
import-in-the-middle:
specifier: ^3.0.0
version: 3.0.0
valibot:
specifier: ^1.2.0
version: 1.2.0(typescript@5.9.3)