Yoko.Tool.Serilog 0.1.5

dotnet add package Yoko.Tool.Serilog --version 0.1.5                
NuGet\Install-Package Yoko.Tool.Serilog -Version 0.1.5                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Yoko.Tool.Serilog" Version="0.1.5" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Yoko.Tool.Serilog --version 0.1.5                
#r "nuget: Yoko.Tool.Serilog, 0.1.5"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Yoko.Tool.Serilog as a Cake Addin
#addin nuget:?package=Yoko.Tool.Serilog&version=0.1.5

// Install Yoko.Tool.Serilog as a Cake Tool
#tool nuget:?package=Yoko.Tool.Serilog&version=0.1.5                

📚 使用示例

Program.cs

try
{
    var builder = WebApplication.CreateBuilder(args);

    // 注册配置文件
    builder.Services.AddConfiguration<AppSettings>(builder.Configuration, "AppSettings");


   //初始化日志服务
    Log.Logger = new LoggerConfiguration()
        .WriteTo.Console()
        .MinimumLevel.Debug()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .MinimumLevel.Override("Default", LogEventLevel.Warning)
        .MinimumLevel.Override("System", LogEventLevel.Warning)
        .MinimumLevel.Override("Quartz", LogEventLevel.Warning)
        .MinimumLevel.Override("TouchSocket", LogEventLevel.Warning)
        .MinimumLevel.Override("FastEndpoints", LogEventLevel.Warning)
        .Enrich.FromLogContext()
        .Enrich.WithTraceContextHeader() // 提取追踪上下文
        .WriteTo.Http(requestUri: AppSettings.LogCenter  //接口地址
            , queueLimitBytes: null
            , textFormatter: new LogFormatter()   // ============================>使用日志格式化器
        )
    .WriteTo.File(
        outputTemplate: "{Message:lj}{NewLine}",  // 直接定义输出模板
        //formatter: new LogFormatter(true), // ============================> 使用日志格式化器
        path: $"{AppDomain.CurrentDomain.BaseDirectory}/Logs/DC-.log",
        rollingInterval: RollingInterval.Day,//日志按天保存
        rollOnFileSizeLimit: true,//限制单个文件的最大长度
        fileSizeLimitBytes: 10485760,//单个文件最大10M
        encoding: System.Text.Encoding.UTF8,//文件字符编码
        retainedFileCountLimit: 200,//将被保留的日志文件的最大数量,包括当前日志文件。对于无限保留,传递null。默认值为31。
        shared: true//允许多个进程共享日志文件。默认值为false
    )
    .CreateLogger(); //立即配置 Serilog
    builder.Services.AddSerilog(); // 使用 Serilog

    var app = builder.Build();

    app.MapGet("/ok", () => "服务运行正常!").WithTags("健康检查");

    Log.Information("服务启动成功");

    app.Run();
}
catch (Exception e)
{
    Log.Fatal("服务意外终止!{msg}", e.Message);
}
finally
{
    Log.CloseAndFlush();
}

📚 使用组件

📒 获取请求中的追踪id

可以从 HTTP 请求头部的 “traceparent” 字段中提取追踪上下文,并将其添加到 Serilog 的日志事件中。

它遵循 W3C Trace Context 规范

按W3C Trace Context 规范, “traceparent” 头部的值应遵循 00-{traceId}-{spanId}-{traceFlags} 的格式

其中:

  • traceId 是一个 32 个十六进制数字的字符串,表示追踪操作的唯一标识符。
  • spanId 是一个 16 个十六进制数字的字符串,表示单个操作的唯一标识符 (例如,一个 HTTP 请求)。
  • traceFlags 是一个 2 个十六进制数字的字符串,表示追踪选项。目前,唯一定义的选项是 “01”,表示记录追踪数据

示例值:

00-83efd447300bf4dfa660e807869e78f0-3f977cb3083d2ac6-01

📖使用方法

首先,你需要在你的 Serilog 配置中使用 WithTraceContextHeader 方法:

Log.Logger = new LoggerConfiguration()
    .Enrich.WithTraceContextHeader()
    // 其他配置...
    .CreateLogger();

默认情况下,这个插件会从 “traceparent” 头部提取追踪上下文。

如果你的应用程序使用了不同的头部名称,你可以将其作为参数传递给 WithTraceContextHeader 方法:

Log.Logger = new LoggerConfiguration()
    .Enrich.WithTraceContextHeader("your-header-name")
    // 其他配置...
    .CreateLogger();

然后,你就可以像平常一样使用 Serilog 来记录日志。

每个日志事件都会包含两个额外的属性:TraceIdSpanId

这些属性的值来自 “traceparent” 头部。

📖 推荐 使用 Flurl.Http 库来传递追踪上下文信息

扩展 Flurl 请求来添加追踪上下文,创建一个扩展方法来为 Flurl 请求注入追踪上下文信息。这个方法会提取当前的 Activity 信息,并将其添加到 HTTP 头部中。

