CodeGym /Kursy /C# SELF /Strukturalne logowanie i S...

Strukturalne logowanie i Serilog

C# SELF
Poziom 64, Lekcja 1
Dostępny

1. Wprowadzenie

Jeśli zwykłe tekstowe logowanie to twój dziennik z notatkami "Ja dziś jadłem", to strukturalne logowanie zamienia każdy wpis w kartę z polami: {Data: ..., Zdarzenie: "Zjadł", Kalorie: 500, Danie: "Smażone mięso"}. To znaczy, że potem możesz nie tylko przeczytać dziennik, ale i zbudować wykres kalorii za miesiąc, przefiltrować zdarzenia po daniu i dowiedzieć się, kiedy jadłeś za późno.

Dlaczego zwykły tekst to za mało?

Z samym tekstem wszystko jest proste... do pewnego momentu. Spróbuj zebrać statystyki błędów w logach, wolumen sprzedaży w sklepie internetowym, ciąg akcji jednego użytkownika po jego ID (np. 42), jeśli wszystkie dane to ściany tekstu. Strukturalne logowanie pozwala podłączyć analizę, a nawet AI do logów. Z nim można szukać anomalii, budować dashboardy i reagować na problemy automatycznie.

Zalety

  • Pozwala logować nie tylko wiadomości, ale też powiązane z nimi dane (pola/właściwości).
  • Logi można analizować automatycznie: liczyć, filtrować, budować raporty.
  • Używane są standaryzowane formaty, takie jak JSON, które łatwo parsować maszynowo.

Serilog: co to i dlaczego?

Serilog (oficjalna strona: serilog.net, dokumentacja: github.com/serilog/serilog/wiki) — popularna biblioteka do strukturalnego logowania w .NET. Świetnie integruje się z Microsoft.Extensions.Logging, obsługuje wysyłkę do dziesiątek systemów (plik, konsola, Seq, ElasticSearch, Grafana, Azure itd.), minimalnie wpływa na wydajność i jest prosta w konfiguracji.

Czym Serilog różni się od "zwykłego logowania"?

  • Struktura: logi to obiekty z polami, po których można filtrować (np. wszystkie błędy użytkownika o ID 42).
  • Formaty: potrafi zapisywać nie tylko tekst, ale i JSON, XML, co ułatwia dalsze przetwarzanie.
  • Elastyczność: masa gotowych pakietów‑sinków do wysyłki logów gdzie chcesz.

Struktura wpisu loga w Serilog

Rzućmy okiem na strukturalny log, zanim napiszemy kod.

{
  "Timestamp": "2024-06-22T10:23:45.123Z",
  "Level": "Information",
  "MessageTemplate": "Użytkownik {UserId} zalogował się do systemu",
  "Properties": {
    "UserId": 42,
    "IpAddress": "127.0.0.1"
  }
}

Tutaj nawet podstawowa analiza zrozumie: chodzi o użytkownika nr 42 i jego adres IP.

2. Instalacja i podstawowa konfiguracja Serilog w projekcie C#

Krok 1. Instalacja pakietów NuGet

W Rider/Visual Studio przez NuGet Package Manager zainstaluj:

  • Serilog
  • Serilog.Sinks.Console (wyjście do konsoli)
  • Serilog.Extensions.Logging (do integracji z Microsoft.Extensions.Logging)

Przez wiersz poleceń:

dotnet add package Serilog
dotnet add package Serilog.Sinks.Console

Krok 2. Minimalna konfiguracja

Dodamy konfigurację w Program.cs i zapisemy pierwszy log.

using System;
using Serilog;

namespace MySuperApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. Podstawowa konfiguracja Serilog: wyjście do konsoli
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Console()
                .CreateLogger();

            // 2. Przykład strukturalnego logowania
            int userId = 42;
            string ip = "127.0.0.1";
            Log.Information("Użytkownik {UserId} zalogował się do systemu z IP {IpAddress}", userId, ip);

            Log.CloseAndFlush();
        }
    }
}

W konsoli zobaczymy mniej więcej coś takiego:

[10:30:16 INF] Użytkownik 42 zalogował się do systemu z IP 127.0.0.1

Później łatwo skierować wyjście do pliku JSON, Seq lub innego systemu.

3. Formatowanie logów: Message Template

W Serilog zamiast konkatenacji stringów używa się składni szablonów:

Log.Information("Operacja {Operation} na pliku {FileName}", "usuwanie", "test.txt");

To nie tylko ładny zapis — to strukturalne logowanie: do wpisu trafią pola Operation i FileName, dostępne do filtrowania i agregacji.

Czym to różni się od string.Format?

string.Format("Operacja {0} na pliku {1}", operation, fileName) po prostu skleja string z placeholderami {0}, {1}. Serilog robi z tego osobne pola, z którymi później można pracować analitycznie.

Elastyczna konfiguracja: poziomy, filtry, różne "sinki"

Serilog może zapisywać logi jednocześnie w kilka miejsc.

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console()
    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

Teraz logi zapisywane są zarówno do konsoli, jak i do pliku z rotacją dzienną.

4. Przykład

Załóżmy, że robimy aplikację konsolową‑"notes", pozwalającą tworzyć wpisy użytkownika. Dodajmy strukturalne logowanie akcji.

using System;
using Serilog;

