From ae68e230ae89cec597fa3d28814062646cab175b Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:22:44 -0800 Subject: [PATCH 1/5] feat: Add support for breadcrumb filtering. --- .../__tests__/BrowserTelemetryImpl.test.ts | 151 ++++++++++++++++++ .../__tests__/options.test.ts | 2 + .../src/BrowserTelemetryImpl.ts | 36 ++++- .../browser-telemetry/src/api/Options.ts | 46 +++++- .../src/collectors/http/fetchDecorator.ts | 3 +- .../browser-telemetry/src/options.ts | 21 ++- 6 files changed, 250 insertions(+), 9 deletions(-) diff --git a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts index 8233f46fb4..baeec92010 100644 --- a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts +++ b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts @@ -22,6 +22,7 @@ const defaultOptions: ParsedOptions = { }, evaluations: true, flagChange: true, + breadcrumbFilters: [], }, stack: { source: { @@ -208,3 +209,153 @@ it('unregisters collectors on close', () => { expect(mockCollector.unregister).toHaveBeenCalled(); }); + +it('filters breadcrumbs using provided filter', () => { + const options: ParsedOptions = { + ...defaultOptions, + breadcrumbs: { + ...defaultOptions.breadcrumbs, + click: false, + evaluations: false, + flagChange: false, + http: { instrumentFetch: false, instrumentXhr: false }, + keyboardInput: false, + breadcrumbFilters: [ + // Filter to remove breadcrumbs with id:2 + (breadcrumb) => { + if (breadcrumb.type === 'custom' && breadcrumb.data?.id === 2) { + return undefined; + } + return breadcrumb; + }, + // Filter to transform breadcrumbs with id:3 + (breadcrumb) => { + if (breadcrumb.type === 'custom' && breadcrumb.data?.id === 3) { + return { + ...breadcrumb, + data: { id: 'filtered-3' }, + }; + } + return breadcrumb; + }, + ], + }, + }; + const telemetry = new BrowserTelemetryImpl(options); + + telemetry.addBreadcrumb({ + type: 'custom', + data: { id: 1 }, + timestamp: Date.now(), + class: 'custom', + level: 'info', + }); + + telemetry.addBreadcrumb({ + type: 'custom', + data: { id: 2 }, + timestamp: Date.now(), + class: 'custom', + level: 'info', + }); + + telemetry.addBreadcrumb({ + type: 'custom', + data: { id: 3 }, + timestamp: Date.now(), + class: 'custom', + level: 'info', + }); + + const error = new Error('Test error'); + telemetry.captureError(error); + telemetry.register(mockClient); + + expect(mockClient.track).toHaveBeenCalledWith( + '$ld:telemetry:error', + expect.objectContaining({ + breadcrumbs: expect.arrayContaining([ + expect.objectContaining({ data: { id: 1 } }), + expect.objectContaining({ data: { id: 'filtered-3' } }), + ]), + }), + ); + + // Verify breadcrumb with id:2 was filtered out + expect(mockClient.track).toHaveBeenCalledWith( + '$ld:telemetry:error', + expect.objectContaining({ + breadcrumbs: expect.not.arrayContaining([expect.objectContaining({ data: { id: 2 } })]), + }), + ); +}); + +it('omits breadcrumb when a filter throws an exception', () => { + const breadSpy = jest.fn((breadcrumb) => breadcrumb); + const options: ParsedOptions = { + ...defaultOptions, + breadcrumbs: { + ...defaultOptions.breadcrumbs, + breadcrumbFilters: [ + () => { + throw new Error('Filter error'); + }, + // This filter should never run + breadSpy, + ], + }, + }; + const telemetry = new BrowserTelemetryImpl(options); + + telemetry.addBreadcrumb({ + type: 'custom', + data: { id: 1 }, + timestamp: Date.now(), + class: 'custom', + level: 'info', + }); + + const error = new Error('Test error'); + telemetry.captureError(error); + telemetry.register(mockClient); + + expect(mockClient.track).toHaveBeenCalledWith( + '$ld:telemetry:error', + expect.objectContaining({ + breadcrumbs: [], + }), + ); + + expect(breadSpy).not.toHaveBeenCalled(); +}); + +it('omits breadcrumb when a filter is not a function throws an exception', () => { + const options: ParsedOptions = { + ...defaultOptions, + breadcrumbs: { + ...defaultOptions.breadcrumbs, + // @ts-ignore + breadcrumbFilters: ['potato'], + }, + }; + const telemetry = new BrowserTelemetryImpl(options); + + telemetry.addBreadcrumb({ + type: 'custom', + data: { id: 1 }, + timestamp: Date.now(), + class: 'custom', + level: 'info', + }); + + const error = new Error('Test error'); + telemetry.captureError(error); + telemetry.register(mockClient); + + expect(mockClient.track).toHaveBeenCalledWith( + '$ld:telemetry:error', + expect.objectContaining({ + breadcrumbs: [], + }), + ); +}); diff --git a/packages/telemetry/browser-telemetry/__tests__/options.test.ts b/packages/telemetry/browser-telemetry/__tests__/options.test.ts index 1d5004ba08..83af287e47 100644 --- a/packages/telemetry/browser-telemetry/__tests__/options.test.ts +++ b/packages/telemetry/browser-telemetry/__tests__/options.test.ts @@ -22,6 +22,7 @@ it('can set all options at once', () => { click: false, evaluations: false, flagChange: false, + breadcrumbFilters: [(breadcrumb) => breadcrumb], }, collectors: [new ErrorCollector(), new ErrorCollector()], }); @@ -38,6 +39,7 @@ it('can set all options at once', () => { instrumentFetch: true, instrumentXhr: true, }, + breadcrumbFilters: expect.any(Array), }, stack: { source: { diff --git a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts index 6de65b1ed6..bcf00114f0 100644 --- a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts +++ b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts @@ -5,7 +5,7 @@ */ import type { LDContext, LDEvaluationDetail, LDInspection } from '@launchdarkly/js-client-sdk'; -import { LDClientTracking } from './api'; +import { BreadcrumbFilter, LDClientTracking } from './api'; import { Breadcrumb, FeatureManagementBreadcrumb } from './api/Breadcrumb'; import { BrowserTelemetry } from './api/BrowserTelemetry'; import { Collector } from './api/Collector'; @@ -52,6 +52,28 @@ function safeValue(u: unknown): string | boolean | number | undefined { } } +function applyBreadcrumbFilter( + breadcrumb: Breadcrumb | undefined, + filter: BreadcrumbFilter, +): Breadcrumb | undefined { + return breadcrumb === undefined ? undefined : filter(breadcrumb); +} + +function applyBreadcrumbFilters( + breadcrumb: Breadcrumb, + filters: BreadcrumbFilter[], +): Breadcrumb | undefined { + try { + return filters.reduce( + (breadcrumbToFilter: Breadcrumb | undefined, filter: BreadcrumbFilter) => + applyBreadcrumbFilter(breadcrumbToFilter, filter), + breadcrumb, + ); + } catch (e) { + return undefined; + } +} + function configureTraceKit(options: ParsedStackOptions) { const TraceKit = getTraceKit(); // Include before + after + source line. @@ -191,9 +213,15 @@ export default class BrowserTelemetryImpl implements BrowserTelemetry { } addBreadcrumb(breadcrumb: Breadcrumb): void { - this._breadcrumbs.push(breadcrumb); - if (this._breadcrumbs.length > this._maxBreadcrumbs) { - this._breadcrumbs.shift(); + const filtered = applyBreadcrumbFilters( + breadcrumb, + this._options.breadcrumbs.breadcrumbFilters, + ); + if (filtered !== undefined) { + this._breadcrumbs.push(filtered); + if (this._breadcrumbs.length > this._maxBreadcrumbs) { + this._breadcrumbs.shift(); + } } } diff --git a/packages/telemetry/browser-telemetry/src/api/Options.ts b/packages/telemetry/browser-telemetry/src/api/Options.ts index 4238af19b6..e9722e0c1e 100644 --- a/packages/telemetry/browser-telemetry/src/api/Options.ts +++ b/packages/telemetry/browser-telemetry/src/api/Options.ts @@ -1,3 +1,4 @@ +import { Breadcrumb } from './Breadcrumb'; import { Collector } from './Collector'; /** @@ -22,7 +23,17 @@ export interface UrlFilter { (url: string): string; } -export interface HttpBreadCrumbOptions { +/** + * Interface for breadcrumb filters. + * + * Given a breadcrumb the filter may return a modified breadcrumb or undefined to + * exclude the breadcrumb. + */ +export interface BreadcrumbFilter { + (breadcrumb: Breadcrumb): Breadcrumb | undefined; +} + +export interface HttpBreadcrumbOptions { /** * If fetch should be instrumented and breadcrumbs included for fetch requests. * @@ -131,7 +142,38 @@ export interface Options { * http: false * ``` */ - http?: HttpBreadCrumbOptions | false; + http?: HttpBreadcrumbOptions | false; + + /** + * Custom breadcrumb filters. + * + * Can be used to redact or modify breadcrumbs. + * + * Example: + * ``` + * // We want to redact any click events that include the message 'sneaky-button' + * breadcrumbFilters: [ + * (breadcrumb) => { + * if( + * breadcrumb.class === 'ui' && + * breadcrumb.type === 'click' && + * breadcrumb.message?.includes('sneaky-button') + * ) { + * return; + * } + * return breadcrumb; + * } + * ] + * ``` + * + * If you want to redact or modify URLs in breadcrumbs, then a urlFilter should be used. + * + * If any breadcrumFilters throw an exception while processing a breadcrumb, then that breadcrumb will be excluded. + * + * If any breadcrumbFilter cannot be executed, for example because it is not a function, then all breadcrumbs will + * be excluded. + */ + breadcrumbFilters?: BreadcrumbFilter[]; }; /** diff --git a/packages/telemetry/browser-telemetry/src/collectors/http/fetchDecorator.ts b/packages/telemetry/browser-telemetry/src/collectors/http/fetchDecorator.ts index 85dea49da7..d87d26d07d 100644 --- a/packages/telemetry/browser-telemetry/src/collectors/http/fetchDecorator.ts +++ b/packages/telemetry/browser-telemetry/src/collectors/http/fetchDecorator.ts @@ -77,7 +77,8 @@ export default function decorateFetch(callback: (breadcrumb: HttpBreadcrumb) => return response; }); } - wrapper.prototype = originalFetch.prototype; + + wrapper.prototype = originalFetch?.prototype; try { // Use defineProperty to prevent this value from being enumerable. diff --git a/packages/telemetry/browser-telemetry/src/options.ts b/packages/telemetry/browser-telemetry/src/options.ts index a801f5ed47..db1cda8920 100644 --- a/packages/telemetry/browser-telemetry/src/options.ts +++ b/packages/telemetry/browser-telemetry/src/options.ts @@ -1,5 +1,11 @@ import { Collector } from './api/Collector'; -import { HttpBreadCrumbOptions, Options, StackOptions, UrlFilter } from './api/Options'; +import { + BreadcrumbFilter, + HttpBreadcrumbOptions, + Options, + StackOptions, + UrlFilter, +} from './api/Options'; import { MinLogger } from './MinLogger'; export function defaultOptions(): ParsedOptions { @@ -14,6 +20,7 @@ export function defaultOptions(): ParsedOptions { instrumentFetch: true, instrumentXhr: true, }, + breadcrumbFilters: [], }, stack: { source: { @@ -55,7 +62,7 @@ function itemOrDefault(item: T | undefined, defaultValue: T, checker?: (item: } function parseHttp( - options: HttpBreadCrumbOptions | false | undefined, + options: HttpBreadcrumbOptions | false | undefined, defaults: ParsedHttpOptions, logger?: MinLogger, ): ParsedHttpOptions { @@ -163,6 +170,11 @@ export default function parse(options: Options, logger?: MinLogger): ParsedOptio checkBasic('boolean', 'breadcrumbs.keyboardInput', logger), ), http: parseHttp(options.breadcrumbs?.http, defaults.breadcrumbs.http, logger), + breadcrumbFilters: itemOrDefault( + options.breadcrumbs?.breadcrumbFilters, + defaults.breadcrumbs.breadcrumbFilters, + checkBasic('array', 'breadcrumbs.breadcrumbFilters', logger), + ), }, stack: parseStack(options.stack, defaults.stack), maxPendingEvents: itemOrDefault( @@ -271,6 +283,11 @@ export interface ParsedOptions { * Settings for http instrumentation and breadcrumbs. */ http: ParsedHttpOptions; + + /** + * Custom breadcrumb filters. + */ + breadcrumbFilters: BreadcrumbFilter[]; }; /** From 74d4fe7f2b001d074196be98d8517814493b2077 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Wed, 15 Jan 2025 13:33:51 -0800 Subject: [PATCH 2/5] Update test names. --- .../browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts index baeec92010..7354198ea3 100644 --- a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts +++ b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts @@ -210,7 +210,7 @@ it('unregisters collectors on close', () => { expect(mockCollector.unregister).toHaveBeenCalled(); }); -it('filters breadcrumbs using provided filter', () => { +it('filters breadcrumbs using provided filters', () => { const options: ParsedOptions = { ...defaultOptions, breadcrumbs: { @@ -329,7 +329,7 @@ it('omits breadcrumb when a filter throws an exception', () => { expect(breadSpy).not.toHaveBeenCalled(); }); -it('omits breadcrumb when a filter is not a function throws an exception', () => { +it('omits breadcrumbs when a filter is not a function', () => { const options: ParsedOptions = { ...defaultOptions, breadcrumbs: { From 3e3993b2fd3d6e5960bf6caaaa89b9c272cc6825 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:07:16 -0800 Subject: [PATCH 3/5] Update naming. Add test for invalid filters. --- .../__tests__/BrowserTelemetryImpl.test.ts | 8 ++++---- .../__tests__/options.test.ts | 20 +++++++++++++++++-- .../src/BrowserTelemetryImpl.ts | 10 ++-------- .../browser-telemetry/src/api/Options.ts | 4 ++-- .../browser-telemetry/src/options.ts | 12 +++++------ 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts index 7354198ea3..bb27da82ce 100644 --- a/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts +++ b/packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts @@ -22,7 +22,7 @@ const defaultOptions: ParsedOptions = { }, evaluations: true, flagChange: true, - breadcrumbFilters: [], + filters: [], }, stack: { source: { @@ -220,7 +220,7 @@ it('filters breadcrumbs using provided filters', () => { flagChange: false, http: { instrumentFetch: false, instrumentXhr: false }, keyboardInput: false, - breadcrumbFilters: [ + filters: [ // Filter to remove breadcrumbs with id:2 (breadcrumb) => { if (breadcrumb.type === 'custom' && breadcrumb.data?.id === 2) { @@ -296,7 +296,7 @@ it('omits breadcrumb when a filter throws an exception', () => { ...defaultOptions, breadcrumbs: { ...defaultOptions.breadcrumbs, - breadcrumbFilters: [ + filters: [ () => { throw new Error('Filter error'); }, @@ -335,7 +335,7 @@ it('omits breadcrumbs when a filter is not a function', () => { breadcrumbs: { ...defaultOptions.breadcrumbs, // @ts-ignore - breadcrumbFilters: ['potato'], + filters: ['potato'], }, }; const telemetry = new BrowserTelemetryImpl(options); diff --git a/packages/telemetry/browser-telemetry/__tests__/options.test.ts b/packages/telemetry/browser-telemetry/__tests__/options.test.ts index 83af287e47..c3c51f7314 100644 --- a/packages/telemetry/browser-telemetry/__tests__/options.test.ts +++ b/packages/telemetry/browser-telemetry/__tests__/options.test.ts @@ -22,7 +22,7 @@ it('can set all options at once', () => { click: false, evaluations: false, flagChange: false, - breadcrumbFilters: [(breadcrumb) => breadcrumb], + filters: [(breadcrumb) => breadcrumb], }, collectors: [new ErrorCollector(), new ErrorCollector()], }); @@ -39,7 +39,7 @@ it('can set all options at once', () => { instrumentFetch: true, instrumentXhr: true, }, - breadcrumbFilters: expect.any(Array), + filters: expect.any(Array), }, stack: { source: { @@ -422,3 +422,19 @@ it('warns when breadcrumbs.http.customUrlFilter is not a function', () => { 'The "breadcrumbs.http.customUrlFilter" must be a function. Received string', ); }); + +it('warns when filters is not an array', () => { + const outOptions = parse( + { + breadcrumbs: { + // @ts-ignore + filters: 'not an array', + }, + }, + mockLogger, + ); + expect(outOptions.breadcrumbs.filters).toEqual([]); + expect(mockLogger.warn).toHaveBeenCalledWith( + 'Config option "breadcrumbs.filters" should be of type array, got string, using default value', + ); +}); diff --git a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts index bcf00114f0..2ceb36a6de 100644 --- a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts +++ b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts @@ -59,10 +59,7 @@ function applyBreadcrumbFilter( return breadcrumb === undefined ? undefined : filter(breadcrumb); } -function applyBreadcrumbFilters( - breadcrumb: Breadcrumb, - filters: BreadcrumbFilter[], -): Breadcrumb | undefined { +function applyfilters(breadcrumb: Breadcrumb, filters: BreadcrumbFilter[]): Breadcrumb | undefined { try { return filters.reduce( (breadcrumbToFilter: Breadcrumb | undefined, filter: BreadcrumbFilter) => @@ -213,10 +210,7 @@ export default class BrowserTelemetryImpl implements BrowserTelemetry { } addBreadcrumb(breadcrumb: Breadcrumb): void { - const filtered = applyBreadcrumbFilters( - breadcrumb, - this._options.breadcrumbs.breadcrumbFilters, - ); + const filtered = applyfilters(breadcrumb, this._options.breadcrumbs.filters); if (filtered !== undefined) { this._breadcrumbs.push(filtered); if (this._breadcrumbs.length > this._maxBreadcrumbs) { diff --git a/packages/telemetry/browser-telemetry/src/api/Options.ts b/packages/telemetry/browser-telemetry/src/api/Options.ts index e9722e0c1e..5de73f1b0a 100644 --- a/packages/telemetry/browser-telemetry/src/api/Options.ts +++ b/packages/telemetry/browser-telemetry/src/api/Options.ts @@ -152,7 +152,7 @@ export interface Options { * Example: * ``` * // We want to redact any click events that include the message 'sneaky-button' - * breadcrumbFilters: [ + * filters: [ * (breadcrumb) => { * if( * breadcrumb.class === 'ui' && @@ -173,7 +173,7 @@ export interface Options { * If any breadcrumbFilter cannot be executed, for example because it is not a function, then all breadcrumbs will * be excluded. */ - breadcrumbFilters?: BreadcrumbFilter[]; + filters?: BreadcrumbFilter[]; }; /** diff --git a/packages/telemetry/browser-telemetry/src/options.ts b/packages/telemetry/browser-telemetry/src/options.ts index db1cda8920..8621fcc7b8 100644 --- a/packages/telemetry/browser-telemetry/src/options.ts +++ b/packages/telemetry/browser-telemetry/src/options.ts @@ -20,7 +20,7 @@ export function defaultOptions(): ParsedOptions { instrumentFetch: true, instrumentXhr: true, }, - breadcrumbFilters: [], + filters: [], }, stack: { source: { @@ -170,10 +170,10 @@ export default function parse(options: Options, logger?: MinLogger): ParsedOptio checkBasic('boolean', 'breadcrumbs.keyboardInput', logger), ), http: parseHttp(options.breadcrumbs?.http, defaults.breadcrumbs.http, logger), - breadcrumbFilters: itemOrDefault( - options.breadcrumbs?.breadcrumbFilters, - defaults.breadcrumbs.breadcrumbFilters, - checkBasic('array', 'breadcrumbs.breadcrumbFilters', logger), + filters: itemOrDefault( + options.breadcrumbs?.filters, + defaults.breadcrumbs.filters, + checkBasic('array', 'breadcrumbs.filters', logger), ), }, stack: parseStack(options.stack, defaults.stack), @@ -287,7 +287,7 @@ export interface ParsedOptions { /** * Custom breadcrumb filters. */ - breadcrumbFilters: BreadcrumbFilter[]; + filters: BreadcrumbFilter[]; }; /** From 02ec60dc7389a2fdd8f7290604149ab07e987239 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:08:40 -0800 Subject: [PATCH 4/5] More consistent naming. --- .../browser-telemetry/src/BrowserTelemetryImpl.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts index 2ceb36a6de..2e16a4f249 100644 --- a/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts +++ b/packages/telemetry/browser-telemetry/src/BrowserTelemetryImpl.ts @@ -59,7 +59,10 @@ function applyBreadcrumbFilter( return breadcrumb === undefined ? undefined : filter(breadcrumb); } -function applyfilters(breadcrumb: Breadcrumb, filters: BreadcrumbFilter[]): Breadcrumb | undefined { +function applyBreadcrumbFilters( + breadcrumb: Breadcrumb, + filters: BreadcrumbFilter[], +): Breadcrumb | undefined { try { return filters.reduce( (breadcrumbToFilter: Breadcrumb | undefined, filter: BreadcrumbFilter) => @@ -210,7 +213,7 @@ export default class BrowserTelemetryImpl implements BrowserTelemetry { } addBreadcrumb(breadcrumb: Breadcrumb): void { - const filtered = applyfilters(breadcrumb, this._options.breadcrumbs.filters); + const filtered = applyBreadcrumbFilters(breadcrumb, this._options.breadcrumbs.filters); if (filtered !== undefined) { this._breadcrumbs.push(filtered); if (this._breadcrumbs.length > this._maxBreadcrumbs) { From c5a9130f807594474360a5a41c0c6ef4609087e3 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:40:39 -0800 Subject: [PATCH 5/5] Update packages/telemetry/browser-telemetry/src/api/Options.ts Co-authored-by: Stacy Harrison <11901347+stasquatch@users.noreply.github.com> --- packages/telemetry/browser-telemetry/src/api/Options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/telemetry/browser-telemetry/src/api/Options.ts b/packages/telemetry/browser-telemetry/src/api/Options.ts index 5de73f1b0a..ea8de25b06 100644 --- a/packages/telemetry/browser-telemetry/src/api/Options.ts +++ b/packages/telemetry/browser-telemetry/src/api/Options.ts @@ -168,7 +168,7 @@ export interface Options { * * If you want to redact or modify URLs in breadcrumbs, then a urlFilter should be used. * - * If any breadcrumFilters throw an exception while processing a breadcrumb, then that breadcrumb will be excluded. + * If any breadcrumb filters throw an exception while processing a breadcrumb, then that breadcrumb will be excluded. * * If any breadcrumbFilter cannot be executed, for example because it is not a function, then all breadcrumbs will * be excluded.