-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy path_error.ts
69 lines (60 loc) · 2.87 KB
/
_error.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { captureException, withScope } from '@sentry/core';
import { getCurrentHub } from '@sentry/hub';
import { addExceptionMechanism, addRequestDataToEvent } from '@sentry/utils';
import { NextPageContext } from 'next';
type ContextOrProps = {
req?: NextPageContext['req'];
res?: NextPageContext['res'];
err?: NextPageContext['err'] | string;
pathname?: string;
statusCode?: number;
};
/** Platform-agnostic version of `flush` */
function flush(timeout?: number): PromiseLike<boolean> {
const client = getCurrentHub().getClient();
return client ? client.flush(timeout) : Promise.resolve(false);
}
/**
* Capture the exception passed by nextjs to the `_error` page, adding context data as appropriate.
*
* @param contextOrProps The data passed to either `getInitialProps` or `render` by nextjs
*/
export async function captureUnderscoreErrorException(contextOrProps: ContextOrProps): Promise<void> {
const { req, res, err } = contextOrProps;
// 404s (and other 400-y friends) can trigger `_error`, but we don't want to send them to Sentry
const statusCode = (res && res.statusCode) || contextOrProps.statusCode;
if (statusCode && statusCode < 500) {
return Promise.resolve();
}
// In previous versions of the suggested `_error.js` page in which this function is meant to be used, there was a
// workaround for https://github.com/vercel/next.js/issues/8592 which involved an extra call to this function, in the
// custom error component's `render` method, just in case it hadn't been called by `getInitialProps`. Now that that
// issue has been fixed, the second call is unnecessary, but since it lives in user code rather than our code, users
// have to be the ones to get rid of it, and guaraneteedly, not all of them will. So, rather than capture the error
// twice, we just bail if we sense we're in that now-extraneous second call. (We can tell which function we're in
// because Nextjs passes `pathname` to `getInitialProps` but not to `render`.)
if (!contextOrProps.pathname) {
return Promise.resolve();
}
withScope(scope => {
scope.addEventProcessor(event => {
addExceptionMechanism(event, {
type: 'instrument',
handled: true,
data: {
function: '_error.getInitialProps',
},
});
return event;
});
if (req) {
scope.addEventProcessor(event => addRequestDataToEvent(event, req));
}
// If third-party libraries (or users themselves) throw something falsy, we want to capture it as a message (which
// is what passing a string to `captureException` will wind up doing)
captureException(err || `_error.js called with falsy error (${err})`);
});
// In case this is being run as part of a serverless function (as is the case with the server half of nextjs apps
// deployed to vercel), make sure the error gets sent to Sentry before the lambda exits.
await flush(2000);
}