11import {
2+ type Span ,
23 type StartSpanOptions ,
34 addBreadcrumb ,
45 captureException ,
@@ -19,6 +20,11 @@ type PreparedStatementType = 'get' | 'run' | 'all' | 'raw';
1920 */
2021const patchedStatement = new WeakSet < PreparedStatement > ( ) ;
2122
23+ /**
24+ * The Sentry origin for the database plugin.
25+ */
26+ const SENTRY_ORIGIN = 'auto.db.nuxt' ;
27+
2228/**
2329 * Creates a Nitro plugin that instruments the database calls.
2430 */
@@ -49,38 +55,19 @@ function instrumentDatabase(db: Database): void {
4955 const query = args [ 0 ] ?. [ 0 ] ?? '' ;
5056 const opts = createStartSpanOptions ( query , db . dialect ) ;
5157
52- return startSpan ( opts , async span => {
53- try {
54- const result = await target . apply ( thisArg , args ) ;
55-
56- return result ;
57- } catch ( error ) {
58- span . setStatus ( { code : SPAN_STATUS_ERROR , message : 'internal_error' } ) ;
59- captureException ( error , {
60- mechanism : {
61- handled : false ,
62- type : opts . attributes ?. [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] ,
63- } ,
64- } ) ;
65-
66- // Re-throw the error to be handled by the caller
67- throw error ;
68- } finally {
69- await flushIfServerless ( ) ;
70- }
71- } ) ;
58+ return startSpan (
59+ opts ,
60+ handleSpanStart ( ( ) => target . apply ( thisArg , args ) ) ,
61+ ) ;
7262 } ,
7363 } ) ;
7464
7565 db . exec = new Proxy ( db . exec , {
7666 apply ( target , thisArg , args : Parameters < typeof db . exec > ) {
77- return startSpan ( createStartSpanOptions ( args [ 0 ] , db . dialect , 'run' ) , async ( ) => {
78- const result = await target . apply ( thisArg , args ) ;
79-
80- createBreadcrumb ( args [ 0 ] , 'run' ) ;
81-
82- return result ;
83- } ) ;
67+ return startSpan (
68+ createStartSpanOptions ( args [ 0 ] , db . dialect , 'run' ) ,
69+ handleSpanStart ( ( ) => target . apply ( thisArg , args ) , { query : args [ 0 ] , type : 'run' } ) ,
70+ ) ;
8471 } ,
8572 } ) ;
8673}
@@ -118,37 +105,30 @@ function instrumentPreparedStatementQueries(
118105 // eslint-disable-next-line @typescript-eslint/unbound-method
119106 statement . get = new Proxy ( statement . get , {
120107 apply ( target , thisArg , args : Parameters < typeof statement . get > ) {
121- return startSpan ( createStartSpanOptions ( query , dialect , 'get' ) , async ( ) => {
122- const result = await target . apply ( thisArg , args ) ;
123- createBreadcrumb ( query , 'get' ) ;
124-
125- return result ;
126- } ) ;
108+ return startSpan (
109+ createStartSpanOptions ( query , dialect , 'get' ) ,
110+ handleSpanStart ( ( ) => target . apply ( thisArg , args ) , { query, type : 'get' } ) ,
111+ ) ;
127112 } ,
128113 } ) ;
129114
130115 // eslint-disable-next-line @typescript-eslint/unbound-method
131116 statement . run = new Proxy ( statement . run , {
132117 apply ( target , thisArg , args : Parameters < typeof statement . run > ) {
133- return startSpan ( createStartSpanOptions ( query , dialect , 'run' ) , async ( ) => {
134- const result = await target . apply ( thisArg , args ) ;
135- createBreadcrumb ( query , 'run' ) ;
136-
137- return result ;
138- } ) ;
118+ return startSpan (
119+ createStartSpanOptions ( query , dialect , 'run' ) ,
120+ handleSpanStart ( ( ) => target . apply ( thisArg , args ) , { query, type : 'run' } ) ,
121+ ) ;
139122 } ,
140123 } ) ;
141124
142125 // eslint-disable-next-line @typescript-eslint/unbound-method
143126 statement . all = new Proxy ( statement . all , {
144127 apply ( target , thisArg , args : Parameters < typeof statement . all > ) {
145- return startSpan ( createStartSpanOptions ( query , dialect , 'all' ) , async ( ) => {
146- const result = await target . apply ( thisArg , args ) ;
147- // Since all has no regular shape, we can assume if it returns an array, it's a success.
148- createBreadcrumb ( query , 'all' ) ;
149-
150- return result ;
151- } ) ;
128+ return startSpan (
129+ createStartSpanOptions ( query , dialect , 'all' ) ,
130+ handleSpanStart ( ( ) => target . apply ( thisArg , args ) , { query, type : 'all' } ) ,
131+ ) ;
152132 } ,
153133 } ) ;
154134
@@ -157,6 +137,35 @@ function instrumentPreparedStatementQueries(
157137 return statement ;
158138}
159139
140+ /**
141+ * Creates a span start callback handler
142+ */
143+ function handleSpanStart ( fn : ( ) => unknown , breadcrumbOpts ?: { query : string ; type : PreparedStatementType } ) {
144+ return async ( span : Span ) => {
145+ try {
146+ const result = await fn ( ) ;
147+ if ( breadcrumbOpts ) {
148+ createBreadcrumb ( breadcrumbOpts . query , breadcrumbOpts . type ) ;
149+ }
150+
151+ return result ;
152+ } catch ( error ) {
153+ span . setStatus ( { code : SPAN_STATUS_ERROR , message : 'internal_error' } ) ;
154+ captureException ( error , {
155+ mechanism : {
156+ handled : false ,
157+ type : SENTRY_ORIGIN ,
158+ } ,
159+ } ) ;
160+
161+ // Re-throw the error to be handled by the caller
162+ throw error ;
163+ } finally {
164+ await flushIfServerless ( ) ;
165+ }
166+ } ;
167+ }
168+
160169function createBreadcrumb ( query : string , type : PreparedStatementType ) : void {
161170 addBreadcrumb ( {
162171 category : 'query' ,
@@ -177,7 +186,7 @@ function createStartSpanOptions(query: string, dialect: string, type?: PreparedS
177186 attributes : {
178187 'db.system' : dialect ,
179188 'db.query_type' : type ,
180- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.db.nuxt' ,
189+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : SENTRY_ORIGIN ,
181190 } ,
182191 } ;
183192}
0 commit comments