using Flurl.Http;
using System.Diagnostics;

public static class FlurlRequestExtensions
{
    public static IFlurlRequest WithTracingContext(this string url)
    {
        var request = new FlurlRequest(url);
        var activity = Activity.Current;
        if (activity != null)
        {
            var traceParent = $"00-{activity.TraceId}-{activity.SpanId}-01";
            request.WithHeader("traceparent", traceParent);
        }
        return request;
    }
}

http请求示例

 var response = await "http://localhost:6689/api"
     .WithTracingContext() // 使用扩展方法注入追踪上下文
     .GetAsync();

📖 使用常规的HttpClient请求

需要注意的是,在使用HttpClient的时候,要注册名为 “TracingClient” 的 HttpClient

using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using Microsoft.Extensions.Logging;

namespace YourNamespace.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class YourController : ControllerBase
    {
        private readonly ILogger<YourController> _logger;
        private readonly HttpClient _client;

        public YourController(ILogger<YourController> logger, IHttpClientFactory clientFactory)
        {
            _logger = logger;
            //  ============================>  注意这里
            _client = clientFactory.CreateClient("TracingClient");
        }

        [HttpGet("get")]
        public async Task<IActionResult> GetAsync()
        {
            var response = await _client.GetAsync("http://example.com/api/values");
            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                return Ok(content);
            }
            else
            {
                return StatusCode((int)response.StatusCode, response.ReasonPhrase);
            }
        }

    }
}


📒 日志格式化器

插件还包含一些自定义的日志格式化器,它可以输出两种不同的日志格式:

  • JSON格式:new LogFormatter();
  • 文件格式:new LogFormatter(isFileLog: true,version: AppVersion.Current);
    • isFileLog: true 输出实体文件
    • version:版本号,不填则默认1.0.0

📖使用方法

首先,创建一个 LogFormatter 实例。你可以选择是否使用文件日志格式:

formatter : new LogFormatter(isFileLog: true,version: AppVersion.Current);  // 使用实体文件日志格式
formatter : new LogFormatter();  // 使用JSON日志格式

然后,你可以在你的日志配置中使用这个格式化器:

.WriteTo.Http(
       textFormatter: new LogFormatter() // ==================> 使用JSON格式化器
    )
//============================================================
    .WriteTo.File(
       formatter: new LogFormatter(true), //==================> 使用文件格式化器
    )

📖特性

  • 两种日志格式:这个格式化器可以输出JSON格式的日志,也可以输出文件格式的日志。
  • 灵活的配置:你可以在创建格式化器的时候选择使用哪种日志格式。
  • 包含版本信息:日志中包含了程序集的版本信息。

📖格式说明

🔎 JSON日志格式

JSON日志格式是一种结构化的日志格式,它使用JSON(JavaScript Object Notation)数据交换格式来表示日志事件。这种格式的优点是易于机器处理和查询,特别是在大数据和日志分析环境中。

以下是一个JSON日志格式的示例:

{
    "TimeStamp": "2024-04-29 10:35:34.576",
    "Level": "Information",
    "Message": "服务启动成功",
    "TrackingId": "1234567890",
    "Path": "/api/start",
    "Source": "MyApp",
    "Version": "1.0.0"
}
🔎 文件日志格式

文件日志格式是一种非结构化的日志格式,它将日志事件表示为简单的文本消息。这种格式的优点是易于人类阅读和理解,特别是在进行故障排查和调试时。

以下是一个文件日志格式的示例:

[2024-04-29 10:35:34.576] [Information] [1234567890] [/api/start] 服务启动成功

在这个示例中,每个方括号内的字段分别代表时间戳、日志级别、跟踪ID和请求路径,最后是日志消息本身。

📒 自定义日志格式化器

自定义一个格式化器,然后继承 ITextFormatter 实现对应的方法即可

示例:自带的类型判断的格式化器

public class DcLogFormatter : ITextFormatter
{
    public void Format(LogEvent logEvent, TextWriter output)
    {
        var type = 0;
        if (logEvent.Properties.TryGetValue("type", out var typeValue) && typeValue is ScalarValue scalarTypeValue)
        {
            type = scalarTypeValue.Value.ToInt32();
        }
        if (type == 1)
        {
            var json = logEvent.RenderMessage();
            output.Write(json);
        }
    }
}

internal static class StringExtensions
{
    internal static int ToInt32(this object s)
    {
        if (s == null)
        {
            return 0;
        }
        return int.TryParse(s.ToString(), out int result) ? result : 0;
    }
}

使用示例:

using (LogContext.PushProperty("type", 1))
{
    Log.Information(new
    {
        CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
        TimeStamp = model.Tstamp.ToString("yyyy-MM-dd HH:mm:ss.fff"),
        State = state
    }.ToJson());
}

更新日志

【新增】日志格式化器版本号参数

【新增】可选是否使用日志格式化器

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.