C# Programming Tutorial 0/45 lessons ~6 min read Lesson 42

    Logging

    ILogger<T> structured logging integrates Console, Debug, EventSource, and third-party sinks (Serilog, Application Insights).

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    ILogger<T> structured logging integrates Console, Debug, EventSource, and third-party sinks (Serilog, Application Insights). Log levels Trace→Critical filter noise; structured placeholders enable queryable logs.

    Never log passwords or PAN. Correlation IDs trace requests across microservices. Interviewers ask log levels and difference from metrics/tracing.

    The story

    When a bank transfer fails at 2 AM, on-call engineers search centralized logs by account IDs — not by parsing free-text messages. Structured logging with scopes attaches FromAccount and ToAccount to every log line in the transfer operation, and message templates like {Amount} make amounts queryable in Seq or Application Insights.

    Understanding the topic

    Key concepts

    • ILogger LogInformation LogWarning LogError.
    • Structured: LogInformation('Order {OrderId} placed', id).
    • LogLevel hierarchy filters minimum level.
    • Category named after T in ILogger.
    • Scopes push properties for nested operations.
    • OpenTelemetry bridges logs, metrics, traces.
    text
    flowchart LR
    App --> ILogger
    ILogger --> Providers[Console / File / Seq]
    Providers --> Aggregation[Centralized Logs]

    Step-by-step explanation

    1. Register logging in WebApplication.CreateBuilder.
    2. Inject ILogger constructor.
    3. Configuration appsettings Logging:LogLevel.
    4. Serilog replaces default via UseSerilog.
    5. BeginScope adds correlationId for request.
    6. Exception overload logs stack and inner.

    Practical code example

    Structured logging with scopes in ASP.NET Core service:

    csharp
    namespace TechLearningPro.Logging;
    public sealed class TransferService(ILogger<TransferService> logger, IBankRepository repo)
    {
    public async Task<bool> TransferAsync(Guid from, Guid to, decimal amount, CancellationToken ct)
    {
    using (logger.BeginScope(new Dictionary<string, object>
    {
    ["FromAccount"] = from,
    ["ToAccount"] = to
    }))
    {
    logger.LogInformation("Transfer started for amount {Amount}", amount);
    try
    {
    await repo.TransferAsync(from, to, amount, ct);
    logger.LogInformation("Transfer completed");
    return true;
    }
    catch (Exception ex)
    {
    logger.LogError(ex, "Transfer failed for amount {Amount}", amount);
    throw;
    }
    }
    }
    }

    Line-by-line code explanation

    • TransferService(ILogger<TransferService> logger, IBankRepository repo) injects a typed logger category.
    • logger.BeginScope(new Dictionary<string, object> { ... }) pushes scope properties for nested log lines.
    • ["FromAccount"] = from attaches structured context visible in log aggregation tools.
    • using (...) disposes the scope when the transfer block exits — even on exceptions.
    • logger.LogInformation("Transfer started for amount {Amount}", amount) uses a template — not string interpolation.
    • await repo.TransferAsync(from, to, amount, ct) performs the actual database transfer.
    • logger.LogInformation("Transfer completed") records success within the same scope.
    • catch (Exception ex) logger.LogError(ex, "Transfer failed...") logs the exception object with stack trace.
    • throw; rethrows after logging so callers and middleware can still handle the failure.

    Key takeaway: Message templates use {Name} placeholders — not string interpolation — for structured querying in Seq/Application Insights.

    Real-world use

    Where you'll use this in production

    • Production incident debugging with correlation ID.
    • Audit trails complementing security logs.
    • Performance slow query logging in EF.
    • Centralized ELK/Splunk aggregation.

    Best practices

    • Use structured logging templates.
    • Correct level — Error for failures, Information for business events.
    • Redact PII and secrets.
    • Include correlation ID middleware early.
    • Sample verbose logs in high-traffic paths.

    Common mistakes

    • String interpolation destroys structured properties.
    • Logging inside tight loops at Information.
    • Swallowing exceptions without LogError.
    • Logging full credit card numbers.

    Advanced interview questions

    Q1BeginnerILogger log levels order?
    Trace, Debug, Information, Warning, Error, Critical.
    Q2BeginnerWhy structured logging?
    Queryable fields in log aggregation systems.
    Q3IntermediateLogger category purpose?
    Filter/configure verbosity per namespace/class.
    Q4IntermediateLogs vs metrics vs traces?
    Logs discrete events; metrics aggregated numbers; traces request flow spans.
    Q5AdvancedDesign logging for PCI-compliant payment service.
    No PAN/CVV; tokenized IDs only; separate audit log immutable store; retention policy; access controls.

    Summary

    ILogger provides structured categorized logging. Use message templates and appropriate levels. Scopes and correlation IDs aid distributed tracing. Never log secrets or excessive PII. Next: unit testing with xUnit.

    Ready to mark this lesson complete?Track your journey across the entire course.