Skip to content

OP-12: Dispose and flush a configured logger

Field Value
Operation ID OP-12
Trigger The host disposes the logger instance — directly, or via DI container teardown when the logger is registered with a disposable lifetime.
Inputs None beyond the logger instance's own configured state.
Outputs The process-global Serilog logger (Log.Logger) flushed and closed; for ConsoleLogService, every auxiliary LogWriter disposed first.
Primary components SaifLogBase.Dispose, ConsoleLogService.Dispose (override)
Entry point Dispose()

Steps

  1. SaifLogBase.Dispose() (public virtual) calls Log.CloseAndFlush() on the process-global Serilog logger, flushing buffered output for synchronous sinks (Console, Event Log). This does not wait for or flush an in-flight LoggingApiSink POST: Emit is async void with no completion signal exposed to the caller, so CloseAndFlush() has no awaitable handle to that in-flight call and cannot block on it.
  2. ConsoleLogService.Dispose() (public override) first disposes every registered auxiliary LogWriter in _loggers — releasing each file writer's own independent Serilog logger and file handle — and only then calls Log.CloseAndFlush() if the service IsConfigured.
  3. SaifLog and SaifWindowsServiceLog do not override Dispose; they use the base SaifLogBase.Dispose() behavior directly.

Process flow

flowchart TD
    A[Host disposes logger instance] --> B{Logger type}
    B -->|SaifLog / SaifWindowsServiceLog| C["SaifLogBase.Dispose: Log.CloseAndFlush()"]
    B -->|ConsoleLogService| D["Dispose each auxiliary LogWriter first"]
    D --> E{IsConfigured?}
    E -->|Yes| F["Then Log.CloseAndFlush()"]
    E -->|No| G[Skip Log.CloseAndFlush]

Failure and edge-case behavior

  • Log.CloseAndFlush() acts on the single process-global Serilog.Log.Logger; disposing one logger instance in a process that hosts multiple SaifLogBase-derived loggers flushes/closes the shared static logger for all of them, not just the instance being disposed.
  • ConsoleLogService.Dispose() disposes auxiliary LogWriter instances unconditionally, even if the service itself was never successfully configured; it only conditions the Log.CloseAndFlush() call on IsConfigured.
  • Disposal does not flush any in-flight LoggingApiSink.Emit call; because Emit is async void with no awaited completion signal exposed to the caller, a POST in progress at shutdown may be abandoned.

Sources

  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifLogBase.cs
  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/ConsoleLogService.cs
  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/Console/LogWriter.cs