# Seq per ASP.NET Logging - Tracing con SerilogTracing

<datetime class="hidden">2024-08-31T11:20</datetime>

<!--category-- ASP.NET, Seq, Serilog -->
# Introduzione

Nella parte precedente vi ho mostrato come organizzare. [auto hosting per Seq usando ASP.NET Core ](/blog/selfhostingseq). Ora che l'abbiamo configurata'ha tempo di usarne di piùM SK2s caratteristiche per permettere un'aumento completo dell'archiviazione & il tracciamento usando la nostra nuova instance SeqMSC4

[TOC]

# Tracciare

Tracciare è come registrarsi++ ti dà un strato extra di informazione su cosa sta succedendo nella tua applicazioneM SK1 . E' particolarmente utile quando hai un sistema distribuito e devi tracciare una richiesta attraverso diversi servizi.
In questo sito io ' lo uso per rintracciare i problemi rapidamente ; solo perché questo è un sito di hobby non significa che sfaccio da parte le mie norme professionali.

## La configurazione di Serilog

Inserire il tracciamento con Serilog è molto semplice usando [Tracciamento Serilog](https://github.com/serilog-tracing/serilog-tracing) package. Prima dovete installare i pacchetti:

Qui aggiungiamo anche il pannello Console e il pannellino Seq.

```bash
dotnet add package SerilogTracing
dotnet add package SerilogTracing.Expressions
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.Seq
```

La console è sempre utile per la debugging e Seq è quello che noi'siamo qui per. Seq possiede anche un gruppo di M SK2enricher ' che può aggiungere informazioni aggiuntive ai vostri log.

```bash
  "Serilog": {
    "Enrich": ["FromLogContext", "WithThreadId", "WithThreadName", "WithProcessId", "WithProcessName", "FromLogContext"],
    "MinimumLevel": "Warning",
    "WriteTo": [
        {
          "Name": "Seq",
          "Args":
          {
            "serverUrl": "http://seq:5341",
            "apiKey": ""
          }
        },
      {
        "Name": "Console"
      },
      {
        "Name": "File",
        "Args": {
          "path": "logs/applog-.txt",
          "rollingInterval": "Day"
        }
      }

    ],
    "Properties": {
      "ApplicationName": "mostlylucid"
    }
  }
```

Per usare questi enrichori dovete aggiungerli al vostro computer. `Serilog` nella vostra configurazione. `appsettings.json` file. Dobbiamo anche installare tutti gli enrichori separati usando Nuget.

E' una delle cose buone e cattive di Serilog.
Ecco la mia miniera.

![Enrichori Serilog](serilogenrichers.png)

Con tutti questi bombardamenti ricevo un log piuttosto buono in Seq.

![Errore Serilog Seq](serilogerror.png)

Qui vedete il messaggio di errore, la traccia dello scaffale , l'id del thread, l’id del processo e il nome del processoM SK3 Questa è tutta una informazione utile quando si prova a rintracciare un problema.

Una cosa da notare è che I' ha stabilito il `  "MinimumLevel": "Warning",` nel mio lavoro. `appsettings.json` file. Questo significa che solo i segnali e quelli superiori saranno registrati a Seq. È utile per mantenere il rumore in basso nei vostri logM SK2

Tuttavia in Seq si può anche indicare questo per Api Key; così da poter avere `Information` (o se siete davvero entusiasti `Debug`) logging qui e limitare ciò che Seq cattura realmente con la chiave API.

![La chiave Seq Api](apikey.png)

Nota: avete ancora l'app sopra la testaM SK1 potete anche rendere più dinamico così da poter regolare il livello in volo). Vedete i [Seq sink ](https://github.com/datalust/serilog-sinks-seq)per i dettagli.

```json
{
    "Serilog":
    {
        "LevelSwitches": { "$controlSwitch": "Information" },
        "MinimumLevel": { "ControlledBy": "$controlSwitch" },
        "WriteTo":
        [{
            "Name": "Seq",
            "Args":
            {
                "serverUrl": "http://localhost:5341",
                "apiKey": "yeEZyL3SMcxEKUijBjN",
                "controlLevelSwitch": "$controlSwitch"
            }
        }]
    }
}
```

## Tracciare

Ora aggiungiamo il Tracing, di nuovo usando SerilogTracing it's pretty simpleM SK2 Abbiamo la stessa configurazione prima, ma aggiunsiamo un nuovo tubo per il tracciamento .

```bash
dotnet add package SerilogTracing
dontet add package SerilogTracing.Expressions
dotnet add SerilogTracing.Instrumentation.AspNetCore
```

Aggiungiamo anche un pacchetto extra per registrare informazioni più dettagliate sul core di aspnet.

### Costruirsi in `Program.cs`

Ora possiamo iniziare a usare realmente il tracciamento. Prima dobbiamo aggiungere il tracciato al nostro `Program.cs` file.

```csharp
    using var listener = new ActivityListenerConfiguration()
        .Instrument.HttpClientRequests().Instrument
        .AspNetCoreRequests()
        .TraceToSharedLogger();
```

Il tracciamento usa il concetto di 'Actività' che rappresentano un'unità di lavoroM SK2 Si può iniziare un'attività , fare qualche lavoro e poi fermarloMSC4 Questo è utile per tracciare una richiesta attraverso diversi serviziMNK5

In questo caso aggiungiamo il tracciamento extra per le richieste di HttpClient e le richieste AspNetCore. aggiuniamo anche un `TraceToSharedLogger` che registrerà l'attività nello stesso registratore del resto della nostra applicazione.

## Usare il tracciamento in un servizio

Ora abbiamo un sistema di tracciamento e possiamo iniziare a usarlo nella nostra applicazione. Qui' è un esempio di un servizio che usa il tracciamentoM SK2

```csharp
    public async Task<PostListViewModel> GetPostsByCategory(string category, int page = 1, int pageSize = 10,
        string language = MarkdownBaseService.EnglishLanguage)
    {
        using var activity = Log.Logger.StartActivity("GetPostsByCategory {Category}, {Page}, {PageSize}, {Language}",
            new { category, page, pageSize, language });
        try
        {
            var count = await NoTrackingQuery()
                .Where(x => x.Categories.Any(c => c.Name == category) && x.LanguageEntity.Name == language)
                .CountAsync();
            var posts = await PostsQuery()
                .Where(x => x.Categories.Any(c => c.Name == category) && x.LanguageEntity.Name == language)
                .OrderByDescending(x => x.PublishedDate.DateTime)
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();

            var languages = await GetLanguagesForSlugs(posts.Select(x => x.Slug).ToList());
            var postListViewModel = new PostListViewModel
            {
                Page = page,
                PageSize = pageSize,
                TotalItems = count,
                Posts = posts.Select(x => x.ToListModel(
                    languages.FirstOrDefault(entry => entry.Key == x.Slug).Value.ToArray())).ToList()
            };
            activity.Complete();
            return postListViewModel;
        }
        catch (Exception e)
        {
            activity.Complete(LogEventLevel.Error, e);
        }

        return new PostListViewModel();
    }
```

Le linee importanti qui sono:

```csharp
  using var activity = Log.Logger.StartActivity("GetPostsByCategory {Category}, {Page}, {PageSize}, {Language}",
            new { category, page, pageSize, language });
```

Questo inizia una nuova 'attività' che è un'unità di lavoroM SK2 E' utile per tracciare una richiesta attraverso diversi serviziMSC4
Dato che l'abbiamo avvolto in un'affermazione di uso questo si completa e si smalti alla fine del nostro metodo ma è la buona pratica di completarlo esplicitamente.

```csharp
            activity.Complete();
```

Nella nostra cattura di eccezioni completamo anche l'attività, ma con un livello di errore e l'eccezione. È utile per rintracciare problemi nella vostra applicazione.

## Utilizzare tracce

Ora abbiamo tutta questa configurazione e possiamo iniziare a usarla. Qui'è un esempio di traccia nella mia applicazione

![Trace di Http](httptrace.png)

Questo vi mostra la traduzione di un singolo post decimato. Potete vedere i vari passaggi per un solo post e tutte le richieste e i tempi del HttpClient.

Nota Ho usato Postgres per la mia base di dati, a differenza del server SQL il driver npgsql ha supporto nativo per il tracciamento così potete ottenere dati molto utili dalle vostre ricerche di database come l'exécuzione SQL, timing etcM SK2 Questi sono conservati come 'spansMSC4 in Seq e guardate liek le followingMSSK5

```json
  "@t": "2024-08-31T15:23:31.0872838Z",
"@mt": "mostlylucid",
"@m": "mostlylucid",
"@i": "3c386a9a",
"@tr": "8f9be07e41f7121cbf2866c6cd886a90",
"@sp": "8d716c5f01ad07a0",
"@st": "2024-08-31T15:23:31.0706848Z",
"@ps": "622f1c86a8b33304",
"@sk": "Client",
"ActionId": "91f5105d-93fa-4e7f-9708-b1692e046a8a",
"ActionName": "Mostlylucid.Controllers.HomeController.Index (Mostlylucid)",
"ApplicationName": "mostlylucid",
"ConnectionId": "0HN69PVEQ9S7C",
"ProcessId": 30496,
"ProcessName": "Mostlylucid",
"RequestId": "0HN69PVEQ9S7C:00000015",
"RequestPath": "/",
"SourceContext": "Npgsql",
"ThreadId": 47,
"ThreadName": ".NET TP Worker",
"db.connection_id": 1565,
"db.connection_string": "Host=localhost;Database=mostlylucid;Port=5432;Username=postgres;Application Name=mostlylucid",
"db.name": "mostlylucid",
"db.statement": "SELECT t.\"Id\", t.\"ContentHash\", t.\"HtmlContent\", t.\"LanguageId\", t.\"Markdown\", t.\"PlainTextContent\", t.\"PublishedDate\", t.\"SearchVector\", t.\"Slug\", t.\"Title\", t.\"UpdatedDate\", t.\"WordCount\", t.\"Id0\", t0.\"BlogPostId\", t0.\"CategoryId\", t0.\"Id\", t0.\"Name\", t.\"Name\"\r\nFROM (\r\n    SELECT b.\"Id\", b.\"ContentHash\", b.\"HtmlContent\", b.\"LanguageId\", b.\"Markdown\", b.\"PlainTextContent\", b.\"PublishedDate\", b.\"SearchVector\", b.\"Slug\", b.\"Title\", b.\"UpdatedDate\", b.\"WordCount\", l.\"Id\" AS \"Id0\", l.\"Name\", b.\"PublishedDate\" AT TIME ZONE 'UTC' AS c\r\n    FROM mostlylucid.\"BlogPosts\" AS b\r\n    INNER JOIN mostlylucid.\"Languages\" AS l ON b.\"LanguageId\" = l.\"Id\"\r\n    WHERE l.\"Name\" = @__language_0\r\n    ORDER BY b.\"PublishedDate\" AT TIME ZONE 'UTC' DESC\r\n    LIMIT @__p_2 OFFSET @__p_1\r\n) AS t\r\nLEFT JOIN (\r\n    SELECT b0.\"BlogPostId\", b0.\"CategoryId\", c.\"Id\", c.\"Name\"\r\n    FROM mostlylucid.blogpostcategory AS b0\r\n    INNER JOIN mostlylucid.\"Categories\" AS c ON b0.\"CategoryId\" = c.\"Id\"\r\n) AS t0 ON t.\"Id\" = t0.\"BlogPostId\"\r\nORDER BY t.c DESC, t.\"Id\", t.\"Id0\", t0.\"BlogPostId\", t0.\"CategoryId\"",
"db.system": "postgresql",
"db.user": "postgres",
"net.peer.ip": "::1",
"net.peer.name": "localhost",
"net.transport": "ip_tcp",
"otel.status_code": "OK"
```

Potete vedere che include quasi tutto quello di cui avete bisogno per sapere sulla domanda, l'exécuzione SQL, la sequenza di connessioni, ecc.

# Conclusione

I'ho solo scacchiato la superficie del Tracing qui , è una zona un po' stretta con sostenitori appassionati. Spero di aver mostrato quanto sia semplice andare avanti con il semplice tracciamento usando Seq M SK5 Serilog per ASPMska6Applications Core NETMske7 In questo modo posso ottenere gran parte dei benefici di strumenti più potenti come Application Insights senza i costi dell'Azure |( |Queste cose possono diventare costose quando i log sono grandi | ).