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), andtime(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
performanceAPI) - 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;
// shut down I/O here
});
Benchmarks
Contributing
create an account on gitea.proxnet.dev, fork, then PR