2024-01-12 08:17:25 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2024-04-10 02:43:44 +00:00
|
|
|
// This module is browser compatible.
|
2024-02-27 21:57:25 +00:00
|
|
|
import {
|
|
|
|
getLevelByName,
|
|
|
|
getLevelName,
|
|
|
|
type LevelName,
|
|
|
|
type LogLevel,
|
|
|
|
} from "./levels.ts";
|
2024-01-12 08:17:25 +00:00
|
|
|
import type { LogRecord } from "./logger.ts";
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
export type { LevelName, LogLevel, LogRecord };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A function type that defines the structure of a formatter function.
|
|
|
|
*
|
|
|
|
* @param logRecord The log record that needs to be formatted.
|
|
|
|
* @returns A string representation of the log record.
|
|
|
|
*/
|
2024-01-12 08:17:25 +00:00
|
|
|
export type FormatterFunction = (logRecord: LogRecord) => string;
|
2024-01-25 08:03:19 +00:00
|
|
|
const DEFAULT_FORMATTER: FormatterFunction = ({ levelName, msg }) =>
|
|
|
|
`${levelName} ${msg}`;
|
2024-01-12 08:17:25 +00:00
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/** Options for {@linkcode BaseHandler}. */
|
2024-01-12 08:17:25 +00:00
|
|
|
export interface BaseHandlerOptions {
|
2024-09-27 03:31:58 +00:00
|
|
|
/** A function that formats log records. */
|
2024-01-25 08:03:19 +00:00
|
|
|
formatter?: FormatterFunction;
|
2024-01-12 08:17:25 +00:00
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* A base class for all log handlers.
|
|
|
|
*
|
|
|
|
* This class is abstract and should not be instantiated directly. Instead, it
|
|
|
|
* should be extended by other classes that implement the `log` method.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-08-22 06:46:53 +00:00
|
|
|
export abstract class BaseHandler {
|
2024-02-26 13:22:21 +00:00
|
|
|
#levelName: LevelName;
|
|
|
|
#level: LogLevel;
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* The function that formats log records.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogRecord } from "@std/log/logger";
|
|
|
|
* import { LogLevels } from "@std/log/levels";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* const record = new LogRecord({
|
|
|
|
* msg: "Hello, world!",
|
|
|
|
* args: ["foo", "bar"],
|
|
|
|
* level: LogLevels.INFO,
|
|
|
|
* loggerName: "example",
|
|
|
|
* });
|
|
|
|
* const formatted = handler.formatter(record);
|
|
|
|
* assertEquals(formatted, "INFO Hello, world!");
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-25 08:03:19 +00:00
|
|
|
formatter: FormatterFunction;
|
2024-01-12 08:17:25 +00:00
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Constructs a new instance.
|
|
|
|
*
|
|
|
|
* @param levelName The name of the log level to handle.
|
|
|
|
* @param options Options for the handler.
|
|
|
|
*/
|
2024-02-26 13:22:21 +00:00
|
|
|
constructor(
|
|
|
|
levelName: LevelName,
|
2024-07-19 04:12:45 +00:00
|
|
|
options?: BaseHandlerOptions,
|
2024-02-26 13:22:21 +00:00
|
|
|
) {
|
2024-07-19 04:12:45 +00:00
|
|
|
const { formatter = DEFAULT_FORMATTER } = options ?? {};
|
2024-02-26 13:22:21 +00:00
|
|
|
this.#levelName = levelName;
|
|
|
|
this.#level = getLevelByName(levelName);
|
|
|
|
this.formatter = formatter;
|
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Getter for the log level that this handler will handle.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogLevels } from "@std/log/levels";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* assertEquals(handler.level, LogLevels.INFO);
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @returns The log level to handle.
|
|
|
|
*/
|
2024-02-27 18:44:33 +00:00
|
|
|
get level(): LogLevel {
|
2024-02-26 13:22:21 +00:00
|
|
|
return this.#level;
|
|
|
|
}
|
2024-02-27 18:44:33 +00:00
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Setter for the log level that this handler will handle.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogLevels } from "@std/log/levels";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* handler.level = LogLevels.DEBUG;
|
|
|
|
* assertEquals(handler.level, LogLevels.DEBUG);
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param level The log level to handle.
|
|
|
|
*/
|
2024-02-26 13:22:21 +00:00
|
|
|
set level(level: LogLevel) {
|
|
|
|
this.#level = level;
|
|
|
|
this.#levelName = getLevelName(level);
|
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Getter for the name of the log level that this handler will handle.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* assertEquals(handler.levelName, "INFO");
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @returns The name of the log level to handle.
|
|
|
|
*/
|
2024-02-27 18:44:33 +00:00
|
|
|
get levelName(): LevelName {
|
2024-02-26 13:22:21 +00:00
|
|
|
return this.#levelName;
|
|
|
|
}
|
2024-09-27 03:31:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Setter for the name of the log level that this handler will handle.
|
|
|
|
*
|
|
|
|
* @param levelName The name of the log level to handle.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* handler.levelName = "DEBUG";
|
|
|
|
* assertEquals(handler.levelName, "DEBUG");
|
|
|
|
* ```
|
|
|
|
*/
|
2024-02-26 13:22:21 +00:00
|
|
|
set levelName(levelName: LevelName) {
|
|
|
|
this.#levelName = levelName;
|
|
|
|
this.#level = getLevelByName(levelName);
|
2024-01-12 08:17:25 +00:00
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Handles a log record.
|
|
|
|
*
|
|
|
|
* @param logRecord The log record to handle.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogRecord } from "@std/log/logger";
|
|
|
|
* import { LogLevels } from "@std/log/levels";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* const record = new LogRecord({
|
|
|
|
* msg: "Hello, world!",
|
|
|
|
* args: ["foo", "bar"],
|
|
|
|
* level: LogLevels.INFO,
|
|
|
|
* loggerName: "example",
|
|
|
|
* });
|
|
|
|
* handler.handle(record);
|
|
|
|
*
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-12 08:17:25 +00:00
|
|
|
handle(logRecord: LogRecord) {
|
|
|
|
if (this.level > logRecord.level) return;
|
|
|
|
|
|
|
|
const msg = this.format(logRecord);
|
2024-04-11 10:30:50 +00:00
|
|
|
this.log(msg);
|
2024-01-12 08:17:25 +00:00
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Formats a log record.
|
|
|
|
*
|
|
|
|
* @param logRecord The log record to format.
|
|
|
|
* @returns A string representation of the log record.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogRecord } from "@std/log/logger";
|
|
|
|
* import { LogLevels } from "@std/log/levels";
|
|
|
|
* import { assertEquals } from "@std/assert/equals";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* const record = new LogRecord({
|
|
|
|
* msg: "Hello, world!",
|
|
|
|
* args: ["foo", "bar"],
|
|
|
|
* level: LogLevels.INFO,
|
|
|
|
* loggerName: "example",
|
|
|
|
* });
|
|
|
|
* const formatted = handler.format(record);
|
|
|
|
* assertEquals(formatted, "INFO Hello, world!");
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-12 08:17:25 +00:00
|
|
|
format(logRecord: LogRecord): string {
|
2024-01-25 08:03:19 +00:00
|
|
|
return this.formatter(logRecord);
|
2024-01-12 08:17:25 +00:00
|
|
|
}
|
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Logs a message.
|
|
|
|
*
|
|
|
|
* This method should be implemented by subclasses to handle the log record.
|
|
|
|
*
|
|
|
|
* @param msg The message to log.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* handler.log("Hello, world!"); // Prints "Hello, world!"
|
|
|
|
*
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-08-22 06:46:53 +00:00
|
|
|
abstract log(msg: string): void;
|
2024-09-27 03:31:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the handler.
|
|
|
|
*
|
|
|
|
* This method is called when the handler is added to a logger. It can be
|
|
|
|
* used to perform any setup that is required by the handler.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* override setup() {
|
|
|
|
* console.log("Handler setup!");
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* handler.setup(); // Prints "Handler setup!"
|
|
|
|
*
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-12 08:17:25 +00:00
|
|
|
setup() {}
|
2024-09-27 03:31:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroys the handler, performing any cleanup that is required.
|
|
|
|
*
|
|
|
|
* This method is called when the handler is removed from a logger. It can be
|
|
|
|
* used to perform any cleanup that is required by the handler.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* override destroy() {
|
|
|
|
* console.log("Handler destroyed!");
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* const handler = new MyHandler("INFO");
|
|
|
|
* handler.destroy(); // Prints "Handler destroyed!"
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-12 08:17:25 +00:00
|
|
|
destroy() {}
|
2024-01-15 04:06:25 +00:00
|
|
|
|
2024-09-27 03:31:58 +00:00
|
|
|
/**
|
|
|
|
* Automatically disposes of the handler when instantiated with the `using`
|
|
|
|
* keyword by calling the {@linkcode BaseHandler.destroy} method.
|
|
|
|
*
|
|
|
|
* @example Usage
|
|
|
|
* ```ts
|
|
|
|
* import { BaseHandler } from "@std/log/base-handler";
|
|
|
|
* import { LogRecord } from "@std/log/logger";
|
|
|
|
* import { assertInstanceOf } from "@std/assert/instance-of";
|
|
|
|
*
|
|
|
|
* class MyHandler extends BaseHandler {
|
|
|
|
* log(msg: string) {
|
|
|
|
* console.log(msg);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* using handler = new MyHandler("INFO");
|
|
|
|
* assertInstanceOf(handler, BaseHandler);
|
|
|
|
* ```
|
|
|
|
*/
|
2024-01-15 04:06:25 +00:00
|
|
|
[Symbol.dispose]() {
|
|
|
|
this.destroy();
|
|
|
|
}
|
2024-01-12 08:17:25 +00:00
|
|
|
}
|