Files
undead-logging/README.md
zombieb 5db910ca14 Added global time format and log timing controls using LoggingConfiguration
* Bench doc fixes
* README fixes
* Added test scripts in `tests/`
2025-07-19 18:51:28 -04:00

4.3 KiB

Undead Logging

Logging for stupid idiots like me

  • Pluggable event listeners
  • Per-source hushing, global log type hushing
  • Log timing control
  • Time display modes
import Logging from "@proxnet/undead-logging"

const log = new Logging("Main");

log.i("Hello World!");

Disable a source:

// .. logging source is in the scope
log.visible = false;

log.debug("I can't be seen!");

// no output

Change a source's name:

// .. logging source "Main" is in the scope

log.n("Network is networking");
log.source = "Main2";
log.n("Something happened");

// output:
// 2024-11-14T01:21:40.350Z Main [NETWORK] Network is networking
// 2024-11-14T01:21:40.350Z Main2 [NETWORK] Something happened

Disable a type of message globally:

import Logging, { MessageTypeVisibility } from "@proxnet/undead-logging";
// .. logging source "Main" is in the scope

MessageTypeVisibility.Error = false;

// somewhere else, could be a different script
log.i("I am visible");
log.error("I am not visible");

// output:
// 2024-11-14T01:21:40.350Z Main [INFO] I am visible

Event Listeners

Event listeners are called when a message is logged on any logging source

An event callback can either receive messages as either:

  • Whole lines, including formatting, colors, excluding newlines or
  • Individual msg (string), type (MessageType), source (string), and time (Date) arguments

Callback ran when a message is logged anywhere:

LoggingListeners.onmsg('basic', msg => {
    // `msg` is a string containing the entire line w/ formatting
});

Callback ran when a message is logged anywhere (this time components are split up):

LoggingListeners.onmsg('type', (msg, type, source, time) => {
    // msg: string
    // type: MessageType - import { MessageType } from "@proxnet/undead-logging";
    // source: string
    // time: Date
});

Remove callback:

const cb = msg => { /* do something with msg: string */ };
LoggingListeners.onmsg('basic', cb);
LoggingListeners.offmsg('basic', cb);

Time display modes

You can display four different formats for time:

  • UTC
  • Unix time (in milliseconds)
  • Local [process] time (in milliseconds, from the performance API)
  • RoundedLocal: Same as above, but rounded to the nearest whole ms

Set the time format:

import { LoggingConfiguration, TimeFormat } from "@proxnet/undead-logging";

LoggingConfiguration.timeFormat = TimeFormat.Local;
// or
LoggingConfiguration.timeFormat = TimeFormat.Utc;

(advanced) Logging timing

You can control when log functions are executed using LoggingConfiguration.logTiming.

Logs are sent synchronously by default. You can optionally defer logs with setImmediate using LogTiming.Deferred

LoggingConfiguration.logTiming = LogTiming.Sync;
// or
LoggingConfiguration.logTiming = LogTiming.Deferred;

You might prefer to defer logs in asynchronous situations where order does not matter and
you'd like to prevent slowing down I/O.
You might also prefer to reset all sources to synchronous logging during app shutdown.
This can help debug issues with how your app closes. (see example below)

Global resets

Every source is tracked by this module in a Set.

You can reset every source's log timing or time format with LoggingConfiguration.reset(something).
The corresponding property will be updated on LoggingConfiguration:

import Logging, { LoggingConfiguration, LogTiming } from "@proxnet/undead-logging";

const log = new Logging("Logger");

log.logTiming = LogTiming.Sync; // the default
LoggingConfiguration.resetLogTiming = LogTiming.Deferred;

// both are LogTiming.Deferred
log.d(`My log timing: LogTiming.${LogTiming[log.logTiming]}`);
log.d(`Global: LogTiming.${LogTiming[LoggingConfiguration.logTiming]}`);

This is useful when you want to use synchronous logging during a shutdown:

// something is keeping the event loop alive (HTTP server, a database, some I/O?)

LoggingConfiguration.logTiming = LogTiming.Deferred;
const log = new Logging("Main");

Deno.addSignalListener('SIGINT', () => {
    LoggingConfiguration.resetLogTiming = LogTiming.Sync;
});

See tests/shutdown.ts.

Benchmarks

Contributing

Are you crazy? This ol' thing is just.. "meh" at most. You're sure?

... anyway, create an account on gitea.proxnet.dev, fork, then PR.