namespace NotesApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.Console()
                .WriteTo.File("notes-log.json", rollingInterval: RollingInterval.Day, 
                              formatter: new Serilog.Formatting.Json.JsonFormatter())
                .CreateLogger();

            Console.WriteLine("Wpisz nazwę użytkownika:");
            string userName = Console.ReadLine();

            Log.Information("Użytkownik {UserName} uruchomił aplikację NotesApp", userName);

            while (true)
            {
                Console.WriteLine("Wpisz tekst notatki (lub wpisz 'wyjście'):");
                string note = Console.ReadLine();

                if (note == "wyjście")
                {
                    Log.Information("Użytkownik {UserName} zakończył pracę", userName);
                    break;
                }

                Log.Information("Użytkownik {UserName} stworzył notatkę: {NoteText}", userName, note);
            }

            Log.CloseAndFlush();
        }
    }
}

Komentarz:
Log rejestruje, kto uruchamia program, co wpisuje i kiedy kończy pracę. W pliku notes-log.json każdy wpis to obiekt JSON, który łatwo analizować.

5. Przydatne niuanse

Najlepsze praktyki strukturalnego logowania

  • Nie nadużywaj poziomów Debug/Trace w produkcji — używaj Information i Warning rozsądnie.
  • Używaj nazwanych parametrów w szablonach zamiast konkatenacji stringów.
  • Nigdy nie loguj danych wrażliwych (hasła, tokeny, klucze).
  • Loguj ważne zdarzenia biznesowe, nie tylko błędy i wyjątki.
  • Skonfiguruj rotację i czyszczenie logów, żeby nie zabrakło miejsca na dysku.

Wizualizacja i analiza: Seq, Kibana, Application Insights

Serilog wspiera mnóstwo sinków — punktów docelowych, do których wysyłane są logi.

Sink Krótki opis Gdzie używane
Console Prosto do konsoli Development, testy
File Do lokalnego lub sieciowego pliku Małe projekty, dev
Seq Interfejs webowy z filtrowaniem i dashboardami Enterprise, analityka
ElasticSearch Mocny system przechowywania i analizy Duże firmy
Azure Application Insights Monitorowanie w chmurze i telemetria Serwisy obciążone w Azure

Seq (datalust.co/seq) — bardzo popularne rozwiązanie do developmentu i użytku wewnętrznego: wygodne filtrowanie, wyszukiwanie po polach i szybkie wdrożenie.

Tabelki i wizualizacja

Poniżej krótka tabela tego, co można logować strukturalnie:

Co logujemy Jak wygląda w Serilog Przykład wartości
ID użytkownika
{UserId}
123
Akcja
{Action}
"Usuwanie"
Błąd
Log.Error(ex, "Błąd w {Module}")
"Moduł rejestracji"
Czas operacji {Elapsed:0.000} sek 1.234
Nazwa pliku
{FileName}
"report.pdf"

Ciekawe bajery i dodatkowe możliwości Serilog

  • Enrichers: dodają do każdego logu właściwości (np. .Enrich.WithMachineName()).
  • Powiązane logi: dodawaj RequestId do korelacji łańcucha zdarzeń.
  • Konfiguracja przez appsettings.json: wygodne rozwiązanie dla produkcji.
{
  "Serilog": {
    "MinimumLevel": "Debug",
    "WriteTo": [
      { "Name": "Console" },
      { "Name": "File", "Args": { "path": "log.txt" } }
    ]
  }
}

Advanced sinks: można wysyłać logi do Slacka, Telegrama, e‑mailem (ale ostrożnie, żeby nie dostać tysiąca wiadomości na każdy błąd).

6. Część praktyczna: integracja z Microsoft.Extensions.Logging

W .NET często używa się standardowego interfejsu ILogger, żeby nie wiązać się z konkretną biblioteką. Serilog można podpiąć jako provider.

Krok 1. Instalacja pakietu

dotnet add package Serilog.Extensions.Logging

Krok 2. Konfiguracja

using Microsoft.Extensions.Logging;
using Serilog;

// ...

// Skonfiguruj Serilog jak zwykle:
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateLogger();

// Teraz używamy Microsoft.Extensions.Logging
var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddSerilog();
});

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Testowy komunikat: {TestValue}", 123);

// Nie zapominaj zamknąć:
Log.CloseAndFlush();

Komentarz:
Teraz cały twój kod korzystający z ILogger<T> jest niezależny od providera — w razie potrzeby możesz przejść na NLog lub Log4Net.

7. Typowe błędy przy pracy z Serilog

Przeładowanie logów: jeśli zapisujesz wszystko bez selekcji, przydatnej informacji będzie trudno szukać.

Logowanie wyjątków jako tekst: używaj przeciążenia z wyjątkiem — wtedy w logu trafi struktura błędu.

try
{
    // some code
}
catch (Exception ex)
{
    Log.Error(ex, "Wystąpił błąd podczas wykonania zapytania");
}

Nadużywanie konfiguracji: nie zamieniaj konfiguracji w śmietnik — dodawaj tylko potrzebne sinki i poziomy.

2
Zadanie
C# SELF, poziom 64, lekcja 1
Niedostępne
Podstawowe strukturalne logowanie z Serilog
Podstawowe strukturalne logowanie z Serilog
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION