Application Insights Integration

January 24, 2026 · View on GitHub

The Durable Task Framework provides deep integration with Azure Application Insights for monitoring, diagnostics, and performance analysis.

Installation

dotnet add package Microsoft.Azure.DurableTask.ApplicationInsights
dotnet add package Microsoft.ApplicationInsights

Setup

Basic Configuration

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Azure.DurableTask.ApplicationInsights;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();

// Add Application Insights
services.AddApplicationInsightsTelemetryWorkerService(options =>
{
    options.ConnectionString = "InstrumentationKey=your-key;...";
});

// Add DurableTask telemetry module for distributed tracing
services.TryAddEnumerable(
    ServiceDescriptor.Singleton<ITelemetryModule, DurableTelemetryModule>());

var serviceProvider = services.BuildServiceProvider();

ASP.NET Core Integration

// In Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add Application Insights
builder.Services.AddApplicationInsightsTelemetry();

// Add DurableTask telemetry module
builder.Services.TryAddEnumerable(
    ServiceDescriptor.Singleton<ITelemetryModule, DurableTelemetryModule>());

var app = builder.Build();

Console Application

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Azure.DurableTask.ApplicationInsights;
using DurableTask.Core;
using DurableTask.Emulator;

// Configure Application Insights
var configuration = TelemetryConfiguration.CreateDefault();
configuration.ConnectionString = "InstrumentationKey=...";

// Add the DurableTask telemetry module
var module = new DurableTelemetryModule();
module.Initialize(configuration);

var telemetryClient = new TelemetryClient(configuration);

// Create logger factory for diagnostics
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Information);
});

// Create DTFx components
var service = new LocalOrchestrationService();
var worker = new TaskHubWorker(service, loggerFactory);
worker.AddTaskOrchestrations(typeof(MyOrchestration));
worker.AddTaskActivities(typeof(MyActivity));

await worker.StartAsync();

// ... run orchestrations ...

await worker.StopAsync();

// Ensure telemetry is flushed
telemetryClient.Flush();
await Task.Delay(TimeSpan.FromSeconds(5));

What Gets Tracked

Automatic Telemetry

The DurableTelemetryModule automatically tracks:

Telemetry TypeDescription
RequestsOrchestration and activity executions
DependenciesActivity calls, sub-orchestrations
TracesLog messages from DTFx
ExceptionsFailures in orchestrations and activities
Custom EventsOrchestration lifecycle events

Distributed Tracing

Operations are automatically correlated:

Request: OrderOrchestration (parent)
├── Dependency: ValidateOrderActivity
├── Dependency: ProcessPaymentActivity
├── Dependency: ShippingOrchestration (sub-orchestration)
│   └── Dependency: CreateShipmentActivity
└── Dependency: SendConfirmationActivity

Custom Telemetry

Adding Custom Properties

public class OrderOrchestration : TaskOrchestration<OrderResult, OrderInput>
{
    private readonly TelemetryClient _telemetryClient;
    
    public OrderOrchestration(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient;
    }
    
    public override async Task<OrderResult> RunTask(
        OrchestrationContext context, 
        OrderInput input)
    {
        // Track custom event
        if (!context.IsReplaying)
        {
            _telemetryClient.TrackEvent("OrderProcessingStarted", new Dictionary<string, string>
            {
                ["InstanceId"] = context.OrchestrationInstance.InstanceId,
                ["OrderId"] = input.OrderId,
                ["CustomerId"] = input.CustomerId
            });
        }
        
        // ... orchestration logic ...
        
        if (!context.IsReplaying)
        {
            _telemetryClient.TrackEvent("OrderProcessingCompleted", new Dictionary<string, string>
            {
                ["InstanceId"] = context.OrchestrationInstance.InstanceId,
                ["OrderId"] = input.OrderId,
                ["Status"] = "Success"
            });
        }
        
        return result;
    }
}

Tracking Metrics

if (!context.IsReplaying)
{
    _telemetryClient.TrackMetric("OrderProcessingDuration", 
        (context.CurrentUtcDateTime - startTime).TotalMilliseconds);
    
    _telemetryClient.TrackMetric("OrderItemCount", input.Items.Count);
}

Tracking Exceptions

try
{
    await context.ScheduleTask<string>(typeof(RiskyActivity), input);
}
catch (TaskFailedException ex)
{
    if (!context.IsReplaying)
    {
        _telemetryClient.TrackException(ex.InnerException, new Dictionary<string, string>
        {
            ["InstanceId"] = context.OrchestrationInstance.InstanceId,
            ["ActivityName"] = ex.Name
        });
    }
    throw;
}

Querying Data

Kusto Queries (Log Analytics)

Orchestration execution times:

requests
| where name contains "orchestration"
| summarize avg(duration), percentile(duration, 95) by name
| order by avg_duration desc

Failed orchestrations:

requests
| where name contains "orchestration" and success == false
| project timestamp, name, duration, customDimensions
| order by timestamp desc

Activity performance:

dependencies
| where type == "DurableTask"
| summarize count(), avg(duration) by name
| order by count_ desc

End-to-end traces:

union requests, dependencies, traces
| where operation_Id == "your-operation-id"
| order by timestamp asc
| project timestamp, itemType, name, message, duration

Live Metrics

Application Insights Live Metrics shows real-time:

  • Incoming request rate
  • Failure rate
  • Dependency call duration
  • Server response time

Enable Live Metrics in your configuration:

services.AddApplicationInsightsTelemetryWorkerService(options =>
{
    options.ConnectionString = "...";
    options.EnableLiveMetrics = true;
});

Alerts

Configure alerts for common scenarios:

High Failure Rate

requests
| where name contains "orchestration"
| summarize failureCount = countif(success == false), totalCount = count() by bin(timestamp, 5m)
| extend failureRate = failureCount * 100.0 / totalCount
| where failureRate > 5

Long-Running Orchestrations

requests
| where name contains "orchestration"
| where duration > 300000  // 5 minutes
| project timestamp, name, duration, operation_Id

Stuck Orchestrations

Monitor for orchestrations that haven't progressed:

customEvents
| where name == "OrchestrationStarted"
| join kind=leftanti (
    customEvents
    | where name == "OrchestrationCompleted"
    | project completedInstanceId = tostring(customDimensions["InstanceId"])
) on $left.customDimensions["InstanceId"] == $right.completedInstanceId
| where timestamp < ago(1h)

Sampling

For high-volume scenarios, configure sampling:

services.AddApplicationInsightsTelemetryWorkerService(options =>
{
    options.ConnectionString = "...";
});

services.Configure<TelemetryConfiguration>(config =>
{
    config.DefaultTelemetrySink.TelemetryProcessorChainBuilder
        .UseAdaptiveSampling(maxTelemetryItemsPerSecond: 5)
        .Build();
});

Best Practices

1. Use IsReplaying for Custom Telemetry

if (!context.IsReplaying)
{
    _telemetryClient.TrackEvent("CustomEvent");
}

2. Include Correlation IDs

_telemetryClient.TrackEvent("OrderProcessed", new Dictionary<string, string>
{
    ["InstanceId"] = context.OrchestrationInstance.InstanceId,
    ["OrderId"] = input.OrderId
});

3. Flush Before Shutdown

await worker.StopAsync();
telemetryClient.Flush();
await Task.Delay(TimeSpan.FromSeconds(5));  // Allow time for flush

4. Monitor Key Metrics

  • Orchestration success/failure rate
  • Activity duration
  • Queue depth (if applicable)
  • Concurrent orchestrations

Samples

See the complete working sample:

Next Steps