本文介绍如何在.NET 6 API中使用Serilog的APM。
1. 引用Serilog相关的packages
<PackageReferenceInclude="Elastic.Apm.SerilogEnricher"Version="8.11.1"/><PackageReferenceInclude="Serilog.AspNetCore"Version="8.0.2"/><PackageReferenceInclude="Serilog.Enrichers.Environment"Version="3.0.1"/><PackageReferenceInclude="Serilog.Exceptions"Version="8.4.0"/><PackageReferenceInclude="Serilog.Formatting.Elasticsearch"Version="10.0.0"/><PackageReferenceInclude="Serilog.Settings.Configuration"Version="8.0.2"/><PackageReferenceInclude="Serilog.Sinks.Elasticsearch"Version="10.0.0"/>2. appsettings.json添加配置文件
"SeriLog":{"Using":["Serilog.Sinks.Console","Serilog.Sinks.File","Serilog.Sinks.Elasticsearch"],"MinimumLevel":{"Default":"Information"},"Enrich":["FromLogContext","WithMachineName","WithThreadId","WithElasticApmCorrelationInfo"]},"SerilogSupplementer":{"WriteToFile":true,"LogFilePath":"c:/temp/logs/mes-api/mes-api-.json","FileRestrictToMinimumLevel":"Information","FileSizeLimitBytes":10485760,//10 MB"RetainedFileTimeLimit":"10.00:00",// Retain files for a maximum of 10 days 0 Hrs 0 Mins"rollOnFileSizeLimit":true,"EnrichFromLogContext":true,"MinimumLevelControlledBy":null,"EnrichProperties":{"Application":"mes-api","Environment":"Development"},"MinimumLevelOverrides":{"Microsoft.NetCore":"Warning","Elastic.Apm":"Warning"},"EnrichWithExceptionDetails":true,"AddElasticApmCorrelationInfo":true,"WriteToConsole":true,"ConsoleFormat":"{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] [{SourceContext}] [{EventId}] {Message}{NewLine}{Exception}"},"ElasticApm":{"ServerUrls":"http://localhost:8200",// URL of your APM server"ServiceName":"mes-api","Environment":"Development","CentralConfig":false,"LogLevel":"Error"},3. 注册
3.1 创建SerilogSupplementerConfiguration.cs
usingSerilog.Core;usingSerilog.Events;namespaceMES.API.Logging;publicclassSerilogSupplementerConfiguration{publicboolWriteToFile{get;set;}publicstringLogFilePath{get;set;}=string.Empty;publicLogEventLevelFileRestrictedToMinimumLevel{get;set;}=LogEventLevel.Debug;publicboolEnrichFromLogContext{get;set;}=true;publicLoggingLevelSwitch?MinimumLevelControlledBy{get;set;}publicDictionary<string,object>EnrichProperties{get;set;}=new();publicDictionary<string,LogEventLevel>MinimumLevelOverrides{get;set;}=new();publicboolEnrichWithExceptionDetails{get;set;}=true;publicboolAddElasticApmCorrelationInfo{get;set;}publicboolWriteToConsole{get;set;}publicstringConsoleFormat{get;set;}=string.Empty;publicstringRetainedFileTimeLimit{get;set;}="10.00:00";//Default to 10 dayspubliclongFileSizeLimitBytes{get;set;}=10485760;//Default to 10 MBpublicboolRollOnFileSizeLimit{get;set;}}3.2 注册
usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;usingAlterDomus.a360.Core.Logging;usingSerilog;usingSerilog.Exceptions;usingElastic.Apm.SerilogEnricher;usingSerilog.Formatting.Elasticsearch;usingSerilog.Exceptions.Core;namespaceMES.API.Extensions;publicstaticclassMESExtensions{/// <summary>/// Add Serilog ILogger using configuration. SerilogSupplementerConfiguration will be read from configuration if exists./// </summary>/// <param name="services"></param>/// <param name="configuration"></param>/// <param name="logArgs"></param>publicstaticIServiceCollectionAddSerilog(thisIServiceCollectionservices,IConfigurationconfiguration){varserilogConfig=newSerilog.LoggerConfiguration().ReadFrom.Configuration(configuration);varserilogSupplementer=configuration.GetSection("SerilogSupplementer").Get<SerilogSupplementerConfiguration>()??new();varretainedFileTimeLimit=TimeSpan.Parse(serilogSupplementer.RetainedFileTimeLimit);varfileSizeLimitBytes=serilogSupplementer.FileSizeLimitBytes;varrollOnFileSizeLimit=serilogSupplementer.RollOnFileSizeLimit;if(serilogSupplementer!=null){if(serilogSupplementer.MinimumLevelControlledBy!=null){serilogConfig.MinimumLevel.ControlledBy(serilogSupplementer.MinimumLevelControlledBy);}foreach(varkvpinserilogSupplementer.MinimumLevelOverrides){serilogConfig.MinimumLevel.Override(kvp.Key,kvp.Value);}if(serilogSupplementer.EnrichFromLogContext){serilogConfig.Enrich.FromLogContext();}if(serilogSupplementer.AddElasticApmCorrelationInfo){serilogConfig.Enrich.WithElasticApmCorrelationInfo();}if(serilogSupplementer.WriteToConsole||!string.IsNullOrEmpty(serilogSupplementer.ConsoleFormat)){if(string.IsNullOrEmpty(serilogSupplementer.ConsoleFormat)){serilogConfig.WriteTo.Console();}else{serilogConfig.WriteTo.Console(outputTemplate:serilogSupplementer.ConsoleFormat);}}if(serilogSupplementer.EnrichWithExceptionDetails){serilogConfig.Enrich.WithExceptionDetails(newDestructuringOptionsBuilder().WithDefaultDestructurers());}if(serilogSupplementer.WriteToFile){serilogConfig.WriteTo.File(newElasticsearchJsonFormatter(renderMessage:true,renderMessageTemplate:false),path:serilogSupplementer.LogFilePath,restrictedToMinimumLevel:serilogSupplementer.FileRestrictedToMinimumLevel,rollingInterval:RollingInterval.Day,fileSizeLimitBytes:fileSizeLimitBytes,retainedFileTimeLimit:retainedFileTimeLimit,rollOnFileSizeLimit:rollOnFileSizeLimit,shared:true);}foreach(varkvpinserilogSupplementer.EnrichProperties){serilogConfig.Enrich.WithProperty(kvp.Key,kvp.Value);}if(!serilogSupplementer.EnrichProperties.ContainsKey("UserName")){serilogConfig.Enrich.WithProperty("UserName",Environment.UserName);}}ILoggerlogger=serilogConfig.CreateLogger();services.AddSingleton<Serilog.ILogger>(logger);returnservices;}}3.3 在program.cs使用
builder.Services.AddSerilog(builder.Configuration);builder.Host.UseSerilog();builder.Services.AddAllElasticApm();