Skip to content

Commit fe9624e

Browse files
committed
fix: Ensure client logger is always wrapped in a safe logger.
1 parent 9e00eb6 commit fe9624e

File tree

4 files changed

+69
-15
lines changed

4 files changed

+69
-15
lines changed

packages/shared/sdk-client/__tests__/configuration/Configuration.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* eslint-disable no-console */
2+
import { createSafeLogger } from '@launchdarkly/js-sdk-common';
3+
24
import ConfigurationImpl from '../../src/configuration/Configuration';
35

46
describe('Configuration', () => {
@@ -120,3 +122,48 @@ describe('Configuration', () => {
120122
},
121123
);
122124
});
125+
126+
it('makes a safe logger', () => {
127+
const badLogger = {
128+
debug: () => {
129+
throw new Error('bad');
130+
},
131+
info: () => {
132+
throw new Error('bad');
133+
},
134+
warn: () => {
135+
throw new Error('bad');
136+
},
137+
error: () => {
138+
throw new Error('bad');
139+
},
140+
};
141+
const config = new ConfigurationImpl({
142+
logger: badLogger,
143+
});
144+
145+
expect(() => config.logger.debug('debug')).not.toThrow();
146+
expect(() => config.logger.info('info')).not.toThrow();
147+
expect(() => config.logger.warn('warn')).not.toThrow();
148+
expect(() => config.logger.error('error')).not.toThrow();
149+
expect(config.logger).not.toBe(badLogger);
150+
});
151+
152+
it('does not wrap already safe loggers', () => {
153+
const logger = createSafeLogger({
154+
debug: () => {
155+
throw new Error('bad');
156+
},
157+
info: () => {
158+
throw new Error('bad');
159+
},
160+
warn: () => {
161+
throw new Error('bad');
162+
},
163+
error: () => {
164+
throw new Error('bad');
165+
},
166+
});
167+
const config = new ConfigurationImpl({ logger });
168+
expect(config.logger).toBe(logger);
169+
});

packages/shared/sdk-client/__tests__/context/addAutoEnv.test.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ describe('automatic environment attributes', () => {
233233

234234
await addAutoEnv(context, mockPlatform, config);
235235

236-
expect(config.logger.warn).toHaveBeenCalledTimes(1);
237-
expect(config.logger.warn).toHaveBeenCalledWith(
236+
expect(logger.warn).toHaveBeenCalledTimes(1);
237+
expect(logger.warn).toHaveBeenCalledWith(
238238
expect.stringMatching(/ld_application.*already exists/),
239239
);
240240
});
@@ -251,10 +251,8 @@ describe('automatic environment attributes', () => {
251251

252252
await addAutoEnv(context, mockPlatform, config);
253253

254-
expect(config.logger.warn).toHaveBeenCalledTimes(1);
255-
expect(config.logger.warn).toHaveBeenCalledWith(
256-
expect.stringMatching(/ld_device.*already exists/),
257-
);
254+
expect(logger.warn).toHaveBeenCalledTimes(1);
255+
expect(logger.warn).toHaveBeenCalledWith(expect.stringMatching(/ld_device.*already exists/));
258256
});
259257

260258
test('single context with an attribute called ld_application should have auto env attributes', async () => {

packages/shared/sdk-client/src/configuration/Configuration.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
LDLogger,
77
NumberWithMinimum,
88
OptionMessages,
9+
SafeLogger,
910
ServiceEndpoints,
1011
TypeValidators,
1112
} from '@launchdarkly/js-sdk-common';
@@ -21,9 +22,6 @@ export interface LDClientInternalOptions extends internal.LDInternalOptions {
2122

2223
export interface Configuration {
2324
readonly logger: LDLogger;
24-
readonly baseUri: string;
25-
readonly eventsUri: string;
26-
readonly streamUri: string;
2725
readonly maxCachedContexts: number;
2826
readonly capacity: number;
2927
readonly diagnosticRecordingInterval: number;
@@ -61,12 +59,20 @@ const DEFAULT_STREAM: string = 'https://clientstream.launchdarkly.com';
6159

6260
export { DEFAULT_POLLING, DEFAULT_STREAM };
6361

62+
function ensureSafeLogger(logger?: LDLogger): LDLogger {
63+
if (logger instanceof SafeLogger) {
64+
return logger;
65+
}
66+
// Even if logger is not defined this will produce a valid logger.
67+
return createSafeLogger(logger);
68+
}
69+
6470
export default class ConfigurationImpl implements Configuration {
6571
public readonly logger: LDLogger = createSafeLogger();
6672

67-
public readonly baseUri = DEFAULT_POLLING;
68-
public readonly eventsUri = ServiceEndpoints.DEFAULT_EVENTS;
69-
public readonly streamUri = DEFAULT_STREAM;
73+
private readonly baseUri = DEFAULT_POLLING;
74+
private readonly eventsUri = ServiceEndpoints.DEFAULT_EVENTS;
75+
private readonly streamUri = DEFAULT_STREAM;
7076

7177
public readonly maxCachedContexts = 5;
7278

@@ -116,6 +122,7 @@ export default class ConfigurationImpl implements Configuration {
116122
[index: string]: any;
117123

118124
constructor(pristineOptions: LDOptions = {}, internalOptions: LDClientInternalOptions = {}) {
125+
this.logger = ensureSafeLogger(pristineOptions.logger);
119126
const errors = this.validateTypesAndNames(pristineOptions);
120127
errors.forEach((e: string) => this.logger.warn(e));
121128

@@ -161,6 +168,8 @@ export default class ConfigurationImpl implements Configuration {
161168
} else {
162169
errors.push(OptionMessages.wrongOptionType(k, validator.getType(), typeof v));
163170
}
171+
} else if (k === 'logger') {
172+
// Logger already assigned.
164173
} else {
165174
// if an option is explicitly null, coerce to undefined
166175
this[k] = v ?? undefined;

packages/shared/sdk-client/src/diagnostics/createDiagnosticsInitConfig.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ export type DiagnosticsInitConfig = {
1818
bootstrapMode: boolean;
1919
};
2020
const createDiagnosticsInitConfig = (config: Configuration): DiagnosticsInitConfig => ({
21-
customBaseURI: config.baseUri !== DEFAULT_POLLING,
22-
customStreamURI: config.streamUri !== DEFAULT_STREAM,
23-
customEventsURI: config.eventsUri !== ServiceEndpoints.DEFAULT_EVENTS,
21+
customBaseURI: config.serviceEndpoints.polling !== DEFAULT_POLLING,
22+
customStreamURI: config.serviceEndpoints.streaming !== DEFAULT_STREAM,
23+
customEventsURI: config.serviceEndpoints.events !== ServiceEndpoints.DEFAULT_EVENTS,
2424
eventsCapacity: config.capacity,
2525
eventsFlushIntervalMillis: secondsToMillis(config.flushInterval),
2626
reconnectTimeMillis: secondsToMillis(config.streamInitialReconnectDelay),

0 commit comments

Comments
 (0)