Skip to content

Commit 32d4a22

Browse files
authored
Merge branch 'main' into mzafir/react-native-jest-mock
2 parents 2fc00e4 + 008dcf0 commit 32d4a22

File tree

11 files changed

+273
-52
lines changed

11 files changed

+273
-52
lines changed

actions/package-size/action.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ runs:
3131
echo "PACK_SIZE=$PACK_SIZE" >> $GITHUB_ENV
3232
3333
- name: Find Size Comment
34+
# Only do commenting on non-forks. A fork does not have permissions for comments.
35+
if: github.event.pull_request.head.repo.full_name == github.repository
3436
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e
3537
id: fc
3638
with:
@@ -39,7 +41,7 @@ runs:
3941
body-includes: '${{ inputs.package_name }} size report'
4042

4143
- name: Create comment
42-
if: steps.fc.outputs.comment-id == ''
44+
if: steps.fc.outputs.comment-id == '' && github.event.pull_request.head.repo.full_name == github.repository
4345
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
4446
with:
4547
issue-number: ${{ inputs.pr_number }}
@@ -50,7 +52,7 @@ runs:
5052
Size limit: ${{ inputs.size_limit }}
5153
5254
- name: Update comment
53-
if: steps.fc.outputs.comment-id != ''
55+
if: steps.fc.outputs.comment-id != '' && github.event.pull_request.head.repo.full_name == github.repository
5456
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
5557
with:
5658
comment-id: ${{ steps.fc.outputs.comment-id }}

