Skip to content

Commit 6b73699

Browse files
authored
fix: Log errors when there is no error event handler. (#495)
When there are no error event handlers the server SDKs should log the errors instead. This behavior was missed during the typescript re-write. We may want to consider if we always want to log errors, but I understand the logic of this. If you are listening to this, then you may also be logging it, and if you are not logging it, then you are at least getting the event. I imagine most consumers are not using the error events.
1 parent 138cc06 commit 6b73699

File tree

7 files changed

+64
-8
lines changed

7 files changed

+64
-8
lines changed

packages/sdk/server-node/__tests__/LDClientNode.listeners.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { integrations } from '@launchdarkly/js-server-sdk-common';
2+
import { logger } from '@launchdarkly/private-js-mocks';
23

3-
import { LDClient } from '../src';
4+
import { Context, LDClient } from '../src';
45
import LDClientNode from '../src/LDClientNode';
56

67
describe('given an LDClient with test data', () => {
@@ -12,6 +13,7 @@ describe('given an LDClient with test data', () => {
1213
client = new LDClientNode('sdk-key', {
1314
updateProcessor: td.getFactory(),
1415
sendEvents: false,
16+
logger,
1517
});
1618
});
1719

@@ -78,4 +80,16 @@ describe('given an LDClient with test data', () => {
7880
td.update(td.flag('flag1').on(false));
7981
td.update(td.flag('flag2').on(false));
8082
});
83+
84+
it('logs errors when there are no event handlers', () => {
85+
// Empty kind is not valid.
86+
const invalidContext = { key: 'key', kind: '' };
87+
client.variation('flag', { key: 'key', kind: '' }, false);
88+
const referenceContext = Context.fromLDContext(invalidContext);
89+
expect(referenceContext.message).toBeDefined();
90+
expect(logger.error).toHaveBeenNthCalledWith(
91+
1,
92+
`${referenceContext.message} returning default value.`,
93+
);
94+
});
8195
});

packages/sdk/server-node/src/LDClientNode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class LDClientNode extends LDClientImpl {
4343
onError: (err: Error) => {
4444
if (emitter.listenerCount('error')) {
4545
emitter.emit('error', err);
46+
} else {
47+
logger.error(err.message);
4648
}
4749
},
4850
onFailed: (err: Error) => {

packages/shared/akamai-edgeworker-sdk/src/api/LDClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class LDClient extends LDClientImpl {
2929
options: LDOptions,
3030
storeProvider: CacheableStoreProvider,
3131
) {
32-
super(sdkKey, platform, createOptions(options), createCallbacks());
32+
const finalOptions = createOptions(options);
33+
super(sdkKey, platform, finalOptions, createCallbacks(finalOptions.logger));
3334
this.cacheableStoreProvider = storeProvider;
3435
}
3536

packages/shared/akamai-edgeworker-sdk/src/utils/createCallbacks.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import { LDLogger } from '@launchdarkly/js-server-sdk-common';
2+
13
// eslint-disable-next-line import/prefer-default-export
2-
export const createCallbacks = () => ({
3-
onError: (_err: Error) => {},
4+
export const createCallbacks = (logger?: LDLogger) => ({
5+
onError: (err: Error) => {
6+
logger?.error?.(err.message);
7+
},
48
onFailed: (_err: Error) => {},
59
onReady: () => {},
610
onUpdate: (_key: string) => {},

packages/shared/sdk-server-edge/src/api/LDClient.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@ export default class LDClient extends LDClientImpl {
2121
diagnosticEventPath: `/events/diagnostic/${clientSideID}`,
2222
includeAuthorizationHeader: false,
2323
};
24-
super(clientSideID, platform, createOptions(options), createCallbacks(em), internalOptions);
24+
25+
const finalOptions = createOptions(options);
26+
27+
super(
28+
clientSideID,
29+
platform,
30+
finalOptions,
31+
createCallbacks(em, finalOptions.logger),
32+
internalOptions,
33+
);
2534
this.emitter = em;
2635
}
2736
}

packages/shared/sdk-server-edge/src/api/createCallbacks.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EventEmitter } from 'node:events';
22

33
import { noop } from '@launchdarkly/js-server-sdk-common';
4+
import { logger } from '@launchdarkly/private-js-mocks';
45

56
import createCallbacks from './createCallbacks';
67

@@ -17,7 +18,7 @@ describe('createCallbacks', () => {
1718
jest.resetAllMocks();
1819
});
1920

20-
test('onError', () => {
21+
test('onError calls the emitter', () => {
2122
emitter.on('error', noop);
2223

2324
const { onError } = createCallbacks(emitter);
@@ -26,6 +27,29 @@ describe('createCallbacks', () => {
2627
expect(emitter.emit).toHaveBeenNthCalledWith(1, 'error', err);
2728
});
2829

30+
test('onError does not log when there are listeners', () => {
31+
emitter.on('error', noop);
32+
33+
const { onError } = createCallbacks(emitter, logger);
34+
onError(err);
35+
36+
expect(emitter.emit).toHaveBeenNthCalledWith(1, 'error', err);
37+
expect(logger.error).not.toHaveBeenCalled();
38+
expect(logger.warn).not.toHaveBeenCalled();
39+
expect(logger.info).not.toHaveBeenCalled();
40+
expect(logger.debug).not.toHaveBeenCalled();
41+
});
42+
43+
test('onError logs when there are no listeners', () => {
44+
const { onError } = createCallbacks(emitter, logger);
45+
onError(err);
46+
47+
expect(logger.error).toHaveBeenNthCalledWith(1, err.message);
48+
expect(logger.warn).not.toHaveBeenCalled();
49+
expect(logger.info).not.toHaveBeenCalled();
50+
expect(logger.debug).not.toHaveBeenCalled();
51+
});
52+
2953
test('onError should not be called', () => {
3054
const { onError } = createCallbacks(emitter);
3155
onError(err);

packages/shared/sdk-server-edge/src/api/createCallbacks.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { EventEmitter } from 'node:events';
22

3-
import { noop } from '@launchdarkly/js-server-sdk-common';
3+
import { LDLogger, noop } from '@launchdarkly/js-server-sdk-common';
44

5-
const createCallbacks = (emitter: EventEmitter) => ({
5+
const createCallbacks = (emitter: EventEmitter, logger?: LDLogger) => ({
66
onError: (err: Error) => {
77
if (emitter.listenerCount('error')) {
88
emitter.emit('error', err);
9+
} else {
10+
logger?.error(err.message);
911
}
1012
},
1113
onFailed: (err: Error) => {

0 commit comments

Comments
 (0)