NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Sunday, 27 October 2024
//Less than a minute
Logging est DE COURS une partie critique des applications mais je vois souvent qu'il a mal compris / mal utilisé dans les applications ASP.NET. Il s'agit d'un manifeste partiel sur la façon de se connecter efficacement aux applications ASP.NET.
Ce n'est pas un guide complet de l'enregistrement ; il y a des LOTS de ceux là-bas ; il s'agit plutôt de choisir une stratégie de logage efficace pour vos applications ASP.NET.
Dans l'enregistrement principal devrait être USEFUL; que ce soit l'enregistrement pendant que vous développez ou l'enregistrement dans la production, il devrait être utile pour vous / votre équipe / vos utilisateurs.
Trop souvent, l'enregistrement est considéré comme la chose «ne le faire que lorsqu'il y a des exceptions». Je pense que cela comprend mal ce que devrait être l'exploitation forestière.
LOGGING N'EST PAS SEULEMENT POUR LES EXCEPTIONS
En général, vous devriez être en mesure d'exécuter une partie importante de votre demande localement; dans ce contexte log.LogInformation
C'est ton ami.
Au cours des 30 années où j'ai écrit du code, j'ai vu quelques exemples de bon logging et WAY plus d'exemples de mauvais logging.
Principes d'une bonne exploitation forestière:
Rappelez-vous ; l'enregistrement ALWAYS entraîne les performances de votre application ; vous devriez enregistrer ce dont vous avez besoin pour diagnostiquer un problème mais pas plus dans la production / où les performances sont critiques (p. ex., ne pas exécuter un test de performance lors de l'utilisation complète de Debug Logging).
Dans ASP.NET, vous avez déjà une construction dans le système d'enregistrement; Microsoft.Extensions.Logging
C'est ce que j'ai dit. C'est un bon système d'enregistrement, mais il n'est pas aussi flexible que Serilog. Serilog est un système d'enregistrement plus flexible qui vous permet de vous connecter à plusieurs puits (sorties) et d'enrichir vos journaux avec des informations supplémentaires.
C'est l'enregistrement qui se produit lorsque votre application démarre. C'est la première chose qui arrive, et c'est la première chose que vous devriez voir quand vous lancez votre application. Dans ASP.NET surtout lorsque vous utilisez la configuration, il est essentiel que vous compreniez ce qui se passe lorsque votre application démarre. C'est une source de problèmes très courante dans les applications ASP.NET.
Par exemple, dans Serilog, vous pouvez faire ceci:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/boot-*.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
.CreateBootstrapLogger();
REMARQUE: Ceci est limité car vous n'avez pas accès à la configuration à ce moment-ci donc par exemple pour utiliser AppInsights vous auriez probablement besoin d'un #if RELEASE
bloc pour définir la clé appropriée.
Ce que cela fait est de vous donner des données sur tous les problèmes de démarrage dans votre application; il écrit à la fois pour consoler et pour un fichier. Il est également important de s'assurer que vous ne sauvegardez pas TOUS les fichiers journaux; vous pouvez voir ici que nous ne sauvons que 7 jours de journaux.
Vous voudrez également envelopper votre méthode de démarrage (dans cette application, j'utilise la nouvelle Program.cs
méthode) dans un essai / prise et enregistrer toutes les exceptions qui se produisent là-bas.
try
{
..all your startup code
}
catch (Exception ex)
{
if(args.Contains("migrate"))
{
Log.Information("Migration complete");
return;
}
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
Le Log.FermerAndFlush() est important car il garantit que tous les logs sont écrits sur le disque (votre application s'écrase ainsi sinon il sortira avant qu'il ne le fasse).
Ici, je détecte également si l'application est en cours d'exécution en mode migration et si c'est le cas, je l'enregistre et je quitte.
Log.Fatal
est le niveau de log le plus sévère; il est utilisé lorsque votre application est sur le point de s'écraser.
Toutes les exceptions ne sont pas fatales - vous devriez utiliser Log.Error
pour ceux (à moins qu'ils ne signifient que l'APP (et non la requête) ne peut pas continuer au-delà de ce point).
Dans ASP.NET (et.NET plus généralement), vous avez un certain nombre de niveaux de log:
Log.Fatal
- C'est le niveau de log le plus sévère; il est utilisé lorsque votre application est sur le point de s'écraser.Log.Error
- Ceci est utilisé lorsqu'une exception se produit, ce qui signifie que l'APP (pas la requête) ne peut pas continuer au-delà de ce point.Log.Warning
- Ceci est utilisé lorsque quelque chose se produit qui n'est pas une erreur, mais est quelque chose dont vous devriez être conscient (par exemple un service dégradé / quelque chose pas tout à fait bien mais pas une erreur).Log.Information
- Ceci est utilisé pour des informations générales sur ce qui se passe dans votre application.Log.Debug
- Ceci est utilisé pour des informations qui ne sont utiles que lorsque vous débogez votre application (c'est tout dans le développement mais devrait être désactivé dans la production).Pour la production, j'avais généralement établi que l'exploitation forestière était Log.Fatal
, Log.Error
et Log.Warning
Seulement.
Contrairement à l'enregistrement de démarrage, c'est l'enregistrement qui se produit lorsque votre application est en cours d'exécution. C'est l'enregistrement qui vous indique ce qui se passe dans votre application à un moment donné.
Par exemple, pour les utiliser dans Serilog, vous feriez ceci :
"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"
}
},
Comme vous le verrez, je suis un très grand fan de Serilog; c'est une excellente bibliothèque d'enregistrement qui est très flexible. Une des choses que j'aime à ce sujet est la capacité d'enrichir vos journaux avec des informations supplémentaires. Cela peut être très utile dans le diagnostic des problèmes dans votre application. Dans l'exemple ci-dessus, vous pouvez voir que j'enrichis mes journaux avec l'id thread, le nom thread, l'id process et le nom process. Cela peut être très utile dans le diagnostic des problèmes dans votre application.
J'ai également défini la session pour aller à plusieurs 'puits' (outputs); dans ce cas, je l'envoie à la console, à un fichier et à Seq (un service de session).
Avoir plusieurs puits est pratique dans le cas où on échoue, dans ce cas mon service d'enregistrement préféré est Seq, donc je l'envoie d'abord là-bas. Si ça échoue, je l'envoie à la console et à un fichier.
J'ai également défini la propriété ApplicationName dans les journaux; cela peut être utile si vous avez plusieurs applications qui se connectent au même service (ce que vous allez souvent faire pour les applications distribuées; avec un ID de corrélation pour relier les journaux pour une seule demande).
Par exemple, si vous avez un front end JS et un backend.NET, vous pouvez définir l'ID de corrélation dans le front end et le passer au backend. Cela vous permet de voir tous les journaux pour une seule requête en un seul endroit. OU si vous utilisez HttpClient dans votre backend, vous pouvez passer l'ID de corrélation dans les en-têtes à l'autre service.
Il y a une excellente couverture sur la façon dont vous pourriez faire ceci ici: https://josef.codes/append-correlation-id-to-all-log-entries-in-asp-net-core/ mais je vais le couvrir dans un futur post.
L'enregistrement structuré est un moyen d'enregistrement qui facilite la recherche et le filtrage de vos journaux. Dans Serilog vous pouvez le faire en utilisant le Log.Information("This is a log message with {Property1} and {Property2}", property1, property2);
syntaxe. Cela facilite la recherche de journaux avec une propriété particulière.
En utilisant Serilog, vous pouvez également utiliser LogContext.PushProperty
pour ajouter des propriétés à vos journaux qui ne sont pertinentes que pour une portée particulière. Cela peut être très utile dans le diagnostic des problèmes dans votre application.
Serilog est super flexible en ce sens qu'il vous permet de le configurer en code ainsi que par config. Par exemple, pour utiliser la configuration ci-dessus, vous feriez ceci :
builder.Host.UseSerilog((context, services, configuration) =>
{
configuration
.MinimumLevel.Warning()
.Enrich.FromLogContext()
.Enrich.WithThreadId()
.Enrich.WithThreadName()
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.WriteTo.Seq("http://seq:5341", apiKey: "")
.WriteTo.Console()
.WriteTo.File("logs/applog-.txt", rollingInterval: RollingInterval.Day)
.Enrich.WithProperty("ApplicationName", "mostlylucid");
});
Ceci est identique à la configuration ci-dessus mais en code. C'est utile si vous voulez configurer votre code de connexion ; c'est vraiment à vous de le faire.
Dans ASP.NET, vous pouvez utiliser des filtres d'exception pour attraper des exceptions et les enregistrer. C'est un excellent moyen de vous assurer que vous enregistrez toutes les exceptions dans votre application. Chaque fois qu'il ne s'agit pas d'un remplacement pour l'enregistrement au niveau de la méthode, vous devriez toujours vous connecter au niveau de la méthode afin que vous puissiez voir ce qui se passe dans votre application en détail; le filtre Exception montre simplement ce qui se passe une fois que la pile de requête entière a été déroutée et peut souvent être très confuse pour déterminer ce qui s'est passé.
Cela a changé dans ASP.NET Core 8 et il y a un TON que vous pouvez faire avec ces nouvelles fonctionnalités.
Boguez de nouveau les mêmes principes s'appliquent; vous devez vous connecter au niveau de la méthode afin de voir ce qui se passe dans votre application en détail; les filtres d'exception / gestionnaires d'état juste montrer ce qui se passe une fois que la pile de requête entière a été déroutée et peut souvent être très confus pour travailler sur ce qui s'est passé.
L'exploitation devrait être adaptée à l'environnement; dans Développement, vous enregistrez tout de sorte que vous puissiez voir ce qui se passe à chaque point de votre application, mais dans Test, vous avez besoin de moins d'enregistrement (peut-être l'information de log ici) et dans Production, vous avez besoin encore moins (Attention et plus).
C'est tentant de tout enregistrer dans la production, mais c'est une mauvaise idée. Vous devriez enregistrer tout ce dont vous avez besoin pour diagnostiquer un problème, mais pas plus. Dans les fournisseurs de cloud, vous pouvez facilement être facturé pour la quantité de données que vous envoyez au service d'enregistrement, de sorte que vous devriez être prudent sur ce que vous enregistrez et combien de temps vous conservez ces journaux (Application Insights stocke les journaux pendant 90 jours par défaut; ceci est souvent TOO LONG et vous coûtera aussi longtemps que les données de log sont stockées).
Pour une application très "active", vous n'aurez pas besoin de l'enregistrement à long terme de ces données ; vous aurez une bonne idée de ce qui se passe dans l'application depuis les derniers jours de journaux.
Une fois que le problème commun que je vois dans la production est l'enregistrement des demandes échouées; bien que ceux-ci peuvent être intéressants (personne ne veut un 404 / 401), ils peuvent être une quantité énorme de données et peuvent être très coûteux à stocker. Tu ne devrais qu'enregistrer les choses. vous avez l'intention de réparer, pour un 404 il se peut que cela soit important car il peut indiquer un lien rompu dans votre application; pour un 401, il se peut que cela soit important car il peut indiquer un système d'authentification rompu.
QUOI que je l'ai mentionné ci-dessus, ils sont mieux traités dans le code dans lequel ils se produisent (dans le cas de 401); il se peut que ceux-ci devraient également être enregistrés comme un Warning
ou Error
dans le code qui génère effectivement le 401.
Pour configurer Request Logging in Serilog, vous pouvez faire ceci :
app.UseSerilogRequestLogging();
Cela enregistrera toutes les demandes à votre application; c'est une excellente façon de voir ce qui se passe dans votre application à un niveau élevé; mais encore une fois, vous devriez faire attention à ce que vous log et combien de temps vous conservez ces logs.
Pour l'application Insights, vous pouvez toujours vouloir vous connecter en utilisant le niveau Information car il vous donnera la fonctionnalité Nifty User Journey ; c'est une excellente façon de voir comment les utilisateurs utilisent votre application et peuvent être très utiles pour diagnostiquer des problèmes ; cependant, encore une fois, ces coûts accumulent rapidement de sorte que vous devriez être prudent sur ce que vous enregistrez et combien de temps vous conservez ces journaux.
C'est donc ça, un rapide exercice de la façon de se connecter aux applications ASP.NET. Il s'agit en grande partie d'une réaction aux logs trop zélés et inutiles que je vois dans de nombreuses applications de production. Dans le développement que vous voulez voir comment fonctionne l'application; dans la production vous voulez voir comment l'application échoue. L'exploitation forestière est trop souvent une partie inutile et coûteuse du développement d'applications. Comme avec tout dans l'enregistrement de développement logiciel devrait être concentré sur l'USER; si son vous / les autres développeurs tout en travaillant sur l'application dans votre IDE / localement ou de trier les problèmes dans la production rapidement et efficacement.