packages/sdk/browser/src/BrowserClient.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
AutoEnvAttributes,
33
base64UrlEncode,
4+
BasicLogger,
45
LDClient as CommonClient,
56
Configuration,
6-
createSafeLogger,
77
Encoding,
88
FlagManager,
99
internal,
@@ -98,15 +98,18 @@ export class BrowserClient extends LDClientImpl implements LDClient {
9898
// Overrides the default logger from the common implementation.
9999
const logger =
100100
customLogger ??
101-
createSafeLogger({
102-
// eslint-disable-next-line no-console
103-
debug: debug ? console.debug : () => {},
104-
// eslint-disable-next-line no-console
105-
info: console.info,
106-
// eslint-disable-next-line no-console
107-
warn: console.warn,
108-
// eslint-disable-next-line no-console
109-
error: console.error,
101+
new BasicLogger({
102+
destination: {
103+
// eslint-disable-next-line no-console
104+
debug: console.debug,
105+
// eslint-disable-next-line no-console
106+
info: console.info,
107+
// eslint-disable-next-line no-console
108+
warn: console.warn,
109+
// eslint-disable-next-line no-console
110+
error: console.error,
111+
},
112+
level: debug ? 'debug' : 'info',
110113
});
111114

112115
// TODO: Use the already-configured baseUri from the SDK config. SDK-560

packages/sdk/browser/src/compat/index.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,59 @@
55
* Some code changes may still be required, for example {@link LDOptions} removes
66
* support for some previously available options.
77
*/
8-
import { LDContext, LDOptions } from '..';
8+
import {
9+
basicLogger,
10+
EvaluationSeriesContext,
11+
EvaluationSeriesData,
12+
Hook,
13+
HookMetadata,
14+
IdentifySeriesContext,
15+
IdentifySeriesData,
16+
IdentifySeriesResult,
17+
IdentifySeriesStatus,
18+
LDContext,
19+
LDContextCommon,
20+
LDContextMeta,
21+
LDEvaluationDetail,
22+
LDEvaluationDetailTyped,
23+
LDEvaluationReason,
24+
LDFlagSet,
25+
LDIdentifyOptions,
26+
LDLogger,
27+
LDLogLevel,
28+
LDMultiKindContext,
29+
LDOptions,
30+
LDSingleKindContext,
31+
} from '..';
932
import { LDClient } from './LDClientCompat';
1033
import LDClientCompatImpl from './LDClientCompatImpl';
1134

35+
export type {
36+
LDClient,
37+
LDFlagSet,
38+
LDContext,
39+
LDContextCommon,
40+
LDContextMeta,
41+
LDMultiKindContext,
42+
LDSingleKindContext,
43+
LDLogLevel,
44+
LDLogger,
45+
LDOptions,
46+
LDEvaluationDetail,
47+
LDEvaluationDetailTyped,
48+
LDEvaluationReason,
49+
LDIdentifyOptions,
50+
Hook,
51+
HookMetadata,
52+
EvaluationSeriesContext,
53+
EvaluationSeriesData,
54+
IdentifySeriesContext,
55+
IdentifySeriesData,
56+
IdentifySeriesResult,
57+
IdentifySeriesStatus,
58+
basicLogger,
59+
};
60+
1261
/**
1362
* Creates an instance of the LaunchDarkly client. This version of initialization is for
1463
* improved backwards compatibility. In general the `initialize` function from the root packge

packages/sdk/browser/src/index.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*/
1313
import {
1414
AutoEnvAttributes,
15+
BasicLogger,
16+
BasicLoggerOptions,
1517
EvaluationSeriesContext,
1618
EvaluationSeriesData,
1719
Hook,
@@ -27,6 +29,7 @@ import {
2729
LDEvaluationDetailTyped,
2830
LDEvaluationReason,
2931
LDFlagSet,
32+
LDInspection,
3033
LDLogger,
3134
LDLogLevel,
3235
LDMultiKindContext,
@@ -62,6 +65,7 @@ export type {
6265
IdentifySeriesData,
6366
IdentifySeriesResult,
6467
IdentifySeriesStatus,
68+
LDInspection,
6569
};
6670

6771
/**
@@ -84,3 +88,54 @@ export function initialize(clientSideId: string, options?: LDOptions): LDClient
8488
// AutoEnvAttributes are not supported yet in the browser SDK.
8589
return new BrowserClient(clientSideId, AutoEnvAttributes.Disabled, options);
8690
}
91+
92+
/**
93+
* Provides a simple {@link LDLogger} implementation.
94+
*
95+
* This logging implementation uses a simple format that includes only the log level
96+
* and the message text. By default the output is written to `console.error`.
97+
*
98+
* To use the logger created by this function, put it into {@link LDOptions.logger}. If
99+
* you do not set {@link LDOptions.logger} to anything, the SDK uses a default logger
100+
* that will log "info" level and higher priorty messages and it will log messages to
101+
* console.info, console.warn, and console.error.
102+
*
103+
* @param options Configuration for the logger. If no options are specified, the
104+
* logger uses `{ level: 'info' }`.
105+
*
106+
* @example
107+
* This example shows how to use `basicLogger` in your SDK options to enable console
108+
* logging only at `warn` and `error` levels.
109+
* ```javascript
110+
* const ldOptions = {
111+
* logger: basicLogger({ level: 'warn' }),
112+
* };
113+
* ```
114+
*
115+
* @example
116+
* This example shows how to use `basicLogger` in your SDK options to cause all
117+
* log output to go to `console.log`
118+
* ```javascript
119+
* const ldOptions = {
120+
* logger: basicLogger({ destination: console.log }),
121+
* };
122+
* ```
123+
*
124+
* * @example
125+
* The configuration also allows you to control the destination for each log level.
126+
* ```javascript
127+
* const ldOptions = {
128+
* logger: basicLogger({
129+
* destination: {
130+
* debug: console.debug,
131+
* info: console.info,
132+
* warn: console.warn,
133+
* error:console.error
134+
* }
135+
* }),
136+
* };
137+
* ```
138+
*/
139+
export function basicLogger(options: BasicLoggerOptions): LDLogger {
140+
return new BasicLogger(options);
141+
}

packages/shared/common/__tests__/logging/BasicLogger.test.ts

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { BasicLogger, LDLogLevel } from '../../src';
22

33
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
44

5+
beforeEach(() => {
6+
jest.clearAllMocks();
7+
});
8+
59
describe.each<[LDLogLevel, string[]]>([
610
[
711
'debug',
@@ -64,10 +68,6 @@ describe('given a logger with a custom name', () => {
6468
describe('given a default logger', () => {
6569
const logger = new BasicLogger({});
6670

67-
beforeEach(() => {
68-
jest.clearAllMocks();
69-
});
70-
7171
it('logs to the console', () => {
7272
logger.warn('potato', 'bacon');
7373
expect(spy).toHaveBeenCalledWith('potato', 'bacon');
@@ -81,10 +81,6 @@ describe('given a logger with a destination that throws', () => {
8181
},
8282
});
8383

84-
beforeEach(() => {
85-
jest.clearAllMocks();
86-
});
87-
8884
it('logs to the console instead of throwing', () => {
8985
logger.error('a');
9086
expect(spy).toHaveBeenCalledWith('error: [LaunchDarkly] a');
@@ -94,10 +90,6 @@ describe('given a logger with a destination that throws', () => {
9490
describe('given a logger with a formatter that throws', () => {
9591
const strings: string[] = [];
9692

97-
beforeEach(() => {
98-
jest.clearAllMocks();
99-
});
100-
10193
const logger = new BasicLogger({
10294
destination: (...args: any) => {
10395
strings.push(args.join(' '));
@@ -112,3 +104,102 @@ describe('given a logger with a formatter that throws', () => {
112104
expect(spy).toHaveBeenCalledTimes(0);
113105
});
114106
});
107+
108+
it('dispatches logs correctly with multiple destinations', () => {
109+
const debug = jest.fn();
110+
const info = jest.fn();
111+
const warn = jest.fn();
112+
const error = jest.fn();
113+
114+
const logger = new BasicLogger({
115+
destination: {
116+
debug,
117+
info,
118+
warn,
119+
error,
120+
},
121+
level: 'debug',
122+
});
123+
124+
logger.debug('toDebug');
125+
logger.info('toInfo');
126+
logger.warn('toWarn');
127+
logger.error('toError');
128+
129+
expect(debug).toHaveBeenCalledTimes(1);
130+
expect(debug).toHaveBeenCalledWith('debug: [LaunchDarkly] toDebug');
131+
132+
expect(info).toHaveBeenCalledTimes(1);
133+
expect(info).toHaveBeenCalledWith('info: [LaunchDarkly] toInfo');
134+
135+
expect(warn).toHaveBeenCalledTimes(1);
136+
expect(warn).toHaveBeenCalledWith('warn: [LaunchDarkly] toWarn');
137+
138+
expect(error).toHaveBeenCalledTimes(1);
139+
expect(error).toHaveBeenCalledWith('error: [LaunchDarkly] toError');
140+
});
141+
142+
it('handles destinations which throw', () => {
143+
const debug = jest.fn(() => {
144+
throw new Error('bad');
145+
});
146+
const info = jest.fn(() => {
147+
throw new Error('bad');
148+
});
149+
const warn = jest.fn(() => {
150+
throw new Error('bad');
151+
});
152+
const error = jest.fn(() => {
153+
throw new Error('bad');
154+
});
155+
156+
const logger = new BasicLogger({
157+
destination: {
158+
debug,
159+
info,
160+
warn,
161+
error,
162+
},
163+
level: 'debug',
164+
});
165+
166+
logger.debug('toDebug');
167+
logger.info('toInfo');
168+
logger.warn('toWarn');
169+
logger.error('toError');
170+
171+
expect(spy).toHaveBeenCalledTimes(4);
172+
expect(spy).toHaveBeenCalledWith('debug: [LaunchDarkly] toDebug');
173+
expect(spy).toHaveBeenCalledWith('info: [LaunchDarkly] toInfo');
174+
expect(spy).toHaveBeenCalledWith('warn: [LaunchDarkly] toWarn');
175+
expect(spy).toHaveBeenCalledWith('error: [LaunchDarkly] toError');
176+
});
177+
178+
it('handles destinations which are not defined', () => {
179+
const debug = jest.fn();
180+
const info = jest.fn();
181+
const logger = new BasicLogger({
182+
// @ts-ignore
183+
destination: {
184+
debug,
185+
info,
186+
},
187+
level: 'debug',
188+
});
189+
190+
logger.debug('toDebug');
191+
logger.info('toInfo');
192+
logger.warn('toWarn');
193+
logger.error('toError');
194+
195+
expect(debug).toHaveBeenCalledTimes(1);
196+
expect(debug).toHaveBeenCalledWith('debug: [LaunchDarkly] toDebug');
197+
198+
expect(info).toHaveBeenCalledTimes(1);
199+
expect(info).toHaveBeenCalledWith('info: [LaunchDarkly] toInfo');
200+
201+
expect(spy).toHaveBeenCalledTimes(2);
202+
203+
expect(spy).toHaveBeenCalledWith('toWarn');
204+
expect(spy).toHaveBeenCalledWith('toError');
205+
});

packages/shared/common/src/api/logging/BasicLoggerOptions.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,23 @@ export interface BasicLoggerOptions {
2121
name?: string;
2222

2323
/**
24-
* An optional function to use to print each log line.
24+
* An optional function, or map of levels to functions, to use to print each log line.
2525
*
26-
* If this is specified, `basicLogger` calls it to write each line of output. The
26+
* If not specified, the default is `console.error`.
27+
*
28+
* If a function is specified, `basicLogger` calls it to write each line of output. The
2729
* argument is a fully formatted log line, not including a linefeed. The function
2830
* is only called for log levels that are enabled.
2931
*
30-
* If not specified, the default is `console.error`.
32+
* If a map is specified, then each entry will be used as the destination for the corresponding
33+
* log level. Any level that is not specified will use the default of `console.error`.
3134
*
3235
* Setting this property to anything other than a function will cause SDK
3336
* initialization to fail.
3437
*/
35-
destination?: (line: string) => void;
38+
destination?:
39+
| ((line: string) => void)
40+
| Record<'debug' | 'info' | 'warn' | 'error', (line: string) => void>;
3641

3742
/**
3843
* An optional formatter to use. The formatter should be compatible

0 commit comments

Comments
 (0)