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

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    5 questions
    1BeginnerQuestionILogger log levels order?+

    Answer

    Trace, Debug, Information, Warning, Error, Critical.
    2BeginnerQuestionWhy structured logging?+

    Answer

    Queryable fields in log aggregation systems.
    3IntermediateQuestionLogger category purpose?+

    Answer

    Filter/configure verbosity per namespace/class.
    4IntermediateQuestionLogs vs metrics vs traces?+

    Answer

    Logs discrete events; metrics aggregated numbers; traces request flow spans.
    5AdvancedQuestionDesign logging for PCI-compliant payment service.+

    Answer

    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.