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 | 222x 142x 8x 222x 205x 222x 222x 576x 1763x 576x 2179x 209x 209x 22x 165x 58x 325x 409x 208x 15x 16x 48x 48x 30x 86x 86x 50x 19x 19x 16x 16x 16x 13x 18x 18x 16x 1787x 1787x 1518x 944x 1518x 192x 1326x 1272x 1518x 1787x 1579x 208x 208x 208x 648x 479x 648x 407x 36x 407x | import { emptyArray } from '../../utils/common/empty.ts';
import type { StringifyOptions } from '../../utils/converter/stringify.ts';
import { stringify } from '../../utils/converter/stringify.ts';
import type { Logger, LogLevel, LogMessage, LogTemplateStringsArray } from '../definition.ts';
import { shouldEmitEntry } from './level-utils.ts';
/**
* Options for the BaseLogger class.
*/
export type BaseLoggerOptions = {
/**
* Options for how values are stringified in log messages.
*/
readonly stringifyOptions?: StringifyOptions;
};
/**
* 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 {
/**
* Converts an error input to a log message and arguments.
*
* @param logger The logger to use for stringification
* @param input The input to convert
* @param args The arguments to convert
*/
public static convertErrorInput(
logger: Logger,
input: LogMessage | Error | { error: unknown },
args: readonly unknown[],
): { readonly message: LogMessage; readonly args: readonly unknown[] } {
const stringifyValue =
logger instanceof BaseLogger
? (value: unknown) => logger.stringifyValue(value)
: (value: unknown) => stringify(value);
const message: LogMessage = () =>
typeof input === 'function'
? input()
: input && typeof input === 'object' && 'error' in input
? stringifyValue(input.error)
: stringifyValue(input);
const convertedArgs = typeof input === 'object' ? (args.length ? [input, ...args] : [input]) : args;
return { message, args: convertedArgs };
}
/**
* The minimum severity level for log entries to be emitted. Log entries with levels below this threshold will be
* filtered out. Default is 'info'.
*/
private readonly _levelProvider: () => LogLevel | 'off';
/**
* Additional arguments to include with the next template literal log entry. This is reset after each log operation.
*/
private _pendingArgs: unknown[] = [];
private readonly _options?: BaseLoggerOptions;
/**
* Creates a new BaseLogger with the specified minimum severity level.
*
* @param level The minimum severity level for log entries or a function that returns this value
* @param options Options for how values are stringified in log messages
*/
public constructor(level: LogLevel | 'off' | (() => LogLevel | 'off'), options?: BaseLoggerOptions) {
this._levelProvider = typeof level === 'function' ? level : () => level;
this._options = options;
}
public get level(): LogLevel | 'off' {
return this._levelProvider();
}
public args(...args: unknown[]): Logger {
this._pendingArgs.push(...args);
return this;
}
public trace(message: LogMessage, ...args: readonly unknown[]): void {
this.log('trace', message, ...args);
}
public t(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('trace', () => this.taggedLog(strings, values));
}
public debug(message: LogMessage, ...args: readonly unknown[]): void {
this.log('debug', message, ...args);
}
public d(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('debug', () => this.taggedLog(strings, values));
}
public info(message: LogMessage, ...args: readonly unknown[]): void {
this.log('info', message, ...args);
}
public i(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('info', () => this.taggedLog(strings, values));
}
public notice(message: LogMessage, ...args: unknown[]): void {
this.log('notice', message, ...args);
}
public n(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('notice', () => this.taggedLog(strings, values));
}
public warning(input: LogMessage | Error | { error: unknown }, ...args: readonly unknown[]): void {
const converted = BaseLogger.convertErrorInput(this, input, args);
this.log('warning', converted.message, ...converted.args);
}
public w(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('warning', () => this.taggedLog(strings, values));
}
public error(input: LogMessage | Error | { error: unknown }, ...args: readonly unknown[]): void {
const converted = BaseLogger.convertErrorInput(this, input, args);
this.log('error', converted.message, ...converted.args);
}
public e(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('error', () => this.taggedLog(strings, values));
}
public critical(input: LogMessage | Error | { error: unknown }, ...args: unknown[]): void {
const converted = BaseLogger.convertErrorInput(this, input, args);
this.log('critical', converted.message, ...converted.args);
}
public c(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('critical', () => this.taggedLog(strings, values));
}
public alert(input: LogMessage | Error | { error: unknown }, ...args: readonly unknown[]): void {
const converted = BaseLogger.convertErrorInput(this, input, args);
this.log('alert', converted.message, ...converted.args);
}
public a(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('alert', () => this.taggedLog(strings, values));
}
public emergency(input: LogMessage | Error | { error: unknown }, ...args: readonly unknown[]): void {
const converted = BaseLogger.convertErrorInput(this, input, args);
this.log('emergency', converted.message, ...converted.args);
}
public em(strings: LogTemplateStringsArray, ...values: readonly unknown[]): void {
this.log('emergency', () => this.taggedLog(strings, values));
}
public log(level: LogLevel, message: LogMessage, ...args: readonly unknown[]): void {
const pendingArgs = this.consumePendingArgs();
if (shouldEmitEntry(this, level)) {
if (typeof message === 'function') {
message = message();
}
if (pendingArgs) {
args = args.length ? [...pendingArgs, ...args] : pendingArgs;
} else if (!args.length) {
args = emptyArray();
}
this.emit(level, String(message), args);
}
}
/**
* 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;
}
protected taggedLog(strings: LogTemplateStringsArray, values: readonly unknown[]): string {
if (typeof strings === 'function') {
strings = strings();
}
return String.raw({ raw: strings }, ...values.map((arg) => this.stringifyValue(arg)));
}
/**
* Stringifies a value.
*
* @param value The message to stringify
* @returns The stringified message
*/
protected stringifyValue(value: unknown): string {
if (typeof value === 'function') {
value = (value as () => unknown)();
}
return stringify(value, this._options?.stringifyOptions);
}
/**
* Emits the resolved log message at the specified level and extra arguments.
*
* @param level
* @param message
* @param args
*/
protected abstract emit(level: LogLevel, message: string, args: readonly unknown[]): void;
}
|