04 - Logging and Monitoring (Dedicated)¶
Enable production-grade observability with Application Insights, structured logs, and baseline alerting for .NET isolated worker handlers.
Prerequisites¶
| Tool | Version | Purpose |
|---|---|---|
| .NET SDK | 8.0 (LTS) | Build and run isolated worker functions |
| Azure Functions Core Tools | v4 | Start local host and publish artifacts |
| Azure CLI | 2.61+ | Provision Azure resources and inspect app state |
Dedicated plan basics
Dedicated (App Service Plan) runs on pre-provisioned compute with predictable cost. Always On keeps the host loaded for non-HTTP triggers. Supports VNet integration and deployment slots on eligible SKUs. No execution timeout limit.
What You'll Build¶
You will instrument .NET isolated worker handlers with structured logs via ILogger<T>, route telemetry to Application Insights, and validate query-based monitoring signals for a Dedicated-hosted app.
flowchart LR
A["ILogger<T> in handler"] --> B[FunctionAppLogs]
B --> C[Application Insights]
C --> D[Dashboards and alerts] Steps¶
Step 1 - Emit structured logs in handler methods¶
The .NET isolated worker uses constructor-injected ILogger<T> for structured logging. Here is the LogLevelsFunction that emits at multiple severity levels:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace AzureFunctionsGuide.Functions;
public class LogLevelsFunction
{
private readonly ILogger<LogLevelsFunction> _logger;
public LogLevelsFunction(ILogger<LogLevelsFunction> logger)
{
_logger = logger;
}
[Function("logLevels")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "loglevels")] HttpRequest req)
{
_logger.LogDebug("Debug level log message");
_logger.LogInformation("Info level log message");
_logger.LogWarning("Warning level log message");
_logger.LogError("Error level log message");
_logger.LogCritical("Critical level log message");
return new OkObjectResult(new { logged = true });
}
}
Step 2 - Register Application Insights in the isolated worker¶
The Program.cs must register Application Insights services for telemetry collection:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.Build();
host.Run();
Isolated worker telemetry packages
The reference app includes Microsoft.ApplicationInsights.WorkerService and Microsoft.Azure.Functions.Worker.ApplicationInsights packages in the .csproj for telemetry collection.
Step 3 - Generate telemetry by calling endpoints¶
# Trigger structured logging
curl --request GET "https://$APP_NAME.azurewebsites.net/api/loglevels"
# Trigger health check
curl --request GET "https://$APP_NAME.azurewebsites.net/api/health"
# Trigger intentional errors for error telemetry
curl --request GET "https://$APP_NAME.azurewebsites.net/api/testerror"
Telemetry ingestion delay
Application Insights telemetry takes 2-5 minutes to become available for queries after the first request. Wait before running queries.
Step 4 - Confirm Application Insights connection¶
Application Insights is auto-created with the function app. Verify the connection:
az functionapp config appsettings list \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "[?name=='APPLICATIONINSIGHTS_CONNECTION_STRING'].value" \
--output tsv
Step 5 - Query recent traces¶
az monitor app-insights query \
--app "$APP_NAME" \
--resource-group "$RG" \
--analytics-query "traces | where timestamp > ago(30m) | project timestamp, message, severityLevel | order by timestamp desc | take 20"
Use function app name for --app
Since Application Insights is auto-created with the same name as the function app, use --app "$APP_NAME" for queries. Add --resource-group "$RG" to avoid ambiguity.
Step 6 - Query request metrics¶
az monitor app-insights query \
--app "$APP_NAME" \
--resource-group "$RG" \
--analytics-query "requests | where timestamp > ago(30m) | project timestamp, name, resultCode, duration | order by timestamp desc | take 20"
Step 7 - View live log stream¶
Streaming logs work on Dedicated
Unlike Consumption and Flex Consumption plans where az webapp log tail returns 404 errors, Dedicated plans keep the host always running. Streaming logs connect immediately and show real-time output including host startup, function invocations, and worker logs.
Sample streaming log output:
2026-04-09T18:39:09 Welcome, you are now connected to log-streaming service.
Starting Log Tail -n 10 of existing logs ----
2026-04-09T18:39:09.970Z Hosting environment: Production
2026-04-09T18:39:09.970Z Content root path: /azure-functions-host
2026-04-09T18:39:09.978Z Now listening on: http://[::]:80
2026-04-09T18:39:09.979Z Application started. Press Ctrl+C to shut down.
Ending Log Tail of existing logs ---
Starting Live Log Stream ---
Step 8 - Add an alert for HTTP 5xx spikes¶
FUNCTION_APP_ID=$(az functionapp show \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "id" \
--output tsv)
az monitor metrics alert create \
--name "func-dotnet-ded-http5xx" \
--resource-group "$RG" \
--scopes "$FUNCTION_APP_ID" \
--condition "total Http5xx > 5" \
--window-size 5m \
--evaluation-frequency 1m
Verification¶
Traces query output:
timestamp message severityLevel
--------------------------- -------------------------------- -------------
2026-04-09T18:44:20.000Z Info level log message 1
2026-04-09T18:44:20.000Z Warning level log message 2
2026-04-09T18:44:20.000Z Error level log message 3
2026-04-09T18:44:20.000Z Critical level log message 4
Requests query output:
timestamp name resultCode duration
--------------------------- -------------- ---------- --------
2026-04-09T18:44:20.000Z logLevels 200 45.12
2026-04-09T18:44:19.000Z health 200 12.34
2026-04-09T18:44:18.000Z testError 500 8.56
LogLevels endpoint response:
Next Steps¶
See Also¶
- Tutorial Overview & Plan Chooser
- .NET Language Guide
- Platform: Hosting Plans
- Operations: Deployment
- Recipes Index