/

OpenTelemetry Configuration

Configure OpenTelemetry to work with ByteHide Logger for comprehensive observability across your .NET applications. This setup enables automatic trace correlation and standardized log export.

Basic Setup

Program.cs Configuration

using OpenTelemetry;
using OpenTelemetry.Logs;
using OpenTelemetry.Trace;
using Bytehide.Logger;

var builder = WebApplication.CreateBuilder(args);

// Configure ByteHide Logger
Log.SetProjectToken("your-project-token");

// Configure OpenTelemetry
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddSource("YourApp"))
    .WithLogging(logging => logging
        .AddConsoleExporter())
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation());

var app = builder.Build();

Activity Source Setup

public class OrderService
{
    private static readonly ActivitySource ActivitySource = new("OrderService");
    
    public async Task ProcessOrderAsync(Order order)
    {
        using var activity = ActivitySource.StartActivity("ProcessOrder");
        activity?.SetTag("order.id", order.Id);
        
        Log.WithCorrelationId(Activity.Current?.TraceId.ToString())
           .WithMetadata("orderId", order.Id)
           .Info("Starting order processing");
        
        try
        {
            await ValidateOrderAsync(order);
            await SaveOrderAsync(order);
            
            Log.WithCorrelationId(Activity.Current?.TraceId.ToString())
               .Info("Order processing completed");
        }
        catch (Exception ex)
        {
            Log.WithCorrelationId(Activity.Current?.TraceId.ToString())
               .Error("Order processing failed", ex);
            throw;
        }
    }
}

ASP.NET Core Integration

Startup Configuration

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Configure ByteHide Logger
        Log.SetProjectToken(Configuration["ByteHide:ProjectToken"]);
        
        // Add OpenTelemetry
        services.AddOpenTelemetry()
            .WithTracing(builder => builder
                .SetSampler(new AlwaysOnSampler())
                .AddAspNetCoreInstrumentation(options =>
                {
                    options.RecordException = true;
                    options.Filter = httpContext => 
                        !httpContext.Request.Path.StartsWithSegments("/health");
                })
                .AddHttpClientInstrumentation()
                .AddEntityFrameworkCoreInstrumentation()
                .AddJaegerExporter());
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // Add correlation middleware
        app.UseMiddleware<CorrelationMiddleware>();
        
        // Other middleware...
    }
}

Correlation Middleware

public class CorrelationMiddleware
{
    private readonly RequestDelegate _next;
    
    public CorrelationMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        var correlationId = context.TraceIdentifier;
        
        // Set correlation ID for all logs in this request
        using var scope = new CorrelationScope(correlationId);
        
        Log.WithCorrelationId(correlationId)
           .WithMetadata("requestPath", context.Request.Path)
           .WithMetadata("requestMethod", context.Request.Method)
           .Info("Request started");
        
        try
        {
            await _next(context);
            
            Log.WithCorrelationId(correlationId)
               .WithMetadata("statusCode", context.Response.StatusCode)
               .Info("Request completed");
        }
        catch (Exception ex)
        {
            Log.WithCorrelationId(correlationId)
               .Error("Request failed", ex);
            throw;
        }
    }
}

Configuration Options

ByteHide Logger Settings

// Configure ByteHide Logger for OpenTelemetry
var logSettings = new LogSettings
{
    Persist = true,
    FilePath = "logs/app.log",
    ConsoleEnabled = true,
    IncludeCallerInfo = true,
    MinimumLevel = LogLevel.Info
};

Log.Configure(logSettings);
Log.SetProjectToken("your-project-token");

OpenTelemetry Trace Configuration

services.AddOpenTelemetry()
    .WithTracing(builder => builder
        .SetSampler(new TraceIdRatioBasedSampler(0.1)) // Sample 10% of traces
        .AddAspNetCoreInstrumentation(options =>
        {
            options.RecordException = true;
            options.EnrichWithHttpRequest = (activity, request) =>
            {
                activity.SetTag("http.request.user_agent", request.Headers.UserAgent.ToString());
            };
            options.EnrichWithHttpResponse = (activity, response) =>
            {
                activity.SetTag("http.response.content_type", response.ContentType);
            };
        })
        .AddHttpClientInstrumentation(options =>
        {
            options.RecordException = true;
        }));

Environment-Specific Configuration

