For Serilog users
Every Serilog API and its logit spelling, and the two things that differ.
logit is Serilog's model — templates, structured capture, enrichment, filtering, sinks, output templates, CLEF — written for JavaScript. If you know Serilog you know logit; this page is the dictionary.
The dictionary#
| Serilog | logit |
|---|---|
new LoggerConfiguration()…CreateLogger() | new LoggerConfiguration()…createLogger() — or createLogger({ … }) with an options object |
Log.Logger = logger | configure({ … }) reconfigures the global log in place |
Log.Information(…), Log.Error(ex, …) | log.info(…), log.error(err, …) |
Log.ForContext<T>() / ForContext("SourceContext", "…") | log.forSource('app.db') |
Log.ForContext("UserId", id) | log.forContext('UserId', id) or log.forContext({ UserId: id }) |
Log.ForContext("Order", order, destructureObjects: true) | log.forContext('Order', order, true) |
Log.CloseAndFlush() | await closeAndFlush() |
Log.IsEnabled(level) | log.isEnabled(level) |
LogContext.PushProperty("RequestId", id) in a using | using _ = LogContext.push({ RequestId: id }) — or LogContext.run({ … }, fn) |
Enrich.FromLogContext() | on by default (logContext: false to turn it off) |
Enrich.WithProperty("App", "shop") | .enrich.withProperty('App', 'shop') / enrichers: [withProperty(…)] |
Enrich.WithMachineName(), WithProcessId(), WithEnvironmentName() | withMachineName(), withProcessId(), withEnvironment() |
Enrich.With(new MyEnricher()) | enrichers: [(event) => event.addPropertyIfAbsent(…)] |
MinimumLevel.Debug() | .minimumLevel.debug() / minimumLevel: 'debug' |
MinimumLevel.Override("Microsoft", Warning) | .minimumLevel.override('next', 'warn') / overrides: { next: 'warn' } |
MinimumLevel.ControlledBy(levelSwitch) | .minimumLevel.controlledBy(levelSwitch) / minimumLevel: levelSwitch |
LoggingLevelSwitch | LevelSwitch |
WriteTo.Console(outputTemplate: "…") | .writeTo.console({ format: 'text', outputTemplate: '…' }) |
WriteTo.Console(new CompactJsonFormatter()) | .writeTo.console({ format: 'clef' }) |
WriteTo.File("log-.txt", rollingInterval: Day, retainedFileCountLimit: 14) | fileSink({ path: 'log.txt', rolling: 'day', retainedFileCount: 14 }) |
WriteTo.Seq("http://…", apiKey: …) | .writeTo.seq({ serverUrl, apiKey }) |
WriteTo.OpenTelemetry(…) | otlpHttpSink({ … }) |
WriteTo.Logger(lc => …) | .writeTo.logger((lc) => …) or a Logger in sinks |
WriteTo.Conditional(pred, wt => …) | conditional(pred, sink) |
AuditTo.Sink(…) | auditSinks: [sink] / audit(sink) |
restrictedToMinimumLevel: | restrictedToMinimumLevel: on every sink, or restricted(sink, level) |
Filter.ByExcluding(Matching.FromSource("…")) | .filter.byExcluding(Matching.fromSource('…')) |
Filter.ByIncludingOnly(Matching.WithProperty<int>("Count", c => c < 10)) | .filter.byIncludingOnly(Matching.withProperty('Count', (c: number) => c < 10)) |
Destructure.ByTransforming<T>(t => …) | .destructure.byTransforming(T, (t) => …) |
Destructure.ToMaximumDepth(n), ToMaximumStringLength, ToMaximumCollectionCount | the same names on .destructure, or destructuring: { maxDepth, maxStringLength, maxCollectionCount } |
IDestructuringPolicy | (value: object) => { value } | undefined |
Serilog.Enrichers.Sensitive (by key) | destructuring: { redact: [...] } |
SelfLog.Enable(Console.Error) | selfLog.enable('stderr') |
UseSerilogRequestLogging() | withLogging() (Next.js) / requestLogger() (Express) |
IDiagnosticContext.Set(…) | diagnosticContext.set(…) |
Operation.Begin(…), Operation.Time(…) (SerilogTimings) | log.beginOperation(…), log.timed(…) |
CompactJsonFormatter / RenderedCompactJsonFormatter | clefFormatter() / clefFormatter({ renderMessage: true }) |
MessageTemplateTextFormatter | textFormatter({ outputTemplate }) |
Serilog.Expressions | on the roadmap |
Serilog.Settings.Configuration | on the roadmap; LOGIT_LEVEL / LOGIT_OVERRIDES today |
Level names#
The methods are JavaScript's: verbose debug info warn error fatal. Serilog's names are accepted anywhere a level is parsed — 'Information', 'Warning' — and are what CLEF's @l and {Level} in an output template print, so Seq dashboards and output templates carry over unchanged.
What differs, and why#
Plain objects are data. In Serilog an object without @ is ToString()'d. In JavaScript a literal { city, zip } has no ToString worth logging, and dumping it is what everyone wants — so plain objects and arrays are captured structurally without an operator. @ keeps its job for class instances, which otherwise render with their own toString() / toJSON() or class name. $ is unchanged. See Structured data.
There is a one-off properties form. log.info({ userId }, 'Signed in') adds properties to one event — a nod to pino and winston users. Serilog has no equivalent; forContext is the idiomatic way in both.
No Log.Logger assignment. The global log is a logger whose pipeline configure() swaps; loggers derived from it before the call follow the new configuration. A logger from createLogger() is independent, as a Serilog Logger instance is.
Enrichers are functions, filters are predicates, sinks are objects with emit — no interfaces to implement.
using needs TypeScript 5.2+. Without it, LogContext.run(props, fn) is the callback form and op.complete() / op.abandon() are explicit.
Example#
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", "shop")
.WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Seq("http://localhost:5341")
.CreateLogger();configure(
new LoggerConfiguration()
.minimumLevel.debug()
.minimumLevel.override('next', 'warn')
.enrich.fromLogContext()
.enrich.withProperty('Application', 'shop')
.writeTo.console({ format: 'text', outputTemplate: '{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}' })
.writeTo.seq({ serverUrl: 'http://localhost:5341' }),
);