diff --git a/rules/dist/ime-log-patterns.json b/rules/dist/ime-log-patterns.json index 497372e8..cf3e1f40 100644 --- a/rules/dist/ime-log-patterns.json +++ b/rules/dist/ime-log-patterns.json @@ -235,7 +235,7 @@ { "patternId": "IME-ERROR-UNMAPPED-EXIT", "category": "currentPhase", - "pattern": "\\[Win32App\\] Admin did NOT set mapping for lpExitCode\\W+\\d+ of app\\W+{GUID}", + "pattern": "\\[Win32App\\] Admin did NOT set mapping for lpExitCode\\W+(?\\d+) of app\\W+{GUID}", "action": "updateStateError", "description": "Detects when an app installer returned an exit code that has no mapping configured in Intune.", "enabled": true diff --git a/rules/ime-log-patterns/IME-ERROR-UNMAPPED-EXIT.json b/rules/ime-log-patterns/IME-ERROR-UNMAPPED-EXIT.json index 397b4884..0a25b5ab 100644 --- a/rules/ime-log-patterns/IME-ERROR-UNMAPPED-EXIT.json +++ b/rules/ime-log-patterns/IME-ERROR-UNMAPPED-EXIT.json @@ -2,7 +2,7 @@ "$schema": "../schema/ime-log-pattern.schema.json", "patternId": "IME-ERROR-UNMAPPED-EXIT", "category": "currentPhase", - "pattern": "\\[Win32App\\] Admin did NOT set mapping for lpExitCode\\W+\\d+ of app\\W+{GUID}", + "pattern": "\\[Win32App\\] Admin did NOT set mapping for lpExitCode\\W+(?\\d+) of app\\W+{GUID}", "action": "updateStateError", "description": "Detects when an app installer returned an exit code that has no mapping configured in Intune.", "enabled": true diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/AppPackageState.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/AppPackageState.cs index f42df178..761eb86b 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/AppPackageState.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/AppPackageState.cs @@ -90,6 +90,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking public long BytesTotal { get; private set; } = 0; public string ErrorPatternId { get; private set; } public string ErrorDetail { get; private set; } + public string ErrorCode { get; private set; } // Delivery Optimization telemetry (populated from [DO TEL] log entries) public long DoFileSize { get; private set; } @@ -136,7 +137,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking HashSet dependsOn, AppInstallationState installationState, bool downloadingOrInstallingSeen, int? progressPercent, long bytesDownloaded, long bytesTotal, - string errorPatternId = null, string errorDetail = null, + string errorPatternId = null, string errorDetail = null, string errorCode = null, long doFileSize = 0, long doTotalBytesDownloaded = 0, long doBytesFromPeers = 0, int doPercentPeerCaching = 0, long doBytesFromLanPeers = 0, long doBytesFromGroupPeers = 0, @@ -158,6 +159,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking BytesTotal = bytesTotal, ErrorPatternId = errorPatternId, ErrorDetail = errorDetail, + ErrorCode = errorCode, InstallationStateLastChangedTicks = Stopwatch.GetTimestamp(), DoFileSize = doFileSize, DoTotalBytesDownloaded = doTotalBytesDownloaded, @@ -234,10 +236,12 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking /// /// Sets the error context for the app (called when an error pattern is matched). /// - public void SetErrorContext(string patternId, string detail) + public void SetErrorContext(string patternId, string detail, string errorCode = null) { ErrorPatternId = patternId; ErrorDetail = detail; + if (!string.IsNullOrEmpty(errorCode)) + ErrorCode = errorCode; } /// @@ -415,6 +419,8 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking data["errorPatternId"] = ErrorPatternId; if (!string.IsNullOrEmpty(ErrorDetail)) data["errorDetail"] = ErrorDetail; + if (!string.IsNullOrEmpty(ErrorCode)) + data["errorCode"] = ErrorCode; if (HasDoTelemetry) { diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.Handlers.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.Handlers.cs index 6bf3a4f5..2f710f4a 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.Handlers.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.Handlers.cs @@ -463,14 +463,14 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking _packageStates.SetCurrent(newId); } - private void UpdateStateWithCallback(string id, AppInstallationState newState, int? progressPercent = null, string errorPatternId = null, string errorDetail = null) + private void UpdateStateWithCallback(string id, AppInstallationState newState, int? progressPercent = null, string errorPatternId = null, string errorDetail = null, string errorCode = null) { var pkg = _packageStates.GetPackage(id); if (pkg == null) return; // Set error context before state change so it's available in ToEventData() if (newState == AppInstallationState.Error && !string.IsNullOrEmpty(errorPatternId)) - pkg.SetErrorContext(errorPatternId, errorDetail); + pkg.SetErrorContext(errorPatternId, errorDetail, errorCode); var oldState = pkg.InstallationState; var changed = _packageStates.UpdateState(id, newState, progressPercent); 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 6a6543fc..a9416843 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.LogProcessing.cs @@ -249,16 +249,23 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking break; case "updatestateerror": + // Extract structured error code from named capture groups (exitCode, hresult, errorCode) + var extractedErrorCode = match.Groups["exitCode"]?.Value; + if (string.IsNullOrEmpty(extractedErrorCode)) + extractedErrorCode = match.Groups["hresult"]?.Value; + if (string.IsNullOrEmpty(extractedErrorCode)) + extractedErrorCode = match.Groups["errorCode"]?.Value; + if (pattern.Parameters.ContainsKey("checkTo") && pattern.Parameters["checkTo"] == "true") { // Only apply error if the "to" value is "Error" var toValue = match.Groups["to"]?.Value; if (string.Equals(toValue, "Error", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(id)) - UpdateStateWithCallback(id, AppInstallationState.Error, errorPatternId: pattern.PatternId, errorDetail: message); + UpdateStateWithCallback(id, AppInstallationState.Error, errorPatternId: pattern.PatternId, errorDetail: message, errorCode: extractedErrorCode); } else if (!string.IsNullOrEmpty(id)) { - UpdateStateWithCallback(id, AppInstallationState.Error, errorPatternId: pattern.PatternId, errorDetail: message); + UpdateStateWithCallback(id, AppInstallationState.Error, errorPatternId: pattern.PatternId, errorDetail: message, errorCode: extractedErrorCode); } break; diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs index 6d649d33..3bcaa5b7 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeLogTracker.cs @@ -320,6 +320,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking p.DependsOn != null ? new HashSet(p.DependsOn) : new HashSet(), (AppInstallationState)p.InstallationState, p.DownloadingOrInstallingSeen, p.ProgressPercent, p.BytesDownloaded, p.BytesTotal, + errorPatternId: p.ErrorPatternId, errorDetail: p.ErrorDetail, errorCode: p.ErrorCode, doFileSize: p.DoFileSize, doTotalBytesDownloaded: p.DoTotalBytesDownloaded, doBytesFromPeers: p.DoBytesFromPeers, doPercentPeerCaching: p.DoPercentPeerCaching, doBytesFromLanPeers: p.DoBytesFromLanPeers, doBytesFromGroupPeers: p.DoBytesFromGroupPeers, @@ -380,6 +381,9 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking ProgressPercent = p.ProgressPercent, BytesDownloaded = p.BytesDownloaded, BytesTotal = p.BytesTotal, + ErrorPatternId = p.ErrorPatternId, + ErrorDetail = p.ErrorDetail, + ErrorCode = p.ErrorCode, DoFileSize = p.DoFileSize, DoTotalBytesDownloaded = p.DoTotalBytesDownloaded, DoBytesFromPeers = p.DoBytesFromPeers, diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeTrackerStatePersistence.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeTrackerStatePersistence.cs index c5aca943..70f4a6f1 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeTrackerStatePersistence.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/ImeTrackerStatePersistence.cs @@ -123,6 +123,11 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking public long BytesDownloaded { get; set; } public long BytesTotal { get; set; } + // Error context + public string ErrorPatternId { get; set; } + public string ErrorDetail { get; set; } + public string ErrorCode { get; set; } + // Delivery Optimization telemetry public long DoFileSize { get; set; } public long DoTotalBytesDownloaded { get; set; }