diff --git a/packages/browser/src/integrations/contextlines.ts b/packages/browser/src/integrations/contextlines.ts index 70da4bac7504..330806883883 100644 --- a/packages/browser/src/integrations/contextlines.ts +++ b/packages/browser/src/integrations/contextlines.ts @@ -7,22 +7,25 @@ const DEFAULT_LINES_OF_CONTEXT = 7; const INTEGRATION_NAME = 'ContextLines'; +// TODO(v11): Use `dataCollection.frameContextLines` default (5) interface ContextLinesOptions { /** * Sets the number of context lines for each frame when loading a file. * Defaults to 7. * * Set to 0 to disable loading and inclusion of source files. + * + * When set, this option takes precedence over `dataCollection.frameContextLines`. **/ frameContextLines?: number; } const _contextLinesIntegration = ((options: ContextLinesOptions = {}) => { - const contextLines = options.frameContextLines != null ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; - return { name: INTEGRATION_NAME, - processEvent(event) { + processEvent(event, _hint, client) { + const contextLines = + options.frameContextLines ?? client?.getDataCollectionOptions().frameContextLines ?? DEFAULT_LINES_OF_CONTEXT; return addSourceContext(event, contextLines); }, }; diff --git a/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts b/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts index 54eb0f43ccb7..e87cd8ae7614 100644 --- a/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts +++ b/packages/core/src/utils/data-collection/defaultPiiToCollectionOptions.ts @@ -14,7 +14,7 @@ export function defaultPiiToCollectionOptions(sendDefaultPii?: boolean): Resolve queryParams: true, genAI: { inputs: true, outputs: true }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, // default should be 5, but ContextLines integration uses 7 } : { userInfo: false, @@ -24,6 +24,6 @@ export function defaultPiiToCollectionOptions(sendDefaultPii?: boolean): Resolve queryParams: { deny: PII_HEADER_SNIPPETS }, genAI: { inputs: false, outputs: false }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, // default should be 5, but ContextLines integration uses 7 }; } diff --git a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts index d287a820644c..fcd9463e7f0f 100644 --- a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts +++ b/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts @@ -11,7 +11,7 @@ describe('defaultPiiToCollectionOptions', () => { queryParams: true, genAI: { inputs: true, outputs: true }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, }); }); @@ -27,7 +27,7 @@ describe('defaultPiiToCollectionOptions', () => { queryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, genAI: { inputs: false, outputs: false }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, }); }); @@ -43,7 +43,7 @@ describe('defaultPiiToCollectionOptions', () => { queryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, genAI: { inputs: false, outputs: false }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, }); }); @@ -59,7 +59,7 @@ describe('defaultPiiToCollectionOptions', () => { queryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, genAI: { inputs: false, outputs: false }, stackFrameVariables: true, - frameContextLines: 5, + frameContextLines: 7, }); }); }); diff --git a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts index 82c58b1fa8cf..284882d58766 100644 --- a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts +++ b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts @@ -22,7 +22,7 @@ describe('resolveDataCollectionOptions', () => { expect(result.httpBodies).toEqual([]); expect(result.genAI).toEqual({ inputs: false, outputs: false }); expect(result.stackFrameVariables).toBe(true); - expect(result.frameContextLines).toBe(5); + expect(result.frameContextLines).toBe(7); }); it('returns spec defaults when dataCollection is explicitly set to empty object', () => { diff --git a/packages/deno/src/integrations/contextlines.ts b/packages/deno/src/integrations/contextlines.ts index cf13252052b8..053e2ee9907d 100644 --- a/packages/deno/src/integrations/contextlines.ts +++ b/packages/deno/src/integrations/contextlines.ts @@ -36,22 +36,25 @@ async function readSourceFile(filename: string): Promise { return content; } +// TODO(v11): Use `dataCollection.frameContextLines` default (5) interface ContextLinesOptions { /** * Sets the number of context lines for each frame when loading a file. * Defaults to 7. * * Set to 0 to disable loading and inclusion of source files. - */ + * + * When set, this option takes precedence over `dataCollection.frameContextLines`. + **/ frameContextLines?: number; } const _contextLinesIntegration = ((options: ContextLinesOptions = {}) => { - const contextLines = options.frameContextLines !== undefined ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; - return { name: INTEGRATION_NAME, - processEvent(event) { + processEvent(event, _hint, client) { + const contextLines = + options.frameContextLines ?? client?.getDataCollectionOptions().frameContextLines ?? DEFAULT_LINES_OF_CONTEXT; return addSourceContext(event, contextLines); }, }; diff --git a/packages/node-core/src/integrations/contextlines.ts b/packages/node-core/src/integrations/contextlines.ts index 5c99166d0d54..6996951294c7 100644 --- a/packages/node-core/src/integrations/contextlines.ts +++ b/packages/node-core/src/integrations/contextlines.ts @@ -14,12 +14,15 @@ const INTEGRATION_NAME = 'ContextLines'; export const MAX_CONTEXTLINES_COLNO: number = 1000; export const MAX_CONTEXTLINES_LINENO: number = 10000; +// TODO(v11): Use `dataCollection.frameContextLines` default (5) interface ContextLinesOptions { /** * Sets the number of context lines for each frame when loading a file. * Defaults to 7. * * Set to 0 to disable loading and inclusion of source files. + * + * When set, this option takes precedence over `dataCollection.frameContextLines`. **/ frameContextLines?: number; } @@ -398,11 +401,11 @@ function makeContextRange(line: number, linecontext: number): [start: number, en /** Exported only for tests, as a type-safe variant. */ export const _contextLinesIntegration = ((options: ContextLinesOptions = {}) => { - const contextLines = options.frameContextLines !== undefined ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; - return { name: INTEGRATION_NAME, - processEvent(event) { + processEvent(event, _hint, client) { + const contextLines = + options.frameContextLines ?? client?.getDataCollectionOptions().frameContextLines ?? DEFAULT_LINES_OF_CONTEXT; return addSourceContext(event, contextLines); }, }; diff --git a/packages/node-core/test/integrations/contextlines.test.ts b/packages/node-core/test/integrations/contextlines.test.ts index ccb963723d39..c1037d4e8136 100644 --- a/packages/node-core/test/integrations/contextlines.test.ts +++ b/packages/node-core/test/integrations/contextlines.test.ts @@ -231,4 +231,56 @@ describe('ContextLines', () => { expect(readStreamSpy).not.toHaveBeenCalled(); }); }); + + describe('dataCollection.frameContextLines', () => { + function clientWithFrameContextLines(frameContextLines: number) { + return { + getDataCollectionOptions: () => ({ frameContextLines }), + } as unknown as Parameters>[2]; + } + + test('uses dataCollection.frameContextLines when no integration option is set', async () => { + contextLines = _contextLinesIntegration(); + const frames = parseStackFrames(defaultStackParser, new Error('test')); + + await contextLines.processEvent( + { exception: { values: [{ stacktrace: { frames } }] } }, + {}, + clientWithFrameContextLines(2), + ); + + const frame = frames.find(f => f.context_line !== undefined); + expect(frame?.pre_context).toHaveLength(2); + expect(frame?.post_context).toHaveLength(2); + }); + + test('does not read source files when dataCollection.frameContextLines is 0', async () => { + contextLines = _contextLinesIntegration(); + const readStreamSpy = vi.spyOn(fs, 'createReadStream'); + const frames = parseStackFrames(defaultStackParser, new Error('test')); + + await contextLines.processEvent( + { exception: { values: [{ stacktrace: { frames } }] } }, + {}, + clientWithFrameContextLines(0), + ); + + expect(readStreamSpy).not.toHaveBeenCalled(); + }); + + test('integration option takes precedence over dataCollection.frameContextLines', async () => { + contextLines = _contextLinesIntegration({ frameContextLines: 1 }); + const frames = parseStackFrames(defaultStackParser, new Error('test')); + + await contextLines.processEvent( + { exception: { values: [{ stacktrace: { frames } }] } }, + {}, + clientWithFrameContextLines(5), + ); + + const frame = frames.find(f => f.context_line !== undefined); + expect(frame?.pre_context).toHaveLength(1); + expect(frame?.post_context).toHaveLength(1); + }); + }); });