Skip to content

[Robustness] EventLogLogger.Info/Warn/Error — EventLog.WriteEntry calls have no try/catch and no length truncation (32766-char limit) #971

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Warning

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

Lines: 113, 127, 141

Code (representative):

public void Info(string message)
{
    if (_currentLogLevel <= LogLevel.Info)
    {
        var formattedMessage = Format(message);
        if (_isEventLogEnabled)
        {
            _eventLog?.WriteEntry(formattedMessage, EventLogEntryType.Information, EventIds.Info);
        }
        Logger.Info(formattedMessage);
    }
}

Explanation:

EventLog.WriteEntry throws when the message exceeds Windows' per-entry size limit of 31,839 characters (the API documents the limit as 32,766 bytes; the effective char limit is lower because the writer uses Unicode). It also throws on transient I/O errors (event log full, log corrupted, RPC failure). Three problems result:

  1. No try/catch. A single oversized log entry crashes whatever code path is currently logging — including failure-recovery paths like ServiceRestarter and pre-stop handlers. The fallback to file logging in InitializeEventLog only handles initial open; runtime write failures escape.
  2. No truncation. Process stdout/stderr captured by Service.cs and forwarded through IServyLogger.Error can easily exceed 31,839 chars when the child app dumps a stack trace or large diagnostic block.
  3. Asymmetric with file Logger. When EventLog throws, Logger.Info(formattedMessage) after it never runs, so the message is lost in both sinks even though the file sink would have accepted it.

Suggested fix:

Wrap each WriteEntry in a try/catch, truncate to a safe limit (~31,000 chars to leave headroom), and ensure the file Logger always runs regardless of EventLog outcome:

private const int EventLogMessageMaxChars = 31000;

public void Info(string message)
{
    if (_currentLogLevel <= LogLevel.Info)
    {
        var formattedMessage = Format(message);
        if (_isEventLogEnabled)
        {
            var safe = formattedMessage.Length > EventLogMessageMaxChars
                ? formattedMessage.Substring(0, EventLogMessageMaxChars) + "...[truncated]"
                : formattedMessage;
            try { _eventLog?.WriteEntry(safe, EventLogEntryType.Information, EventIds.Info); }
            catch (Exception ex) { Logger.Warn($"EventLog write failed: {ex.Message}"); }
        }
        Logger.Info(formattedMessage);
    }
}

The same change applies to Warn and Error.

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