Skip to content

Commit 9ed9920

Browse files
committed
Merge branch 'main' into rlamb/emsr-6/browser-telemetry-logging
2 parents da9f668 + 5c327a1 commit 9ed9920

File tree

13 files changed

+2159
-13
lines changed

13 files changed

+2159
-13
lines changed

packages/sdk/browser/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"rootDir": ".",
1212
"outDir": "dist",
1313
"skipLibCheck": true,
14-
"sourceMap": false,
14+
"sourceMap": true,
15+
"inlineSources": true,
1516
"strict": true,
1617
"stripInternal": true,
1718
"target": "ES2017",

packages/sdk/browser/tsup.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default defineConfig({
1010
minify: true,
1111
format: ['esm', 'cjs'],
1212
splitting: false,
13-
sourcemap: false,
13+
sourcemap: true,
1414
clean: true,
1515
noExternal: ['@launchdarkly/js-sdk-common', '@launchdarkly/js-client-sdk-common'],
1616
dts: true,

packages/telemetry/browser-telemetry/__tests__/BrowserTelemetryImpl.test.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const defaultOptions: ParsedOptions = {
2222
},
2323
evaluations: true,
2424
flagChange: true,
25+
filters: [],
2526
},
2627
stack: {
2728
source: {
@@ -232,3 +233,153 @@ it('logs event dropped message when maxPendingEvents is reached', () => {
232233
telemetry.captureError(new Error('Test error 4'));
233234
expect(mockLogger.warn).toHaveBeenCalledTimes(1);
234235
});
236+
237+
it('filters breadcrumbs using provided filters', () => {
238+
const options: ParsedOptions = {
239+
...defaultOptions,
240+
breadcrumbs: {
241+
...defaultOptions.breadcrumbs,
242+
click: false,
243+
evaluations: false,
244+
flagChange: false,
245+
http: { instrumentFetch: false, instrumentXhr: false },
246+
keyboardInput: false,
247+
filters: [
248+
// Filter to remove breadcrumbs with id:2
249+
(breadcrumb) => {
250+
if (breadcrumb.type === 'custom' && breadcrumb.data?.id === 2) {
251+
return undefined;
252+
}
253+
return breadcrumb;
254+
},
255+
// Filter to transform breadcrumbs with id:3
256+
(breadcrumb) => {
257+
if (breadcrumb.type === 'custom' && breadcrumb.data?.id === 3) {
258+
return {
259+
...breadcrumb,
260+
data: { id: 'filtered-3' },
261+
};
262+
}
263+
return breadcrumb;
264+
},
265+
],
266+
},
267+
};
268+
const telemetry = new BrowserTelemetryImpl(options);
269+
270+
telemetry.addBreadcrumb({
271+
type: 'custom',
272+
data: { id: 1 },
273+
timestamp: Date.now(),
274+
class: 'custom',
275+
level: 'info',
276+
});
277+
278+
telemetry.addBreadcrumb({
279+
type: 'custom',
280+
data: { id: 2 },
281+
timestamp: Date.now(),
282+
class: 'custom',
283+
level: 'info',
284+
});
285+
286+
telemetry.addBreadcrumb({
287+
type: 'custom',
288+
data: { id: 3 },
289+
timestamp: Date.now(),
290+
class: 'custom',
291+
level: 'info',
292+
});
293+
294+
const error = new Error('Test error');
295+
telemetry.captureError(error);
296+
telemetry.register(mockClient);
297+
298+
expect(mockClient.track).toHaveBeenCalledWith(
299+
'$ld:telemetry:error',
300+
expect.objectContaining({
301+
breadcrumbs: expect.arrayContaining([
302+
expect.objectContaining({ data: { id: 1 } }),
303+
expect.objectContaining({ data: { id: 'filtered-3' } }),
304+
]),
305+
}),
306+
);
307+
308+
// Verify breadcrumb with id:2 was filtered out
309+
expect(mockClient.track).toHaveBeenCalledWith(
310+
'$ld:telemetry:error',
311+
expect.objectContaining({
312+
breadcrumbs: expect.not.arrayContaining([expect.objectContaining({ data: { id: 2 } })]),
313+
}),
314+
);
315+
});
316+
317+
it('omits breadcrumb when a filter throws an exception', () => {
318+
const breadSpy = jest.fn((breadcrumb) => breadcrumb);
319+
const options: ParsedOptions = {
320+
...defaultOptions,
321+
breadcrumbs: {
322+
...defaultOptions.breadcrumbs,
323+
filters: [
324+
() => {
325+
throw new Error('Filter error');
326+
},
327+
// This filter should never run
328+
breadSpy,
329+
],
330+
},
331+
};
332+
const telemetry = new BrowserTelemetryImpl(options);
333+
334+
telemetry.addBreadcrumb({
335+
type: 'custom',
336+
data: { id: 1 },
337+
timestamp: Date.now(),
338+
class: 'custom',
339+
level: 'info',
340+
});
341+
342+
const error = new Error('Test error');
343+
telemetry.captureError(error);
344+
telemetry.register(mockClient);
345+
346+
expect(mockClient.track).toHaveBeenCalledWith(
347+
'$ld:telemetry:error',
348+
expect.objectContaining({
349+
breadcrumbs: [],
350+
}),
351+
);
352+
353+
expect(breadSpy).not.toHaveBeenCalled();
354+
});
355+
356+
it('omits breadcrumbs when a filter is not a function', () => {
357+
const options: ParsedOptions = {
358+
...defaultOptions,
359+
breadcrumbs: {
360+
...defaultOptions.breadcrumbs,
361+
// @ts-ignore
362+
filters: ['potato'],
363+
},
364+
};
365+
const telemetry = new BrowserTelemetryImpl(options);
366+
367+
telemetry.addBreadcrumb({
368+
type: 'custom',
369+
data: { id: 1 },
370+
timestamp: Date.now(),
371+
class: 'custom',
372+
level: 'info',
373+
});
374+
375+
const error = new Error('Test error');
376+
telemetry.captureError(error);
377+
telemetry.register(mockClient);
378+
379+
expect(mockClient.track).toHaveBeenCalledWith(
380+
'$ld:telemetry:error',
381+
expect.objectContaining({
382+
breadcrumbs: [],
383+
}),
384+
);
385+
});

packages/telemetry/browser-telemetry/__tests__/options.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ it('can set all options at once', () => {
2222
click: false,
2323
evaluations: false,
2424
flagChange: false,
25+
filters: [(breadcrumb) => breadcrumb],
2526
},
2627
collectors: [new ErrorCollector(), new ErrorCollector()],
2728
});
@@ -38,6 +39,7 @@ it('can set all options at once', () => {
3839
instrumentFetch: true,
3940
instrumentXhr: true,
4041
},
42+
filters: expect.any(Array),
4143
},
4244
stack: {
4345
source: {
@@ -420,3 +422,19 @@ it('warns when breadcrumbs.http.customUrlFilter is not a function', () => {
420422
'LaunchDarkly - Browser Telemetry: The "breadcrumbs.http.customUrlFilter" must be a function. Received string',
421423
);
422424
});
425+
426+
it('warns when filters is not an array', () => {
427+
const outOptions = parse(
428+
{
429+
breadcrumbs: {
430+
// @ts-ignore
431+
filters: 'not an array',
432+
},
433+
},
434+
mockLogger,
435+
);
436+
expect(outOptions.breadcrumbs.filters).toEqual([]);
437+
expect(mockLogger.warn).toHaveBeenCalledWith(
438+
'LaunchDarkly - Browser Telemetry: Config option "breadcrumbs.filters" should be of type array, got string, using default value',
439+
);
440+
});

0 commit comments

Comments
 (0)