Azure Functions Debuggen met Application Insights: Van Blackbox naar Glashelder
Serverless voelt als een blackbox totdat Application Insights goed is ingericht. Praktische KQL queries, alerting en diagnostics voor Azure Functions.
Jean-Pierre Broeders
Freelance DevOps Engineer
Azure Functions Debuggen met Application Insights
Serverless is fantastisch. Tot er iets misgaat en niemand weet waar het probleem zit. Geen server logs om in te duiken, geen IIS waar even snel naar gekeken kan worden. Azure Functions draaien ergens in de cloud en als ze falen, is het zoeken naar een speld in een hooiberg — tenzij Application Insights goed staat ingesteld.
De basis: meer dan alleen aanzetten
De meeste tutorials stoppen bij "zet Application Insights aan in de portal." Dat is alsof je een rookmelder koopt en 'm in de la legt. De standaard telemetrie vangt wel wat op, maar de echte waarde zit in aangepaste configuratie.
In host.json bepaalt de logging-configuratie hoeveel data er überhaupt naar Application Insights stroomt:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"maxTelemetryItemsPerSecond": 20,
"excludedTypes": "Request"
}
},
"logLevel": {
"default": "Information",
"Host.Results": "Error",
"Function": "Information",
"Host.Aggregator": "Trace"
}
}
}
Die excludedTypes: "Request" is cruciaal. Zonder die instelling worden requests gesampled en verdwijnen er af en toe aanroepen uit de telemetrie. Bij het debuggen van sporadische fouten is dat precies de data die je nodig hebt.
KQL queries die daadwerkelijk helpen
De Log Analytics workspace achter Application Insights werkt met Kusto Query Language. Geen SQL, maar het went snel. Een paar queries die regelmatig van pas komen:
Alle mislukte function executions van de laatste 24 uur:
requests
| where timestamp > ago(24h)
| where success == false
| summarize count() by cloud_RoleName, resultCode
| order by count_ desc
Langzame executions opsporen (boven de 5 seconden):
requests
| where timestamp > ago(7d)
| where duration > 5000
| project timestamp, name, duration, resultCode
| order by duration desc
| take 50
Dependency failures — als een downstream service het laat afweten:
dependencies
| where timestamp > ago(1h)
| where success == false
| summarize failCount=count() by target, type, resultCode
| order by failCount desc
Die laatste is goud waard. Een Azure Function die een API of database aanroept kan prima draaien, maar als de dependency stilvalt, zijn het de dependency-logs die het verhaal vertellen. Niet de function zelf.
Custom telemetrie toevoegen
De standaard metrics dekken 80% van de gevallen. Voor die andere 20% is TelemetryClient nodig:
public class OrderProcessor
{
private readonly TelemetryClient _telemetry;
public OrderProcessor(TelemetryClient telemetry)
{
_telemetry = telemetry;
}
[Function("ProcessOrder")]
public async Task Run(
[QueueTrigger("orders")] OrderMessage order)
{
var stopwatch = Stopwatch.StartNew();
try
{
await ProcessAsync(order);
_telemetry.TrackMetric("OrderProcessingMs",
stopwatch.ElapsedMilliseconds);
_telemetry.TrackEvent("OrderProcessed", new Dictionary<string, string>
{
["OrderId"] = order.Id,
["ProductCount"] = order.Items.Count.ToString()
});
}
catch (Exception ex)
{
_telemetry.TrackException(ex, new Dictionary<string, string>
{
["OrderId"] = order.Id,
["Stage"] = "Processing"
});
throw;
}
}
}
Die custom properties bij TrackException zijn het verschil tussen "er ging iets mis" en "order 12345 faalde tijdens de processing-stap." In een productieomgeving met honderden aanroepen per minuut scheelt dat uren zoekwerk.
Alerting: niet alles is even urgent
Een veelgemaakte fout is om op elke exception een alert te zetten. Binnen een week staat de mailbox vol en worden alle alerts genegeerd. Effectiever: gelaagde alerts.
| Niveau | Conditie | Actie |
|---|---|---|
| Kritiek | Function failure rate > 25% in 5 min | SMS + PagerDuty |
| Waarschuwing | P95 latency > 10s in 15 min | Teams/Slack notificatie |
| Info | Dagelijkse samenvatting failures | Email digest |
In de Azure Portal gaat dat via Alerts → New Alert Rule, maar de ARM template is herbruikbaar en versioneerbaar:
{
"type": "Microsoft.Insights/metricAlerts",
"apiVersion": "2018-03-01",
"properties": {
"severity": 1,
"evaluationFrequency": "PT5M",
"windowSize": "PT5M",
"criteria": {
"odata.type": "Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria",
"allOf": [
{
"name": "HighFailureRate",
"metricName": "Http5xx",
"operator": "GreaterThan",
"threshold": 10,
"timeAggregation": "Total"
}
]
}
}
}
Live Metrics Stream voor real-time debugging
Soms is er een probleem dat alleen optreedt tijdens piekuren. Live Metrics Stream toont real-time wat er gebeurt: incoming requests, failures, dependency calls, alles met minder dan een seconde vertraging.
Het is geen vervanging voor KQL queries achteraf, maar voor het in real-time volgen van een deployment of het opsporen van een actief probleem is het onmisbaar. Eén tip: laat het niet de hele dag open staan. Live Metrics kost extra resources op de function app.
Distributed tracing over meerdere functions
Een queue-triggered function die weer een HTTP call maakt naar een andere function — daar wordt het zonder tracing een chaos. Application Insights koppelt automatisch een operation_id aan gerelateerde telemetrie, maar alleen als de Activity context correct doorstroomt.
requests
| where operation_Id == "abc123"
| union dependencies
| where operation_Id == "abc123"
| order by timestamp asc
| project timestamp, itemType, name, duration, success
Die query laat de hele keten zien: van de eerste trigger tot de laatste dependency call. Handig om te zien waar de vertraging precies zit.
Kosten in de gaten houden
Application Insights rekent per GB ingested data. Bij high-throughput functions loopt dat snel op. Sampling verlaagt de kosten maar vermindert ook de zichtbaarheid. Een balans vinden is nodig.
Vuistregel: sample alles behalve failures. Foutscenario's wil je altijd volledig vastleggen. Succesvolle requests mogen gesampled worden — het patroon is toch zichtbaar in de aggregaties.
Het verschil tussen een serverless setup die werkt en eentje waar vertrouwen in is? Monitoring. Niet achteraf als het al fout gaat, maar vanaf dag één als onderdeel van de architectuur.
