1
- import type { ExportedHandler , ExportedHandlerFetchHandler } from '@cloudflare/workers-types' ;
2
- import type { Options } from '@sentry/types' ;
1
+ import type {
2
+ ExportedHandler ,
3
+ ExportedHandlerFetchHandler ,
4
+ ExportedHandlerScheduledHandler ,
5
+ } from '@cloudflare/workers-types' ;
6
+ import {
7
+ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
8
+ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
9
+ captureException ,
10
+ flush ,
11
+ startSpan ,
12
+ withIsolationScope ,
13
+ } from '@sentry/core' ;
3
14
import { setAsyncLocalStorageAsyncContextStrategy } from './async' ;
15
+ import type { CloudflareOptions } from './client' ;
4
16
import { wrapRequestHandler } from './request' ;
17
+ import { addCloudResourceContext } from './scope-utils' ;
18
+ import { init } from './sdk' ;
5
19
6
20
/**
7
21
* Extract environment generic from exported handler.
@@ -21,7 +35,7 @@ type ExtractEnv<P> = P extends ExportedHandler<infer Env> ? Env : never;
21
35
*/
22
36
// eslint-disable-next-line @typescript-eslint/no-explicit-any
23
37
export function withSentry < E extends ExportedHandler < any > > (
24
- optionsCallback : ( env : ExtractEnv < E > ) => Options ,
38
+ optionsCallback : ( env : ExtractEnv < E > ) => CloudflareOptions ,
25
39
handler : E ,
26
40
) : E {
27
41
setAsyncLocalStorageAsyncContextStrategy ( ) ;
@@ -40,5 +54,52 @@ export function withSentry<E extends ExportedHandler<any>>(
40
54
( handler . fetch as any ) . __SENTRY_INSTRUMENTED__ = true ;
41
55
}
42
56
57
+ if (
58
+ 'scheduled' in handler &&
59
+ typeof handler . scheduled === 'function' &&
60
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
61
+ ! ( handler . scheduled as any ) . __SENTRY_INSTRUMENTED__
62
+ ) {
63
+ handler . scheduled = new Proxy ( handler . scheduled , {
64
+ apply ( target , thisArg , args : Parameters < ExportedHandlerScheduledHandler < ExtractEnv < E > > > ) {
65
+ const [ event , env , context ] = args ;
66
+ return withIsolationScope ( isolationScope => {
67
+ const options = optionsCallback ( env ) ;
68
+ const client = init ( options ) ;
69
+ isolationScope . setClient ( client ) ;
70
+
71
+ addCloudResourceContext ( isolationScope ) ;
72
+
73
+ return startSpan (
74
+ {
75
+ op : 'faas.cron' ,
76
+ name : `Scheduled Cron ${ event . cron } ` ,
77
+ attributes : {
78
+ 'faas.cron' : event . cron ,
79
+ 'faas.time' : new Date ( event . scheduledTime ) . toISOString ( ) ,
80
+ 'faas.trigger' : 'timer' ,
81
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.faas.cloudflare' ,
82
+ [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'task' ,
83
+ } ,
84
+ } ,
85
+ async ( ) => {
86
+ try {
87
+ return await ( target . apply ( thisArg , args ) as ReturnType < typeof target > ) ;
88
+ } catch ( e ) {
89
+ captureException ( e , { mechanism : { handled : false , type : 'cloudflare' } } ) ;
90
+ throw e ;
91
+ } finally {
92
+ context . waitUntil ( flush ( 2000 ) ) ;
93
+ }
94
+ } ,
95
+ ) ;
96
+ } ) ;
97
+ } ,
98
+ } ) ;
99
+
100
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
101
+ ( handler . scheduled as any ) . __SENTRY_INSTRUMENTED__ = true ;
102
+ }
103
+
43
104
return handler ;
44
105
}
0 commit comments