Levels
Six levels, minimums, per-source overrides, runtime switches, per-sink restrictions.
The six levels#
| logit | Serilog | pino | Meaning |
|---|---|---|---|
verbose | Verbose | trace (10) | Everything, for the one afternoon you need it |
debug | Debug | debug (20) | Internal flow, for developers |
info | Information | info (30) | What the system did — the default minimum |
warn | Warning | warn (40) | Something is off and was handled |
error | Error | error (50) | An operation failed |
fatal | Fatal | fatal (60) | The process cannot go on |
One method per level on every logger: log.verbose() … log.fatal(). log.write(level, …) takes the level as a value.
Wherever a level is read from text — configuration, LOGIT_LEVEL, parseLevel() — the other spellings are accepted too: information, warning, trace, critical, the three-letter codes, pino's numbers. parseLevel('Warning') is 'warn'; an unknown name throws, so a typo fails at startup instead of silencing a logger.
Minimum level#
Events below the minimum are dropped before anything is parsed or captured. The default is info, or LOGIT_LEVEL from the environment when set.
configure({ minimumLevel: 'debug' });logger.isEnabled('debug') is the cheap check to put before expensive argument building:
if (log.isEnabled('verbose')) log.verbose('State: {@State}', buildExpensiveSnapshot());Overrides by source#
Serilog's MinimumLevel.Override. Keys are SourceContext prefixes on dot boundaries; the longest match wins; a source with no match uses the minimum.
configure({
minimumLevel: 'info',
overrides: {
next: 'warn', // 'next' and 'next.anything' — the framework's own noise
'app.db': 'verbose', // 'app.db', 'app.db.query', … — but not 'app.dbx'
},
});
log.forSource('app.db.query').verbose('…'); // written
log.forSource('next.router').info('…'); // droppedLOGIT_OVERRIDES="next=warn,app.db=verbose" sets the same thing from the environment; explicit overrides win over it key by key.
Runtime switches#
A LevelSwitch is a level that can change while the application runs — Serilog's LoggingLevelSwitch. Use the same instance as the minimum, as an override, or on a sink, and flip it from an admin route or a signal handler:
import { LevelSwitch, configure } from '@unhingged/logit';
export const levelSwitch = new LevelSwitch('info');
configure({ minimumLevel: levelSwitch, overrides: { 'app.db': levelSwitch } });
// later, from an admin route:
levelSwitch.level = 'debug';levelSwitch.onChange(fn) notifies listeners; logger.minimumLevel reports the current effective level for that logger's source.
Per-sink minimum#
Every built-in sink takes restrictedToMinimumLevel, and restricted(sink, level) wraps any other. It can only raise the bar — a sink never sees what the logger dropped:
configure({
minimumLevel: 'debug',
sinks: [
consoleSink(), // everything from debug
seqSink({ serverUrl: '…', restrictedToMinimumLevel: 'info' }), // info and above
],
});A sub-logger used as a sink has its own minimum and overrides as well — see Sinks.
Where the level shows up#
- The pretty console prints the three-letter code —
VRB DBG INF WRN ERR FTL— in a colour per level. - The JSON formatter writes
"level":"info"by default;levelFormat: 'number'gives pino's 30,'serilog'givesInformation,'upper'givesINFO. - CLEF writes Serilog's name in
@land omits it forinfo, as Serilog does. - Output templates:
{Level}isInformation,{Level:u3}isINF,{Level:w3}isinf,{Level:u}isINFORMATION. - OTLP: severity numbers 1, 5, 9, 13, 17, 21 with the standard texts.