CodeGym /Corsi /C# SELF /Logging: Microsoft.Extensions.Logging

Logging: Microsoft.Extensions.Logging

C# SELF
Livello 64, Lezione 0
Disponibile

1. Introduzione

Nel programming il logging non è semplicemente "stampare qualcosa sulla console". Il logging è la tua black box, il tuo GPS-tracker e il tuo indicatore tutto in uno. Senza log una grande applicazione diventa una scatola nera-misteriosa: "perché il servizio si è bloccato?", "perché l'utente non ha ricevuto la mail?", "ma qualcuno ha lanciato questo modulo negli ultimi 3 mesi?" — a tutte queste domande spesso si può rispondere solo se i log vengono conservati e sono accessibili.

Perché il logging serve nella realtà?

Cerca e diagnosi degli errori
Se il programma è crashato — i log diranno dove e perché. Se non è crashato ma si comporta in modo strano — i log indicheranno i passi che hanno portato a quel comportamento.

Monitoring dello stato
Attraverso i log puoi sapere se il sistema è operativo ora, quanti request arrivano al server, se ci sono errori, chi e cosa sta facendo.

Sicurezza
Logging dei tentativi di accesso non autorizzato, attività sospette, errori di autenticazione.

Audit
Chi, cosa e quando ha fatto qualcosa. Se se ne va un admin cattivo e cancella dei dati, dai log si può ricostruire tutto (o almeno capire cosa ha fatto).

Supporto nello sviluppo e nelle operations
I log non sono solo per il programmatore, ma anche per il tester, l'operatore, l'amministratore. Tra sei mesi ti ringrazierai: 'Grazie per aver aggiunto i log!'

Da Console.WriteLine al logging di produzione

La reazione iniziale del principiante: "Davvero, non basta solo Console.WriteLine?". Per piccoli programmi didattici spesso basta. Ma quando l'app gira su un server, opera in parallelo, o viene usata da decine o centinaia di utenti, la console non è più sufficiente. Serve:

  • Separare le informazioni importanti da quelle di debug.
  • Inviare i log non solo alla console, ma anche a file, database, sistemi centralizzati.
  • Modificare il livello di dettaglio dei log (minimo — solo errori, massimo — tutto).
  • Arricchire automaticamente le entry con data, ora e metadati.
  • Configurare in modo flessibile.
  • E soprattutto — non cambiare il codice per reindirizzare i log altrove.

Qui inizia l'era dei logger "veri".

2. Fondamenti di un sistema di logging moderno in .NET

Nell'ecosistema .NET esiste un framework standard, potente e flessibile per il logging — Microsoft.Extensions.Logging. Fa parte della "nuova ondata" di librerie .NET arrivate con ASP.NET Core, ma oggi si usa ovunque: server, desktop e persino mobile.

Perché questo framework è buono?

  • Astrattazione — non ti lega a un'implementazione specifica (il logger può scrivere su file, console, cloud, o su tutto contemporaneamente).
  • Supporto dei livelli di logging (Trace, Debug, Information, Warning, Error, Critical).
  • Integrazione nel DI-container e supporto per tutte le moderne applicazioni .NET.
  • Ecologia ricca di estensioni: supporto per logging strutturato, formatter avanzati e integrazioni.

Concetti e classi principali

Conosciamo gli oggetti chiave che ci serviranno per lavorare con Microsoft.Extensions.Logging:

Classe/Interfaccia Scopo
ILogger<T>
Interfaccia per il logging, tipizzata per classe
ILogger
Interfaccia generica del logger
ILoggerFactory
Factory per creare istanze di logger
ILoggingBuilder
Permette di configurare il logging nell'applicazione
LogLevel
Enumerazione dei livelli di log (Trace, Debug, Information, ...)

Livelli di logging

La separazione dei messaggi per livello di importanza permette di filtrare il "rumore" e trovare ciò che serve:

Livello (LogLevel) Quando usarlo?
Trace
Debug estremamente dettagliato, "rumore", dati temporanei
Debug
Informazioni principali di debugging
Information
Messaggi chiave di eventi per il normale funzionamento
Warning
Avvisi su potenziali problemi, ma il sistema continua
Error
Errori che richiedono attenzione, ma l'app è ancora viva
Critical
Guasti critici che minacciano l'intero sistema

3. Pratica: aggiungiamo il logging alla nostra applicazione

Non scriviamo codice astratto: continuiamo con la nostra applicazione demo. Supponiamo di avere già una semplice classe Calculator che estendiamo durante il corso.

Esempio: calcolatore base

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
    // Altri metodi...
}

Ora integreremo il logging. Ci serve l'interfaccia ILogger<Calculator>, che riceveremo dall'esterno (per esempio via Dependency Injection, DI).

using Microsoft.Extensions.Logging;

public class Calculator
{
    private readonly ILogger<Calculator> _logger;

    public Calculator(ILogger<Calculator> logger)
    {
        _logger = logger;
    }

    public int Add(int a, int b)
    {
        int result = a + b;
        _logger.LogInformation("Eseguita somma: {A} + {B} = {Result}", a, b, result);
        return result;
    }
}

Curiosità:
Invece di concatenare stringhe i logger supportano template e parametri nominati ({A}, {B}, {Result}), il che rende i log strutturati e comodi per l'elaborazione e la ricerca automatica.

4. Come creare e configurare il logger in un'app console

1. Aggiungiamo i pacchetti NuGet

