@thi.ng/logger
Advanced tools
Comparing version 2.1.10 to 3.0.0
@@ -1,2 +0,2 @@ | ||
import { LogLevel, type ILogger, type LogLevelName } from "./api.js"; | ||
import { LogLevel, type ILogger, type LogEntry, type LogLevelName } from "./api.js"; | ||
/** | ||
@@ -6,5 +6,8 @@ * Abstract {@link ILogger} base implementation. | ||
export declare abstract class ALogger implements ILogger { | ||
parent?: ILogger | undefined; | ||
id: string; | ||
level: LogLevel; | ||
constructor(id: string, level?: LogLevel | LogLevelName); | ||
constructor(id?: string, level?: LogLevel | LogLevelName, parent?: ILogger | undefined); | ||
addChild(logger: ILogger): ILogger; | ||
abstract childLogger(id: string, level?: LogLevel): ILogger; | ||
enabled(level: LogLevel): boolean; | ||
@@ -16,4 +19,5 @@ fine(...args: any[]): void; | ||
severe(...args: any[]): void; | ||
protected abstract log(level: LogLevel, args: any[]): void; | ||
protected log(level: LogLevel, args: any[]): void; | ||
abstract logEntry(entry: LogEntry): void; | ||
} | ||
//# sourceMappingURL=alogger.d.ts.map |
@@ -1,8 +0,16 @@ | ||
import { LogLevel } from "./api.js"; | ||
import { | ||
LogLevel | ||
} from "./api.js"; | ||
let __nextID = 0; | ||
class ALogger { | ||
constructor(id, level = LogLevel.FINE, parent) { | ||
this.parent = parent; | ||
this.id = id || `logger-${__nextID++}`; | ||
this.level = typeof level === "string" ? LogLevel[level] : level; | ||
} | ||
id; | ||
level; | ||
constructor(id, level = LogLevel.FINE) { | ||
this.id = id; | ||
this.level = typeof level === "string" ? LogLevel[level] : level; | ||
addChild(logger) { | ||
logger.parent = this; | ||
return logger; | ||
} | ||
@@ -13,16 +21,19 @@ enabled(level) { | ||
fine(...args) { | ||
this.level <= LogLevel.FINE && this.log(LogLevel.FINE, args); | ||
this.log(LogLevel.FINE, args); | ||
} | ||
debug(...args) { | ||
this.level <= LogLevel.DEBUG && this.log(LogLevel.DEBUG, args); | ||
this.log(LogLevel.DEBUG, args); | ||
} | ||
info(...args) { | ||
this.level <= LogLevel.INFO && this.log(LogLevel.INFO, args); | ||
this.log(LogLevel.INFO, args); | ||
} | ||
warn(...args) { | ||
this.level <= LogLevel.WARN && this.log(LogLevel.WARN, args); | ||
this.log(LogLevel.WARN, args); | ||
} | ||
severe(...args) { | ||
this.level <= LogLevel.SEVERE && this.log(LogLevel.SEVERE, args); | ||
this.log(LogLevel.SEVERE, args); | ||
} | ||
log(level, args) { | ||
this.level <= level && this.logEntry([level, this.id, Date.now(), ...args]); | ||
} | ||
} | ||
@@ -29,0 +40,0 @@ export { |
61
api.d.ts
@@ -12,6 +12,11 @@ export declare enum LogLevel { | ||
/** | ||
* This logger's configured minimum log level | ||
* This logger's configured minimum log level. Any log messages with a lower | ||
* level will not be processed and/or propagated further. | ||
*/ | ||
level: LogLevel; | ||
/** | ||
* Parent logger. See {@link ILogger.logEntry}. | ||
*/ | ||
parent?: ILogger; | ||
/** | ||
* Returns true if the logger is currently enabled for given `level`. | ||
@@ -22,7 +27,61 @@ * | ||
enabled(level: LogLevel): boolean; | ||
/** | ||
* Syntax sugar for {@link ILogger.logEntry} and guard to produce a log | ||
* message with level {@link LogLevel.FINE}. | ||
* | ||
* @param args | ||
*/ | ||
fine(...args: any[]): void; | ||
/** | ||
* Syntax sugar for {@link ILogger.logEntry} and guard to produce a log | ||
* message with level {@link LogLevel.DEBUG}. | ||
* | ||
* @param args | ||
*/ | ||
debug(...args: any[]): void; | ||
/** | ||
* Syntax sugar for {@link ILogger.logEntry} and guard to produce a log | ||
* message with level {@link LogLevel.INFO}. | ||
* | ||
* @param args | ||
*/ | ||
info(...args: any[]): void; | ||
/** | ||
* Syntax sugar for {@link ILogger.logEntry} and guard to produce a log | ||
* message with level {@link LogLevel.WARN}. | ||
* | ||
* @param args | ||
*/ | ||
warn(...args: any[]): void; | ||
/** | ||
* Syntax sugar for {@link ILogger.logEntry} and guard to produce a log | ||
* message with level {@link LogLevel.SEVERE}. | ||
* | ||
* @param args | ||
*/ | ||
severe(...args: any[]): void; | ||
/** | ||
* If this logger has a {@link ILogger.parent}, it will simply forward the | ||
* given log entry to it. Otherwise this method performs the actual logging. | ||
* | ||
* @param e | ||
*/ | ||
logEntry(e: LogEntry): void; | ||
/** | ||
* Configures the given logger to become a child of this one (i.e. by | ||
* setting its {@link ILogger.parent} to this instance). | ||
* | ||
* @param logger | ||
*/ | ||
addChild(logger: ILogger): ILogger; | ||
/** | ||
* Obtain a new logger instance (usually of same type) with given `id` and | ||
* optional custom log level (default is current log level of this | ||
* instance). The new instance will be configured as child logger for this | ||
* instance. | ||
* | ||
* @param id | ||
* @param level | ||
*/ | ||
childLogger(id?: string, level?: LogLevel): ILogger; | ||
} | ||
@@ -29,0 +88,0 @@ /** |
# Change Log | ||
- **Last updated**: 2024-02-10T08:59:56Z | ||
- **Last updated**: 2024-02-16T20:01:44Z | ||
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub) | ||
@@ -12,2 +12,17 @@ | ||
# [3.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/logger@3.0.0) (2024-02-16) | ||
#### 🛑 Breaking changes | ||
- update/extend ILogger interface ([887e839](https://github.com/thi-ng/umbrella/commit/887e839)) | ||
- 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 | ||
## [2.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/logger@2.1.0) (2023-12-18) | ||
@@ -14,0 +29,0 @@ |
import { ALogger } from "./alogger.js"; | ||
import { LogLevel } from "./api.js"; | ||
import { LogLevel, type LogEntry } from "./api.js"; | ||
/** | ||
@@ -7,4 +7,5 @@ * {@link ILogger} implementation writing messages via `console.log`. | ||
export declare class ConsoleLogger extends ALogger { | ||
protected log(level: LogLevel, args: any[]): void; | ||
childLogger(id?: string, level?: LogLevel): ConsoleLogger; | ||
logEntry(e: LogEntry): void; | ||
} | ||
//# sourceMappingURL=console.d.ts.map |
@@ -5,5 +5,11 @@ import { ALogger } from "./alogger.js"; | ||
class ConsoleLogger extends ALogger { | ||
log(level, args) { | ||
console.log(`[${LogLevel[level]}] ${this.id}:`, ...expandArgs(args)); | ||
childLogger(id, level) { | ||
return new ConsoleLogger(id, level ?? this.level, this); | ||
} | ||
logEntry(e) { | ||
if (e[0] < this.level) | ||
return; | ||
console.log(`[${LogLevel[e[0]]}] ${e[1]}:`, ...expandArgs(e.slice(3))); | ||
this.parent && this.parent.logEntry(e); | ||
} | ||
} | ||
@@ -10,0 +16,0 @@ export { |
@@ -6,4 +6,5 @@ export * from "./api.js"; | ||
export * from "./null.js"; | ||
export * from "./root.js"; | ||
export * from "./stream.js"; | ||
export * from "./utils.js"; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -6,3 +6,4 @@ export * from "./api.js"; | ||
export * from "./null.js"; | ||
export * from "./root.js"; | ||
export * from "./stream.js"; | ||
export * from "./utils.js"; |
import { ALogger } from "./alogger.js"; | ||
import type { LogEntry, LogLevel, LogLevelName } from "./api.js"; | ||
import type { ILogger, LogEntry, LogLevel, LogLevelName } from "./api.js"; | ||
export declare class MemoryLogger extends ALogger { | ||
limit: number; | ||
journal: LogEntry[]; | ||
constructor(id: string, level?: LogLevel | LogLevelName, limit?: number); | ||
constructor(id?: string, level?: LogLevel | LogLevelName, parent?: ILogger, limit?: number); | ||
childLogger(id?: string, level?: LogLevel): MemoryLogger; | ||
logEntry(e: LogEntry): void; | ||
/** | ||
@@ -20,4 +22,3 @@ * Clears the {@link MemoryLogger.journal} of all recorded log entries. | ||
messages(): string[]; | ||
protected log(level: LogLevel, args: any[]): void; | ||
} | ||
//# sourceMappingURL=memory.d.ts.map |
import { ALogger } from "./alogger.js"; | ||
import { expandArgs } from "./utils.js"; | ||
class MemoryLogger extends ALogger { | ||
constructor(id, level, limit = 1e3) { | ||
super(id, level); | ||
constructor(id, level, parent, limit = 1e3) { | ||
super(id, level, parent); | ||
this.limit = limit; | ||
} | ||
journal = []; | ||
childLogger(id, level) { | ||
return new MemoryLogger(id, level ?? this.level, this, this.limit); | ||
} | ||
logEntry(e) { | ||
if (e[0] < this.level) | ||
return; | ||
if (this.journal.length >= this.limit) | ||
this.journal.shift(); | ||
this.journal.push([e[0], e[1], e[2], ...expandArgs(e.slice(3))]); | ||
this.parent && this.parent.logEntry(e); | ||
} | ||
/** | ||
@@ -26,7 +37,2 @@ * Clears the {@link MemoryLogger.journal} of all recorded log entries. | ||
} | ||
log(level, args) { | ||
if (this.journal.length >= this.limit) | ||
this.journal.shift(); | ||
this.journal.push([level, this.id, Date.now(), ...expandArgs(args)]); | ||
} | ||
} | ||
@@ -33,0 +39,0 @@ export { |
import { LogLevel } from "./api.js"; | ||
const NULL_LOGGER = Object.freeze({ | ||
level: LogLevel.NONE, | ||
addChild(l) { | ||
return l; | ||
}, | ||
childLogger: () => NULL_LOGGER, | ||
enabled: () => false, | ||
@@ -14,2 +18,4 @@ fine() { | ||
severe() { | ||
}, | ||
logEntry() { | ||
} | ||
@@ -16,0 +22,0 @@ }); |
{ | ||
"name": "@thi.ng/logger", | ||
"version": "2.1.10", | ||
"description": "Types & basis infrastructure for arbitrary logging (w/ default impls)", | ||
"version": "3.0.0", | ||
"description": "Basis types for arbitrary & hierarchical logging", | ||
"type": "module", | ||
@@ -84,2 +84,5 @@ "module": "./index.js", | ||
}, | ||
"./root": { | ||
"default": "./root.js" | ||
}, | ||
"./stream": { | ||
@@ -97,3 +100,3 @@ "default": "./stream.js" | ||
}, | ||
"gitHead": "e5e7d5c6ed2eadee7a91d59cbd0c86ce880ab1c5\n" | ||
"gitHead": "25ee18f7db6d03f0b76787267ab071d16df94888\n" | ||
} |
@@ -30,2 +30,3 @@ <!-- This file is generated - DO NOT EDIT! --> | ||
- [Log levels](#log-levels) | ||
- [Logging hierarchies](#logging-hierarchies) | ||
- [Supplied implementations](#supplied-implementations) | ||
@@ -44,3 +45,3 @@ - [Lazy evaluation](#lazy-evaluation) | ||
Types & basis infrastructure for arbitrary logging (w/ default impls). | ||
Basis types for arbitrary & hierarchical logging. | ||
@@ -63,5 +64,29 @@ The types & implementations provided by this package are used in various places | ||
Logging calls targetting lower levels than configured in the logger will be | ||
Logging calls targeting lower levels than configured in the logger will be | ||
ignored. | ||
### Logging hierarchies | ||
Each [`ILogger`](https://docs.thi.ng/umbrella/logger/interfaces/ILogger.html) | ||
instance (i.e. all supplied here) can have an associated parent logger to which | ||
any non-filtered messages can be propagated. This allows for the easy creation | ||
of logging hierarchies with each logger able to control its own log level. | ||
To that end the package also provides a `ROOT` logger. | ||
```ts | ||
import { ConsoleLogger, ROOT } from "@thi.ng/logger"; | ||
// create a child logger | ||
const myLogger = ROOT.childLogger("custom"); | ||
// use console output for root logger (and for all its children) | ||
ROOT.set(new ConsoleLogger()); | ||
// forwards message to root and then writes to console | ||
myLogger.debug("hello"); | ||
// [DEBUG] custom: hello | ||
``` | ||
### Supplied implementations | ||
@@ -73,2 +98,4 @@ | ||
- [`MemoryLogger`](https://docs.thi.ng/umbrella/logger/classes/MemoryLogger.html): writes output to in-memory journal | ||
- [`ProxyLogger`](https://docs.thi.ng/umbrella/logger/classes/ProxyLogger.html): proxy impl for another logger | ||
- [`StreamLogger`](https://docs.thi.ng/umbrella/logger/classes/StreamLogger.html): writes output to NodeJS stream | ||
- [`NULL_LOGGER`](https://docs.thi.ng/umbrella/logger/variables/NULL_LOGGER.html): no-op logger, suppresses all output | ||
@@ -131,3 +158,3 @@ | ||
Package sizes (brotli'd, pre-treeshake): ESM: 695 bytes | ||
Package sizes (brotli'd, pre-treeshake): ESM: 870 bytes | ||
@@ -134,0 +161,0 @@ ## Dependencies |
/// <reference types="node" /> | ||
import { ALogger } from "./alogger.js"; | ||
import { LogLevel, type LogLevelName } from "./api.js"; | ||
import { LogLevel, type LogEntry, type LogLevelName, type ILogger } from "./api.js"; | ||
/** | ||
@@ -11,5 +11,6 @@ * {@link ILogger} implementation writing messages to provided NodeJS-compatible | ||
protected target: NodeJS.WriteStream; | ||
constructor(target: NodeJS.WriteStream, id: string, level?: LogLevel | LogLevelName); | ||
protected log(level: LogLevel, args: any[]): void; | ||
constructor(target: NodeJS.WriteStream, id?: string, level?: LogLevel | LogLevelName, parent?: ILogger); | ||
childLogger(id?: string, level?: LogLevel): StreamLogger; | ||
logEntry(e: LogEntry): void; | ||
} | ||
//# sourceMappingURL=stream.d.ts.map |
import { ALogger } from "./alogger.js"; | ||
import { LogLevel } from "./api.js"; | ||
import { | ||
LogLevel | ||
} from "./api.js"; | ||
import { expandArgsJSON } from "./utils.js"; | ||
class StreamLogger extends ALogger { | ||
constructor(target, id, level = LogLevel.FINE) { | ||
super(id, level); | ||
constructor(target, id, level, parent) { | ||
super(id, level, parent); | ||
this.target = target; | ||
} | ||
log(level, args) { | ||
childLogger(id, level) { | ||
return new StreamLogger(this.target, id, level ?? this.level, this); | ||
} | ||
logEntry(e) { | ||
if (e[0] < this.level) | ||
return; | ||
this.target.write( | ||
`[${LogLevel[level]}] ${this.id}: ${expandArgsJSON(args)} | ||
`[${LogLevel[e[0]]}] ${e[1]}: ${expandArgsJSON(e.slice(3))} | ||
` | ||
); | ||
this.parent && this.parent.logEntry(e); | ||
} | ||
@@ -15,0 +23,0 @@ } |
36310
22
426
194