11import "./polyfills/compression" ;
22import { auth } from "@databuddy/auth" ;
3- import { appRouter , createRPCContext } from "@databuddy/rpc" ;
3+ import {
4+ appRouter ,
5+ createAbortSignalInterceptor ,
6+ createRPCContext ,
7+ setupUncaughtErrorHandlers ,
8+ } from "@databuddy/rpc" ;
49import { logger } from "@databuddy/shared/logger" ;
510import cors from "@elysiajs/cors" ;
6- import { opentelemetry } from "@elysiajs/opentelemetry" ;
7- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto" ;
8- import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node" ;
911import { onError } from "@orpc/server" ;
1012import { RPCHandler } from "@orpc/server/fetch" ;
1113import { autumnHandler } from "autumn-js/elysia" ;
1214import { Elysia } from "elysia" ;
15+ import {
16+ endRequestSpan ,
17+ initTracing ,
18+ shutdownTracing ,
19+ startRequestSpan ,
20+ } from "./lib/tracing" ;
1321import { assistant } from "./routes/assistant" ;
1422// import { customSQL } from './routes/custom-sql';
1523import { exportRoute } from "./routes/export" ;
1624import { health } from "./routes/health" ;
1725import { publicApi } from "./routes/public" ;
1826import { query } from "./routes/query" ;
1927
28+ initTracing ( ) ;
29+ setupUncaughtErrorHandlers ( ) ;
30+
2031const rpcHandler = new RPCHandler ( appRouter , {
2132 interceptors : [
33+ createAbortSignalInterceptor ( ) ,
2234 onError ( ( error ) => {
2335 logger . error ( error ) ;
2436 } ) ,
2537 ] ,
2638} ) ;
2739
2840const app = new Elysia ( )
29- . use (
30- opentelemetry ( {
31- spanProcessors : [
32- new BatchSpanProcessor (
33- new OTLPTraceExporter ( {
34- url : "https://api.axiom.co/v1/traces" ,
35- headers : {
36- Authorization : `Bearer ${ process . env . AXIOM_TOKEN } ` ,
37- "X-Axiom-Dataset" : process . env . AXIOM_DATASET ?? "api" ,
38- } ,
39- } )
40- ) ,
41- ] ,
42- } )
43- )
41+ . state ( "tracing" , {
42+ span : null as ReturnType < typeof startRequestSpan > | null ,
43+ startTime : 0 ,
44+ } )
4445 . use ( publicApi )
4546 . use (
4647 cors ( {
@@ -54,6 +55,23 @@ const app = new Elysia()
5455 } )
5556 )
5657 . use ( health )
58+ . onBeforeHandle ( function startTrace ( { request, path, store } ) {
59+ const method = request . method ;
60+ const startTime = Date . now ( ) ;
61+ const span = startRequestSpan ( method , request . url , path ) ;
62+
63+ // Store span and start time in Elysia store
64+ store . tracing = {
65+ span,
66+ startTime,
67+ } ;
68+ } )
69+ . onAfterHandle ( function endTrace ( { response, store } ) {
70+ if ( store . tracing ?. span && store . tracing . startTime ) {
71+ const statusCode = response instanceof Response ? response . status : 200 ;
72+ endRequestSpan ( store . tracing . span , statusCode , store . tracing . startTime ) ;
73+ }
74+ } )
5775 . use (
5876 autumnHandler ( {
5977 identify : async ( { request } ) => {
@@ -63,21 +81,15 @@ const app = new Elysia()
6381 } ) ;
6482
6583 return {
66- customerId : session ?. user . id ,
84+ customerId : session ?. user . id ?? undefined ,
6785 customerData : {
68- name : session ?. user . name ,
69- email : session ?. user . email ,
86+ name : session ?. user . name ?? undefined ,
87+ email : session ?. user . email ?? undefined ,
7088 } ,
7189 } ;
7290 } catch ( error ) {
7391 logger . error ( { error } , "Failed to get session for autumn handler" ) ;
74- return {
75- customerId : null ,
76- customerData : {
77- name : null ,
78- email : null ,
79- } ,
80- } ;
92+ return null ;
8193 }
8294 } ,
8395 } )
@@ -104,7 +116,12 @@ const app = new Elysia()
104116 parse : "none" ,
105117 }
106118 )
107- . onError ( function handleError ( { error, code } ) {
119+ . onError ( function handleError ( { error, code, store } ) {
120+ if ( store . tracing ?. span && store . tracing . startTime ) {
121+ const statusCode = code === "NOT_FOUND" ? 404 : 500 ;
122+ endRequestSpan ( store . tracing . span , statusCode , store . tracing . startTime ) ;
123+ }
124+
108125 const errorMessage = error instanceof Error ? error . message : String ( error ) ;
109126 logger . error ( { error, code } , errorMessage ) ;
110127
@@ -123,12 +140,18 @@ export default {
123140 port : 3001 ,
124141} ;
125142
126- process . on ( "SIGINT" , ( ) => {
127- logger . info ( { message : "SIGINT signal received, shutting down..." } ) ;
143+ process . on ( "SIGINT" , async ( ) => {
144+ logger . info ( "SIGINT received, shutting down gracefully..." ) ;
145+ await shutdownTracing ( ) . catch ( ( error ) =>
146+ logger . error ( { error } , "Shutdown error" )
147+ ) ;
128148 process . exit ( 0 ) ;
129149} ) ;
130150
131- process . on ( "SIGTERM" , ( ) => {
132- logger . info ( { message : "SIGTERM signal received, shutting down..." } ) ;
151+ process . on ( "SIGTERM" , async ( ) => {
152+ logger . info ( "SIGTERM received, shutting down gracefully..." ) ;
153+ await shutdownTracing ( ) . catch ( ( error ) =>
154+ logger . error ( { error } , "Shutdown error" )
155+ ) ;
133156 process . exit ( 0 ) ;
134157} ) ;
0 commit comments