209 lines
7 KiB
TypeScript
209 lines
7 KiB
TypeScript
import {expect, jest, test} from '@jest/globals';
|
|
import { Manager } from '../../src/manager';
|
|
import { Logger, RootLogger } from '../../src/logger';
|
|
import { Handler } from '../../src/handler';
|
|
import { LogRecord } from '../../src/log-record';
|
|
import { WARNING, DEBUG, INFO, NOTSET } from '../../src/log-level';
|
|
|
|
function makeManager(): Manager {
|
|
return new Manager(new RootLogger(WARNING));
|
|
}
|
|
|
|
describe('Manager', () => {
|
|
describe('constructor', () => {
|
|
test('stores the root logger', () => {
|
|
const root = new RootLogger(WARNING);
|
|
const manager = new Manager(root);
|
|
expect(manager.root).toBe(root);
|
|
});
|
|
});
|
|
|
|
describe('getLogger', () => {
|
|
test('returns a Logger instance', () => {
|
|
const manager = makeManager();
|
|
const logger = manager.getLogger('app');
|
|
expect(logger).toBeInstanceOf(Logger);
|
|
expect(logger.scope).toBe('app');
|
|
});
|
|
|
|
test('returns the same logger for the same scope', () => {
|
|
const manager = makeManager();
|
|
const a = manager.getLogger('app');
|
|
const b = manager.getLogger('app');
|
|
expect(a).toBe(b);
|
|
});
|
|
|
|
test('returns different loggers for different scopes', () => {
|
|
const manager = makeManager();
|
|
const a = manager.getLogger('app');
|
|
const b = manager.getLogger('lib');
|
|
expect(a).not.toBe(b);
|
|
});
|
|
|
|
test('sets parent to root for top-level loggers', () => {
|
|
const manager = makeManager();
|
|
const logger = manager.getLogger('app');
|
|
expect(logger.parent).toBe(manager.root);
|
|
});
|
|
|
|
test('sets parent to existing parent logger', () => {
|
|
const manager = makeManager();
|
|
const parent = manager.getLogger('app');
|
|
const child = manager.getLogger('app.module');
|
|
expect(child.parent).toBe(parent);
|
|
});
|
|
|
|
test('establishes hierarchy for deeply nested loggers', () => {
|
|
const manager = makeManager();
|
|
const top = manager.getLogger('a');
|
|
const mid = manager.getLogger('a.b');
|
|
const leaf = manager.getLogger('a.b.c');
|
|
expect(leaf.parent).toBe(mid);
|
|
expect(mid.parent).toBe(top);
|
|
expect(top.parent).toBe(manager.root);
|
|
});
|
|
|
|
test('creates placeholders for intermediate loggers', () => {
|
|
const manager = makeManager();
|
|
const leaf = manager.getLogger('a.b.c');
|
|
expect(leaf.parent).toBe(manager.root);
|
|
|
|
const mid = manager.getLogger('a.b');
|
|
expect(leaf.parent).toBe(mid);
|
|
expect(mid.parent).toBe(manager.root);
|
|
});
|
|
|
|
test('fixes up children when intermediate logger is created', () => {
|
|
const manager = makeManager();
|
|
const leaf = manager.getLogger('a.b.c');
|
|
const top = manager.getLogger('a');
|
|
|
|
expect(top.parent).toBe(manager.root);
|
|
|
|
const mid = manager.getLogger('a.b');
|
|
expect(leaf.parent).toBe(mid);
|
|
});
|
|
});
|
|
|
|
describe('disable', () => {
|
|
test('defaults to 0', () => {
|
|
const manager = makeManager();
|
|
expect(manager.disable).toBe(0);
|
|
});
|
|
|
|
test('can be set to a level', () => {
|
|
const manager = makeManager();
|
|
manager.disable = WARNING;
|
|
expect(manager.disable).toBe(WARNING);
|
|
});
|
|
});
|
|
|
|
describe('loggerClass', () => {
|
|
test('accepts Logger subclass', () => {
|
|
const manager = makeManager();
|
|
class CustomLogger extends Logger {}
|
|
expect(() => { manager.loggerClass = CustomLogger as any }).not.toThrow();
|
|
});
|
|
|
|
test('rejects non-Logger class', () => {
|
|
const manager = makeManager();
|
|
class NotALogger {}
|
|
expect(() => {
|
|
manager.loggerClass = NotALogger as any;
|
|
}).toThrow(TypeError);
|
|
});
|
|
|
|
test('accepts Logger itself', () => {
|
|
const manager = makeManager();
|
|
expect(() => { manager.loggerClass = Logger as any }).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('getLogger - manager assignment', () => {
|
|
test('sets manager on newly created loggers', () => {
|
|
const manager = makeManager();
|
|
const logger = manager.getLogger('app');
|
|
expect(logger.manager).toBe(manager);
|
|
});
|
|
|
|
test('sets manager on loggers created from placeholders', () => {
|
|
const manager = makeManager();
|
|
manager.getLogger('a.b.c');
|
|
const mid = manager.getLogger('a.b');
|
|
expect(mid.manager).toBe(manager);
|
|
});
|
|
|
|
test('isEnabledFor respects manager.disable via getLogger', () => {
|
|
const manager = makeManager();
|
|
const logger = manager.getLogger('app');
|
|
logger.setLevel(DEBUG);
|
|
|
|
expect(logger.isEnabledFor(DEBUG)).toBe(true);
|
|
|
|
manager.disable = WARNING;
|
|
logger.clear();
|
|
|
|
expect(logger.isEnabledFor(DEBUG)).toBe(false);
|
|
expect(logger.isEnabledFor(WARNING)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('propagation through hierarchy', () => {
|
|
test('child logger propagates records to parent handler', () => {
|
|
const manager = makeManager();
|
|
const parent = manager.getLogger('app');
|
|
const child = manager.getLogger('app.module');
|
|
|
|
parent.setLevel(DEBUG);
|
|
child.setLevel(DEBUG);
|
|
|
|
const emitted: string[] = [];
|
|
const handler = new (class extends Handler {
|
|
emit(record: LogRecord) {
|
|
emitted.push(record.msg);
|
|
}
|
|
})(DEBUG);
|
|
|
|
parent.addHandler(handler);
|
|
child.info('propagated message');
|
|
|
|
expect(emitted).toContain('propagated message');
|
|
});
|
|
|
|
test('child does not propagate to unrelated logger', () => {
|
|
const manager = makeManager();
|
|
const unrelated = manager.getLogger('other');
|
|
const child = manager.getLogger('app.module');
|
|
|
|
unrelated.setLevel(DEBUG);
|
|
child.setLevel(DEBUG);
|
|
|
|
const emitted: string[] = [];
|
|
const handler = new (class extends Handler {
|
|
emit(record: LogRecord) {
|
|
emitted.push(record.msg);
|
|
}
|
|
})(DEBUG);
|
|
|
|
unrelated.addHandler(handler);
|
|
child.info('should not reach');
|
|
|
|
expect(emitted).not.toContain('should not reach');
|
|
});
|
|
});
|
|
|
|
describe('clear', () => {
|
|
test('clears logger caches', () => {
|
|
const manager = makeManager();
|
|
const logger = manager.getLogger('test');
|
|
logger.isEnabledFor(DEBUG);
|
|
manager.clear();
|
|
});
|
|
|
|
test('does not throw when placeholders exist', () => {
|
|
const manager = makeManager();
|
|
manager.getLogger('a.b.c');
|
|
expect(() => manager.clear()).not.toThrow();
|
|
});
|
|
});
|
|
});
|