diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs index 6b0bafcf..6a6543fc 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs @@ -57,12 +57,56 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking using (var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { + // Buffer for multiline CMTrace entries (e.g. AgentExecutor.log + // "write output done. output = ..." spans many lines) + StringBuilder multiLineBuffer = null; + int multiLineCount = 0; + string line; while ((line = await reader.ReadLineAsync()) != null) { if (token.IsCancellationRequested) break; - // Parse CMTrace format to get the message content + // --- Multiline CMTrace buffering --- + // CMTrace entries: + // When message contains newlines, the entry spans multiple lines. + // We buffer until we find the closing ]LOG]!> tag. + if (multiLineBuffer != null) + { + // Continuing a multiline entry + multiLineBuffer.Append('\n').Append(line); + multiLineCount++; + + if (line.Contains("]LOG]!>")) + { + // Entry complete — use the assembled line + line = multiLineBuffer.ToString(); + multiLineBuffer = null; + multiLineCount = 0; + } + else if (multiLineCount >= MaxMultiLineBufferLines) + { + // Safety limit — discard to prevent unbounded memory usage + _logger.Debug($"ImeLogTracker: discarding multiline CMTrace buffer after {multiLineCount} lines (corrupt entry?)"); + multiLineBuffer = null; + multiLineCount = 0; + continue; + } + else + { + // Still accumulating — read next line + continue; + } + } + else if (line.StartsWith("")) + { + // Start of a multiline CMTrace entry + multiLineBuffer = new StringBuilder(line); + multiLineCount = 1; + continue; + } + + // --- Normal processing (single-line or completed multiline) --- CmTraceLogEntry entry; string messageToMatch; if (CmTraceLogParser.TryParseLine(line, out entry)) diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs index 4f63641e..6d649d33 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs @@ -100,6 +100,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking new Dictionary(StringComparer.OrdinalIgnoreCase); private string _lastPlatformScriptPolicyId; private const int MaxScriptOutputLength = 2048; + private const int MaxMultiLineBufferLines = 100; // Set synchronously during HandlePatternMatch so callbacks can read it public string LastMatchedPatternId { get; private set; } diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt index 611de253..064c0200 100644 --- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt @@ -1 +1 @@ -743 +744