-
-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(logger): update/extend ILogger interface
BREAKING CHANGE: update/extend ILogger interface to support hierarchies of loggers - update ALogger impl, update ctor - update ConsoleLogger, MemoryLogger, StreamLogger classes - update NULL_LOGGER - add ROOT logger and ProxyLogger class - add/update docs - update tests - update pkg exports
- Loading branch information
1 parent
1714067
commit 887e839
Showing
10 changed files
with
200 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,62 @@ | ||
import { LogLevel, type ILogger, type LogLevelName } from "./api.js"; | ||
|
||
import { | ||
LogLevel, | ||
type ILogger, | ||
type LogEntry, | ||
type LogLevelName, | ||
} from "./api.js"; | ||
|
||
let __nextID = 0; | ||
/** | ||
* Abstract {@link ILogger} base implementation. | ||
*/ | ||
export abstract class ALogger implements ILogger { | ||
id: string; | ||
level: LogLevel; | ||
|
||
constructor(id: string, level: LogLevel | LogLevelName = LogLevel.FINE) { | ||
this.id = id; | ||
constructor( | ||
id?: string, | ||
level: LogLevel | LogLevelName = LogLevel.FINE, | ||
public parent?: ILogger | ||
) { | ||
this.id = id || `logger-${__nextID++}`; | ||
this.level = typeof level === "string" ? LogLevel[level] : level; | ||
} | ||
|
||
addChild(logger: ILogger): ILogger { | ||
logger.parent = this; | ||
return logger; | ||
} | ||
|
||
abstract childLogger(id: string, level?: LogLevel): ILogger; | ||
|
||
enabled(level: LogLevel) { | ||
return this.level <= level; | ||
} | ||
|
||
fine(...args: any[]): void { | ||
this.level <= LogLevel.FINE && this.log(LogLevel.FINE, args); | ||
fine(...args: any[]) { | ||
this.log(LogLevel.FINE, args); | ||
} | ||
|
||
debug(...args: any[]) { | ||
this.log(LogLevel.DEBUG, args); | ||
} | ||
|
||
debug(...args: any[]): void { | ||
this.level <= LogLevel.DEBUG && this.log(LogLevel.DEBUG, args); | ||
info(...args: any[]) { | ||
this.log(LogLevel.INFO, args); | ||
} | ||
|
||
info(...args: any[]): void { | ||
this.level <= LogLevel.INFO && this.log(LogLevel.INFO, args); | ||
warn(...args: any[]) { | ||
this.log(LogLevel.WARN, args); | ||
} | ||
|
||
warn(...args: any[]): void { | ||
this.level <= LogLevel.WARN && this.log(LogLevel.WARN, args); | ||
severe(...args: any[]) { | ||
this.log(LogLevel.SEVERE, args); | ||
} | ||
|
||
severe(...args: any[]): void { | ||
this.level <= LogLevel.SEVERE && this.log(LogLevel.SEVERE, args); | ||
protected log(level: LogLevel, args: any[]) { | ||
this.level <= level && | ||
this.logEntry([level, this.id, Date.now(), ...args]); | ||
} | ||
|
||
protected abstract log(level: LogLevel, args: any[]): void; | ||
abstract logEntry(entry: LogEntry): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,18 @@ | ||
import { ALogger } from "./alogger.js"; | ||
import { LogLevel } from "./api.js"; | ||
import { LogLevel, type LogEntry, type ILogger } from "./api.js"; | ||
import { expandArgs } from "./utils.js"; | ||
|
||
/** | ||
* {@link ILogger} implementation writing messages via `console.log`. | ||
*/ | ||
export class ConsoleLogger extends ALogger { | ||
protected log(level: LogLevel, args: any[]) { | ||
console.log(`[${LogLevel[level]}] ${this.id}:`, ...expandArgs(args)); | ||
childLogger(id?: string, level?: LogLevel): ConsoleLogger { | ||
return new ConsoleLogger(id, level ?? this.level, this); | ||
} | ||
|
||
logEntry(e: LogEntry) { | ||
if (e[0] < this.level) return; | ||
console.log(`[${LogLevel[e[0]]}] ${e[1]}:`, ...expandArgs(e.slice(3))); | ||
this.parent && this.parent.logEntry(e); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { ALogger } from "./alogger.js"; | ||
import { LogLevel, type ILogger, type LogEntry } from "./api.js"; | ||
import { NULL_LOGGER } from "./null.js"; | ||
|
||
/** | ||
* A special {@link ILogger} implementation which only proxies its | ||
* {@link ILogger.parent}. Used for {@link ROOT} to allow provision & | ||
* configuration of a single endpoint for an entire tree of child loggers. See | ||
* {@link ROOT} for more details. | ||
*/ | ||
export class ProxyLogger extends ALogger { | ||
set(logger: ILogger) { | ||
this.parent = logger; | ||
} | ||
|
||
childLogger(id?: string, level?: LogLevel): ProxyLogger { | ||
return new ProxyLogger(id, level ?? this.level, this); | ||
} | ||
|
||
logEntry(e: LogEntry) { | ||
this.parent!.logEntry(e); | ||
} | ||
} | ||
|
||
/** | ||
* thi.ng/umbrella global root logger, by default configured to not produce any | ||
* output. | ||
* | ||
* @remarks | ||
* Users can attach and create hierarchies of child loggers (each one feeding | ||
* into this root logger) by calling {@link ILogger.childLogger} or | ||
* {@link ILogger.addChild}. | ||
* | ||
* To enable actual (global) logging output for this root logger, use | ||
* `.set()` and provide a {@link ILogger} implementation. | ||
* | ||
* @example | ||
* ```ts | ||
* const myLogger = ROOT.childLogger("custom"); | ||
* | ||
* // use console output for root logger | ||
* ROOT.set(new ConsoleLogger("root")); | ||
* | ||
* // log message will be forwarded to root | ||
* myLogger.debug("hello"); | ||
* | ||
* // [DEBUG] custom: hello | ||
* ``` | ||
*/ | ||
export const ROOT = new ProxyLogger("root", LogLevel.FINE, NULL_LOGGER); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters