@@ -11,12 +11,13 @@ import type {
11
11
SeverityLevel ,
12
12
TraceContext ,
13
13
} from '@sentry/types' ;
14
- import { eventFromMessage , eventFromUnknownInput , logger , uuid4 } from '@sentry/utils' ;
14
+ import { eventFromMessage , eventFromUnknownInput , logger , resolvedSyncPromise , uuid4 } from '@sentry/utils' ;
15
15
16
16
import { BaseClient } from './baseclient' ;
17
17
import { createCheckInEnvelope } from './checkin' ;
18
18
import { getCurrentHub } from './hub' ;
19
19
import type { Scope } from './scope' ;
20
+ import { SessionFlusher } from './sessionflusher' ;
20
21
import { addTracingExtensions , getDynamicSamplingContextFromClient } from './tracing' ;
21
22
22
23
export interface ServerRuntimeClientOptions extends ClientOptions < BaseTransportOptions > {
@@ -31,6 +32,8 @@ export interface ServerRuntimeClientOptions extends ClientOptions<BaseTransportO
31
32
export class ServerRuntimeClient <
32
33
O extends ClientOptions & ServerRuntimeClientOptions = ServerRuntimeClientOptions ,
33
34
> extends BaseClient < O > {
35
+ protected _sessionFlusher : SessionFlusher | undefined ;
36
+
34
37
/**
35
38
* Creates a new Edge SDK instance.
36
39
* @param options Configuration options for this SDK.
@@ -46,7 +49,7 @@ export class ServerRuntimeClient<
46
49
* @inheritDoc
47
50
*/
48
51
public eventFromException ( exception : unknown , hint ?: EventHint ) : PromiseLike < Event > {
49
- return Promise . resolve ( eventFromUnknownInput ( getCurrentHub , this . _options . stackParser , exception , hint ) ) ;
52
+ return resolvedSyncPromise ( eventFromUnknownInput ( getCurrentHub , this . _options . stackParser , exception , hint ) ) ;
50
53
}
51
54
52
55
/**
@@ -58,11 +61,83 @@ export class ServerRuntimeClient<
58
61
level : Severity | SeverityLevel = 'info' ,
59
62
hint ?: EventHint ,
60
63
) : PromiseLike < Event > {
61
- return Promise . resolve (
64
+ return resolvedSyncPromise (
62
65
eventFromMessage ( this . _options . stackParser , message , level , hint , this . _options . attachStacktrace ) ,
63
66
) ;
64
67
}
65
68
69
+ /**
70
+ * @inheritDoc
71
+ */
72
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
73
+ public captureException ( exception : any , hint ?: EventHint , scope ?: Scope ) : string | undefined {
74
+ // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only
75
+ // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload
76
+ // sent to the Server only when the `requestHandler` middleware is used
77
+ if ( this . _options . autoSessionTracking && this . _sessionFlusher && scope ) {
78
+ const requestSession = scope . getRequestSession ( ) ;
79
+
80
+ // Necessary checks to ensure this is code block is executed only within a request
81
+ // Should override the status only if `requestSession.status` is `Ok`, which is its initial stage
82
+ if ( requestSession && requestSession . status === 'ok' ) {
83
+ requestSession . status = 'errored' ;
84
+ }
85
+ }
86
+
87
+ return super . captureException ( exception , hint , scope ) ;
88
+ }
89
+
90
+ /**
91
+ * @inheritDoc
92
+ */
93
+ public captureEvent ( event : Event , hint ?: EventHint , scope ?: Scope ) : string | undefined {
94
+ // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only
95
+ // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload
96
+ // sent to the Server only when the `requestHandler` middleware is used
97
+ if ( this . _options . autoSessionTracking && this . _sessionFlusher && scope ) {
98
+ const eventType = event . type || 'exception' ;
99
+ const isException =
100
+ eventType === 'exception' && event . exception && event . exception . values && event . exception . values . length > 0 ;
101
+
102
+ // If the event is of type Exception, then a request session should be captured
103
+ if ( isException ) {
104
+ const requestSession = scope . getRequestSession ( ) ;
105
+
106
+ // Ensure that this is happening within the bounds of a request, and make sure not to override
107
+ // Session Status if Errored / Crashed
108
+ if ( requestSession && requestSession . status === 'ok' ) {
109
+ requestSession . status = 'errored' ;
110
+ }
111
+ }
112
+ }
113
+
114
+ return super . captureEvent ( event , hint , scope ) ;
115
+ }
116
+
117
+ /**
118
+ *
119
+ * @inheritdoc
120
+ */
121
+ public close ( timeout ?: number ) : PromiseLike < boolean > {
122
+ if ( this . _sessionFlusher ) {
123
+ this . _sessionFlusher . close ( ) ;
124
+ }
125
+ return super . close ( timeout ) ;
126
+ }
127
+
128
+ /** Method that initialises an instance of SessionFlusher on Client */
129
+ public initSessionFlusher ( ) : void {
130
+ const { release, environment } = this . _options ;
131
+ if ( ! release ) {
132
+ __DEBUG_BUILD__ && logger . warn ( 'Cannot initialise an instance of SessionFlusher if no release is provided!' ) ;
133
+ } else {
134
+ this . _sessionFlusher = new SessionFlusher ( this , {
135
+ release,
136
+ environment,
137
+ } ) ;
138
+ }
139
+ }
140
+
66
141
/**
67
142
* Create a cron monitor check in and send it to Sentry.
68
143
*
@@ -121,6 +196,18 @@ export class ServerRuntimeClient<
121
196
return id ;
122
197
}
123
198
199
+ /**
200
+ * Method responsible for capturing/ending a request session by calling `incrementSessionStatusCount` to increment
201
+ * appropriate session aggregates bucket
202
+ */
203
+ protected _captureRequestSession ( ) : void {
204
+ if ( ! this . _sessionFlusher ) {
205
+ __DEBUG_BUILD__ && logger . warn ( 'Discarded request mode session because autoSessionTracking option was disabled' ) ;
206
+ } else {
207
+ this . _sessionFlusher . incrementSessionStatusCount ( ) ;
208
+ }
209
+ }
210
+
124
211
/**
125
212
* @inheritDoc
126
213
*/
0 commit comments