Skip to content

Commit d33795b

Browse files
committed
add RequestData integration
1 parent c0629ab commit d33795b

File tree

4 files changed

+121
-2
lines changed

4 files changed

+121
-2
lines changed

packages/node/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export {
4747
export { NodeClient } from './client';
4848
export { makeNodeTransport } from './transports';
4949
export { defaultIntegrations, init, defaultStackParser, lastEventId, flush, close, getSentryRelease } from './sdk';
50-
export { addRequestDataToEvent, extractRequestData } from './requestdata';
50+
export { addRequestDataToEvent, DEFAULT_USER_INCLUDES, extractRequestData } from './requestdata';
5151
export { deepReadDirSync } from './utils';
5252

5353
import { Integrations as CoreIntegrations } from '@sentry/core';

packages/node/src/integrations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { LinkedErrors } from './linkederrors';
66
export { Modules } from './modules';
77
export { ContextLines } from './contextlines';
88
export { Context } from './context';
9+
export { RequestData } from './requestdata';
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// TODO (v8 or v9): Whenever this becomes a default integration for `@sentry/browser`, move this to `@sentry/core`. For
2+
// now, we leave it in `@sentry/integrations` so that it doesn't contribute bytes to our CDN bundles.
3+
4+
import { EventProcessor, Hub, Integration } from '@sentry/types';
5+
6+
import { addRequestDataToEvent, AddRequestDataToEventOptions, DEFAULT_USER_INCLUDES } from '../requestdata';
7+
8+
type RequestDataOptions = {
9+
/**
10+
* Controls what data is pulled from the request and added to the event
11+
*/
12+
include?: {
13+
cookies?: boolean;
14+
data?: boolean;
15+
headers?: boolean;
16+
ip?: boolean;
17+
query_string?: boolean;
18+
url?: boolean;
19+
user?: boolean | Array<typeof DEFAULT_USER_INCLUDES[number]>;
20+
};
21+
22+
/**
23+
* Function for adding request data to event. Defaults to `addRequestDataToEvent` from `@sentry/node` for now, but
24+
* left injectable so this integration can be moved to `@sentry/core` and used in browser-based SDKs in the future.
25+
*
26+
* @hidden
27+
*/
28+
addRequestData?: typeof addRequestDataToEvent;
29+
};
30+
31+
const DEFAULT_OPTIONS = {
32+
addRequestData: addRequestDataToEvent,
33+
include: {
34+
cookies: true,
35+
data: true,
36+
headers: true,
37+
ip: false,
38+
query_string: true,
39+
url: true,
40+
user: DEFAULT_USER_INCLUDES,
41+
},
42+
};
43+
44+
/** Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/integrations`
45+
* so it can be used in cross-platform SDKs like `@sentry/nextjs`. */
46+
export class RequestData implements Integration {
47+
/**
48+
* @inheritDoc
49+
*/
50+
public static id: string = 'RequestData';
51+
52+
/**
53+
* @inheritDoc
54+
*/
55+
public name: string = RequestData.id;
56+
57+
private _options: RequestDataOptions;
58+
59+
/**
60+
* @inheritDoc
61+
*/
62+
public constructor(options: RequestDataOptions = {}) {
63+
this._options = {
64+
...DEFAULT_OPTIONS,
65+
...options,
66+
include: {
67+
// @ts-ignore It's mad because `method` isn't a known `include` key. (It's only here and not set by default in
68+
// `addRequestDataToEvent` for legacy reasons. TODO (v8): Change that.)
69+
method: true,
70+
...DEFAULT_OPTIONS.include,
71+
...options.include,
72+
},
73+
};
74+
}
75+
76+
/**
77+
* @inheritDoc
78+
*/
79+
public setupOnce(addGlobalEventProcessor: (eventProcessor: EventProcessor) => void, getCurrentHub: () => Hub): void {
80+
const { include, addRequestData } = this._options;
81+
82+
addGlobalEventProcessor(event => {
83+
const self = getCurrentHub().getIntegration(RequestData);
84+
const req = event.sdkProcessingMetadata && event.sdkProcessingMetadata.request;
85+
86+
// If the globally installed instance of this integration isn't associated with the current hub, `self` will be
87+
// undefined
88+
if (!self || !req) {
89+
return event;
90+
}
91+
92+
// For some reason TS can't figure out that after the constructor runs, `_addReqDataCallback` will always be defined
93+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
94+
return addRequestData!(event, req, { include: formatIncludeOption(include) });
95+
});
96+
}
97+
}
98+
99+
/** Convert `include` option to match what `addRequestDataToEvent` expects */
100+
/** TODO: Can possibly be deleted once https://github.com/getsentry/sentry-javascript/issues/5718 is fixed */
101+
function formatIncludeOption(
102+
integrationInclude: RequestDataOptions['include'] = {},
103+
): AddRequestDataToEventOptions['include'] {
104+
const { ip, user, ...requestOptions } = integrationInclude;
105+
106+
const requestIncludeKeys: string[] = [];
107+
for (const [key, value] of Object.entries(requestOptions)) {
108+
if (value) {
109+
requestIncludeKeys.push(key);
110+
}
111+
}
112+
113+
return {
114+
ip,
115+
user,
116+
request: requestIncludeKeys.length !== 0 ? requestIncludeKeys : undefined,
117+
};
118+
}

packages/node/src/requestdata.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const DEFAULT_INCLUDES = {
1010
user: true,
1111
};
1212
const DEFAULT_REQUEST_INCLUDES = ['cookies', 'data', 'headers', 'method', 'query_string', 'url'];
13-
const DEFAULT_USER_INCLUDES = ['id', 'username', 'email'];
13+
export const DEFAULT_USER_INCLUDES = ['id', 'username', 'email'];
1414

1515
/**
1616
* Options deciding what parts of the request to use when enhancing an event

0 commit comments

Comments
 (0)