UNPKG

7.57 kBJavaScriptView Raw
1import { startTransaction, getCurrentHub, withScope, captureException } from '@sentry/core';
2import { isString, extractTraceparentData, parseBaggageSetMutability, extractPathForTransaction, addRequestDataToTransaction, logger } from '@sentry/utils';
3import * as domain from 'domain';
4import { parseRequest } from './requestDataDeprecated.js';
5export { extractRequestData, parseRequest } from './requestDataDeprecated.js';
6import { extractRequestData, isAutoSessionTrackingEnabled, addRequestDataToEvent, flush } from './sdk.js';
7
8/**
9 * Express-compatible tracing handler.
10 * @see Exposed as `Handlers.tracingHandler`
11 */
12function tracingHandler()
13
14 {
15 return function sentryTracingMiddleware(
16 req,
17 res,
18 next,
19 ) {
20 // If there is a trace header set, we extract the data from it (parentSpanId, traceId, and sampling decision)
21 var traceparentData =
22 req.headers && isString(req.headers['sentry-trace']) && extractTraceparentData(req.headers['sentry-trace']);
23 var rawBaggageString = req.headers && isString(req.headers.baggage) && req.headers.baggage;
24
25 var baggage = parseBaggageSetMutability(rawBaggageString, traceparentData);
26
27 var transaction = startTransaction(
28 {
29 name: extractPathForTransaction(req, { path: true, method: true }),
30 op: 'http.server',
31 ...traceparentData,
32 metadata: { baggage },
33 },
34 // extra context passed to the tracesSampler
35 { request: extractRequestData(req) },
36 );
37
38 // We put the transaction on the scope so users can attach children to it
39 getCurrentHub().configureScope(scope => {
40 scope.setSpan(transaction);
41 });
42
43 // We also set __sentry_transaction on the response so people can grab the transaction there to add
44 // spans to it later.
45 (res ).__sentry_transaction = transaction;
46
47 res.once('finish', () => {
48 // Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction
49 // closes
50 setImmediate(() => {
51 addRequestDataToTransaction(transaction, req);
52 transaction.setHttpStatus(res.statusCode);
53 transaction.finish();
54 });
55 });
56
57 next();
58 };
59}
60
61/**
62 * Express compatible request handler.
63 * @see Exposed as `Handlers.requestHandler`
64 */
65function requestHandler(
66 options,
67) {
68 var currentHub = getCurrentHub();
69 var client = currentHub.getClient();
70 // Initialise an instance of SessionFlusher on the client when `autoSessionTracking` is enabled and the
71 // `requestHandler` middleware is used indicating that we are running in SessionAggregates mode
72 if (client && isAutoSessionTrackingEnabled(client)) {
73 client.initSessionFlusher();
74
75 // If Scope contains a Single mode Session, it is removed in favor of using Session Aggregates mode
76 var scope = currentHub.getScope();
77 if (scope && scope.getSession()) {
78 scope.setSession();
79 }
80 }
81
82 return function sentryRequestMiddleware(
83 req,
84 res,
85 next,
86 ) {
87 // TODO (v8 / XXX) Remove this shim and just use `addRequestDataToEvent`
88 let backwardsCompatibleEventProcessor;
89 if (options && 'include' in options) {
90 backwardsCompatibleEventProcessor = (event) => addRequestDataToEvent(event, req, options);
91 } else {
92 backwardsCompatibleEventProcessor = (event) => parseRequest(event, req, options );
93 }
94
95 if (options && options.flushTimeout && options.flushTimeout > 0) {
96 var _end = res.end;
97 res.end = function (chunk, encoding, cb) {
98 void flush(options.flushTimeout)
99 .then(() => {
100 _end.call(this, chunk, encoding, cb);
101 })
102 .then(null, e => {
103 (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(e);
104 _end.call(this, chunk, encoding, cb);
105 });
106 };
107 }
108 var local = domain.create();
109 local.add(req);
110 local.add(res);
111 local.on('error', next);
112
113 local.run(() => {
114 var currentHub = getCurrentHub();
115
116 currentHub.configureScope(scope => {
117 scope.addEventProcessor(backwardsCompatibleEventProcessor);
118 var client = currentHub.getClient();
119 if (isAutoSessionTrackingEnabled(client)) {
120 var scope = currentHub.getScope();
121 if (scope) {
122 // Set `status` of `RequestSession` to Ok, at the beginning of the request
123 scope.setRequestSession({ status: 'ok' });
124 }
125 }
126 });
127
128 res.once('finish', () => {
129 var client = currentHub.getClient();
130 if (isAutoSessionTrackingEnabled(client)) {
131 setImmediate(() => {
132 if (client && (client )._captureRequestSession) {
133 // Calling _captureRequestSession to capture request session at the end of the request by incrementing
134 // the correct SessionAggregates bucket i.e. crashed, errored or exited
135 (client )._captureRequestSession();
136 }
137 });
138 }
139 });
140 next();
141 });
142 };
143}
144
145/** JSDoc */
146
147/** JSDoc */
148function getStatusCodeFromResponse(error) {
149 var statusCode = error.status || error.statusCode || error.status_code || (error.output && error.output.statusCode);
150 return statusCode ? parseInt(statusCode , 10) : 500;
151}
152
153/** Returns true if response code is internal server error */
154function defaultShouldHandleError(error) {
155 var status = getStatusCodeFromResponse(error);
156 return status >= 500;
157}
158
159/**
160 * Express compatible error handler.
161 * @see Exposed as `Handlers.errorHandler`
162 */
163function errorHandler(options
164
165)
166
167 {
168 return function sentryErrorMiddleware(
169 error,
170 _req,
171 res,
172 next,
173 ) {
174 var shouldHandleError = (options && options.shouldHandleError) || defaultShouldHandleError;
175
176 if (shouldHandleError(error)) {
177 withScope(_scope => {
178 // For some reason we need to set the transaction on the scope again
179 var transaction = (res ).__sentry_transaction ;
180 if (transaction && _scope.getSpan() === undefined) {
181 _scope.setSpan(transaction);
182 }
183
184 var client = getCurrentHub().getClient();
185 if (client && isAutoSessionTrackingEnabled(client)) {
186 // Check if the `SessionFlusher` is instantiated on the client to go into this branch that marks the
187 // `requestSession.status` as `Crashed`, and this check is necessary because the `SessionFlusher` is only
188 // instantiated when the the`requestHandler` middleware is initialised, which indicates that we should be
189 // running in SessionAggregates mode
190 var isSessionAggregatesMode = (client )._sessionFlusher !== undefined;
191 if (isSessionAggregatesMode) {
192 var requestSession = _scope.getRequestSession();
193 // If an error bubbles to the `errorHandler`, then this is an unhandled error, and should be reported as a
194 // Crashed session. The `_requestSession.status` is checked to ensure that this error is happening within
195 // the bounds of a request, and if so the status is updated
196 if (requestSession && requestSession.status !== undefined) {
197 requestSession.status = 'crashed';
198 }
199 }
200 }
201
202 var eventId = captureException(error);
203 (res ).sentry = eventId;
204 next(error);
205 });
206
207 return;
208 }
209
210 next(error);
211 };
212}
213
214// TODO (v8 / #5257): Remove this
215;
216
217export { errorHandler, requestHandler, tracingHandler };
218//# sourceMappingURL=handlers.js.map