Skip to content

Commit a559278

Browse files
committed
Implement client logging
1 parent 504251c commit a559278

File tree

6 files changed

+134
-17
lines changed

6 files changed

+134
-17
lines changed

packages-exp/app-exp/src/api.test.ts

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,35 @@
1616
*/
1717

1818
import { expect } from 'chai';
19-
import { stub } from 'sinon';
19+
import { stub, spy } from 'sinon';
2020
import '../test/setup';
2121
import {
2222
initializeApp,
2323
getApps,
2424
deleteApp,
2525
getApp,
26-
registerVersion
26+
registerVersion,
27+
setLogLevel,
28+
LogLevel,
29+
onLog
2730
} from './api';
2831
import { DEFAULT_ENTRY_NAME } from './constants';
2932
import { FirebaseAppInternal } from '@firebase/app-types-exp';
30-
import { clearComponents, components, registerComponent } from './internal';
33+
import { clearComponents, components, registerComponent, getProvider } from './internal';
3134
import { createTestComponent } from '../test/util';
35+
import { Component, ComponentType } from '@firebase/component';
36+
import { Logger } from '@firebase/logger';
37+
38+
declare module '@firebase/component' {
39+
interface NameServiceMapping {
40+
'test-shell': void;
41+
}
42+
}
3243

3344
describe('API tests', () => {
3445
afterEach(() => {
3546
for (const app of getApps()) {
36-
deleteApp(app).catch(() => {});
47+
deleteApp(app).catch(() => { });
3748
}
3849
});
3950

@@ -132,7 +143,7 @@ describe('API tests', () => {
132143
const app1 = initializeApp({});
133144
const app2 = initializeApp({}, 'App2');
134145

135-
deleteApp(app1).catch(() => {});
146+
deleteApp(app1).catch(() => { });
136147

137148
const apps = getApps();
138149

@@ -146,15 +157,15 @@ describe('API tests', () => {
146157
const app = initializeApp({});
147158
expect((app as FirebaseAppInternal).isDeleted).to.be.false;
148159

149-
await deleteApp(app).catch(() => {});
160+
await deleteApp(app).catch(() => { });
150161
expect((app as FirebaseAppInternal).isDeleted).to.be.true;
151162
});
152163

153164
it('removes App from the cache', () => {
154165
const app = initializeApp({});
155166
expect(getApps().length).to.equal(1);
156167

157-
deleteApp(app).catch(() => {});
168+
deleteApp(app).catch(() => { });
158169
expect(getApps().length).to.equal(0);
159170
});
160171
});
@@ -199,4 +210,73 @@ describe('API tests', () => {
199210
expect(components.size).to.equal(initialSize);
200211
});
201212
});
213+
214+
describe('User Log Methods', () => {
215+
describe('Integration Tests', () => {
216+
217+
beforeEach(() => {
218+
clearComponents();
219+
});
220+
221+
it(`respects log level set through setLogLevel()`, () => {
222+
const warnSpy = spy(console, 'warn');
223+
const infoSpy = spy(console, 'info');
224+
const logSpy = spy(console, 'log');
225+
const app = initializeApp({});
226+
registerComponent(
227+
new Component(
228+
'test-shell',
229+
() => {
230+
const logger = new Logger('@firebase/logger-test');
231+
logger.warn('hello');
232+
expect(warnSpy.called).to.be.true;
233+
setLogLevel(LogLevel.WARN);
234+
logger.info('hi');
235+
expect(infoSpy.called).to.be.false;
236+
logger.log('hi');
237+
expect(logSpy.called).to.be.false;
238+
logSpy.resetHistory();
239+
infoSpy.resetHistory();
240+
setLogLevel(LogLevel.DEBUG);
241+
logger.info('hi');
242+
expect(infoSpy.called).to.be.true;
243+
logger.log('hi');
244+
expect(logSpy.called).to.be.true;
245+
return {};
246+
},
247+
ComponentType.PUBLIC
248+
)
249+
);
250+
251+
getProvider(app, 'test-shell').getImmediate();
252+
});
253+
254+
it(`correctly triggers callback given to onLog()`, () => {
255+
const infoSpy = spy(console, 'info');
256+
let result: any = null;
257+
// Note: default log level is INFO.
258+
const app = initializeApp({});
259+
registerComponent(
260+
new Component(
261+
'test-shell',
262+
() => {
263+
const logger = new Logger('@firebase/logger-test');
264+
onLog(logData => {
265+
result = logData;
266+
});
267+
logger.info('hi');
268+
expect(result.level).to.equal('info');
269+
expect(result.message).to.equal('hi');
270+
expect(result.args).to.deep.equal(['hi']);
271+
expect(result.type).to.equal('@firebase/logger-test');
272+
expect(infoSpy.called).to.be.true;
273+
return {};
274+
},
275+
ComponentType.PUBLIC
276+
)
277+
);
278+
getProvider(app, 'test-shell').getImmediate();
279+
});
280+
});
281+
});
202282
});

