web-dev-qa-db-fra.com

Déstructuration d'exception dans Serilog

Serilog a un moyen pratique de déstructurer des objets comme indiqué dans cet exemple:

logger.Debug(exception, "This is an {Exception} text", exception);
logger.Debug(exception, "This is an {@Exception} structure", exception);

La première ligne oblige l'enregistreur à enregistrer une exception sous forme de texte brut (en appelant ToString ()), et la deuxième ligne oblige l'enregistreur à écrire les propriétés d'exception dans des champs séparés. Mais qu'en est-il de cette surcharge:

logger.Debug(exception, "This is an exception", exception);

Celui-ci prend une exception comme premier argument, et il est toujours écrit sous forme de chaîne. Ce que je voudrais rendre possible, c'est activer l'exception de journalisation de manière structurée. Est-il possible de configurer Serilog pour y parvenir?

METTRE À JOUR. Je suppose que cette question mène à un autre aspect de la journalisation des exceptions: comment puis-je m'assurer que les messages sont enrichis avec des propriétés d'exception (afin qu'ils soient journalisés de manière structurée dans les récepteurs riches comme Elasticsearch) sans écrire toutes les propriétés d'exception dans le message texte rendu ( les enregistreurs de texte en clair ne sont donc pas remplis d'énormes tas de détails d'exception).

25
Vagif Abilov

Il y a un fil de discussion sur ce sujet , dans lequel quelques solutions sont présentées. Thomas Bolon a créé une extension de "déstructuration d'exception" que vous pouvez trouver dans un Gist .

Dans ce cas, vous utilisez uniquement cette syntaxe:

logger.Debug(exception, "This is an exception");

Il n'est pas nécessaire d'ajouter l'exception dans la chaîne de format.

Pour vous assurer que l'exception est imprimée dans les blocs de texte, assurez-vous simplement que {Exception} est inclus dans le modèle de sortie. Les standards intégrés ont déjà cela, par exemple:

outputTemplate: "{Timestamp} [{Level}] {Message}{NewLine}{Exception}";
19
Nicholas Blumhardt

Jetez un œil à Serilog.Exceptions enregistre les détails des exceptions et les propriétés personnalisées qui ne sont pas sorties dans Exception.ToString ().

Cette bibliothèque a un code personnalisé pour gérer les propriétés supplémentaires sur les types d'exceptions les plus courants et ne revient à utiliser la réflexion pour obtenir les informations supplémentaires que si l'exception n'est pas prise en charge par Serilog.Exceptions en interne.

Ajoutez le package NuGet, puis ajoutez l'enricher comme suit:

using Serilog;
using Serilog.Exceptions;

ILogger logger = new LoggerConfiguration()
    .Enrich.WithExceptionDetails()
    .WriteTo.Sink(new RollingFileSink(
        @"C:\logs",
        new JsonFormatter(renderMessage: true))
    .CreateLogger();

Vos journaux JSON seront désormais complétés par des informations détaillées sur les exceptions et même des propriétés d'exception personnalisées. Voici un exemple de ce qui se produit lorsque vous enregistrez une exception DbEntityValidationException à partir d'EntityFramework (Cette exception est connue pour avoir des propriétés personnalisées profondément imbriquées qui ne sont pas incluses dans la .ToString()).

try
{
    ...
}
catch (DbEntityValidationException exception)
{
    logger.Error(exception, "Hello World");
}

Le code ci-dessus enregistre les éléments suivants:

{
  "Timestamp": "2015-12-07T12:26:24.0557671+00:00",
  "Level": "Error",
  "MessageTemplate": "Hello World",
  "RenderedMessage": "Hello World",
  "Exception": "System.Data.Entity.Validation.DbEntityValidationException: Message",
  "Properties": {
    "ExceptionDetail": {
      "EntityValidationErrors": [
        {
          "Entry": null,
          "ValidationErrors": [
            {
              "PropertyName": "PropertyName",
              "ErrorMessage": "PropertyName is Required.",
              "Type": "System.Data.Entity.Validation.DbValidationError"
            }
          ],
          "IsValid": false,
          "Type": "System.Data.Entity.Validation.DbEntityValidationResult"
        }
      ],
      "Message": "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.",
      "Data": {},
      "InnerException": null,
      "TargetSite": null,
      "StackTrace": null,
      "HelpLink": null,
      "Source": null,
      "HResult": -2146232032,
      "Type": "System.Data.Entity.Validation.DbEntityValidationException"
    },
    "Source": "418169ff-e65f-456e-8b0d-42a0973c3577"
  }
}

Serilog.Exceptions prend en charge la norme .NET et prend en charge de nombreux types d'exceptions courantes sans réflexion, mais nous aimerions en ajouter plus, alors n'hésitez pas à contribuer.

Astuce - Traces de pile lisibles par l'homme

Vous pouvez utiliser le package NuGet Ben.Demystifier pour obtenir des traces de pile lisibles par l'homme pour vos exceptions ou les enrichisseurs de serilog -demystify Package NuGet si vous utilisez Serilog.

33

Cela devrait être évité complètement. ElasticSearch et Serilog ne sont pas conçus avec l'idée que vous allez sérialiser des objets arbitraires. La journalisation des objets avec les formes en conflit entraînera le mappage des exceptions dans ElasticSearch. Si vous utilisez le récepteur ElasticSearch dans NuGet, tout ce qui entraîne un conflit de mappage sera perdu. Serilog ne gère pas non plus les relations cycliques, ce qui entraînera des erreurs d'auto-limogeage du limiteur de profondeur. Il existe un projet qui tente de résoudre ce problème en les déstructurant en dictionnaires et en les transmettant à Serilog, mais vous vous retrouverez toujours avec des journaux désordonnés et des exceptions de mappage.

Serilog: https://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/

J'ai trouvé préférable de préciser les propriétés des exceptions de journalisation en fonction de ce que vous trouvez utile dans l'exception.

2
Daniel Leach