Add standalone App Insights AI Monitoring Agent (single C# application)#26
Add standalone App Insights AI Monitoring Agent (single C# application)#26devin-ai-integration[bot] wants to merge 1 commit into
Conversation
- Self-contained ASP.NET Core web application with zero external project dependencies - Includes Azure Application Insights SDK integration with custom telemetry initializers, processors, and per-request metrics collection - AI-powered anomaly detection engine with statistical analysis (error rate spikes, response time degradation, memory pressure, 2-sigma spike detection) - Health scoring engine computing composite 0-100 scores across availability, performance, error rate, and resource utilization - AI insights engine for cross-service pattern analysis with actionable recommendations - Background service for periodic telemetry collection and App Insights metric publishing - REST API endpoints for dashboard, service health, anomalies, insights, history, and system summary - Swagger/OpenAPI documentation enabled in development mode
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| public static MonitoringDashboard? LatestDashboard => | ||
| RecentDashboards.TryPeek(out var dashboard) ? dashboard : null; |
There was a problem hiding this comment.
🔴 LatestDashboard returns the oldest dashboard instead of the most recent one
ConcurrentQueue<T>.TryPeek returns the element at the head of the queue, which is the oldest item (since Enqueue adds to the tail and TryDequeue removes from the head). The LatestDashboard property is supposed to return the most recently collected dashboard snapshot, but instead returns the oldest one still in the queue. This is consumed by the GET /api/monitoring/dashboard/latest endpoint at Controllers/MonitoringController.cs:38, so API callers will receive stale data (up to 60 cycles old) instead of the current state.
Prompt for agents
The LatestDashboard property in MonitoringBackgroundService uses ConcurrentQueue.TryPeek which returns the oldest (head) element, not the newest. The intent is to return the most recently enqueued dashboard. Since ConcurrentQueue does not have a method to peek at the tail, the simplest fix is to maintain a separate field (e.g. a volatile MonitoringDashboard? _latestDashboard) that is updated each time a new dashboard is enqueued in the ExecuteAsync loop (around line 53). The LatestDashboard property would then return that field instead of using TryPeek. Alternatively, the data structure could be changed from ConcurrentQueue to something that supports efficient access to the last element.
Was this helpful? React with 👍 or 👎 to provide feedback.
| RecordSnapshot(snapshot); | ||
|
|
||
| DetectHighErrorRate(snapshot, anomalies); | ||
| DetectSlowResponseTime(snapshot, anomalies); | ||
| DetectHighMemoryUsage(snapshot, anomalies); | ||
| DetectDependencyFailures(snapshot, anomalies); | ||
| DetectResponseTimeSpike(snapshot, anomalies); |
There was a problem hiding this comment.
🔴 Response time spike detection baseline includes the current snapshot being tested
In AnomalyDetectionEngine.Analyze(), RecordSnapshot(snapshot) is called at line 30 before DetectResponseTimeSpike(snapshot, anomalies) at line 36. Inside DetectResponseTimeSpike, the history (now including the current snapshot) is used to compute the baseline mean and standard deviation (lines 131-140). This means the current snapshot's AverageResponseTimeMs inflates both the mean and stddev of the baseline, making it systematically harder to detect a genuine spike — the very value being tested for anomaly is part of its own reference distribution.
| RecordSnapshot(snapshot); | |
| DetectHighErrorRate(snapshot, anomalies); | |
| DetectSlowResponseTime(snapshot, anomalies); | |
| DetectHighMemoryUsage(snapshot, anomalies); | |
| DetectDependencyFailures(snapshot, anomalies); | |
| DetectResponseTimeSpike(snapshot, anomalies); | |
| DetectResponseTimeSpike(snapshot, anomalies); | |
| RecordSnapshot(snapshot); | |
| DetectHighErrorRate(snapshot, anomalies); | |
| DetectSlowResponseTime(snapshot, anomalies); | |
| DetectHighMemoryUsage(snapshot, anomalies); | |
| DetectDependencyFailures(snapshot, anomalies); |
Was this helpful? React with 👍 or 👎 to provide feedback.
| ActiveConnections: 0); | ||
|
|
||
| var resources = new ResourceUtilization( | ||
| CpuPercent: snapshot.CpuTimeSeconds, |
There was a problem hiding this comment.
🔴 CpuPercent field is populated with cumulative CPU time in seconds, not a percentage
ResourceUtilization.CpuPercent is set to snapshot.CpuTimeSeconds (ServiceHealthAggregator.cs:132), which is the total processor time since the process started (e.g. 300.5 seconds). This value is not a percentage (0–100) — it's a monotonically increasing number of seconds. This incorrect metric is then published to Application Insights via MonitoringBackgroundService and exposed in the dashboard API, leading to nonsensical CPU utilization reporting.
Was this helpful? React with 👍 or 👎 to provide feedback.
| var response = await _httpClient.GetAsync($"{baseUrl}/healthz"); | ||
| isReachable = response.IsSuccessStatusCode; |
There was a problem hiding this comment.
🔴 HttpResponseMessage from health probe is never disposed, leaking sockets
HttpResponseMessage implements IDisposable and must be disposed to release the underlying socket connection back to the pool. In ProbeServiceAsync, the response from _httpClient.GetAsync() at line 111 is stored in a local variable but never disposed. Since this method is called once per monitored service per monitoring cycle (every 60s for 6 services by default), this will accumulate undisposed response objects over time, potentially exhausting the socket pool.
| var response = await _httpClient.GetAsync($"{baseUrl}/healthz"); | |
| isReachable = response.IsSuccessStatusCode; | |
| using var response = await _httpClient.GetAsync($"{baseUrl}/healthz"); | |
| isReachable = response.IsSuccessStatusCode; |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds a standalone, self-contained Azure Application Insights AI Monitoring Agent as a single C# ASP.NET Core web application (
AppInsightsMonitoringAgent). This is a single project with zero dependencies on other projects in the solution — it can be built, deployed, and run independently.Project Structure
All components live under
src/Services/Monitoring/AppInsightsMonitoringAgent/:Key Capabilities
/api/monitoring/dashboard,/services,/anomalies,/insights,/history,/summaryReview & Testing Checklist for Human
ApplicationInsights:ConnectionStringinappsettings.jsonbefore deploying to a real Azure environmentMonitoredServicesURLs match your deployment topologydotnet build Services/Monitoring/AppInsightsMonitoringAgent/AppInsightsMonitoringAgent.csprojto confirm it buildsGET /api/monitoring/dashboardreturns valid JSONNotes
/healthzendpoints every 60 seconds (configurable)Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/92d2181c6896487687232a75e23c35d0