coder-csharp-logging

📁 ozerohax/assistagents 📅 9 days ago
1
总安装量
1
周安装量
#50041
全站排名
安装命令
npx skills add https://github.com/ozerohax/assistagents --skill coder-csharp-logging

Agent 安装分布

openclaw 1
opencode 1
cursor 1
qwen-code 1
gemini-cli 1

Skill 文档

<skill_overview> Implement effective logging and observability for .NET applications Setting up logging infrastructure Writing log statements Configuring Serilog Adding health checks Implementing distributed tracing Microsoft Logging Documentation Serilog Wiki </skill_overview> <log_levels> <use_for>Detailed debugging, method entry/exit, variable states</use_for> Never enabled <use_for>Development info, SQL queries, API calls</use_for> Rarely enabled <use_for>Application flow, business events, significant actions</use_for> Default level Order {OrderId} created for customer {CustomerId} <use_for>Recoverable issues, retries, deprecated usage</use_for> Always enabled Retrying API call, attempt {Attempt} <use_for>Failures requiring investigation, exceptions</use_for> Always enabled Failed to process payment for order {OrderId} <use_for>System failures, data loss, immediate attention needed</use_for> Always enabled + alerts Database connection lost </log_levels> <structured_logging> Use message templates, NOT string interpolation

[LoggerMessage(
    EventId = 2000,
    Level = LogLevel.Warning,
    Message = "Payment retry {Attempt} for order {OrderId}")]
public static partial void PaymentRetry(
    this ILogger logger, 
    int attempt, 
    string orderId);

[LoggerMessage(
    EventId = 3000,
    Level = LogLevel.Error,
    Message = "Failed to process order {OrderId}: {ErrorCode}")]
public static partial void OrderFailed(
    this ILogger logger, 
    string orderId, 
    string errorCode);

} // Usage _logger.OrderCreated(order.Id, order.CustomerId); _logger.PaymentRetry(attempt, orderId); </loggermessage_source_generator> Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override(“Microsoft”, LogEventLevel.Warning) .MinimumLevel.Override(“Microsoft.Hosting.Lifetime”, LogEventLevel.Information)

.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithProperty("Application", "MyApp")

.WriteTo.Console(outputTemplate: 
    "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")

.WriteTo.File("logs/app-.txt", 
    rollingInterval: RollingInterval.Day,
    retainedFileCountLimit: 30)

.WriteTo.Seq("http://localhost:5341")

.CreateLogger();

// ASP.NET Core integration builder.Host.UseSerilog(); // Request logging middleware app.UseSerilogRequestLogging(); <log_context> Add properties to all logs in a scope // In middleware – adds to all logs in request using (LogContext.PushProperty(“UserId”, userId)) using (LogContext.PushProperty(“CorrelationId”, correlationId)) { await next(context); } // All logs inside automatically include UserId and CorrelationId _logger.LogInformation(“Processing request”); // Output: UserId=123, CorrelationId=abc-def, Message=”Processing request” </log_context> <correlation_ids> public class CorrelationIdMiddleware { private readonly RequestDelegate _next;

