Skip to main content

Overview

The Intent.OpenTelemetry module provides a comprehensive framework for integrating observability into your ASP.NET Core applications. With OpenTelemetry, you can collect and export telemetry data — including traces, metrics, and logs — to various observability backends, enhancing your ability to monitor application performance and diagnose issues.

What is OpenTelemetry?

OpenTelemetry is an open-source initiative for creating universal standards for telemetry data collection, including distributed tracing, metrics, and logging. By implementing OpenTelemetry, you gain valuable insights into how your system behaves in real time.

Why Use OpenTelemetry?

Applying OpenTelemetry in your applications allows you to:

Improve Performance Monitoring

Track and visualize request paths, system performance, and infrastructure health across distributed services.

Support Error Diagnosis

Identify where errors occur and understand the context in which they happen, including full request traces.

Visualize Metrics

Gain insights into application performance metrics over time, such as request latency, error rates, and throughput.

Vendor-Neutral

Use open standards to avoid vendor lock-in. Switch between observability platforms without code changes.

What Gets Generated

OpenTelemetry Configuration Class

A complete configuration class that sets up telemetry collection:
Infrastructure/Configuration/OpenTelemetryConfiguration.cs
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;

public static class OpenTelemetryConfiguration
{
    public static IServiceCollection AddTelemetryConfiguration(
        this IServiceCollection services, 
        IConfiguration configuration)
    {
        services.AddOpenTelemetry()
            .ConfigureResource(res => res
                .AddService(
                    serviceName: configuration["OpenTelemetry:ServiceName"]!,
                    serviceInstanceId: configuration.GetValue<string?>("OpenTelemetry:ServiceInstanceId")
                )
                .AddTelemetrySdk()
                .AddEnvironmentVariableDetector()
            )
            .WithTracing(trace => trace
                .AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddSqlClientInstrumentation()
                .AddOtlpExporter(opt =>
                {
                    opt.Endpoint = configuration.GetValue<Uri>("open-telemetry-protocol:endpoint")!;
                    opt.Protocol = configuration.GetValue<OtlpExportProtocol>("open-telemetry-protocol:protocol");
                })
            )
            .WithMetrics(metrics => metrics
                .AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddProcessInstrumentation()
                .AddRuntimeInstrumentation()
                .AddOtlpExporter(opt =>
                {
                    opt.Endpoint = configuration.GetValue<Uri>("open-telemetry-protocol:endpoint")!;
                    opt.Protocol = configuration.GetValue<OtlpExportProtocol>("open-telemetry-protocol:protocol");
                })
            );

        return services;
    }
}

Application Settings Configuration

Configuration entries in appsettings.json:
appsettings.json
{
  "OpenTelemetry": {
    "ServiceName": "MyApplication",
    "ServiceInstanceId": null
  },
  "open-telemetry-protocol": {
    "endpoint": "http://localhost:4317",
    "protocol": "Grpc"
  }
}

Startup Integration

Automatic registration in Program.cs:
Program.cs
builder.Services.AddTelemetryConfiguration(builder.Configuration);

Installation

Prerequisites

  • An ASP.NET Core application in Intent Architect
  • An observability backend (Azure Application Insights, Aspire Dashboard, Jaeger, etc.)

Installation Steps

1

Install the module

In Intent Architect, right-click on your application and select Manage Modules. Search for Intent.OpenTelemetry and install it.
2

Configure export options

In Application Settings, navigate to OpenTelemetry and select your export destination.
3

Run the Software Factory

Execute the Software Factory to generate the telemetry configuration.
4

Configure connection settings

Update appsettings.json with your observability backend endpoint and connection details.

Configuration

Export Options

The module supports multiple export destinations:

Azure Application Insights

Directly send telemetry to Azure Application Insights with native integration and Live Metrics support.

Azure Monitor Distro

Use the Azure-specific OpenTelemetry distribution for enhanced compatibility and Azure-native features.

OpenTelemetry Protocol (OTLP)

Export to any OTLP-compatible backend (Jaeger, Prometheus, Grafana, Aspire Dashboard, etc.).

Console

Log telemetry to the console for debugging or local development.

Telemetry Types

Configure what telemetry to capture:
  • Capture Traces: Monitor the journey of requests through your application with distributed tracing
  • Capture Metrics: Collect performance metrics like request counts, error rates, and latencies
  • Capture Logs: Integrate logs as part of your telemetry data, linking them to traces

Application Settings Configuration

Navigate to Application SettingsOpenTelemetry to configure:
  1. Export Method - Choose your observability backend
  2. Capture Traces - Enable/disable distributed tracing
  3. Capture Metrics - Enable/disable metrics collection
  4. Capture Logs - Enable/disable log integration
  5. Instrumentation Options:
    • ASP.NET Core (HTTP requests, middleware)
    • HTTP Client (outbound HTTP calls)
    • SQL Client (database queries)
    • Process metrics (CPU, memory)
    • .NET Runtime metrics (GC, threading)

Usage Examples

Azure Application Insights

