1
1
import {
2
2
captureException ,
3
3
flush ,
4
+ SEMANTIC_ATTRIBUTE_SENTRY_OP ,
4
5
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
5
6
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
6
7
startSpan ,
@@ -66,7 +67,7 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
66
67
'faas.cron' : event . cron ,
67
68
'faas.time' : new Date ( event . scheduledTime ) . toISOString ( ) ,
68
69
'faas.trigger' : 'timer' ,
69
- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.faas.cloudflare' ,
70
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.faas.cloudflare.scheduled ' ,
70
71
[ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'task' ,
71
72
} ,
72
73
} ,
@@ -87,8 +88,122 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
87
88
88
89
markAsInstrumented ( handler . scheduled ) ;
89
90
}
91
+
92
+ if ( 'email' in handler && typeof handler . email === 'function' && ! isInstrumented ( handler . email ) ) {
93
+ handler . email = new Proxy ( handler . email , {
94
+ apply ( target , thisArg , args : Parameters < EmailExportedHandler < Env > > ) {
95
+ const [ emailMessage , env , context ] = args ;
96
+ return withIsolationScope ( isolationScope => {
97
+ const options = getFinalOptions ( optionsCallback ( env ) , env ) ;
98
+
99
+ const client = init ( options ) ;
100
+ isolationScope . setClient ( client ) ;
101
+
102
+ addCloudResourceContext ( isolationScope ) ;
103
+
104
+ return startSpan (
105
+ {
106
+ op : 'faas.email' ,
107
+ name : `Handle Email ${ emailMessage . to } ` ,
108
+ attributes : {
109
+ 'faas.trigger' : 'email' ,
110
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.faas.cloudflare.email' ,
111
+ [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'task' ,
112
+ } ,
113
+ } ,
114
+ async ( ) => {
115
+ try {
116
+ return await ( target . apply ( thisArg , args ) as ReturnType < typeof target > ) ;
117
+ } catch ( e ) {
118
+ captureException ( e , { mechanism : { handled : false , type : 'cloudflare' } } ) ;
119
+ throw e ;
120
+ } finally {
121
+ context . waitUntil ( flush ( 2000 ) ) ;
122
+ }
123
+ } ,
124
+ ) ;
125
+ } ) ;
126
+ } ,
127
+ } ) ;
128
+
129
+ markAsInstrumented ( handler . email ) ;
130
+ }
131
+
132
+ if ( 'queue' in handler && typeof handler . queue === 'function' && ! isInstrumented ( handler . queue ) ) {
133
+ handler . queue = new Proxy ( handler . queue , {
134
+ apply ( target , thisArg , args : Parameters < ExportedHandlerQueueHandler < Env , QueueHandlerMessage > > ) {
135
+ const [ batch , env , context ] = args ;
136
+
137
+ return withIsolationScope ( isolationScope => {
138
+ const options = getFinalOptions ( optionsCallback ( env ) , env ) ;
139
+
140
+ const client = init ( options ) ;
141
+ isolationScope . setClient ( client ) ;
142
+
143
+ addCloudResourceContext ( isolationScope ) ;
144
+
145
+ return startSpan (
146
+ {
147
+ op : 'faas.queue' ,
148
+ name : `process ${ batch . queue } ` ,
149
+ attributes : {
150
+ 'faas.trigger' : 'pubsub' ,
151
+ 'messaging.destination.name' : batch . queue ,
152
+ 'messaging.system' : 'cloudflare' ,
153
+ 'messaging.batch.message_count' : batch . messages . length ,
154
+ 'messaging.message.retry.count' : batch . messages . reduce ( ( acc , message ) => acc + message . attempts , 0 ) ,
155
+ [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : 'queue.process' ,
156
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.faas.cloudflare.queue' ,
157
+ [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'task' ,
158
+ } ,
159
+ } ,
160
+ async ( ) => {
161
+ try {
162
+ return await ( target . apply ( thisArg , args ) as ReturnType < typeof target > ) ;
163
+ } catch ( e ) {
164
+ captureException ( e , { mechanism : { handled : false , type : 'cloudflare' } } ) ;
165
+ throw e ;
166
+ } finally {
167
+ context . waitUntil ( flush ( 2000 ) ) ;
168
+ }
169
+ } ,
170
+ ) ;
171
+ } ) ;
172
+ } ,
173
+ } ) ;
174
+
175
+ markAsInstrumented ( handler . queue ) ;
176
+ }
177
+
178
+ if ( 'tail' in handler && typeof handler . tail === 'function' && ! isInstrumented ( handler . tail ) ) {
179
+ handler . tail = new Proxy ( handler . tail , {
180
+ apply ( target , thisArg , args : Parameters < ExportedHandlerTailHandler < Env > > ) {
181
+ const [ , env , context ] = args ;
182
+
183
+ return withIsolationScope ( async isolationScope => {
184
+ const options = getFinalOptions ( optionsCallback ( env ) , env ) ;
185
+
186
+ const client = init ( options ) ;
187
+ isolationScope . setClient ( client ) ;
188
+
189
+ addCloudResourceContext ( isolationScope ) ;
190
+
191
+ try {
192
+ return await ( target . apply ( thisArg , args ) as ReturnType < typeof target > ) ;
193
+ } catch ( e ) {
194
+ captureException ( e , { mechanism : { handled : false , type : 'cloudflare' } } ) ;
195
+ throw e ;
196
+ } finally {
197
+ context . waitUntil ( flush ( 2000 ) ) ;
198
+ }
199
+ } ) ;
200
+ } ,
201
+ } ) ;
202
+
203
+ markAsInstrumented ( handler . tail ) ;
204
+ }
205
+
90
206
// This is here because Miniflare sometimes cannot get instrumented
91
- //
92
207
} catch ( e ) {
93
208
// Do not console anything here, we don't want to spam the console with errors
94
209
}
0 commit comments