UNPKG

caterpillar

Version:

Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers. Log levels are implemented to the RFC standard. Log entries can be filtered and piped to various streams, including coloured output to the terminal, the browser's console, and

138 lines (137 loc) 4.47 kB
import { Transform } from '../transform.js'; import { inspect } from 'util'; import * as ansi from '@bevry/ansi'; /** * Return the given argument. * Used for when there is no formatter. */ function ansiNoop(a) { return a; } /** * Convert Logger entries into human readable format. * @extends Transform * @example * ``` javascript * import { Logger, Human } from 'caterpillar' * const logger = new Logger() * const human = new Human() * logger.pipe(human).pipe(process.stdout) * logger.log('info', 'some', {data: 'oh yeah'}, 42) * ``` */ export class Human extends Transform { /** Whether or not to use colors? */ color = true; /** Mapping of which log level numbers correspond to which colours */ colors = { '0': 'red', '1': 'red', '2': 'red', '3': 'red', '4': 'yellow', '5': 'yellow', '6': 'green', '7': 'green', }; /** Create our instance and apply our configuration options. */ constructor(opts) { super(); // options if (opts?.color != null) this.color = opts.color; if (opts?.colors != null) this.colors = opts.colors; } /** Get the color for the log level */ getColor(levelNumber) { // Determine const color = this.colors[levelNumber] || false; // Return return color; } /** Pad the left of some content if need be with the specified padding to make the content reach a certain size */ padLeft(padding, size, content) { // Prepare padding = String(padding); content = String(content); // Handle if (content.length < size) { for (let i = 0, n = size - content.length; i < n; ++i) { content = padding + content; } } // Return return content; } /** Convert logger entry arguments into a human readable string */ formatArguments(args) { return args .map((value) => typeof value === 'string' ? value : inspect(value, { showHidden: false, depth: 10, colors: this.color, })) .join(' '); } /** Convert a datetime into a human readable format */ formatDate(datetime) { // Prepare const now = new Date(datetime); const year = now.getFullYear(); const month = this.padLeft('0', 2, now.getMonth() + 1); const date = this.padLeft('0', 2, now.getDate()); const hours = this.padLeft('0', 2, now.getHours()); const minutes = this.padLeft('0', 2, now.getMinutes()); const seconds = this.padLeft('0', 2, now.getSeconds()); const ms = this.padLeft('0', 3, now.getMilliseconds()); // Apply const result = `${year}-${month}-${date} ${hours}:${minutes}:${seconds}.${ms}`; // Return return result; } /** Convert a logger entry into a human readable format */ format(entry) { // Prepare const { color } = this; const useLine = entry.line !== -1; let result; // Format const format = { color: this.getColor(entry.levelNumber), timestamp: this.formatDate(entry.date), text: this.formatArguments(entry.args), }; // Check if (format.text) { // Formatters const levelFormatter = (color && format.color && ansi[format.color]) || ansiNoop; const lineFormatter = (useLine && color && ansi.dim) || ansiNoop; // Message // @ts-ignore const levelString = levelFormatter(`${entry.levelName}:`); const entryString = format.text; const messageString = `${levelString} ${entryString}`; // Format if (useLine) { // Line Information const seperator = '\n '; const debugString = lineFormatter(`→ [${format.timestamp}] [${entry.file}:${entry.line}:${entry.char}] [${entry.method}]`); // Result result = `${messageString}${seperator}${debugString}\n`; } else { // Result result = `${messageString}\n`; } } else { result = format.text; } // Return return result; } } export default Human;