Skip to content

SelfMetrics#2237

Merged
nblumhardt merged 3 commits into
serilog:devfrom
nblumhardt:self-metrics
Jun 15, 2026
Merged

SelfMetrics#2237
nblumhardt merged 3 commits into
serilog:devfrom
nblumhardt:self-metrics

Conversation

@nblumhardt

@nblumhardt nblumhardt commented May 21, 2026

Copy link
Copy Markdown
Member

System.Diagnostics.Metrics is a nice low-cost way to surface things like the logging failure rate without the overhead and risk of actually sending SelfLog output somewhere.

This PR adds four metrics, which I might as well let describe themselves:

public static readonly Counter<long> PipelineCreated = Meter.CreateCounter<long>(
    "serilog.pipeline.created",
    unit: "{pipeline}",
    description: "The number of full logging pipelines constructed.");

public static readonly Counter<long> PipelineEventEmitted = Meter.CreateCounter<long>(
    "serilog.pipeline.event_emitted",
    unit: "{event}",
    description: "The number of events dispatched to sinks through the logging pipeline.");

public static readonly Counter<long> DiagnosticsSelfLogWrites = Meter.CreateCounter<long>(
    "serilog.diagnostics.self_log_writes",
    unit: "{write}",
    description: "The number of calls made to write lines to Serilog's internal diagnostic log.");

public static readonly Counter<long> DiagnosticsDefaultFailureListenerLoggingFailures = Meter.CreateCounter<long>(
    "serilog.diagnostics.default_failure_listener.logging_failures",
    unit: "{failure}",
    description: "The number of logging failures to reach the default failure listener.");

Here's what collecting a few of them with dotnet counters looks like:

image

Tagging etc. is very conservative and should work with pretty much any downstream metrics system.

  • I don't think there's much we can usefully test around these.
  • I prefer letting callers access the raw counters etc. - trying to encapsulate the Add calls adds more lines of code that don't really pull their weight in the kind of usage expected in this codebase.

Performance

The most important benchmark this one touches is PipelineBenchmark, which shows barely any change (the regression is within the range of run-to-run variations on this workstation).

BenchmarkDotNet v0.15.2, Linux Ubuntu 24.04.2 LTS (Noble Numbat)
13th Gen Intel Core i7-13700K 5.40GHz, 1 CPU, 24 logical and 16 physical cores
.NET SDK 10.0.203
  [Host]     : .NET 10.0.7 (10.0.726.21808), X64 RyuJIT AVX2
  DefaultJob : .NET 10.0.7 (10.0.726.21808), X64 RyuJIT AVX2

main

Method Mean Error StdDev Gen0 Allocated
EmitLogEvent 78.44 ns 0.251 ns 0.223 ns 0.0229 360 B
IntProperties 115.54 ns 0.843 ns 0.789 ns 0.0325 512 B

This PR

Method Mean Error StdDev Gen0 Allocated
EmitLogEvent 81.63 ns 0.313 ns 0.278 ns 0.0229 360 B
IntProperties 116.00 ns 0.377 ns 0.352 ns 0.0325 512 B

Comment thread src/Serilog/Core/Logger.cs Outdated

_sink.Emit(logEvent);

SelfMetrics.PipelineEventEmitted.Add(1);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this after the Emit call avoids adding latency. It's not really going to be significant for a (non-observable) counter, just good hygiene.

@nblumhardt
nblumhardt marked this pull request as draft May 21, 2026 01:00
@nblumhardt

This comment was marked as resolved.

@nblumhardt
nblumhardt marked this pull request as ready for review May 21, 2026 01:20
@nblumhardt
nblumhardt merged commit 6d9fc0b into serilog:dev Jun 15, 2026
1 check passed
@nblumhardt nblumhardt mentioned this pull request Jul 10, 2026
This was referenced Jul 10, 2026
This was referenced Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant