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
C#
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();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
C#
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;
}
}
}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
C#
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...
}
}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
C#
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;
}
}
}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
C#
// 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");// 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
C#
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;
}));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
C#
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
});
}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
C#
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
});
}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
C#
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;
}
}
}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
C#
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;
}
}
}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 = truefor 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
C#
// 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");// 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
C#
// 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
});// 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
- Exporter Setup - Configure exporters for different backends
- Best Practices - Optimize your observability setup
- Correlation IDs - Learn more about correlation strategies