Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
UNSTABLE: A customizable logger framework
Examples
Example 1
Example 1
import * as log from "@std/log"; // Simple default logger out of the box. You can customize it // by overriding logger and handler named "default", or providing // additional logger configurations. You can log any data type. log.debug("Hello world"); log.info(123456); log.warn(true); log.error({ foo: "bar", fizz: "bazz" }); log.critical("500 Internal server error"); // custom configuration with 2 loggers (the default and `tasks` loggers). log.setup({ handlers: { console: new log.ConsoleHandler("DEBUG"), file: new log.FileHandler("WARN", { filename: "./log.txt", // you can change format of output message using any keys in `LogRecord`. formatter: (record) => `${record.levelName} ${record.msg}`, }), }, loggers: { // configure default logger available via short-hand methods above. default: { level: "DEBUG", handlers: ["console", "file"], }, tasks: { level: "ERROR", handlers: ["console"], }, }, }); let logger; // get default logger. logger = log.getLogger(); logger.debug("fizz"); // logs to `console`, because `file` handler requires "WARN" level. logger.warn(41256); // logs to both `console` and `file` handlers. // get custom logger logger = log.getLogger("tasks"); logger.debug("fizz"); // won't get output because this logger has "ERROR" level. logger.error({ productType: "book", value: "126.11" }); // log to `console`. // if you try to use a logger that hasn't been configured // you're good to go, it gets created automatically with level set to 0 // so no message is logged. const unknownLogger = log.getLogger("mystery"); unknownLogger.info("foobar"); // no-op
Custom message format example
Custom message format example
import * as log from "@std/log"; log.setup({ handlers: { stringFmt: new log.ConsoleHandler("DEBUG", { formatter: (record) => `[${record.levelName}] ${record.msg}`, }), functionFmt: new log.ConsoleHandler("DEBUG", { formatter: (logRecord) => { let msg = `${logRecord.level} ${logRecord.msg}`; logRecord.args.forEach((arg, index) => { msg += `, arg${index}: ${arg}`; }); return msg; }, }), anotherFmt: new log.ConsoleHandler("DEBUG", { formatter: (record) => `[${record.loggerName}] - ${record.levelName} ${record.msg}`, }), }, loggers: { default: { level: "DEBUG", handlers: ["stringFmt", "functionFmt"], }, dataLogger: { level: "INFO", handlers: ["anotherFmt"], }, }, }); // calling: log.debug("Hello, world!", 1, "two", [3, 4, 5]); // results in: [DEBUG] Hello, world! // output from "stringFmt" handler. // 10 Hello, world!, arg0: 1, arg1: two, arg3: [3, 4, 5] // output from "functionFmt" formatter. // calling: log.getLogger("dataLogger").error("oh no!"); // results in: // [dataLogger] - ERROR oh no! // output from anotherFmt handler.
JSON to stdout with no color example
JSON to stdout with no color example
import * as log from "@std/log"; log.setup({ handlers: { jsonStdout: new log.ConsoleHandler("DEBUG", { formatter: log.formatters.jsonFormatter, useColors: false, }), }, loggers: { default: { level: "DEBUG", handlers: ["jsonStdout"], }, }, }); // calling: log.info("Hey"); // results in: // {"level":"INFO","datetime":1702481922294,"message":"Hey"} // calling: log.info("Hey", { product: "nail" }); // results in: // {"level":"INFO","datetime":1702484111115,"message":"Hey","args":{"product":"nail"}} // calling: log.info("Hey", 1, "two", [3, 4, 5]); // results in: // {"level":"INFO","datetime":1702481922294,"message":"Hey","args":[1,"two",[3,4,5]]}
Custom JSON example
Custom JSON example
import * as log from "@std/log"; log.setup({ handlers: { customJsonFmt: new log.ConsoleHandler("DEBUG", { formatter: (record) => JSON.stringify({ lvl: record.level, msg: record.msg, time: record.datetime.toISOString(), name: record.loggerName, }), useColors: false, }), }, loggers: { default: { level: "DEBUG", handlers: ["customJsonFmt"], }, }, }); // calling: log.info("complete"); // results in: // {"lvl":20,"msg":"complete","time":"2023-12-13T16:38:27.328Z","name":"default"}
Inline Logging
Inline Logging
import * as logger from "@std/log"; const stringData: string = logger.debug("hello world"); const booleanData: boolean = logger.debug(true, 1, "abc"); const fn = (): number => { return 123; }; const resolvedFunctionData: number = logger.debug(fn()); console.log(stringData); // 'hello world' console.log(booleanData); // true console.log(resolvedFunctionData); // 123
Lazy Log Evaluation
Lazy Log Evaluation
import * as log from "@std/log"; log.setup({ handlers: { console: new log.ConsoleHandler("DEBUG"), }, loggers: { tasks: { level: "ERROR", handlers: ["console"], }, }, }); function someExpensiveFn(num: number, bool: boolean) { // do some expensive computation } // not logged, as debug < error. const data = log.debug(() => someExpensiveFn(5, true)); console.log(data); // undefined
Handlers are responsible for actual output of log messages. When a handler is
called by a logger, it firstly checks that LogRecord's level is
not lower than level of the handler. If level check passes, handlers formats
log record into string and outputs it to target.
Custom handlers
Custom handlers can be implemented by subclassing BaseHandler or
WriterHandler.
BaseHandler is bare-bones handler that has no output logic at all,
WriterHandler is an abstract class that supports any target with
Writer interface.
During setup async hooks setup and destroy are called, you can use them
to open and close file/HTTP connection or any other action you might need.
For examples check source code of FileHandlerandTestHandler`.
Classes
- destroy(): voidNo documentation available
- format(logRecord: LogRecord): stringNo documentation available
- formatter: FormatterFunctionNo documentation available
- handle(logRecord: LogRecord): voidNo documentation available
- level(): LogLevelNo documentation available
- levelName(): LevelNameNo documentation available
- log(_msg: string): voidNo documentation available
- setup(): voidNo documentation available
This is the default logger. It will output color coded log messages to the
console via console.log().
- applyColors(): stringmsg: string,level: numberNo documentation available
- format(logRecord: LogRecord): stringNo documentation available
- log(msg: string): voidNo documentation available
This handler will output to a file using an optional mode (default is a,
e.g. append). The file will grow indefinitely. It uses a buffer for writing
to file. Logs can be manually flushed with fileHandler.flush(). Log
messages with a log level greater than error are immediately flushed. Logs
are also flushed on process completion.
- _buf: Uint8ArrayNo documentation available
- _encoder: TextEncoderNo documentation available
- _file: Deno.FsFile | undefinedNo documentation available
- _filename: stringNo documentation available
- _mode: LogModeNo documentation available
- _openOptions: Deno.OpenOptionsNo documentation available
- _pointer: numberNo documentation available
- destroy(): voidNo documentation available
- flush(): voidNo documentation available
- handle(logRecord: LogRecord): voidNo documentation available
- log(msg: string): voidNo documentation available
- setup(): voidNo documentation available
- asString(): stringdata: unknown,isProperty?No documentation available
- critical<T>(): T | undefinedmsg: () => T,...args: unknown[]No documentation available
- debug<T>(): T | undefinedmsg: () => T,...args: unknown[]No documentation available
- error<T>(): T | undefinedmsg: () => T,...args: unknown[]No documentation available
- handlers: BaseHandler[]No documentation available
- info<T>(): T | undefinedmsg: () => T,...args: unknown[]No documentation available
- level(): LogLevel
Use this to retrieve the current numeric log level.
- levelName(): LevelNameNo documentation available
- loggerName(): stringNo documentation available
- warn<T>(): T | undefinedmsg: () => T,...args: unknown[]No documentation available
An object that encapsulates provided message and arguments as well some metadata that can be later used when formatting a message.
This handler extends the functionality of the FileHandler by
"rotating" the log file when it reaches a certain size. maxBytes specifies
the maximum size in bytes that the log file can grow to before rolling over
to a new one. If the size of the new log message plus the current log file
size exceeds maxBytes then a roll-over is triggered. When a roll-over
occurs, before the log message is written, the log file is renamed and
appended with .1. If a .1 version already existed, it would have been
renamed .2 first and so on. The maximum number of log files to keep is
specified by maxBackupCount. After the renames are complete the log message
is written to the original, now blank, file.
- log(msg: string): voidNo documentation available
- rotateLogFiles(): voidNo documentation available
- setup(): voidNo documentation available
Functions
Log with critical level, using default logger.
Log with debug level, using default logger.
Log with error level, using default logger.
Returns the numeric log level associated with the passed, stringy log level name.
Returns the stringy log level name provided the numeric log level.
Get a logger instance. If not specified name, get the default logger.
Log with info level, using default logger.
Setup logger config.
Log with warning level, using default logger.
Interfaces
- formatter: FormatterFunctionNo documentation available
- useColors: booleanNo documentation available
- handlers: BaseHandler[]No documentation available
- args: unknown[]No documentation available
- level: LogLevelNo documentation available
- loggerName: stringNo documentation available
- msg: stringNo documentation available
Type Aliases
Union of valid log level names
Union of valid log levels
Variables
- jsonFormatter(logRecord: LogRecord): stringNo documentation available
Permitted log level names
Use this to retrieve the numeric log level by it's associated name. Defaults to INFO.