Configuration:
appsettings.json
{
  "ApplicationInsights": {
    "ConnectionString": "InstrumentationKey=your-key-here;IngestionEndpoint=https://..."
  },
  "OpenTelemetry": {
    "ServiceName": "OrderManagementApi",
    "ServiceInstanceId": null
  }
}
Result: In Azure Application Insights, you’ll see:
  • Application Map: Visual representation of service dependencies
  • Transaction details: End-to-end request traces across microservices
  • Live Metrics: Real-time performance monitoring
  • Logs correlation: Logs linked to specific traces via Trace ID
Azure Application Insights

Aspire Dashboard (Local Development)

1

Pull the Docker image

docker pull mcr.microsoft.com/dotnet/aspire-dashboard
2

Run the container

docker run -d -p 18888:18888 -p 4317:18889 mcr.microsoft.com/dotnet/aspire-dashboard
3

Configure your application

appsettings.Development.json
{
  "open-telemetry-protocol": {
    "endpoint": "http://localhost:4317",
    "protocol": "Grpc"
  }
}
4

Access the dashboard

Open http://localhost:18888 in your browser to view traces, metrics, and logs.Aspire Dashboard

Trace ID in Error Responses

When errors occur, the Trace ID is returned in the response for easy lookup:
HTTP 500 Response
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
  "title": "An error occurred while processing your request.",
  "status": 500,
  "traceId": "00-25c51c5f8041f49df93f9ea880d4150d-abc123def456-01"
}
Extract the Operation ID (the segment between the first two dashes):
25c51c5f8041f49df93f9ea880d4150d
Search for this ID in your APM to find the complete trace: Trace ID from error responses

Distributed Tracing Example

Consider a microservices architecture with three services:
  1. API Gateway receives the request
  2. Order Service processes the order
  3. Inventory Service checks stock availability
With OpenTelemetry, you can visualize the entire request flow:
[API Gateway] 
  └─ POST /orders (200ms)
      ├─ [Order Service]
      │   └─ CreateOrder (150ms)
      │       ├─ Database Insert (50ms)
      │       └─ HTTP Call to Inventory (80ms)
      └─ [Inventory Service]
          └─ CheckStock (70ms)
              └─ Database Query (40ms)
Each service automatically propagates trace context, creating a unified view across all services.

Advanced Scenarios

Custom Spans

Add custom instrumentation to your code:
using System.Diagnostics;

public class OrderService
{
    private static readonly ActivitySource ActivitySource = new("OrderService");

    public async Task<Order> ProcessOrder(CreateOrderCommand command)
    {
        using var activity = ActivitySource.StartActivity("ProcessOrder");
        activity?.SetTag("order.customerId", command.CustomerId);
        activity?.SetTag("order.itemCount", command.Items.Count);

        try
        {
            var order = await CreateOrderAsync(command);
            activity?.SetTag("order.id", order.Id);
            return order;
        }
        catch (Exception ex)
        {
            activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
            throw;
        }
    }
}

Custom Metrics

Create application-specific metrics:
using System.Diagnostics.Metrics;

public class OrderMetrics
{
    private static readonly Meter Meter = new("OrderService");
    private static readonly Counter<int> OrdersCreated = Meter.CreateCounter<int>("orders.created");
    private static readonly Histogram<double> OrderValue = Meter.CreateHistogram<double>("orders.value");

    public void RecordOrderCreated(Order order)
    {
        OrdersCreated.Add(1, new KeyValuePair<string, object?>("status", order.Status));
        OrderValue.Record(order.TotalAmount, new KeyValuePair<string, object?>("currency", "USD"));
    }
}

Best Practices

Use Semantic Conventions

Follow OpenTelemetry semantic conventions for span names and attributes for consistency.

Sample in Production

Use sampling strategies to reduce telemetry volume in high-traffic production environments.

Correlate Logs and Traces

Always include Trace ID in logs to correlate log messages with distributed traces.

Monitor APM Costs

Be aware of telemetry ingestion costs, especially with cloud-based APM solutions.

Performance Considerations

  • Instrumentation overhead is typically < 5% for most applications
  • Use head-based sampling for high-throughput APIs
  • Export asynchronously to avoid blocking request processing
  • Batch telemetry data to reduce network overhead

Integration with Other Modules

Serilog

Logs are automatically included in traces when using Serilog with OpenTelemetry.

Entity Framework Core

SQL queries are traced automatically with the SQL Client instrumentation.

MassTransit

Message processing is traced across service boundaries in event-driven architectures.

HTTP Clients

Outbound HTTP calls are traced automatically with context propagation.

Troubleshooting

No Telemetry Appearing

Check configuration:
  1. Verify the endpoint URL is correct and accessible
  2. Ensure the export protocol matches your backend (Grpc vs. HttpProtobuf)
  3. Check that the service name is configured
Test with Console exporter:
"open-telemetry-protocol": {
  "endpoint": "",
  "protocol": "Grpc"
}
Switch to Console exporter in Application Settings to verify telemetry is being generated.

High Memory Usage

Reduce instrumentation:
  • Disable unused instrumentations (Process, Runtime if not needed)
  • Implement sampling for traces
  • Reduce metric collection interval

Missing Database Queries

Enable SQL instrumentation: Ensure “SQL Instrumentation” is enabled in Application Settings → OpenTelemetry configuration.

Next Steps

Serilog

Add structured logging to your application

Health Checks

Monitor application health endpoints

Azure Pipelines

Monitor deployments with telemetry

Build docs developers (and LLMs) love