diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Configuration/RemoteConfigService.cs b/src/Agent/AutopilotMonitor.Agent.Core/Configuration/RemoteConfigService.cs index 48edd1ae..c2515626 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Configuration/RemoteConfigService.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Configuration/RemoteConfigService.cs @@ -19,6 +19,7 @@ namespace AutopilotMonitor.Agent.Core.Configuration private readonly string _tenantId; private readonly AgentLogger _logger; private readonly string _cacheFilePath; + private readonly EmergencyReporter _emergencyReporter; private AgentConfigResponse _currentConfig; private readonly object _configLock = new object(); @@ -37,11 +38,12 @@ namespace AutopilotMonitor.Agent.Core.Configuration } } - public RemoteConfigService(BackendApiClient apiClient, string tenantId, AgentLogger logger) + public RemoteConfigService(BackendApiClient apiClient, string tenantId, AgentLogger logger, EmergencyReporter emergencyReporter = null) { _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); _tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _emergencyReporter = emergencyReporter; var cacheDir = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Config"); _cacheFilePath = Path.Combine(cacheDir, "remote-config.json"); @@ -74,6 +76,14 @@ namespace AutopilotMonitor.Agent.Core.Configuration catch (Exception ex) { _logger.Warning($"Failed to fetch remote config: {ex.Message}"); + + // Report to emergency channel if available (not available in --run-gather-rules mode) + if (_emergencyReporter != null) + { + _ = _emergencyReporter.TrySendAsync( + AgentErrorType.ConfigFetchFailed, + ex.Message); + } } // Fall back to cached config diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/DiagnosticsPackageService.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/DiagnosticsPackageService.cs index 08705a17..1c7e7c64 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/DiagnosticsPackageService.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/DiagnosticsPackageService.cs @@ -304,8 +304,17 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core return (true, null); } - lastErrorCode = $"HTTP {(int)response.StatusCode} {response.ReasonPhrase}"; + var statusCode = (int)response.StatusCode; + lastErrorCode = $"HTTP {statusCode} {response.ReasonPhrase}"; var responseBody = await response.Content.ReadAsStringAsync(); + + // Auth errors (401/403) are permanent — SAS token invalid or expired, retrying won't help + if (statusCode == 401 || statusCode == 403) + { + _logger.Warning($"Blob upload auth error (not retryable): {lastErrorCode} - {responseBody}"); + return (false, lastErrorCode); + } + _logger.Warning($"Blob upload attempt {attempt} failed: {lastErrorCode} - {responseBody}"); } catch (Exception ex) diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.cs index 42ecc3ef..73342e16 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.cs @@ -252,7 +252,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core { try { - _remoteConfigService = new RemoteConfigService(_apiClient, _configuration.TenantId, _logger); + _remoteConfigService = new RemoteConfigService(_apiClient, _configuration.TenantId, _logger, _emergencyReporter); _remoteConfigService.FetchConfigAsync().Wait(TimeSpan.FromSeconds(15)); ApplyRuntimeSettingsFromRemoteConfig(); } @@ -546,6 +546,12 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core catch (Exception ex) { _logger.Error("Failed to register session", ex); + + // Report to emergency channel — one-shot, no threshold needed. + // EmergencyReporter dedup ensures RegisterSessionFailed:null sent only once per session. + _ = _emergencyReporter.TrySendAsync( + AgentErrorType.RegisterSessionFailed, + ex.Message); } } diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/BackendApiClient.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/BackendApiClient.cs index c50b0ad5..47e200fd 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/BackendApiClient.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/BackendApiClient.cs @@ -115,6 +115,8 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Network var ndjson = CreateNdjson(request); var compressedContent = CompressWithGzip(ndjson); + _logger?.Debug($"IngestEventsAsync: POST {url} — {request.Events.Count} events, {compressedContent.Length} bytes compressed"); + var httpRequest = new HttpRequestMessage(HttpMethod.Post, url) { Content = new ByteArrayContent(compressedContent) @@ -165,6 +167,8 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Network var httpRequest = new HttpRequestMessage(HttpMethod.Get, url); AddSecurityHeaders(httpRequest); + _logger?.Debug($"GetAgentConfigAsync: GET {url}"); + var sw = Stopwatch.StartNew(); var failed = false; long bytesDown = 0; diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/EmergencyReporter.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/EmergencyReporter.cs index 79b34849..2a2fd4ee 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/EmergencyReporter.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Network/EmergencyReporter.cs @@ -17,7 +17,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Network /// /// A failure in this reporter is silently swallowed — it must never cascade into the main loop. /// - internal class EmergencyReporter + public class EmergencyReporter { /// /// Number of consecutive upload failures required before the first emergency report is sent. diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt index 3f7d1915..cdffbbc4 100644 --- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt @@ -1 +1 @@ -159 +166