提问人:Miriam F. 提问时间:11/7/2023 最后编辑:Miriam F. 更新时间:11/16/2023 访问量:107
如何在 C 中使用 Serilog 记录 classPath、methodName 和 lineNumber#
How to log the classPath, methodName and lineNumber with Serilog in C#
问:
我想将日志从我的系统打印到文件 (.NET Framework 4.6.1) 我想打印以下信息:className、methodName、lineNumber,从中调用了日志条目。
我有一个 Serilog 类: `
public class SerilogClass
{
public static readonly ILogger _log;
static SerilogClass()
{
string logsFolder = ConfigurationManager.AppSettings["logsFolder"];
string environment = ConfigurationManager.AppSettings["environment"];
_log = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File(logsFolder + "//" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log", outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:Ij}{NewLine}{Exception}")
.CreateLogger();
}
}
我正在尝试用日志记录系统:
public class MyClass
{
private readonly ILogger _log = SerilogClass._log;
public void GetData()
{
_log.information("run GetData, **here I want to print by default the class path and the line number**")
}
}
我应该在 SerilogClass 中添加什么? 我很乐意为您提供建议。谢谢。
答:
1赞
Terentiy Gatsukov
11/7/2023
#1
若要在 Serilog 中自动记录类名、方法名和行号,可以使用 Serilog.Enrichers.StackTrace NuGet 包。
public class SerilogClass
{
public static readonly ILogger _log;
static SerilogClass()
{
string logsFolder = ConfigurationManager.AppSettings["logsFolder"];
string environment = ConfigurationManager.AppSettings["environment"];
_log = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.WithDemystifiedStackTraces() // Add this to enrich with stack trace information
.WriteTo.File(
path: Path.Combine(logsFolder, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"),
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}.{Method}({LineNumber}): {Message:lj}{NewLine}{Exception}")
.CreateLogger();
}
}
public class MyClass
{
private readonly ILogger _log = SerilogClass._log.ForContext<MyClass>();
public void GetData()
{
_log.Information("Run GetData");
}
}
下面是使用配置了 Serilog.Enrichers.StackTrace 的 Serilog 时日志条目的外观示例:
[15:42:01 INF] MyNamespace.MyClass.GetData(42): Run GetData
要像 Blindy 所说的那样,在不需要外部包的情况下自动记录类名、方法名和行号,可以使用 C# 提供的编译器服务功能,例如 、 和 。Serilog.Enrichers.StackTrace
CallerMemberName
CallerFilePath
CallerLineNumber
例:
public static class SerilogExtensions
{
public static void LogWithDetailedInfo(
this ILogger logger,
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
var className = Path.GetFileNameWithoutExtension(sourceFilePath);
logger.Information("{ClassName}.{MemberName}({LineNumber}): {Message}", className, memberName, sourceLineNumber, message);
}
}
public static class SerilogClass
{
public static readonly ILogger Log;
static SerilogClass()
{
string logsFolder = "path_to_logs_folder"; // Update with your configuration method
string environment = "development"; // Update with your configuration method
Log = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File(
path: Path.Combine(logsFolder, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"),
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
}
}
public class MyClass
{
private readonly ILogger _log = SerilogClass.Log.ForContext<MyClass>();
public void GetData()
{
_log.LogWithDetailedInfo("Run GetData");
}
}
2赞
Blindy
11/7/2023
#2
您可以使用 CallerMemberName
、CallerLineNumber
和 CallerFilePath
修饰的默认参数编写扩展方法,以生成所需的任何消息并将其转发到记录器。
作为上面 Terntiy 回答的一个好处,这种方法对运行时的影响为零,因为编译器会在编译时将参数注入为纯字符串,而堆栈跟踪扩充需要在运行时检查堆栈跟踪以提取信息(相当昂贵)。此方法也不需要调试符号来解码堆栈跟踪。
评论
0赞
Miriam F.
11/7/2023
首先,谢谢。你有例子吗?
0赞
Terentiy Gatsukov
11/7/2023
@MiriamF。我可以举个例子来补充我的答案。
0赞
Terentiy Gatsukov
11/7/2023
@MiriamF。做!
1赞
Miriam F.
11/7/2023
@TerentiyGatsukov - 谢谢!
评论