Skip to content

feat: Add App Insights AI Monitoring Agent Azure Function (C#)#28

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1777561820-appinsights-ai-monitoring-agent
Open

feat: Add App Insights AI Monitoring Agent Azure Function (C#)#28
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1777561820-appinsights-ai-monitoring-agent

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 30, 2026

Summary

Adds a new Azure Function (C#, .NET 10, isolated worker) that serves as an AI-powered monitoring agent for all microservices using Azure Application Insights and Azure OpenAI.

New Project: Monitoring.Functions

Located at src/Functions/Monitoring/Monitoring.Functions/, this Azure Function app provides:

Timer-Triggered Functions:

  • AnomalyDetector (every 5 min) — Queries App Insights telemetry and detects anomalies using rule-based thresholds + statistical z-score analysis + Azure OpenAI enrichment
  • HealthMonitor (every 30 min) — Generates comprehensive health reports with AI summaries and sends webhook notifications

HTTP-Triggered Functions:

  • GET /api/monitoring/health — Full platform health report with per-service AI insights
  • GET /api/monitoring/services/{name} — Detailed telemetry and AI analysis for a specific service
  • GET /api/monitoring/anomalies — Lists all detected anomalies across services
  • POST /api/monitoring/alerts/webhook — Receives App Insights alert webhooks, enriches with AI analysis
  • POST /api/monitoring/analyze/{name} — Triggers on-demand AI analysis for a specific service

Services:

  • AppInsightsQueryService — KQL queries against Log Analytics (requests, exceptions, dependencies, time-series)
  • AiAnalysisService — Rule-based + z-score statistical + Azure OpenAI anomaly detection and health insight generation
  • AlertService — Adaptive card webhook notifications for Teams/Slack

Other changes:

  • Added Dockerfile and docker-compose service definition (port 7071)
  • Updated Microservices.sln with Functions/Monitoring solution folder
  • Updated README.md with monitoring agent documentation, configuration reference, and architecture

Review & Testing Checklist for Human

  • Verify Azure resource configuration: App Insights connection string, Log Analytics workspace ID, Azure OpenAI endpoint and deployment name must be set in environment variables or local.settings.json
  • Review KQL queries in AppInsightsQueryService.cs to ensure they match your actual App Insights telemetry schema (cloud_RoleName values must match your deployed service names)
  • Test webhook notification format with your Teams/Slack channel — the adaptive card payload in AlertService.cs follows Microsoft Teams format
  • Verify anomaly detection thresholds (FailureRateThresholdPercent: 5%, ResponseTimeThresholdMs: 2000ms) are appropriate for your SLAs
  • Test locally with func start after configuring local.settings.json with real Azure credentials

Notes

  • The project builds successfully against .NET 10 with all NuGet packages resolved
  • Uses DefaultAzureCredential for authentication — works with managed identity in Azure, or Azure CLI / VS Code credentials locally
  • The local.settings.json contains placeholder values that need to be replaced with actual Azure resource details before running

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/e2fc58357f724243b98d9ea2cc72e7dd


Open in Devin Review

- Add Azure Function project (C#, .NET 10, isolated worker) for AI-powered monitoring
- Implement timer-triggered functions: AnomalyDetector (5min), HealthMonitor (30min)
- Implement HTTP-triggered functions: GetHealthReport, GetServiceTelemetry, GetAnomalies, AlertWebhook, TriggerManualAnalysis
- Add AppInsightsQueryService for KQL-based telemetry queries (requests, exceptions, dependencies)
- Add AiAnalysisService with rule-based + statistical z-score + Azure OpenAI anomaly detection
- Add AlertService with Teams/Slack adaptive card webhook notifications
- Add Dockerfile and docker-compose service definition
- Update solution file and README with monitoring agent documentation
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +70 to +76
var query = $"""
exceptions
| where cloud_RoleName == '{serviceName}'
| where timestamp > ago({FormatTimeSpan(period)})
| summarize Count=count(), LastOccurrence=max(timestamp) by type, outerMessage
| top {top} by Count desc
""";
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 KQL injection via unsanitized serviceName in query string interpolation

The serviceName parameter is interpolated directly into KQL queries (e.g., | where cloud_RoleName == '{serviceName}') at 5 locations in AppInsightsQueryService.cs. This value originates from user-controllable sources: the {serviceName} HTTP route parameter in MonitoringDashboardFunction.cs:87-88 and AlertWebhookFunction.cs:83-84, as well as the ResourceName field from external webhook payloads at AlertWebhookFunction.cs:46. A malicious serviceName containing a single quote (e.g., foo' | where 1==1 //) can break out of the string literal and inject arbitrary KQL, potentially exfiltrating data from the Log Analytics workspace.

Affected query locations in AppInsightsQueryService.cs

Lines 72, 103, 132, 161, 197 all use the pattern:

| where cloud_RoleName == '{serviceName}'

with no escaping or parameterization of serviceName.

Prompt for agents
The serviceName parameter from HTTP route parameters and webhook payloads is directly string-interpolated into KQL queries at multiple locations in AppInsightsQueryService.cs (lines 72, 103, 132, 161, 197), creating a KQL injection vulnerability.

To fix this, either:
1. Sanitize/validate serviceName before use: strip or reject any input containing single quotes, pipes, or other KQL metacharacters. A simple allowlist regex like ^[a-zA-Z0-9-]+$ would work since service names should only contain alphanumeric characters and hyphens.
2. Add a validation method (e.g., ValidateServiceName) in AppInsightsQueryService or as a shared utility, and call it at the start of GetServiceTelemetryAsync and any other public method that accepts serviceName.
3. Also validate in the HTTP trigger functions (MonitoringDashboardFunction.GetServiceTelemetryAsync, AlertWebhookFunction.TriggerManualAnalysisAsync, AlertWebhookFunction.RunAsync) before passing to the query service.

All 5 query methods that interpolate serviceName need protection: GetTopExceptionsAsync, GetRequestRateTimeSeriesAsync, GetResponseTimeTimeSeriesAsync, GetDependencyMetricsAsync, and QueryRequestMetricsAsync.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/docker-compose.yml
ports:
- "7071:80"
environment:
- AzureWebJobsStorage=UseDevelopmentStorage=true
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 monitoring-agent will fail in docker-compose: UseDevelopmentStorage=true without Azurite container

The monitoring-agent service sets AzureWebJobsStorage=UseDevelopmentStorage=true which expects Azurite (Azure Storage Emulator) to be available at 127.0.0.1:10000/10001/10002. However, no Azurite container is defined in docker-compose, and in a containerized environment, 127.0.0.1 refers to the container's own loopback — not the host. The Azure Functions runtime requires storage for timer trigger lease management (used by both AnomalyDetector and HealthMonitor functions). Without accessible storage, the function host will fail to start or timer triggers will not fire.

Prompt for agents
The monitoring-agent docker-compose service sets AzureWebJobsStorage=UseDevelopmentStorage=true but there is no Azurite container in the compose file. Azure Functions timer triggers (AnomalyDetector and HealthMonitor) require Azure Storage for lease management.

To fix this, add an Azurite container to docker-compose.yml and update the connection string:

1. Add an Azurite service:
   azurite:
     image: mcr.microsoft.com/azure-storage/azurite
     ports:
       - "10000:10000"
       - "10001:10001"
       - "10002:10002"

2. Change the monitoring-agent AzureWebJobsStorage from UseDevelopmentStorage=true to an explicit connection string pointing to the azurite container:
   AzureWebJobsStorage=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite:10002/devstoreaccount1

3. Add depends_on: azurite to the monitoring-agent service.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants