.NET 6 API使用Serilog APM

本文介绍如何在.NET 6 API中使用Serilog的APM。

1. 引用Serilog相关的packages

csharp 复制代码
<PackageReference Include="Elastic.Apm.SerilogEnricher" Version="8.11.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="10.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.2" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />

2. appsettings.json添加配置文件

csharp 复制代码
 "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

csharp 复制代码
using Serilog.Core;
using Serilog.Events;

namespace MES.API.Logging;

public class SerilogSupplementerConfiguration
{
    public bool WriteToFile { get; set; }
    public string LogFilePath { get; set; } = string.Empty;
    public LogEventLevel FileRestrictedToMinimumLevel { get; set; } = LogEventLevel.Debug;
    public bool EnrichFromLogContext { get; set; } = true;
    public LoggingLevelSwitch? MinimumLevelControlledBy { get; set; }
    public Dictionary<string,object> EnrichProperties { get; set; } = new();
    public Dictionary<string,LogEventLevel> MinimumLevelOverrides { get; set; } = new();
    public bool EnrichWithExceptionDetails { get; set; } = true;
    public bool AddElasticApmCorrelationInfo { get; set; } 
    public bool WriteToConsole { get; set; }
    public string ConsoleFormat { get; set; } = string.Empty;
    public string RetainedFileTimeLimit { get; set; } = "10.00:00"; //Default to 10 days 
    public long FileSizeLimitBytes { get; set; } = 10485760; //Default to 10 MB
    public bool RollOnFileSizeLimit { get; set; }
}

3.2 注册

csharp 复制代码
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AlterDomus.a360.Core.Logging;
using Serilog;
using Serilog.Exceptions;
using Elastic.Apm.SerilogEnricher;
using Serilog.Formatting.Elasticsearch;
using Serilog.Exceptions.Core;

namespace MES.API.Extensions;
public static class MESExtensions
{
    /// <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>
    public static IServiceCollection AddSerilog(this IServiceCollection services, IConfiguration configuration)
    {
        var serilogConfig = new Serilog.LoggerConfiguration()
            .ReadFrom.Configuration(configuration);

        var serilogSupplementer = configuration.GetSection("SerilogSupplementer").Get<SerilogSupplementerConfiguration>() ?? new();
        var retainedFileTimeLimit = TimeSpan.Parse(serilogSupplementer.RetainedFileTimeLimit);
        var fileSizeLimitBytes = serilogSupplementer.FileSizeLimitBytes;
        var rollOnFileSizeLimit = serilogSupplementer.RollOnFileSizeLimit;

        if (serilogSupplementer != null)
        {
            if (serilogSupplementer.MinimumLevelControlledBy != null)
            {
                serilogConfig.MinimumLevel.ControlledBy(serilogSupplementer.MinimumLevelControlledBy);
            }
            foreach (var kvp in serilogSupplementer.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(
                    new DestructuringOptionsBuilder().WithDefaultDestructurers()
                );
            }
            if (serilogSupplementer.WriteToFile)
            {
                serilogConfig.WriteTo.File(
                   new ElasticsearchJsonFormatter(renderMessage: true, renderMessageTemplate: false),
                   path: serilogSupplementer.LogFilePath,
                   restrictedToMinimumLevel: serilogSupplementer.FileRestrictedToMinimumLevel,
                   rollingInterval: RollingInterval.Day,
                   fileSizeLimitBytes: fileSizeLimitBytes,
                   retainedFileTimeLimit: retainedFileTimeLimit,
                   rollOnFileSizeLimit: rollOnFileSizeLimit,
                   shared: true
               );
            }
            foreach (var kvp in serilogSupplementer.EnrichProperties)
            {
                serilogConfig.Enrich.WithProperty(kvp.Key, kvp.Value);
            }
            if (!serilogSupplementer.EnrichProperties.ContainsKey("UserName"))
            {
                serilogConfig.Enrich.WithProperty("UserName", Environment.UserName);
            }
        }

        ILogger logger = serilogConfig.CreateLogger();

        services.AddSingleton<Serilog.ILogger>(logger);
        return services;
    }

}

3.3 在program.cs使用

csharp 复制代码
     builder.Services.AddSerilog(builder.Configuration);
     builder.Host.UseSerilog();
     builder.Services.AddAllElasticApm();
相关推荐
北域码匠9 小时前
PID 控制算法完整详解(C# 原生实现,无第三方库)
c#·pid控制·工控开发·闭环控制·自动控制算法·数字pid·增量式pid
离陌在学C#9 小时前
C# 重载与重写:深入理解面向对象编程的核心概念
java·c#
asdzx6712 小时前
Java 实战:基于 Spire.Doc 高效提取 Word 文档文本与图片
java·c#·word
小金子会发光12 小时前
C# WinForms 基于 Socket 手搓 Modbus TCP 调试助手(支持 01/02/03/04/05/06/0F/10)
c#·socket·plc·modbus tcp·工业通信
MyBili13 小时前
游戏报错缺少dll、无法启动?GRLPackage 运行库合集一键修复指南
游戏·.net·directx·运行库·xna·openal·vc++ redis
慧都小妮子14 小时前
PDF图片提取总“褪色“?Aspose.PDF 多层级提取能力详解
pdf·c#·.net·图片处理·文档处理·色彩空间
-银雾鸢尾-16 小时前
C#中的反射关键类-Type
开发语言·c#
海盗123417 小时前
微软技术周报 · 2026-08-10
microsoft·.net
淡海水17 小时前
15-07-YooAsset面试篇-Unity性能优化与内存管理
java·unity·面试·性能优化·c#·游戏引擎
离陌在学C#18 小时前
C# 多态:面向对象编程的核心特性详解
开发语言·c#