Nel tuo progetto serviranno:

  • Microsoft.Extensions.Logging
  • Microsoft.Extensions.Logging.Console (se vuoi scrivere sulla console)
  • (opzionale) altri provider, se necessari

2. Configuriamo il logger

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// Creiamo il DI-container
var serviceProvider = new ServiceCollection()
    .AddLogging(builder => {
        builder.AddConsole(); // Output su console
        builder.SetMinimumLevel(LogLevel.Debug); // Livello minimo dei log
    })
    .BuildServiceProvider();

// Otteniamo un'istanza del logger del tipo desiderato
var logger = serviceProvider.GetRequiredService<ILogger<Calculator>>();

var calculator = new Calculator(logger);
calculator.Add(5, 3); // Il messaggio finirà nei log

Errore tipico dei principianti
"Perché il log non appare in console?" — controlla che il provider sia stato aggiunto (.AddConsole()) e che il livello minimo sia impostato correttamente (SetMinimumLevel). Se il livello è più alto, i messaggi potrebbero semplicemente essere "filtrati"!

5. Dettagli utili

Logghiamo errori e situazioni non standard

Supponiamo di voler loggare una divisione per zero. Aggiungiamo il metodo corrispondente:

public int Divide(int a, int b)
{
    if (b == 0)
    {
        _logger.LogError("Tentativo di divisione per zero! a={A}", a);
        throw new DivideByZeroException();
    }
    int result = a / b;
    _logger.LogInformation("Eseguita divisione: {A} / {B} = {Result}", a, b, result);
    return result;
}

Perché serve?
In un'app reale, quando qualcosa va storto, i log con livello Error attirano solitamente attenzione speciale: vengono inviati automaticamente agli admin, evidenziati nel monitoring e usati per alert/notifiche.

Uso di categorie e scope

Il logger in .NET supporta gli cosiddetti scopes — metadati aggiuntivi che vengono automaticamente aggiunti a tutti i log durante un blocco di codice. Per esempio, quando gestisci una web request o una sessione utente, puoi aggiungere il suo id nello scope.

using (_logger.BeginScope("UserId: {UserId}", 42))
{
    _logger.LogInformation("Inizio elaborazione dati utente");
    // ...
}

Tutti i messaggi dentro il blocco avranno il tag aggiuntivo UserId: 42, che poi aiuta a cercare i log per utente o operazione.

Esempio: livelli di logging in azione

_logger.LogTrace("Questo è Trace — quasi nessuno lo vedrà");
_logger.LogDebug("Questo è Debug — per gli sviluppatori");
_logger.LogInformation("Questo è Information — per eventi di normale funzionamento");
_logger.LogWarning("Questo è Warning — avviso di possibile problema");
_logger.LogError("Questo è Error — errore che richiede attenzione");
_logger.LogCritical("Questo è Critical — il sistema sta bruciando, serve il pompiere!");

Se hai impostato SetMinimumLevel(LogLevel.Information), vedrai solo i messaggi di livello Information, Warning, Error, Critical.

Trucco:
Lascia i log Trace e Debug per diagnostica dettagliata durante lo sviluppo, e in produzione di solito attiva solo Information e superiori, per non gonfiare i log e non perdere il segnale nel rumore.

Schema visivo: architettura del logging moderno

graph TD
A[Codice dell'applicazione] --ILogger<YourClass>--> B[Microsoft.Extensions.Logging]
B --> C1[Console Provider]
B --> C2[File Provider]
B --> C3[Cloud/Database Provider]
C1 -.-> D1[Log sulla console]
C2 -.-> D2[Log su file]
C3 -.-> D3[Log nel sistema di monitoring]

subgraph Providers
    C1
    C2
    C3
end

6. Funzionalità aggiuntive ed estensioni

Logging strutturato:
I valori dei parametri possono essere conservati non solo nella stringa ma come coppie chiave-valore, permettendo ricerca e aggregazione su questi campi (per esempio con Seq, ELK/ElasticSearch o Application Insights).

Provider di logging:
Puoi aggiungere decine di provider diversi: file, Windows EventLog, Azure ecc.

Configurare il logging tramite appsettings.json
In ASP.NET Core il logging si configura comodamente tramite file di configurazione, senza ricompilare l'applicazione.

Esempio di impostazione del livello minimo tramite config (appsettings.json):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "MyApp.Calculator": "Debug",
      "Microsoft": "Warning"
    }
  }
}

7. Errori tipici usando Microsoft.Extensions.Logging

Errore #1: Scelta sbagliata del livello di logging.
Usare LogInformation per errori invece di LogError o LogCritical rende difficile trovare i problemi in produzione.

Errore #2: Ignorare il logging strutturato.
Concatenare stringhe invece di usare template con placeholder ({Parameter}) toglie i benefici del logging strutturato, come la ricerca per parametro.

Errore #3: Configurazione sbagliata dei livelli di logging.
Se il livello minimo è impostato troppo alto (es. Warning invece di Debug), messaggi importanti possono essere filtrati.

Errore #4: Logging eccessivo o insufficiente.
Log troppo dettagliati (es. Trace in produzione) generano "rumore", mentre la mancanza di log rende difficile la diagnostica.

2
Compito
C# SELF, livello 64, lezione 0
Bloccato
Log di base con 'Microsoft.Extensions.Logging'
Log di base con 'Microsoft.Extensions.Logging'
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION