« Serilog » : différence entre les versions
De Banane Atomic
Aller à la navigationAller à la recherche
(2 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 157 : | Ligne 157 : | ||
= Timing = | = Timing = | ||
NuGet package: Serilog.Extras.Timing | NuGet package: Serilog.Extras.Timing | ||
= ASP.NET web API = | |||
Nuget packages: {{boxx|Serilog.AspNetCore}} | |||
<filebox fn='Program.cs'> | |||
builder.Host.UseSerilog((ctx, services, config) => config.ReadFrom.Configuration(ctx.Configuration)); | |||
</filebox> | |||
= [https://mcguirev10.com/2018/02/07/serilog-dependency-injection-easy-ip-logging.html Dependency Injection] = | |||
{{warn | Utiliser plutôt {{boxx|Serilog.Extensions.Logging.File}} avec la DI par défaut fournit par {{boxx|Microsoft.Extensions.Logging}}}} | |||
<filebox fn='Program.cs'> | |||
static void Main(string[] args) | |||
{ | |||
Log.Logger = new LoggerConfiguration() | |||
.WriteTo.Console(outputTemplate: customTemplate) | |||
.CreateLogger(); | |||
var services = new ServiceCollection(); | |||
services.AddTransient<IMyClass, MyClass>() | |||
.AddSingleton(Log.Logger); | |||
var provider = services.BuildServiceProvider(); | |||
var myObject = provider.GetService<IMyClass>(); | |||
myObject.MyMethod(); | |||
</filebox> | |||
<filebox fn='MyClass.cs'> | |||
public class MyClass : IMyClass | |||
{ | |||
private readonly ILogger logger; | |||
public MyClass(ILogger logger) | |||
{ | |||
this.logger = logger.ForContext<MyClass>(); | |||
} | |||
public void MyMethod() | |||
{ | |||
logger.Debug("message"); | |||
</filebox> | |||
= Configuration file = | = Configuration file = | ||
Ligne 198 : | Ligne 238 : | ||
</kode> | </kode> | ||
<filebox fn='appsettings.json'> | <filebox fn='appsettings.json' collapsed> | ||
"Serilog": { | |||
"Using": [ "Serilog.Sinks.File" ], | |||
"MinimumLevel": "Error", | |||
"WriteTo": [ | |||
{ | |||
"Name": "File", | |||
"Args": { | |||
"path": "logs/API.log", | |||
"rollOnFileSizeLimit": true, | |||
"fileSizeLimitBytes": 10000000, | |||
"retainedFileCountLimit": 3 | |||
} | |||
} | |||
], | |||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] | |||
} | |||
</filebox> | |||
<filebox fn='appsettings.json' collapsed> | |||
{ | { | ||
"Serilog": { | "Serilog": { |
Dernière version du 18 octobre 2024 à 14:39
Utilisation
public sealed class MyClass { private readonly ILogger logger = Log.Logger.ForContext<MyClass>(); public void MyMethod() { logger.Verbose("message"); |
Sinks
Définit où les log doivent être écris.
Console
const string customTemplate = "{Timestamp:yyyy-MMM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"; Log.Logger = new LoggerConfiguration() .WriteTo.Console(outputTemplate: customTemplate) .CreateLogger(); |
Nuget packages: Serilog.Sinks.Console
(Rolling) File
Le fichier sera nommé file-YYYYMMDD.log.
ILogger logger = new LoggerConfiguration() .WriteTo.File( "file.log", rollOnFileSizeLimit: true, fileSizeLimitBytes: 10_000_000, // 10 MB retainedFileCountLimit: 3) // retainedFileCountLimit, max number of log files to keep .CreateLogger(); |
Log4net
// configure log4net XmlConfigurator.Configure(); Log.Logger = new LoggerConfiguration() .WriteTo.Log4Net(supplyContextMessage: true) .CreateLogger(); |
Il n'est pas possible d'utiliser les Repositories. |
Application Insights
Nuget package: Serilog.Sinks.ApplicationInsights
Log.Logger = new LoggerConfiguration() .WriteTo.ApplicationInsights(TelemetryConverter.Traces) .CreateLogger(); |
Trace vs Event
Ne pas oublier de configurer Application Insights.
Structured data
Par défaut, Serilog gère les types suivant: bool numbers string dates nullables IEnumerable Dictionary (si la clé est type de base)
Pour les autres types, ToString est utilisé.
Log.Logger.Information("Text {NamedProperty1} {NamedProperty2}", value1, value2); |
Destructured object
var user = new User { Name = "Joe", Age = 35 }; // pour éviter que ToString ne soit utilisé, ajouter un @ devant le nom Log.Logger.Information("User: {@User}", user); // User: {"Name": "Joe", "Age": 35, "$type": "User"} // configurer la déstructuration ILogger logger = new LoggerConfiguration() .Destructure.ByTransforming<User>(u => new { u.Name, u.Age }) .WriteTo.Console() .CreateLogger(); Log.Logger.Information("User: {@User}", user); // User: {"Name": "Joe", "Age": 35} |
Format
Log.Logger.Information("{StringProperty}", myString); // "MyString" Log.Logger.Information("{StringProperty:l}", myString); // MyString Log.Logger.Information("{NumberProperty:0.00}", Math.PI); // 3,14 |
Level
Par défaut, les levels Verbose et Debug ne sont logués.
Log.Logger.Verbose("Text"); Log.Logger.Debug("Text"); Log.Logger.Information("Text"); Log.Logger.Warning("Text"); Log.Logger.Error("Text"); Log.Logger.Fatal("Text"); ILogger logger = new LoggerConfiguration() .MinimumLevel.Verbose() // définit le level minimum de log pour tous les sink .WriteTo.Console(LogEventLevel.Information) // restreint le level minimum de log pour le sink Console .CreateLogger(); |
Filter
Log.Logger = new LoggerConfiguration() .WriteTo.Console() .Filter.ByIncludingOnly(Matching.FromSource<Program>()) // inclus seulement les log avec un SourceContext = type Program .Filter.ByIncludingOnly(Matching.FromSource("MyNamespace")) // inclus seulement les log avec un SourceContext commençant par MyNamespace .CreateLogger(); // SourceContext Log.Logger.ForContext<Program>().Information("Text"); |
Event enricher
ILogger logger = new LoggerConfiguration() .Enrich.WithProperty("ApplicationName", "MyApp") .WriteTo.Console() .CreateLogger(); Log.Logger.Information("{ApplicationName} - Text"); // MyApp - Text ILogger logger = new LoggerConfiguration() .Enrich.With<MyEventEnricher>() .WriteTo.Console() .CreateLogger(); Log.Logger.Information("{ApplicationName} - {ApplicationVersion} - Text"); // MyApp - 1.0.0.0 - Text |
MyEventEnricher.cs |
class MyEventEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { var applicationAssembly = Assembly.GetEntryAssembly(); var name = applicationAssembly.GetName().Name; var version = applicationAssembly.GetName().Version; logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ApplicationName", name)); logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ApplicationVersion", version)); } } |
Timing
NuGet package: Serilog.Extras.Timing
ASP.NET web API
Nuget packages: Serilog.AspNetCore
Program.cs |
builder.Host.UseSerilog((ctx, services, config) => config.ReadFrom.Configuration(ctx.Configuration)); |
Dependency Injection
Utiliser plutôt Serilog.Extensions.Logging.File avec la DI par défaut fournit par Microsoft.Extensions.Logging |
Program.cs |
static void Main(string[] args) { Log.Logger = new LoggerConfiguration() .WriteTo.Console(outputTemplate: customTemplate) .CreateLogger(); var services = new ServiceCollection(); services.AddTransient<IMyClass, MyClass>() .AddSingleton(Log.Logger); var provider = services.BuildServiceProvider(); var myObject = provider.GetService<IMyClass>(); myObject.MyMethod(); |
MyClass.cs |
public class MyClass : IMyClass { private readonly ILogger logger; public MyClass(ILogger logger) { this.logger = logger.ForContext<MyClass>(); } public void MyMethod() { logger.Debug("message"); |
Configuration file
App.config
Nuget package: Serilog.Settings.AppSettings
var logger = new LoggerConfiguration() .ReadFrom.AppSettings() .CreateLogger(); |
App.config |
<configuration> <appSettings> <add key="serilog:minimum-level" value="Warning" /> <add key="serilog:using:Console" value="Serilog.Sinks.Console" /> <add key="serilog:write-to:Console" /> <add key="serilog:using:ApplicationInsights" value="Serilog.Sinks.ApplicationInsights" /> <add key="serilog:write-to:ApplicationInsights.telemetryConverter" value="Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights" /> <add key="serilog:using:Log4Net" value="Serilog.Sinks.Log4Net" /> <add key="serilog:write-to:Log4Net.supplyContextMessage" value="true" /> </appSettings> |
appsettings.json
Nuget package: Serilog.Settings.Configuration
var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true) .Build(); var logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); |
appsettings.json |
"Serilog": { "Using": [ "Serilog.Sinks.File" ], "MinimumLevel": "Error", "WriteTo": [ { "Name": "File", "Args": { "path": "logs/API.log", "rollOnFileSizeLimit": true, "fileSizeLimitBytes": 10000000, "retainedFileCountLimit": 3 } } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] } |
appsettings.json |
{ "Serilog": { "Using": ["Serilog.Sinks.Console"], "MinimumLevel": "Debug", "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "%TEMP%\\Logs\\serilog-configuration-sample.txt" } } ], "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"], "Destructure": [ { "Name": "With", "Args": { "policy": "Sample.CustomPolicy, Sample" } }, { "Name": "ToMaximumDepth", "Args": { "maximumDestructuringDepth": 4 } }, { "Name": "ToMaximumStringLength", "Args": { "maximumStringLength": 100 } }, { "Name": "ToMaximumCollectionCount", "Args": { "maximumCollectionCount": 10 } } ], "Properties": { "Application": "Sample" } } } |
Debug
// afficher les infos de debug SelfLog.Enable(Console.WriteLine); |