c# - 使用 TextWriter 时 Serilog 未按预期记录
问题描述
我试图弄清楚如何让 Serilog 记录类名和方法/行号,就像我在 C++ 中看到的 log4cxx 一样。
我尽我最大的努力从我正在处理的真实代码中获取所有相关的部分,并提出了一个最小的例子。
我也一直在左右搜索 Serilog,但我没有找到好的文档。我想这是因为基础 serilog 之上有很多库,每个库都需要有自己的文档来告诉我如何做事。
我可以在https://github.com/serilog/serilog/wiki/Configuration-Basics看到有关配置的基础知识,但这似乎使用了来自单独的 Serilog 库和自定义格式化程序的 TextWriter 接收器,这两者我都没有真不明白。
我还可以找到使用简单配置和丰富调用来记录类和方法名称的堆栈溢出示例。
C# ASP.NET Core Serilog 添加类名和方法到日志
我无法让它记录它们。如何在仍然使用自定义格式化程序和 TextWriter 的同时记录类和方法名称或行号?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using Serilog.Events;
using Serilog.Formatting;
namespace SerilogDemo {
// Someone else made this, I just changed the name to protect the innocent
public class SomeonesLogTextFormatter : ITextFormatter
{
public void Format(LogEvent logEvent, TextWriter output)
{
output.Write(logEvent.Level);
output.Write(": ");
logEvent.MessageTemplate.Render(logEvent.Properties, output);
output.WriteLine();
if (logEvent.Exception != null)
{
output.WriteLine(logEvent.Exception);
}
}
}
public class SomeClass
{
private Serilog.ILogger _log = Serilog.Log.ForContext<SomeClass>();
public SomeClass()
{
_log.Debug("SomeClass has been instantiated");
}
public void Foo()
{
_log.Debug("Foo has been called");
}
}
class Program
{
static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.WriteTo.TextWriter(textWriter: Console.Out, formatter: new SomeonesLogTextFormatter())
.CreateLogger();
var poop = new SomeClass();
poop.Foo();
}
}
}
解决方案
Serilog 向日志消息添加更多信息的方法LogContext
是手动添加属性或使用为您执行此操作的 Enricher。阅读更多关于Serilog Enrichment的信息。
默认情况下 Serilog 不会捕获该信息,如果您为每条消息都捕获该信息,这可能会非常昂贵,但实现此目的的方法是使用C# 的调用者信息功能,例如CallerMemberName
, CallerFilePath
, CallerLineNumber
。
这是一个示例,也复制如下:
public static class SerilogWithCallerAttributes
{
public static void Main()
{
Serilog.Log.Logger = new LoggerConfiguration()
.WriteTo.ColoredConsole()
.CreateLogger();
GoDoSomething();
}
public static void GoDoSomething()
{
int score = 12;
Log.Information("Player scored: {Score}", CallerInfo.Create(), score);
}
}
public static class Log
{
public static void Information(string messageTemplate, CallerInfo callerInfo, params object[] propertyValues)
{
Serilog.Log.Logger
.ForHere(callerInfo.CallerFilePath, callerInfo.CallerMemberName, callerInfo.CallerLineNumber)
.Information(messageTemplate, propertyValues);
}
}
public static class LoggerExtensions
{
public static ILogger ForHere(
this ILogger logger,
[CallerFilePath] string callerFilePath = null,
[CallerMemberName] string callerMemberName = null,
[CallerLineNumber] int callerLineNumber = 0)
{
return logger
.ForContext("SourceFile", callerFilePath)
.ForContext("SourceMember", callerMemberName)
.ForContext("SourceLine", callerLineNumber);
}
}
public class CallerInfo
{
public string CallerFilePath { get; private set; }
public string CallerMemberName { get; private set; }
public int CallerLineNumber { get; private set; }
private CallerInfo(string callerFilePath, string callerMemberName, int callerLineNumber)
{
this.CallerFilePath = callerFilePath;
this.CallerMemberName = callerMemberName;
this.CallerLineNumber = callerLineNumber;
}
public static CallerInfo Create(
[CallerFilePath] string callerFilePath = null,
[CallerMemberName] string callerMemberName = null,
[CallerLineNumber] int callerLineNumber = 0)
{
return new CallerInfo(callerFilePath, callerMemberName, callerLineNumber);
}
}
推荐阅读
- c# - 如何保持 splitcontainer 面板大小成比例?
- java - 如何删除字符串中的额外换行符
- sql - 使用 UNIQUE NOT NULL 列时我真的需要 PRIMARY KEY 吗?
- html - 视频未下载 HTML 视频标签
- r - 正态分布bayesAB - 负均值
- r - 使用循环序列的值创建和命名新变量
- salesforce - NLP算法可以在Force.com平台上运行吗?
- groovy - java.lang.ClassCastException:将两个数字作为字符串进行比较时抛出 geb.content.TemplateDerivedPageContent
- javascript - 如何使用 Javascript/jQuery 从 FTP 服务器强制下载而不是在 Chrome 中打开 srt 文件?
- r - 找到偶数个字符的最长单词