@@ -12,10 +12,14 @@ import {
12
12
} from '@sentry/core' ;
13
13
// eslint-disable-next-line import/no-extraneous-dependencies
14
14
import { defineNitroPlugin , useStorage } from 'nitropack/runtime' ;
15
- import type { Driver } from 'unstorage' ;
15
+ import type { Driver , Storage } from 'unstorage' ;
16
16
// @ts -expect-error - This is a virtual module
17
17
import { userStorageMounts } from '#sentry/storage-config.mjs' ;
18
18
19
+ type MaybeInstrumentedDriver = Driver & {
20
+ __sentry_instrumented__ ?: boolean ;
21
+ } ;
22
+
19
23
/**
20
24
* Creates a Nitro plugin that instruments the storage driver.
21
25
*/
@@ -35,24 +39,30 @@ export default defineNitroPlugin(async _nitroApp => {
35
39
continue ;
36
40
}
37
41
38
- debug . log ( `[Storage Instrumentation] Instrumenting mount: "${ mount . base } "` ) ;
39
-
40
- const driver = instrumentDriver ( mount . driver , mount . base ) ;
41
-
42
42
try {
43
- // Remount with instrumented driver
44
- await storage . unmount ( mount . base ) ;
45
- await storage . mount ( mount . base , driver ) ;
43
+ instrumentDriver ( mount . driver , mount . base ) ;
46
44
} catch {
47
45
debug . error ( `[Storage Instrumentation] Failed to unmount mount: "${ mount . base } "` ) ;
48
46
}
47
+
48
+ // Wrap the mount method to instrument future mounts
49
+ storage . mount = wrapStorageMount ( storage ) ;
49
50
}
50
51
} ) ;
51
52
52
53
/**
53
54
* Instruments a driver by wrapping all method calls using proxies.
54
55
*/
55
- function instrumentDriver ( driver : Driver , mountBase : string ) : Driver {
56
+ function instrumentDriver ( driver : MaybeInstrumentedDriver , mountBase : string ) : Driver {
57
+ // Already instrumented, skip...
58
+ if ( driver . __sentry_instrumented__ ) {
59
+ debug . log ( `[Storage Instrumentation] Driver already instrumented: "${ driver . name } ". Skipping...` ) ;
60
+
61
+ return driver ;
62
+ }
63
+
64
+ debug . log ( `[Storage Instrumentation] Instrumenting driver: "${ driver . name } " on mount: "${ mountBase } "` ) ;
65
+
56
66
// List of driver methods to instrument
57
67
const methodsToInstrument : ( keyof Driver ) [ ] = [
58
68
'hasItem' ,
@@ -80,6 +90,9 @@ function instrumentDriver(driver: Driver, mountBase: string): Driver {
80
90
driver [ methodName ] = createMethodWrapper ( original , methodName , driver . name ?? 'unknown' , mountBase ) ;
81
91
}
82
92
93
+ // Mark as instrumented
94
+ driver . __sentry_instrumented__ = true ;
95
+
83
96
return driver ;
84
97
}
85
98
@@ -96,6 +109,8 @@ function createMethodWrapper(
96
109
async apply ( target , thisArg , args ) {
97
110
const attributes = getSpanAttributes ( methodName , driverName ?? 'unknown' , mountBase ) ;
98
111
112
+ debug . log ( `[Storage Instrumentation] Running method: "${ methodName } " on driver: "${ driverName } "` ) ;
113
+
99
114
return startSpan (
100
115
{
101
116
name : `storage.${ methodName } ` ,
@@ -127,6 +142,23 @@ function createMethodWrapper(
127
142
} ) ;
128
143
}
129
144
145
+ /**
146
+ * Wraps the storage mount method to instrument the driver.
147
+ */
148
+ function wrapStorageMount ( storage : Storage ) : Storage [ 'mount' ] {
149
+ const original = storage . mount ;
150
+
151
+ function mountWithInstrumentation ( base : string , driver : Driver ) : Storage {
152
+ debug . log ( `[Storage Instrumentation] Instrumenting mount: "${ base } "` ) ;
153
+
154
+ const instrumentedDriver = instrumentDriver ( driver , base ) ;
155
+
156
+ return original ( base , instrumentedDriver ) ;
157
+ }
158
+
159
+ return mountWithInstrumentation ;
160
+ }
161
+
130
162
/**
131
163
* Gets the span attributes for the storage method.
132
164
*/
0 commit comments