# Seq für ASP-.-NET-Logging - Tracing mit SerilogTracing

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

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

Im vorherigen Teil habe ich Ihnen gezeigt, wie man [Selbst-Hosting für Seq unter Verwendung von ASP .. .NET Core ](/blog/selfhostingseq)Jetzt, da wir es eingerichtet haben, ist es Zeit von ', mehr davon zu verwenden.', um eine vollständigere Protokollierung mit unserer neuen Seq-Instanz zu ermöglichen.

[TOC]

# Aufspüren

Tracing ist wie logging-++, es gibt Ihnen eine zusätzliche Ebene von Informationen über das, was geschieht ', die in Ihrer Anwendung geschehen ist.., es ist besonders nützlich, wenn Sie ein verteiltes System haben und Sie müssen eine Anfrage durch mehrere Dienste verfolgen.
Auf dieser Seite I''m mit ihm, um Probleme schnell aufzuspüren.;', nur weil dies ein Hobby-Website doesn't bedeutet, ich gebe meine professionellen Standards auf.

## Einrichtung von Serilog

Das Einrichten von Tracing mit Serilog ist wirklich ziemlich einfach mit dem [Serilog Tracing](https://github.com/serilog-tracing/serilog-tracing) package-.. Zuerst müssen Sie die Pakete installieren.

Hier fügen wir auch das Konsolenwaschbecken und die Seq Spüle hinzu

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

Console ist immer nützlich für Debugging und Seq ist, was wir uns hier für .. Seq verfügt auch über eine Reihe von ' enrichers.'., die zusätzliche Informationen zu Ihren Logs hinzufügen können.

```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"
    }
  }
```

Um diese Anreicherer verwenden Sie müssen sie zu Ihrem hinzufügen `Serilog` Konfiguration in Ihrem `appsettings.json` Sie müssen auch alle separaten Anreicherer mit Nuget-Anreicherung installieren

Es ist eines der guten und schlechten Dinge über Serilog.,, die Sie am Ende eine BUNCH von Paketen installieren, aber es bedeutet, dass Sie nur hinzufügen, was Sie brauchen und nicht nur ein monolithisches Paket...
Hier ist die Mine '.

![Serilog Enrichers](serilogenrichers.png)

Mit all diesen bombinierten bekomme ich eine ziemlich gute Log-Ausgabe in Seq..

![Serilog Seq Fehler](serilogerror.png)

Hier sehen Sie die Fehlermeldung, dass der Stack-Trace, der Thread id, der Prozess-ID und der Prozessname, das ist alles nützliche Informationen, wenn man versucht, ein Problem aufzuspüren.

Eine Sache zu beachten ist, dass I' `  "MinimumLevel": "Warning",` in meinem `appsettings.json` Das bedeutet, dass nur Warnungen und oben bei Seq protokolliert werden.Dies ist nützlich, um das Rauschen in Ihren Logs unten zu halten.

Allerdings in Seq können Sie auch diese pro Api-Key.;, so dass Sie `Information` Oder wenn du wirklich begeistert bist `Debug`Protokollierung hier festlegen und begrenzen, was Seq tatsächlich durch API-Key erfasst

![Seq Api-Schlüssel](apikey.png)

Hinweis: Sie haben immer noch App Overhead, die Sie auch diese dynamischere machen können, so dass Sie das Niveau auf der fly justieren können. [Seq Spülbecken ](https://github.com/datalust/serilog-sinks-seq)für mehr Details

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

## Aufspüren

Jetzt fügen wir Tracing-, , wieder mit SerilogTracing it , ' , ziemlich einfach Wir haben das gleiche Setup wie zuvor, aber wir fügen eine neue Spüle für die Rückverfolgung ,.

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

Wir fügen auch ein zusätzliches Paket hinzu, um detailliertere aspnet-Kerninformationen zu protokollieren.

### Einrichtung `Program.cs`

Jetzt können wir tatsächlich mit dem Tracing beginnen.... Zuerst müssen wir die Tracing zu unserem `Program.cs` Datei„ ."

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

Tracing verwendet das Konzept von -'.Aktivitäten -', die eine Einheit der Arbeit darstellen -mesK2 .Sie können eine Aktivität starten ., . tun Sie etwas Arbeit und dann stoppen Sie es ?. . Dies ist nützlich für die Verfolgung einer Anfrage durch mehrere Dienste .

In diesem Fall fügen wir zusätzliche Tracing für HttpClient-Anfragen und AspNetCore Anfragen hinzu. `TraceToSharedLogger` welche die Aktivität auf den gleichen Logger wie der Rest unserer Anwendung protokollieren wird

## Tracing in einem Dienst nutzen

Jetzt haben wir Tracing-Setup können wir es in unserer Anwendung zu verwenden beginnen... Hier ist ein Beispiel für einen Dienst, der tracing verwendet.

```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();
    }
```

Die wichtigen Linien hier sind:

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

Dies beginnt eine neue -'-Aktivität, die eine Einheit der Arbeit ist - . , Es ist nützlich für die Verfolgung einer Anfrage durch mehrere Dienste ,. .
Da wir es in eine Verwendung Aussage eingewickelt haben, wird dies am Ende unserer Methode komplettieren und entsorgen, aber es ist gute Praxis, sie explizit zu vollenden.

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

In unserem Ausnahme-Handling fangen wir auch die Aktivität, aber mit einer Fehlerstufe und der Ausnahme-..... Dies ist nützlich für das Aufspüren von Problemen in Ihrer Anwendung.

## Spuren verwenden

Jetzt haben wir all dieses Setup, das wir mit ihm beginnen können... Hier ist ein Beispiel für eine Spur in meiner Anwendung.

![Http Trace](httptrace.png)

Dies zeigt Ihnen die Übersetzung eines einzelnen Markdown Posts.Sie können sehen, die mehrere Schritte für einen einzigen Post und alle HttpClient Anfragen und Timings.

Hinweis Ich verwende Postgres für meine Datenbank..... im Gegensatz zu SQL-Server hat der npgsql-Treiber native Unterstützung für die Nachverfolgung, so dass Sie sehr nützliche Daten aus Ihren Datenbankanfragen wie dem SQL ausgeführt bekommen können... ...... diese werden als '.spans....

```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"
```

Sie können sehen, dass dies so ziemlich alles enthält, was Sie über die Abfrage wissen müssen.,.Das SQL executed...,.Das ist alles nützliche Informationen, wenn Sie versuchen, ein Problem aufzuspüren ?..In einer kleineren App wie diesem ist dies nur interessant.,. in einer verteilten Anwendung es ' ist solide Gold-Informationen, um Probleme aufzuspüren.MSC7.

# Schlussfolgerung

I'®ve kratzte hier nur die Oberfläche von Tracing.,® it'®s ein bisschen Bereich mit leidenschaftlichen Fürsprechern.MSC3® Hoffentlich zeigte IMSC4®ve, wie einfach es ist, mit der einfachen Nachverfolgung mit Seq zu kommen ?&? Serilog für ASPC-.®NET Core-Anwendungen?MSC7? Auf diese Weise kann ich viel vom Nutzen von leistungsfähigeren Werkzeugen wie Application Insights ohne die Kosten von Azure erhalten.(... diese Dinge können verausgabt werden, wenn die Protokolle groß sind...).