Skip to main content

correlation-id-tracking

Manages correlation-id in .NET applications using AsyncLocal for async context isolation. Use when implementing correlation-id tracking, HTTP request/response correlation, logging integration, or when working with distributed tracing in .NET applications.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
whitebeardit/.cursor
آخر نشاط في المصدر
٣١ يناير ٢٠٢٦ في ٢٣:٠٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٢
التفرعات
٦

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
correlation-id-tracking
description
Manages correlation-id in .NET applications using AsyncLocal for async context isolation. Use when implementing correlation-id tracking, HTTP request/response correlation, logging integration, or when working with distributed tracing in .NET applications.
# Using Traceability Package for Correlation-ID Tracking This skill helps you use the **WhiteBeard.Traceability** NuGet package to implement correlation-id tracking in .NET applications. The package provides automatic correlation-id management with zero-configuration setup. ## Installation ```bash dotnet add package WhiteBeard.Traceability ``` Or via Package Manager: ```powershell Install-Package WhiteBeard.Traceability ``` ## Quick Setup ### ASP.NET Core (.NET 8) - Zero Configuration **Minimal setup (one line!):** ```csharp using Traceability.Extensions; var builder = WebApplication.CreateBuilder(args); // Zero configuration - everything is automatic! // - Middleware registered automatically // - HttpClient configured automatically // - Source from TRACEABILITY_SERVICENAME or assembly name builder.Services.AddTraceability(); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run(); ``` **With explicit service name:** ```csharp builder.Services.AddTraceability("MyService"); ``` **Done!** Correlation-id is now automatically: - ✅ Generated on each request (if not provided via `X-Correlation-Id` header) - ✅ Available via `CorrelationContext.Current` - ✅ Added to response headers as `X-Correlation-Id` - ✅ Propagated in HttpClient calls automatically - ✅ Included in logs (when logging is configured) ### ASP.NET Framework 4.8 - Zero Code **Just install the package - no code needed!** The library automatically: - ✅ Registers `CorrelationIdHttpModule` via `PreApplicationStartMethod` - ✅ Manages correlation-id automatically **Optional: Configure Serilog** ```csharp // Global.asax.cs using Traceability.Extensions; using Serilog; protected void Application_Start() { Log.Logger = new LoggerConfiguration() .WithTraceability("MyService") .WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Source} {CorrelationId} {Message:lj}{NewLine}{Exception}") .CreateLogger(); } ``` ## Using Correlation-ID in Code ### In Controllers ```csharp using Traceability; using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class ApiController : ControllerBase { [HttpGet("test")] public IActionResult Test() { // Correlation-id is automatically available var correlationId = CorrelationContext.Current; return Ok(new { CorrelationId = correlationId }); } } ``` ### In Console Applications ```csharp using Traceability; // Get or create correlation-ID var correlationId = CorrelationContext.GetOrCreate(); Console.WriteLine($"Correlation ID: {correlationId}"); // Correlation-id is preserved across async operations await SomeAsyncMethod(); var sameId = CorrelationContext.Current; // Still the same! ``` ### CorrelationContext API ```csharp // Get current (auto-creates if missing) var id = CorrelationContext.Current; // Check if exists without creating if (CorrelationContext.TryGetValue(out var correlationId)) { // Use existing correlation-ID } // Set explicitly CorrelationContext.Current = "existing-correlation-id"; // Clear context CorrelationContext.Clear(); ``` ## HttpClient Integration **Automatic propagation - no extra code needed!** ```csharp // In Program.cs builder.Services.AddTraceability(); builder.Services.AddHttpClient("ExternalApi", client => { client.BaseAddress = new Uri("https://api.example.com/"); }); // In Controller var client = _httpClientFactory.CreateClient("ExternalApi"); // Correlation-id is automatically added to X-Correlation-Id header! var response = await client.GetAsync("posts/1"); ``` The `CorrelationIdHandler` is automatically registered - all HttpClient instances created via `IHttpClientFactory` will include the correlation-ID header. ## Logging Integration ### Serilog ```csharp using Traceability.Logging; using Serilog; Log.Logger = new LoggerConfiguration() .Enrich.With<CorrelationIdEnricher>() .WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {CorrelationId} {Message:lj}{NewLine}{Exception}") .CreateLogger(); // Now all logs automatically include CorrelationId property logger.LogInformation("Processing request"); // Output: [12:34:56 INF] a1b2c3d4e5f6789012345678901234ab Processing request ``` ### Microsoft.Extensions.Logging ```csharp using Traceability.Logging; builder.Services.AddTraceability(); builder.Logging.AddConsole(options => options.IncludeScopes = true); // CorrelationIdScopeProvider is automatically registered // Logs automatically include correlation-ID in scope logger.LogInformation("Processing request"); ``` ## Logging Best Practices ### Log Levels: When to Use Each **DEBUG** - Development and troubleshooting only: - Detailed execution flow - Variable values and intermediate states - Step-by-step process information - **Not visible in production** (typically filtered out) **INFO** - Production-ready, important events: - Request start/completion - Business operations (create, update, delete) - External API calls (start/end) - Important state changes - **Visible in production** **WARNING** - Potential issues that don't break functionality: - Retry attempts - Fallback to default values - Deprecated API usage - Performance degradation **ERROR** - Failures that need attention: - Exceptions and errors - Failed operations - External service failures ### What to Log (and What NOT to Log) **✅ DO Log:** - Request identifiers (correlation-ID, user ID, request ID) - Business operations (what happened) - External service calls (start, end, duration) - Important state changes - Errors with context (correlation-ID, user, operation) **❌ DON'T Log:** - Sensitive data (passwords, tokens, PII, credit cards) - Large payloads (use summaries instead) - Every iteration in loops (log once per operation) - Redundant information (correlation-ID is already in context) - Excessive detail in production (use DEBUG for that) ### Structured Logging with Correlation-ID Always include correlation-ID in logs for traceability: ```csharp // ✅ Good: Structured logging with correlation-ID _logger.LogInformation( "Processing order {OrderId} for user {UserId}. CorrelationId: {CorrelationId}", orderId, userId, CorrelationContext.Current); // ✅ Good: Using structured properties _logger.LogInformation( "External API call completed. Endpoint: {Endpoint}, Duration: {Duration}ms, StatusCode: {StatusCode}", endpoint, duration, statusCode); // ❌ Bad: Logging without correlation-ID context _logger.LogInformation($"Processing order {orderId}"); // Missing correlation-ID! // ❌ Bad: Logging sensitive data _logger.LogInformation($"User password: {password}"); // NEVER log passwords! ``` ### Production vs Development Logging **Production Configuration:** ```csharp // appsettings.Production.json { "Logging": { "LogLevel": { "Default": "Information", // INFO and above "Microsoft": "Warning", // Reduce framework noise "System": "Warning" } } } ``` **Development Configuration:** ```csharp // appsettings.Development.json { "Logging": { "LogLevel": { "Default": "Debug", // DEBUG and above "Microsoft": "Information", "System": "Information" } } } ``` ### Logging Patterns for Debugging **Pattern 1: Request Lifecycle** ```csharp [HttpGet("orders/{id}")] public async Task<IActionResult> GetOrder(int id) { var correlationId = CorrelationContext.Current; // ✅ INFO: Request start (production-visible) _logger.LogInformation( "Getting order {OrderId}. CorrelationId: {CorrelationId}", id, correlationId); try { // ✅ DEBUG: Detailed steps (development only) _logger.LogDebug( "Querying database for order {OrderId}. CorrelationId: {CorrelationId}", id, correlationId); var order = await _repository.GetByIdAsync(id); if (order == null) { // ✅ WARNING: Expected but notable condition _logger.LogWarning( "Order {OrderId} not found. CorrelationId: {CorrelationId}", id, correlationId); return NotFound(); } // ✅ INFO: Successful completion (production-visible) _logger.LogInformation( "Order {OrderId} retrieved successfully. CorrelationId: {CorrelationId}", id, correlationId); return Ok(order); } catch (Exception ex) { // ✅ ERROR: Always log exceptions with correlation-ID _logger.LogError(ex, "Error retrieving order {OrderId}. CorrelationId: {CorrelationId}", id, correlationId); return StatusCode(500); } } ``` **Pattern 2: External Service Calls** ```csharp public async Task<PaymentResult> ProcessPayment(PaymentRequest request) { var correlationId = CorrelationContext.Current; // ✅ INFO: External call start (production-visible) _logger.LogInformation( "Calling payment service. Amount: {Amount}, Currency: {Currency}. CorrelationId: {CorrelationId}", request.Amount, request.Currency, correlationId); var stopwatch = Stopwatch.StartNew(); try { var response = await _paymentClient.ProcessAsync(request); stopwatch.Stop(); // ✅ INFO: Success with duration (production-visible) _logger.LogInformation( "Payment service call completed. Status: {Status}, Duration: {Duration}ms. CorrelationId: {CorrelationId}", response.Status, stopwatch.ElapsedMilliseconds, correlationId); return response; } catch (Exception ex) { stopwatch.Stop(); // ✅ ERROR: Failure with context (production-visible) _logger.LogError(ex, "Payment service call failed. Duration: {Duration}ms. CorrelationId: {CorrelationId}", stopwatch.ElapsedMilliseconds, correlationId); throw; } } ``` **Pattern 3: Conditional Debug Logging** ```csharp public async Task ProcessItems(List<Item> items) { var correlationId = CorrelationContext.Current; // ✅ INFO: Operation start (production-visible) _logger.LogInformation( "Processing {Count} items. CorrelationId: {CorrelationId}", items.Count, correlationId); for (int i = 0; i < items.Count; i++) { // ✅ DEBUG: Detailed per-item info (development only) _logger.LogDebug( "Processing item {Index}/{Total}: {ItemId}. CorrelationId: {CorrelationId}", i + 1, items.Count, items[i].Id, correlationId); await ProcessItem(items[i]); } // ✅ INFO: Operation completion (production-visible) _logger.LogInformation( "Processed {Count} items successfully. CorrelationId: {CorrelationId}", items.Count, correlationId); } ``` ### Key Principles 1. **Correlation-ID Always**: Every log should include correlation-ID (automatically via enricher/scope) 2. **Structured Properties**: Use structured logging with named properties, not string interpolation 3. **Context Matters**: Include relevant context (user ID, operation, IDs) but not sensitive data 4. **Level Appropriately**: Use DEBUG for detailed troubleshooting, INFO for production visibility 5. **Performance Aware**: Don't log in tight loops; summarize instead 6. **Error Context**: Always include correlation-ID and relevant context in error logs ## Environment Variables Set service name via environment variable to reduce code: **Linux/Mac:** ```bash export TRACEABILITY_SERVICENAME="UserService" ``` **Windows PowerShell:** ```powershell $env:TRACEABILITY_SERVICENAME="UserService" ``` Then use: ```csharp // Source comes automatically from TRACEABILITY_SERVICENAME builder.Services.AddTraceability(); ``` ## Common Patterns ### Pattern 1: Reading Correlation-ID from Request The middleware automatically: 1. Reads `X-Correlation-Id` from incoming request headers 2. If present, uses that value 3. If missing, generates new GUID (32 chars, no hyphens) 4. Sets `CorrelationContext.Current` 5. Adds to response headers **No code needed** - this happens automatically! ### Pattern 2: Preserving Across Async Operations ```csharp var correlationId = CorrelationContext.Current; // "abc123" await SomeAsyncMethod(); var sameId = CorrelationContext.Current; // Still "abc123" - preserved! ``` ### Pattern 3: Isolated Contexts ```csharp var mainId = CorrelationContext.Current; // "id1" await Task.Run(async () => { // New isolated context - no correlation-ID unless set if (!CorrelationContext.HasValue) { CorrelationContext.Current = "id2"; } }); ``` ### Pattern 4: Manual Propagation ```csharp // Set correlation-ID from external source CorrelationContext.Current = externalCorrelationId; // Now all operations use this correlation-ID await ProcessRequest(); ``` ## Key Features 1. **Zero Configuration**: Works out of the box with minimal setup 2. **Async-Safe**: Uses `AsyncLocal<string>` to preserve correlation-ID across async/await
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub