mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
add structured error code extraction from IME log patterns
The backend already reads errorCode from event data for FailureCode and failure reason formatting, but the agent never populated it. This change extracts error codes (exit codes, HRESULT) from named regex capture groups in IME log error patterns and sends them as structured errorCode fields. Also fixes a pre-existing bug where ErrorPatternId/ErrorDetail were not persisted across agent restarts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -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+(?<exitCode>\\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
|
||||
|
||||
@@ -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+(?<exitCode>\\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
|
||||
|
||||
@@ -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<string> 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
|
||||
/// <summary>
|
||||
/// Sets the error context for the app (called when an error pattern is matched).
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
+9
-2
@@ -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;
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking
|
||||
p.DependsOn != null ? new HashSet<string>(p.DependsOn) : new HashSet<string>(),
|
||||
(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,
|
||||
|
||||
+5
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user