Skip to content

Serilog does not automatically flush batched output sinks when disposed (and has no manual method for doing so) #2173

@mqudsi

Description

@mqudsi

Description

When using Serilog (in conjunction with an asynchronous logging sink or a batched logging sink) in client-side applications that may terminate at any time due to an unhandled exception (vs in server-side applications where it is expected that requests are failed but the "app" remains running), Serilog currently exits without informing the sink that it should flush its pipeline of batched/deferred log messages.

Ironically, these are probably the most important log events but they are excluded from the log in this manner.

Reproduction

I've reproduced this various batching sinks, most recently with the AWS Cloudwatch sink. The relevant issue in that repo is here where the author reports that this is an upstream serilog problem that affects all batching sinks.

  1. Use Serilog with a batching sink like Seq or AWS Cloudwatch
  2. Ensure the configured sink batch count is sufficiently high and the periodic interval is sufficiently long enough for lone events (at your current logging rate) not to be immediately posted to the backend.
  3. Ensure that Log.CloseAndFlush() is called on normal/abnormal exit
  4. Generate a log event then immediately trigger an exit (that triggers the exit handler that disposes the Serilog instance)
  5. Observe that the most recent log messages that were in the batched pipeline are not written to the destination.

A very contrived version of this can be seen in the following:

var logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .WriteTo.AmazonCloudWatch(..)
    .CreateLogger();
logger.Information("Generating a test log event");
logger.Dispose(); // or await logger.DisposeAsync();
Environment.Exit(0);

Expected behavior
A call to Serilog.Dispose() (or Log.CloseAndFlush()) should trigger a flush of the queued log events to the final destination in asynchronous or batched sinks.

Additionally, there should be a way to explicitly flush all serilog sinks without disposing and resetting the logger - i.e. in the event of a critical but non-fatal error, there should be the option of doing something along the lines of await Log.FlushAsync() that will trigger a clearing of any queued log events in the sinks but without resetting the associated log allowing continued use of all configured log entrypoints.

Relevant package, tooling and runtime versions
Serilog 4.2.0 under .NET 9

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions