UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

108 lines (107 loc) 3.38 kB
/* eslint-disable no-console */ import { deepFreeze } from '@valkyriestudios/utils/deep'; import { isNeObject } from '@valkyriestudios/utils/object'; import { createScrambler, OMIT_PRESETS } from '../../../utils/Scrambler'; /* Default format function */ const DEFAULT_FORMAT = (log) => '[' + log.time.toISOString() + '] [' + log.level + '] ' + log.message; const INCLUSION_FIELDS = { ctx: 1, trace_id: 1, span_id: 1, time: 1, level: 1, global: 1, }; function normalizeInclusion(inclusion) { const acc = new Set(); for (let i = 0; i < inclusion.length; i++) { const val = inclusion[i]; if (INCLUSION_FIELDS[val]) acc.add(val); } return [...acc.values()]; } /** * A structured console logger with support for grouping, custom formatting, * and selective metadata inclusion. * * Ideal for local development, where concise yet contextual logs are key. */ export class ConsoleExporter { #global_attrs = null; /** * Whether or not to use console groups (defaults to false) */ #grouped = false; /** * What aspects of the log object to be included */ #inclusions; /** * Scrambler based on omit pattern provided */ #scramble; /** * Function to use to format the primary label. * default format is "[{time}] [{level}] {message}" */ #format = DEFAULT_FORMAT; constructor(options) { /* Configure grouped if passed */ this.#grouped = options?.grouped === true; /* Configure scrambler */ this.#scramble = createScrambler({ checks: Array.isArray(options?.omit) ? deepFreeze([...options.omit]) : OMIT_PRESETS.default, }); /* Configure format if passed */ if (typeof options?.format === 'function') this.#format = options.format; /* Configure include if passed */ this.#inclusions = normalizeInclusion(Array.isArray(options?.include) ? options.include : []); } init(global_attrs) { this.#global_attrs = this.#scramble(global_attrs); } async pushLog(log) { const msg = this.#scramble({ val: this.#format(log) }).val; let has_meta = false; const meta = {}; /* Data */ if (isNeObject(log.data)) { has_meta = true; meta.data = this.#scramble(log.data); } /* Run inclusions */ if (this.#inclusions.length) { has_meta = true; for (let i = 0; i < this.#inclusions.length; i++) { const inc = this.#inclusions[i]; switch (inc) { case 'global': meta.global = this.#global_attrs; break; case 'ctx': meta[inc] = this.#scramble(log[inc]); break; default: meta[inc] = log[inc]; } } } /* Write */ if (this.#grouped && has_meta) { console.groupCollapsed(msg); console[log.level](meta); console.groupEnd(); } else if (has_meta) { console[log.level](msg, meta); } else { console[log.level](msg); } } async flush() { /* No-Op for console */ } }