Merge branch 'feature/9' into dev

This commit is contained in:
Tiara Rodney 2026-03-14 02:32:40 +01:00
commit e50fccff8f
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
3 changed files with 89 additions and 3 deletions

2
TODO
View file

@ -140,7 +140,7 @@ Content-Type: application/issue
ID: 9 ID: 9
Type: feature Type: feature
Title: implement Manager logger hierarchy Title: implement Manager logger hierarchy
Status: in-progress Status: done
Priority: high Priority: high
Created: 2026-03-13 Created: 2026-03-13
Relationships: dependsOn:5 Relationships: dependsOn:5

View file

@ -79,8 +79,10 @@ export class Manager {
if (existing instanceof Placeholder) { if (existing instanceof Placeholder) {
rv = new (this._loggerClass ?? loggerClass)(scope, NOTSET); rv = new (this._loggerClass ?? loggerClass)(scope, NOTSET);
rv.manager = this;
this.loggers[scope] = rv; this.loggers[scope] = rv;
this._fixupChildren(existing, rv); this._fixupChildren(existing, rv);
this._fixupParents(rv);
} }
else { else {
rv = existing; rv = existing;
@ -88,6 +90,7 @@ export class Manager {
} }
else { else {
rv = new (this._loggerClass ?? loggerClass)(scope, NOTSET); rv = new (this._loggerClass ?? loggerClass)(scope, NOTSET);
rv.manager = this;
this.loggers[scope] = rv; this.loggers[scope] = rv;
this._fixupParents(rv); this._fixupParents(rv);
} }
@ -168,7 +171,9 @@ export class Manager {
*/ */
public clear() { public clear() {
Object.values(this.loggers).forEach((logger) => { Object.values(this.loggers).forEach((logger) => {
logger.clear() if (!(logger instanceof Placeholder)) {
logger.clear();
}
}); });
} }
} }

View file

@ -1,7 +1,9 @@
import {expect, jest, test} from '@jest/globals'; import {expect, jest, test} from '@jest/globals';
import { Manager } from '../../src/manager'; import { Manager } from '../../src/manager';
import { Logger, RootLogger } from '../../src/logger'; import { Logger, RootLogger } from '../../src/logger';
import { WARNING, DEBUG, NOTSET } from '../../src/log-level'; import { Handler } from '../../src/handler';
import { LogRecord } from '../../src/log-record';
import { WARNING, DEBUG, INFO, NOTSET } from '../../src/log-level';
function makeManager(): Manager { function makeManager(): Manager {
return new Manager(new RootLogger(WARNING)); return new Manager(new RootLogger(WARNING));
@ -117,6 +119,79 @@ describe('Manager', () => {
}); });
}); });
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', () => { describe('clear', () => {
test('clears logger caches', () => { test('clears logger caches', () => {
const manager = makeManager(); const manager = makeManager();
@ -124,5 +199,11 @@ describe('Manager', () => {
logger.isEnabledFor(DEBUG); logger.isEnabledFor(DEBUG);
manager.clear(); manager.clear();
}); });
test('does not throw when placeholders exist', () => {
const manager = makeManager();
manager.getLogger('a.b.c');
expect(() => manager.clear()).not.toThrow();
});
}); });
}); });