Skip to content

Commit 62c992f

Browse files
committed
feat: more orpc telemetyr
1 parent 950ef51 commit 62c992f

File tree

8 files changed

+229
-31
lines changed

8 files changed

+229
-31
lines changed

apps/api/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"@elysiajs/cors": "^1.4.0",
2626
"@opentelemetry/api": "^1.9.0",
2727
"@opentelemetry/exporter-trace-otlp-proto": "^0.208.0",
28+
"@opentelemetry/instrumentation-http": "^0.55.0",
29+
"@opentelemetry/instrumentation-pg": "^0.48.0",
2830
"@opentelemetry/resources": "^2.2.0",
2931
"@opentelemetry/sdk-node": "^0.208.0",
3032
"@opentelemetry/sdk-trace-node": "^2.2.0",

apps/api/src/index.ts

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import {
44
appRouter,
55
createAbortSignalInterceptor,
66
createRPCContext,
7+
recordORPCError,
78
setupUncaughtErrorHandlers,
89
} from "@databuddy/rpc";
910
import { logger } from "@databuddy/shared/logger";
1011
import cors from "@elysiajs/cors";
11-
import { onError } from "@orpc/server";
12+
import { context } from "@opentelemetry/api";
13+
import { ORPCError, onError } from "@orpc/server";
1214
import { RPCHandler } from "@orpc/server/fetch";
1315
import { autumnHandler } from "autumn-js/elysia";
1416
import { Elysia } from "elysia";
@@ -39,7 +41,8 @@ const rpcHandler = new RPCHandler(appRouter, {
3941

4042
const app = new Elysia()
4143
.state("tracing", {
42-
span: null as ReturnType<typeof startRequestSpan> | null,
44+
span: null as ReturnType<typeof startRequestSpan>["span"] | null,
45+
activeContext: null as ReturnType<typeof context.active> | null | undefined,
4346
startTime: 0,
4447
})
4548
.use(publicApi)
@@ -58,11 +61,19 @@ const app = new Elysia()
5861
.onBeforeHandle(function startTrace({ request, path, store }) {
5962
const method = request.method;
6063
const startTime = Date.now();
61-
const span = startRequestSpan(method, request.url, path);
6264

63-
// Store span and start time in Elysia store
65+
// Extract route from path (e.g., "/rpc/websites.list" -> "websites.list")
66+
const route = path.startsWith("/rpc/") ? path.slice(5) : path;
67+
const { span, activeContext } = startRequestSpan(
68+
method,
69+
request.url,
70+
route
71+
);
72+
73+
// Store span, context, and start time in Elysia store
6474
store.tracing = {
6575
span,
76+
activeContext,
6677
startTime,
6778
};
6879
})
@@ -99,15 +110,35 @@ const app = new Elysia()
99110
.use(exportRoute)
100111
.all(
101112
"/rpc/*",
102-
async ({ request }: { request: Request }) => {
113+
async ({ request, store }) => {
103114
try {
104-
const context = await createRPCContext({ headers: request.headers });
105-
const { response } = await rpcHandler.handle(request, {
106-
prefix: "/rpc",
107-
context,
108-
});
115+
// Run RPC handler within the active trace context if available
116+
const handler = async () => {
117+
const rpcContext = await createRPCContext({
118+
headers: request.headers,
119+
});
120+
const { response } = await rpcHandler.handle(request, {
121+
prefix: "/rpc",
122+
context: rpcContext,
123+
});
124+
return response;
125+
};
126+
127+
const activeContext = store.tracing?.activeContext;
128+
const response = activeContext
129+
? await context.with(activeContext, handler)
130+
: await handler();
131+
109132
return response ?? new Response("Not Found", { status: 404 });
110133
} catch (error) {
134+
// Record ORPC errors in OpenTelemetry
135+
if (error instanceof ORPCError) {
136+
recordORPCError({
137+
code: error.code,
138+
message: error.message,
139+
});
140+
}
141+
111142
logger.error({ error }, "RPC handler failed");
112143
return new Response("Internal Server Error", { status: 500 });
113144
}

apps/api/src/lib/tracing.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { createORPCInstrumentation } from "@databuddy/rpc";
2-
import { type Span, SpanStatusCode, trace } from "@opentelemetry/api";
2+
import { context, type Span, SpanStatusCode, trace } from "@opentelemetry/api";
33
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
4+
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
5+
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg";
46
import { resourceFromAttributes } from "@opentelemetry/resources";
57
import { NodeSDK } from "@opentelemetry/sdk-node";
68
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
@@ -39,7 +41,16 @@ export function initTracing(): void {
3941
maxExportBatchSize: 512,
4042
maxQueueSize: 2048,
4143
}),
42-
instrumentations: [createORPCInstrumentation()],
44+
instrumentations: [
45+
new HttpInstrumentation({
46+
ignoreIncomingRequestHook: (req: { url?: string }) => {
47+
// Don't trace health checks
48+
return req.url?.includes("/health") ?? false;
49+
},
50+
}),
51+
new PgInstrumentation(),
52+
createORPCInstrumentation(),
53+
],
4354
});
4455

4556
sdk.start();
@@ -99,22 +110,28 @@ export function setAttributes(
99110
}
100111

101112
/**
102-
* Start HTTP request span
113+
* Start HTTP request span and set it as active
114+
* Returns both the span and the context with the span set as active
103115
*/
104116
export function startRequestSpan(
105117
method: string,
106118
path: string,
107119
route?: string
108-
): Span {
120+
): { span: Span; activeContext: ReturnType<typeof context.active> } {
109121
const tracer = getTracer();
110-
return tracer.startSpan(`${method} ${route ?? path}`, {
122+
const span = tracer.startSpan(`${method} ${route ?? path}`, {
111123
kind: 1, // SERVER
112124
attributes: {
113125
"http.method": method,
114126
"http.route": route ?? path,
115127
"http.target": path,
116128
},
117129
});
130+
131+
// Create context with this span as active
132+
const activeContext = trace.setSpan(context.active(), span);
133+
134+
return { span, activeContext };
118135
}
119136

120137
/**

apps/api/src/routes/assistant.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { auth, websitesApi } from "@databuddy/auth";
22
import type { StreamingUpdate } from "@databuddy/shared/types/assistant";
3-
import { record, setAttributes } from "@elysiajs/opentelemetry";
43
import { Elysia } from "elysia";
54
import { processAssistantRequest } from "../agent/processor";
65
import { createStreamingResponse } from "../agent/utils/stream-utils";
6+
import { record, setAttributes } from "../lib/tracing";
77
import { validateWebsite } from "../lib/website-utils";
88
import { AssistantRequestSchema } from "../schemas";
99

0 commit comments

Comments
 (0)