11import {
22 type SpanAttributes ,
3+ type StartSpanOptions ,
34 captureException ,
45 debug ,
56 flushIfServerless ,
@@ -26,20 +27,6 @@ type MaybeInstrumentedDriver = MaybeInstrumented<Driver>;
2627
2728type DriverMethod = keyof Driver ;
2829
29- /**
30- * Methods that should have a key argument.
31- */
32- const KEYED_METHODS = new Set < DriverMethod > ( [
33- 'hasItem' ,
34- 'getItem' ,
35- 'getItemRaw' ,
36- 'getItems' ,
37- 'setItem' ,
38- 'setItemRaw' ,
39- 'setItems' ,
40- 'removeItem' ,
41- ] ) ;
42-
4330/**
4431 * Methods that should have a attribute to indicate a cache hit.
4532 */
@@ -127,45 +114,35 @@ function createMethodWrapper(
127114) : ( ...args : unknown [ ] ) => unknown {
128115 return new Proxy ( original , {
129116 async apply ( target , thisArg , args ) {
130- const attributes = getSpanAttributes ( methodName , driver , mountBase , args ) ;
117+ const options = createSpanStartOptions ( methodName , driver , mountBase , args ) ;
131118
132119 DEBUG_BUILD && debug . log ( `[storage] Running method: "${ methodName } " on driver: "${ driver . name ?? 'unknown' } "` ) ;
133120
134- const spanName = KEYED_METHODS . has ( methodName )
135- ? `${ mountBase } ${ args ?. [ 0 ] } `
136- : `storage.${ normalizeMethodName ( methodName ) } ` ;
137-
138- return startSpan (
139- {
140- name : spanName ,
141- attributes,
142- } ,
143- async span => {
144- try {
145- const result = await target . apply ( thisArg , args ) ;
146- span . setStatus ( { code : SPAN_STATUS_OK } ) ;
147-
148- if ( CACHE_HIT_METHODS . has ( methodName ) ) {
149- span . setAttribute ( SEMANTIC_ATTRIBUTE_CACHE_HIT , ! isEmptyValue ( result ) ) ;
150- }
151-
152- return result ;
153- } catch ( error ) {
154- span . setStatus ( { code : SPAN_STATUS_ERROR , message : 'internal_error' } ) ;
155- captureException ( error , {
156- mechanism : {
157- handled : false ,
158- type : attributes [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] ,
159- } ,
160- } ) ;
161-
162- // Re-throw the error to be handled by the caller
163- throw error ;
164- } finally {
165- await flushIfServerless ( ) ;
121+ return startSpan ( options , async span => {
122+ try {
123+ const result = await target . apply ( thisArg , args ) ;
124+ span . setStatus ( { code : SPAN_STATUS_OK } ) ;
125+
126+ if ( CACHE_HIT_METHODS . has ( methodName ) ) {
127+ span . setAttribute ( SEMANTIC_ATTRIBUTE_CACHE_HIT , ! isEmptyValue ( result ) ) ;
166128 }
167- } ,
168- ) ;
129+
130+ return result ;
131+ } catch ( error ) {
132+ span . setStatus ( { code : SPAN_STATUS_ERROR , message : 'internal_error' } ) ;
133+ captureException ( error , {
134+ mechanism : {
135+ handled : false ,
136+ type : options . attributes ?. [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] ,
137+ } ,
138+ } ) ;
139+
140+ // Re-throw the error to be handled by the caller
141+ throw error ;
142+ } finally {
143+ await flushIfServerless ( ) ;
144+ }
145+ } ) ;
169146 } ,
170147 } ) ;
171148}
@@ -191,11 +168,30 @@ function wrapStorageMount(storage: Storage): Storage['mount'] {
191168
192169 return mountWithInstrumentation ;
193170}
171+ /**
172+ * Normalizes the method name to snake_case to be used in span names or op.
173+ */
174+ function normalizeMethodName ( methodName : string ) : string {
175+ return methodName . replace ( / [ A - Z ] / g, letter => `_${ letter . toLowerCase ( ) } ` ) ;
176+ }
194177
195178/**
196- * Gets the span attributes for the storage method .
179+ * Checks if the value is empty, used for cache hit detection .
197180 */
198- function getSpanAttributes ( methodName : string , driver : Driver , mountBase : string , args : unknown [ ] ) : SpanAttributes {
181+ function isEmptyValue ( value : unknown ) : boolean {
182+ return value === null || value === undefined ;
183+ }
184+
185+ /**
186+ * Creates the span start options for the storage method.
187+ */
188+ function createSpanStartOptions (
189+ methodName : keyof Driver ,
190+ driver : Driver ,
191+ mountBase : string ,
192+ args : unknown [ ] ,
193+ ) : StartSpanOptions {
194+ const key = normalizeKey ( args ?. [ 0 ] ) ;
199195 const attributes : SpanAttributes = {
200196 [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : `cache.${ normalizeMethodName ( methodName ) } ` ,
201197 [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.cache.nuxt' ,
@@ -204,24 +200,38 @@ function getSpanAttributes(methodName: string, driver: Driver, mountBase: string
204200 'db.system.name' : driver . name ?? 'unknown' ,
205201 } ;
206202
207- // Add the key if it's a get/set/del call
208- if ( args ?. [ 0 ] && typeof args [ 0 ] === 'string' ) {
209- attributes [ SEMANTIC_ATTRIBUTE_CACHE_KEY ] = `${ mountBase } ${ args [ 0 ] } ` ;
203+ if ( key ) {
204+ attributes [ SEMANTIC_ATTRIBUTE_CACHE_KEY ] = `${ mountBase } ${ key } ` ;
210205 }
211206
212- return attributes ;
207+ return {
208+ name : `${ normalizeMethodName ( methodName ) } ${ mountBase } ${ key } ` ,
209+ attributes,
210+ } ;
213211}
214212
215213/**
216- * Normalizes the method name to snake_case to be used in span names or op.
214+ * Normalizes the key to a string for display purposes.
215+ * @param key The key to normalize.
217216 */
218- function normalizeMethodName ( methodName : string ) : string {
219- return methodName . replace ( / [ A - Z ] / g, letter => `_${ letter . toLowerCase ( ) } ` ) ;
220- }
217+ function normalizeKey ( key : unknown ) : string {
218+ if ( isEmptyValue ( key ) ) {
219+ return '' ;
220+ }
221221
222- /**
223- * Checks if the value is empty, used for cache hit detection.
224- */
225- function isEmptyValue ( value : unknown ) : boolean {
226- return value === null || value === undefined ;
222+ if ( typeof key === 'string' ) {
223+ return key ;
224+ }
225+
226+ // Handles an object with a key property
227+ if ( typeof key === 'object' && key !== null && 'key' in key ) {
228+ return `${ key . key } ` ;
229+ }
230+
231+ // Handles an array of keys
232+ if ( Array . isArray ( key ) ) {
233+ return key . map ( k => normalizeKey ( k ) ) . join ( ', ' ) ;
234+ }
235+
236+ return String ( key ) ;
227237}
0 commit comments