public async Task InvokeAsync(HttpContext context)
{
    var correlationId = context.Request.Headers["X-Correlation-ID"]
        .FirstOrDefault() ?? Guid.NewGuid().ToString();
    
    context.Response.Headers["X-Correlation-ID"] = correlationId;
    
    using (LogContext.PushProperty("CorrelationId", correlationId))
    {
        await _next(context);
    }
}

} // Register before other middleware app.UseMiddleware<CorrelationIdMiddleware>(); </correlation_ids> <exception_logging> Always pass exception object to logger Include context (IDs, operation name) Don’t duplicate exception message in log message try { await ProcessOrderAsync(order); } catch (Exception ex) { _logger.LogError(ex, “Failed to process order {OrderId} for customer {CustomerId}”, order.Id, order.CustomerId); throw; } // WRONG: Missing exception object _logger.LogError(“Error: ” + ex.Message); // WRONG: Duplicating exception message _logger.LogError(ex, “Error: {Message}”, ex.Message); </exception_logging> <sensitive_data> <never_log> Passwords (even hashed) Credit card numbers Social security numbers API keys and secrets JWT tokens Personal health information </never_log> // Redact sensitive data before logging _logger.LogInformation(“User {Email} logged in from {IpAddress}”, RedactEmail(user.Email), RedactIp(ipAddress)); private string RedactEmail(string email) { var parts = email.Split(‘@’); return parts[0][..Math.Min(3, parts[0].Length)] + “***@” + parts[1]; } </sensitive_data> <health_checks> builder.Services.AddHealthChecks() .AddCheck(“self”, () => HealthCheckResult.Healthy()) .AddSqlServer(connectionString, name: “database”, tags: new[] { “db” }) .AddRedis(redisConnection, name: “redis”, tags: new[] { “cache” }) .AddUrlGroup(new Uri(“https://api.example.com/health“), name: “external-api”); // Endpoints app.MapHealthChecks(“/health”); // All checks app.MapHealthChecks(“/health/ready”, new HealthCheckOptions { Predicate = check => check.Tags.Contains(“ready”) }); app.MapHealthChecks(“/health/live”, new HealthCheckOptions { Predicate = check => check.Tags.Contains(“live”) }); <custom_check> public class ExternalApiHealthCheck : IHealthCheck { private readonly HttpClient _http;

public async Task&lt;HealthCheckResult&gt; CheckHealthAsync(
    HealthCheckContext context,
    CancellationToken ct = default)
{
    try
    {
        var response = await _http.GetAsync("/health", ct);
        return response.IsSuccessStatusCode
            ? HealthCheckResult.Healthy()
            : HealthCheckResult.Degraded($"Status: {response.StatusCode}");
    }
    catch (Exception ex)
    {
        return HealthCheckResult.Unhealthy("API unavailable", ex);
    }
}

} builder.Services.AddHealthChecks() .AddCheck<ExternalApiHealthCheck>(“external-api”); </custom_check> </health_checks> builder.Services.AddOpenTelemetry() .ConfigureResource(r => r.AddService(“MyApp”)) .WithTracing(tracing => { tracing.AddAspNetCoreInstrumentation(); tracing.AddHttpClientInstrumentation(); tracing.AddSqlClientInstrumentation(); tracing.AddSource(“MyApp”); }) .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation(); metrics.AddRuntimeInstrumentation(); metrics.AddMeter(“MyApp”); }); // Export to Azure Application Insights builder.Services.AddOpenTelemetry() .UseAzureMonitor(options => { options.ConnectionString = config[“APPLICATIONINSIGHTS_CONNECTION_STRING”]; }); <custom_activity> using var activity = Activity.StartActivity(“ProcessOrder”); activity?.SetTag(“order.id”, orderId); activity?.SetTag(“customer.id”, customerId); try { await ProcessAsync(); activity?.SetStatus(ActivityStatusCode.Ok); } catch (Exception ex) { activity?.RecordException(ex); activity?.SetStatus(ActivityStatusCode.Error, ex.Message); throw; } </custom_activity> <custom_metrics> public class OrderMetrics { private readonly Counter<long> _ordersProcessed; private readonly Histogram<double> _processingTime;

public OrderMetrics(IMeterFactory meterFactory)
{
    var meter = meterFactory.Create("MyApp.Orders");
    
    _ordersProcessed = meter.CreateCounter&lt;long&gt;(
        "orders.processed",
        description: "Number of orders processed");
    
    _processingTime = meter.CreateHistogram&lt;double&gt;(
        "order.processing.duration",
        unit: "ms",
        description: "Order processing time");
}

public void RecordOrderProcessed(string status) =&gt;
    _ordersProcessed.Add(1, new KeyValuePair&lt;string, object?&gt;("status", status));

public void RecordProcessingTime(double ms) =&gt;
    _processingTime.Record(ms);

} </custom_metrics>