packages-exp/app-exp/src/api.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ import { version } from '../../../packages/firebase/package.json';
3333
import { FirebaseAppImpl } from './firebaseApp';
3434
import { apps, components, registerComponent } from './internal';
3535
import { logger } from './logger';
36+
import {
37+
LogLevel,
38+
setLogLevel as setLogLevelImpl,
39+
LogCallback,
40+
LogOptions,
41+
setUserLogHandler
42+
} from '@firebase/logger';
3643

3744
/**
3845
* The current SDK version.
@@ -243,3 +250,30 @@ export function registerVersion(
243250
)
244251
);
245252
}
253+
254+
/**
255+
* Sets log handler for all Firebase SDKs.
256+
* @param logCallback An optional custom log handler that executes user code whenever
257+
* the Firebase SDK makes a logging call.
258+
*/
259+
export function onLog(logCallback: LogCallback | null, options?: LogOptions): void {
260+
if (logCallback !== null && typeof logCallback !== 'function') {
261+
throw ERROR_FACTORY.create(AppError.INVALID_LOG_ARGUMENT, {
262+
appName: name
263+
});
264+
}
265+
setUserLogHandler(logCallback, options);
266+
}
267+
268+
/**
269+
* Sets log level for all Firebase SDKs.
270+
*
271+
* All of the log types above the current log level are captured (i.e. if
272+
* you set the log level to `info`, errors are logged, but `debug` and
273+
* `verbose` logs are not).
274+
*/
275+
export function setLogLevel(logLevel: LogLevel): void {
276+
setLogLevelImpl(logLevel);
277+
}
278+
279+
export { LogLevel } from '@firebase/logger';

packages-exp/app-exp/src/errors.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export const enum AppError {
2222
BAD_APP_NAME = 'bad-app-name',
2323
DUPLICATE_APP = 'duplicate-app',
2424
APP_DELETED = 'app-deleted',
25-
INVALID_APP_ARGUMENT = 'invalid-app-argument'
25+
INVALID_APP_ARGUMENT = 'invalid-app-argument',
26+
INVALID_LOG_ARGUMENT = 'invalid-log-argument'
2627
}
2728

2829
const ERRORS: ErrorMap<AppError> = {
@@ -34,7 +35,9 @@ const ERRORS: ErrorMap<AppError> = {
3435
[AppError.APP_DELETED]: "Firebase App named '{$appName}' already deleted",
3536
[AppError.INVALID_APP_ARGUMENT]:
3637
'firebase.{$appName}() takes either no argument or a ' +
37-
'Firebase App instance.'
38+
'Firebase App instance.',
39+
[AppError.INVALID_LOG_ARGUMENT]:
40+
'First argument to `onLog` must be null or a function.'
3841
};
3942

4043
type ErrorParams = { [key in AppError]: { appName: string } };

packages-exp/app-exp/src/internal.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ describe('Internal API tests', () => {
4848
const testComp = createTestComponent('test');
4949

5050
addComponent(app, testComp);
51-
51+
5252
expect(app.container.getProvider('test').getComponent()).to.equal(
5353
testComp
5454
);
5555
});
56+
5657
it('does NOT throw registering duplicate components', () => {
5758
const app = initializeApp({}) as FirebaseAppInternal;
5859
const testComp = createTestComponent('test');

packages-exp/app-exp/src/internal.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ export const components = new Map<string, Component<any>>();
3030
* @param component the component being added to this app's container
3131
*/
3232
export function addComponent(
33-
app: FirebaseAppInternal,
33+
app: FirebaseApp,
3434
component: Component
3535
): void {
3636
try {
37-
app.container.addComponent(component);
37+
(app as FirebaseAppInternal).container.addComponent(component);
3838
} catch (e) {
3939
logger.debug(
4040
`Component ${component.name} failed to register with FirebaseApp ${app.name}`,
@@ -44,10 +44,10 @@ export function addComponent(
4444
}
4545

4646
export function addOrOverwriteComponent(
47-
app: FirebaseAppInternal,
47+
app: FirebaseApp,
4848
component: Component
4949
): void {
50-
app.container.addOrOverwriteComponent(component);
50+
(app as FirebaseAppInternal).container.addOrOverwriteComponent(component);
5151
}
5252

5353
/**
@@ -76,10 +76,10 @@ export function registerComponent(component: Component): boolean {
7676
}
7777

7878
export function getProvider<T extends Name>(
79-
app: FirebaseAppInternal,
79+
app: FirebaseApp,
8080
name: T
8181
): Provider<T> {
82-
return app.container.getProvider(name);
82+
return (app as FirebaseAppInternal).container.getProvider(name);
8383
}
8484

8585
/**

packages-exp/app-exp/src/platformLoggerService.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ declare module '@firebase/component' {
3030
interface NameServiceMapping {
3131
'vs1': VersionService;
3232
'vs2': VersionService;
33-
'test-shell': Promise<void>;
3433
}
3534
}
3635

0 commit comments

Comments
 (0)