Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | 18x 18x 18x 18x 337x 337x 337x 137x 137x 16x 13x 294x 324x 331x 156x 21x 14x 42x 20x 53x 49x 28x 49x 8x 8x 3x 5x 49x 25x 19x 11x 17x 10x 20x 11x 582x 812x 812x 757x 1000x 560x 1000x 757x 8x 8x 282x 282x 317x 317x 14x 14x 37x 37x 49x 49x 16x 16x 14x 14x 20x 20x 865x 812x 676x 136x 136x 136x | import { exhaustiveCheck } from '../utils/common/exhaustive-check.ts'; import { stringify } from '../utils/converter/stringify.ts'; import type { Logger, LogLevel, LogMessage } from './definition.ts'; import { shouldEmitEntry } from './level-utils.ts'; /** * Base class for logger implementations, providing a complete implementation of the {@link Logger} interface. * * Logger implementors are strongly encouraged to extend this class to reduce the chances of future modifications * breaking current code. */ export abstract class BaseLogger implements Logger { /** * The minimum severity level for log entries to be emitted. Log entries with levels below this threshold will be * filtered out. Default is 'info'. */ public level: LogLevel | 'off' = 'info'; /** * Additional arguments to include with the next template literal log entry. This is reset after each log operation. */ private _pendingArgs: unknown[] = []; /** * Creates a new BaseLogger with the specified minimum severity level. * * @param level The minimum severity level for log entries (default: 'info') */ public constructor(level: LogLevel | 'off' = 'info') { this.level = level; } public args(...args: unknown[]): Logger { this._pendingArgs = args; return this; } public trace(message: LogMessage, ...args: readonly unknown[]): void { this.log('trace', message, ...args); } public t(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.trace(() => this.taggedLog(strings, ...values)); } public debug(message: LogMessage, ...args: readonly unknown[]): void { this.log('debug', message, ...args); } public d(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.debug(() => this.taggedLog(strings, ...values)); } public info(message: LogMessage, ...args: readonly unknown[]): void { this.log('info', message, ...args); } public i(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.info(() => this.taggedLog(strings, ...values)); } public notice(message: LogMessage, ...args: unknown[]): void { this.log('notice', message, ...args); } public n(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.notice(() => this.taggedLog(strings, ...values)); } public warning(message: LogMessage, ...args: readonly unknown[]): void { this.log('warning', message, ...args); } public w(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.warning(() => this.taggedLog(strings, ...values)); } public error(value: unknown, ...args: readonly unknown[]): void { if (this.shouldEmitEntry('error')) { if (typeof value === 'function') { value = (value as () => unknown)(); } if (value && typeof value === 'object') { args = [value, ...args]; if ('error' in value) { value = this.stringify(value.error); } else { value = this.stringify(value); } } this.log('error', value as string, ...args); } } public e(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.error(() => this.taggedLog(strings, ...values)); } public critical(message: LogMessage, ...args: unknown[]): void { this.log('critical', message, ...args); } public c(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.critical(() => this.taggedLog(strings, ...values)); } public alert(message: LogMessage, ...args: readonly unknown[]): void { this.log('alert', message, ...args); } public a(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.alert(() => this.taggedLog(strings, ...values)); } public emergency(message: LogMessage, ...args: readonly unknown[]): void { this.log('emergency', message, ...args); } public em(strings: TemplateStringsArray, ...values: readonly unknown[]): void { this.emergency(() => this.taggedLog(strings, ...values)); } protected taggedLog(strings: TemplateStringsArray, ...values: readonly unknown[]): string { return String.raw({ raw: strings }, ...values.map((arg) => this.stringify(arg))); } public log(level: LogLevel, message: LogMessage, ...args: readonly unknown[]): void { const pendingArgs = this.consumePendingArgs(); if (this.shouldEmitEntry(level)) { this.emit(level, this.stringify(message), pendingArgs ? [...pendingArgs, ...args] : args); } } /** * Stringifies the message. * * @param message The message to stringify * @returns The stringified message */ protected stringify(message: unknown): string { if (typeof message === 'function') { message = (message as () => unknown)(); } return stringify(message); } /** * Emits the resolved log message at the specified level and extra arguments. * * This method is the ideal extension point for clients providing a different logging mechanism because it is only * invoked if the level is applicable to the logger. * * @param level * @param message * @param args */ protected emit(level: LogLevel, message: string, args: readonly unknown[]): void { switch (level) { case 'trace': this.emitLine(level, message, args); break; case 'debug': this.emitLine(level, message, args); break; case 'info': this.emitLine(level, message, args); break; case 'notice': this.emitLine(level, message, args); break; case 'warning': this.emitLine(level, message, args); break; case 'error': this.emitLine(level, message, args); break; case 'critical': this.emitLine(level, message, args); break; case 'alert': this.emitLine(level, message, args); break; case 'emergency': this.emitLine(level, message, args); break; default: exhaustiveCheck(level); throw new Error(`IllegalArgument: unsupported log level: '${level}'`); } } /** * Returns true if a log with the specified level is written. * * @param level The log level to check * @returns True if the log level is applicable, false otherwise */ protected shouldEmitEntry(level: LogLevel): boolean { return shouldEmitEntry(this.level, level); } /** * Emits a log line. This is the main extensibility point of this class. * * @param line The log line * @param message The log message * @param args The log arguments */ protected abstract emitLine(level: LogLevel, message: string, args: readonly unknown[]): void; /** * Consumes and returns the pending arguments, then clears them. */ protected consumePendingArgs(): readonly unknown[] | undefined { if (!this._pendingArgs.length) { return undefined; } const args = this._pendingArgs; this._pendingArgs = []; return args; } } |