Development Environment

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddOpenTelemetry()
        .WithTracing(tracing => tracing
            .AddConsoleExporter()
            .SetSampler(new AlwaysOnSampler()));
    
    // Enable detailed logging
    Log.Configure(new LogSettings
    {
        ConsoleEnabled = true,
        MinimumLevel = LogLevel.Debug,
        IncludeCallerInfo = true
    });
}

Production Environment

if (builder.Environment.IsProduction())
{
    builder.Services.AddOpenTelemetry()
        .WithTracing(tracing => tracing
            .AddJaegerExporter(options =>
            {
                options.AgentHost = "jaeger-agent";
                options.AgentPort = 6831;
            })
            .SetSampler(new TraceIdRatioBasedSampler(0.05))); // 5% sampling
    
    // Production logging settings
    Log.Configure(new LogSettings
    {
        Persist = true,
        FilePath = "/var/log/app/application.log",
        RollingInterval = RollingInterval.Day,
        MinimumLevel = LogLevel.Warn,
        ConsoleEnabled = false
    });
}

Automatic Correlation

HTTP Client Correlation

public class ApiClient
{
    private readonly HttpClient _httpClient;
    
    public ApiClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
    
    public async Task<T> GetAsync<T>(string endpoint)
    {
        using var activity = ActivitySource.StartActivity($"GET {endpoint}");
        var correlationId = Activity.Current?.TraceId.ToString();
        
        Log.WithCorrelationId(correlationId)
           .WithMetadata("endpoint", endpoint)
           .WithTags("http-client", "api-call")
           .Info("Making API request");
        
        try
        {
            var response = await _httpClient.GetAsync(endpoint);
            response.EnsureSuccessStatusCode();
            
            var content = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize<T>(content);
            
            Log.WithCorrelationId(correlationId)
               .WithMetadata("statusCode", (int)response.StatusCode)
               .Info("API request completed");
            
            return result;
        }
        catch (Exception ex)
        {
            Log.WithCorrelationId(correlationId)
               .Error("API request failed", ex);
            throw;
        }
    }
}

Database Operation Correlation

public class OrderRepository
{
    private static readonly ActivitySource ActivitySource = new("OrderRepository");
    
    public async Task<Order> GetOrderAsync(int orderId)
    {
        using var activity = ActivitySource.StartActivity("GetOrder");
        activity?.SetTag("order.id", orderId);
        
        var correlationId = Activity.Current?.TraceId.ToString();
        
        Log.WithCorrelationId(correlationId)
           .WithMetadata("orderId", orderId)
           .WithTags("database", "query")
           .Debug("Querying order from database");
        
        try
        {
            var order = await _context.Orders.FindAsync(orderId);
            
            if (order == null)
            {
                Log.WithCorrelationId(correlationId)
                   .WithMetadata("orderId", orderId)
                   .Warn("Order not found");
                throw new OrderNotFoundException(orderId);
            }
            
            Log.WithCorrelationId(correlationId)
               .Debug("Order retrieved successfully");
            
            return order;
        }
        catch (Exception ex)
        {
            Log.WithCorrelationId(correlationId)
               .Error("Database query failed", ex);
            throw;
        }
    }
}

Configuration Best Practices

Configuration Best Practices

  • Use environment variables: Store sensitive configuration in environment variables
  • Configure sampling: Use appropriate sampling rates for production (5-10%)
  • Enable exception recording: Set RecordException = true for better error tracking
  • Filter health checks: Exclude health check endpoints from tracing
  • Set resource attributes: Include service name, version, and environment information
  • Use correlation IDs consistently: Apply correlation IDs to all related operations

Troubleshooting

Missing Trace Correlation

// Ensure Activity.Current is available
if (Activity.Current == null)
{
    Log.Warn("No active Activity found - trace correlation may be missing");
}

// Use manual correlation ID if needed
var correlationId = Activity.Current?.TraceId.ToString() ?? Guid.NewGuid().ToString();
Log.WithCorrelationId(correlationId).Info("Manual correlation applied");

Performance Impact

// Use appropriate sampling to reduce overhead
services.AddOpenTelemetry()
    .WithTracing(builder => builder
        .SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(0.1))));

// Configure ByteHide Logger for production
Log.Configure(new LogSettings
{
    MinimumLevel = LogLevel.Warn, // Reduce log volume
    DuplicateSuppressionWindow = TimeSpan.FromMinutes(5) // Suppress duplicates
});

Next Steps

Previous
Overview