@@ -11,12 +11,13 @@ import type {
1111 SeverityLevel ,
1212 TraceContext ,
1313} from '@sentry/types' ;
14- import { eventFromMessage , eventFromUnknownInput , logger , uuid4 } from '@sentry/utils' ;
14+ import { eventFromMessage , eventFromUnknownInput , logger , resolvedSyncPromise , uuid4 } from '@sentry/utils' ;
1515
1616import { BaseClient } from './baseclient' ;
1717import { createCheckInEnvelope } from './checkin' ;
1818import { getCurrentHub } from './hub' ;
1919import type { Scope } from './scope' ;
20+ import { SessionFlusher } from './sessionflusher' ;
2021import { addTracingExtensions , getDynamicSamplingContextFromClient } from './tracing' ;
2122
2223export interface ServerRuntimeClientOptions extends ClientOptions < BaseTransportOptions > {
@@ -31,6 +32,8 @@ export interface ServerRuntimeClientOptions extends ClientOptions<BaseTransportO
3132export class ServerRuntimeClient <
3233 O extends ClientOptions & ServerRuntimeClientOptions = ServerRuntimeClientOptions ,
3334> extends BaseClient < O > {
35+ protected _sessionFlusher : SessionFlusher | undefined ;
36+
3437 /**
3538 * Creates a new Edge SDK instance.
3639 * @param options Configuration options for this SDK.
@@ -46,7 +49,7 @@ export class ServerRuntimeClient<
4649 * @inheritDoc
4750 */
4851 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 ) ) ;
5053 }
5154
5255 /**
@@ -58,11 +61,83 @@ export class ServerRuntimeClient<
5861 level : Severity | SeverityLevel = 'info' ,
5962 hint ?: EventHint ,
6063 ) : PromiseLike < Event > {
61- return Promise . resolve (
64+ return resolvedSyncPromise (
6265 eventFromMessage ( this . _options . stackParser , message , level , hint , this . _options . attachStacktrace ) ,
6366 ) ;
6467 }
6568
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+
66141 /**
67142 * Create a cron monitor check in and send it to Sentry.
68143 *
@@ -121,6 +196,18 @@ export class ServerRuntimeClient<
121196 return id ;
122197 }
123198
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+
124211 /**
125212 * @inheritDoc
126213 */
0 commit comments