Skip to content

[Code Quality] EventLogLogger.CreateScoped — every scoped logger allocates a fresh EventLog handle (resource leak across scopes) #973

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Warning

File: src/Servy.Core/Logging/EventLogLogger.cs

Lines: 73-85

Code:

public IServyLogger CreateScoped(string prefix)
{
    return new EventLogLogger(
        _source,
        _currentLogLevel,
        _isEventLogEnabled,
        prefix
    );
}

Explanation:

CreateScoped instantiates a brand-new EventLogLogger, which in its constructor calls InitializeEventLog() (line 53-56) and allocates a separate System.Diagnostics.EventLog handle. Every call site that builds a scoped logger therefore opens its own native EventLog handle — and most call sites simply use the result locally and let it go out of scope without ever calling Dispose().

EventLog implements IDisposable and holds an unmanaged event-source handle plus an internal listener thread under the hood. Without explicit disposal these accumulate until finalization (or service shutdown), which is observable as RPC handle pressure under sustained scoped-logger churn. It also defeats the implicit assumption that scoped loggers are cheap.

Suggested fix:

Have CreateScoped return a lightweight wrapper that delegates to the parent EventLog instance and only changes the prefix, instead of creating a new EventLog handle:

private sealed class ScopedEventLogLogger : IServyLogger
{
    private readonly EventLogLogger _parent;
    public string? Prefix { get; }
    public ScopedEventLogLogger(EventLogLogger parent, string prefix) { _parent = parent; Prefix = prefix; }
    public void Info(string m)  => _parent.Info(Format(m));
    // ... etc, with Format prepending Prefix
    public void Dispose() { /* no-op; parent owns the EventLog */ }
    public IServyLogger CreateScoped(string p) => new ScopedEventLogLogger(_parent, p);
}

public IServyLogger CreateScoped(string prefix) => new ScopedEventLogLogger(this, prefix);

Side benefit: avoids the duplicated EventLog.SourceExists round-trip on each scope creation.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions