@@ -31,29 +31,40 @@ function enhanceEventWithSdkInfo(event: Event, sdkInfo?: SdkInfo): Event {
3131 return event ;
3232}
3333
34- /** Creates a SentryRequest from an event. */
35- export function sessionToSentryRequest ( session : Session , api : API ) : SentryRequest {
34+ /**
35+ * Create a SentryRequest from an error, message, or transaction event.
36+ *
37+ * @param event The event to send
38+ * @param api Helper to provide the correct url for the request
39+ * @returns SentryRequest representing the event
40+ */
41+ export function eventToSentryRequest ( event : Event , api : API ) : SentryRequest {
3642 const sdkInfo = getSdkMetadataForEnvelopeHeader ( api ) ;
37- const envelopeHeaders = JSON . stringify ( {
38- sent_at : new Date ( ) . toISOString ( ) ,
39- ...( sdkInfo && { sdk : sdkInfo } ) ,
40- } ) ;
41- const itemHeaders = JSON . stringify ( {
42- type : 'session' ,
43- } ) ;
43+ const eventWithSdkInfo = sdkInfo ? enhanceEventWithSdkInfo ( event , api . metadata . sdk ) : event ;
4444
45+ if ( event . type === 'transaction' ) {
46+ return transactionToSentryRequest ( eventWithSdkInfo , api ) ;
47+ }
4548 return {
46- body : ` ${ envelopeHeaders } \n ${ itemHeaders } \n ${ JSON . stringify ( session ) } ` ,
47- type : 'session ',
48- url : api . getEnvelopeEndpointWithUrlEncodedAuth ( ) ,
49+ body : JSON . stringify ( eventWithSdkInfo ) ,
50+ type : event . type || 'event ',
51+ url : api . getStoreEndpointWithUrlEncodedAuth ( ) ,
4952 } ;
5053}
5154
52- /** Creates a SentryRequest from an event. */
53- export function eventToSentryRequest ( event : Event , api : API ) : SentryRequest {
55+ /**
56+ * Create a SentryRequest from a transaction event.
57+ *
58+ * Since we don't need to manipulate envelopes nor store them, there is no exported concept of an Envelope with
59+ * operations including serialization and deserialization. Instead, we only implement a minimal subset of the spec to
60+ * serialize events inline here. See https://develop.sentry.dev/sdk/envelopes/.
61+ *
62+ * @param event The transaction event to send
63+ * @param api Helper to provide the correct url for the request
64+ * @returns SentryRequest in envelope form
65+ */
66+ export function transactionToSentryRequest ( event : Event , api : API ) : SentryRequest {
5467 const sdkInfo = getSdkMetadataForEnvelopeHeader ( api ) ;
55- const eventType = event . type || 'event' ;
56- const useEnvelope = eventType === 'transaction' ;
5768
5869 const { transactionSampling, ...metadata } = event . debug_meta || { } ;
5970 const { method : samplingMethod , rate : sampleRate } = transactionSampling || { } ;
@@ -63,62 +74,76 @@ export function eventToSentryRequest(event: Event, api: API): SentryRequest {
6374 event . debug_meta = metadata ;
6475 }
6576
66- const req : SentryRequest = {
67- body : JSON . stringify ( sdkInfo ? enhanceEventWithSdkInfo ( event , api . metadata . sdk ) : event ) ,
68- type : eventType ,
69- url : useEnvelope ? api . getEnvelopeEndpointWithUrlEncodedAuth ( ) : api . getStoreEndpointWithUrlEncodedAuth ( ) ,
70- } ;
77+ const envelopeHeaders = JSON . stringify ( {
78+ event_id : event . event_id ,
79+ sent_at : new Date ( ) . toISOString ( ) ,
80+ ...( sdkInfo && { sdk : sdkInfo } ) ,
7181
72- // https://develop.sentry.dev/sdk/envelopes/
73-
74- // Since we don't need to manipulate envelopes nor store them, there is no
75- // exported concept of an Envelope with operations including serialization and
76- // deserialization. Instead, we only implement a minimal subset of the spec to
77- // serialize events inline here.
78- if ( useEnvelope ) {
79- const envelopeHeaders = JSON . stringify ( {
80- event_id : event . event_id ,
81- sent_at : new Date ( ) . toISOString ( ) ,
82- ...( sdkInfo && { sdk : sdkInfo } ) ,
83-
84- // trace context for dynamic sampling on relay
85- trace : {
86- trace_id : event . contexts ?. trace ?. trace_id ,
87- public_key : api . getDsn ( ) . publicKey ,
88- environment : event . environment || null ,
89- release : event . release || null ,
90- } ,
91- } ) ;
92-
93- const itemHeaders = JSON . stringify ( {
94- type : event . type ,
95-
96- // TODO: Right now, sampleRate may or may not be defined (it won't be in the cases of inheritance and
97- // explicitly-set sampling decisions). Are we good with that?
98- sample_rates : [ { id : samplingMethod , rate : sampleRate } ] ,
99-
100- // The content-type is assumed to be 'application/json' and not part of
101- // the current spec for transaction items, so we don't bloat the request
102- // body with it.
103- //
104- // content_type: 'application/json',
105- //
106- // The length is optional. It must be the number of bytes in req.Body
107- // encoded as UTF-8. Since the server can figure this out and would
108- // otherwise refuse events that report the length incorrectly, we decided
109- // not to send the length to avoid problems related to reporting the wrong
110- // size and to reduce request body size.
111- //
112- // length: new TextEncoder().encode(req.body).length,
113- } ) ;
114-
115- // The trailing newline is optional. We intentionally don't send it to avoid
116- // sending unnecessary bytes.
82+ // trace context for dynamic sampling on relay
83+ trace : {
84+ trace_id : event . contexts ?. trace ?. trace_id ,
85+ public_key : api . getDsn ( ) . publicKey ,
86+ environment : event . environment || null ,
87+ release : event . release || null ,
88+ } ,
89+ } ) ;
90+
91+ const itemHeaders = JSON . stringify ( {
92+ type : event . type ,
93+
94+ // TODO: Right now, sampleRate will be undefined in the cases of inheritance and explicitly-set sampling decisions.
95+ sample_rates : [ { id : samplingMethod , rate : sampleRate } ] ,
96+
97+ // Note: `content_type` and `length` were left out on purpose. Here's a quick explanation of why, along with the
98+ // value to use if we ever decide to put them back in.
11799 //
118- // const envelope = `${envelopeHeaders}\n${itemHeaders}\n${req.body}\n`;
119- const envelope = `${ envelopeHeaders } \n${ itemHeaders } \n${ req . body } ` ;
120- req . body = envelope ;
121- }
100+ // `content_type`:
101+ // Assumed to be 'application/json' and not part of the current spec for transaction items. No point in bloating the
102+ // request body with it.
103+ //
104+ // would be:
105+ // content_type: 'application/json',
106+ //
107+ // `length`:
108+ // Optional and equal to the number of bytes in req.Body encoded as UTF-8. Since the server can figure this out and
109+ // would otherwise refuse events that report the length incorrectly, we decided not to send the length to avoid
110+ // problems related to reporting the wrong size and to reduce request body size.
111+ //
112+ // would be:
113+ // length: new TextEncoder().encode(req.body).length,
114+ } ) ;
115+
116+ const req : SentryRequest = {
117+ // The trailing newline is optional; leave it off to avoid sending unnecessary bytes.
118+ // body: `${envelopeHeaders}\n${itemHeaders}\n${JSON.stringify(event)\n}`,
119+ body : `${ envelopeHeaders } \n${ itemHeaders } \n${ JSON . stringify ( event ) } ` ,
120+ type : 'transaction' ,
121+ url : api . getEnvelopeEndpointWithUrlEncodedAuth ( ) ,
122+ } ;
122123
123124 return req ;
124125}
126+
127+ /**
128+ * Create a SentryRequest from a session event.
129+ *
130+ * @param event The session event to send
131+ * @param api Helper to provide the correct url for the request
132+ * @returns SentryRequest in envelope form
133+ */
134+ export function sessionToSentryRequest ( session : Session , api : API ) : SentryRequest {
135+ const sdkInfo = getSdkMetadataForEnvelopeHeader ( api ) ;
136+ const envelopeHeaders = JSON . stringify ( {
137+ sent_at : new Date ( ) . toISOString ( ) ,
138+ ...( sdkInfo && { sdk : sdkInfo } ) ,
139+ } ) ;
140+ const itemHeaders = JSON . stringify ( {
141+ type : 'session' ,
142+ } ) ;
143+
144+ return {
145+ body : `${ envelopeHeaders } \n${ itemHeaders } \n${ JSON . stringify ( session ) } ` ,
146+ type : 'session' ,
147+ url : api . getEnvelopeEndpointWithUrlEncodedAuth ( ) ,
148+ } ;
149+ }
0 commit comments