C# Serilog:如何使用字符串插值进行记录并在消息模板中保留参数名称?
C# Serilog: how to log with String interpolation and keep argument names in message templates?
如何替换此代码:
string name = "John";
logger.Information("length of name '{name}' is {nameLength}", name, name.Length);
像这样或类似的 C# 字符串插值
string name = "John";
// :-( lost benefit of structured logging: property names not passed to logger
logger.Information($"length of name '{name}' is {name.Length}");
但保留 属性 名称以使结构化日志记录正常工作?
好处是:
- 提高可读性
- 您永远不会忘记参数列表中的参数或消息模板中的 属性 名称,尤其是当您更改日志代码时
- 您总是知道这个 属性 名称将打印到您的日志中的内容
Add this file to your project. It has ILogger
extension methods VerboseInterpolated()
, DebugInterpolated()
and so on. There are also unit tests here。
格式字符串的用法
string name = "John";
// add 'Interpolated' to method name: InformationInterpolated() instead of Information()
// add name of the property after the expression. Name is passed to the logger
logger.InformationInterpolated($"length of name '{name:name}' is {name.Length:Length}");
但要小心:很容易用错方法。如果您不小心使用了 Serilog 的方法,例如 logger.Debug($"length = {length:propertyNameForLogger}")
,它将记录 length = propertyNameForLogger
,因此 没有参数值 将被记录。这是因为 propertyNameForLogger
是 format 的值。
匿名类型的用法
string name = "John";
// add 'Interpolated' to method name: InformationInterpolated() instead of Information()
// create an anonymous object with 'new { propertyName }'.
// It's much slower because of using Reflection, but allows to write the variable name only once.
logger.InformationInterpolated($"length of name '{new { name }}' is {new { name.Length }}");
// you can also specify other property names
logger.InformationInterpolated($"length of name '{new { userName = name }}' is {new { lengthOfName = name.Length }}");
谢谢你的好主意。我看到了一个缺点,那就是在与 DI 一起使用时不支持通用记录器。我已经扩展了@Artemious 解决方案。如果这不是正确的方法,请告诉我。
public static void LogInformationInterpolated<T>(this ILogger<T> logger, FormattableString? message) =>
WriteInterpolated<T>(logger, null, message, Information);
public static void LogInformationInterpolated<T>(this ILogger<T> logger, Exception? ex, FormattableString? message) =>
WriteInterpolated<T>(logger, ex, message, Information);
public static void WriteInterpolated<T>(this ILogger<T> logger, Exception? ex, FormattableString? message, Serilog.Events.LogEventLevel logEventLevel)
{
var contextedLogger = Log.ForContext<T>();
WriteInterpolated(contextedLogger, ex, message, logEventLevel);
}
ILogger 来自Microsoft.Extensions.Logging
命名空间,Serilog 好像没有。但我不是这方面的专家,因此愿意接受建议。
如何替换此代码:
string name = "John";
logger.Information("length of name '{name}' is {nameLength}", name, name.Length);
像这样或类似的 C# 字符串插值
string name = "John";
// :-( lost benefit of structured logging: property names not passed to logger
logger.Information($"length of name '{name}' is {name.Length}");
但保留 属性 名称以使结构化日志记录正常工作?
好处是:
- 提高可读性
- 您永远不会忘记参数列表中的参数或消息模板中的 属性 名称,尤其是当您更改日志代码时
- 您总是知道这个 属性 名称将打印到您的日志中的内容
Add this file to your project. It has ILogger
extension methods VerboseInterpolated()
, DebugInterpolated()
and so on. There are also unit tests here。
格式字符串的用法
string name = "John";
// add 'Interpolated' to method name: InformationInterpolated() instead of Information()
// add name of the property after the expression. Name is passed to the logger
logger.InformationInterpolated($"length of name '{name:name}' is {name.Length:Length}");
但要小心:很容易用错方法。如果您不小心使用了 Serilog 的方法,例如 logger.Debug($"length = {length:propertyNameForLogger}")
,它将记录 length = propertyNameForLogger
,因此 没有参数值 将被记录。这是因为 propertyNameForLogger
是 format 的值。
匿名类型的用法
string name = "John";
// add 'Interpolated' to method name: InformationInterpolated() instead of Information()
// create an anonymous object with 'new { propertyName }'.
// It's much slower because of using Reflection, but allows to write the variable name only once.
logger.InformationInterpolated($"length of name '{new { name }}' is {new { name.Length }}");
// you can also specify other property names
logger.InformationInterpolated($"length of name '{new { userName = name }}' is {new { lengthOfName = name.Length }}");
谢谢你的好主意。我看到了一个缺点,那就是在与 DI 一起使用时不支持通用记录器。我已经扩展了@Artemious 解决方案。如果这不是正确的方法,请告诉我。
public static void LogInformationInterpolated<T>(this ILogger<T> logger, FormattableString? message) =>
WriteInterpolated<T>(logger, null, message, Information);
public static void LogInformationInterpolated<T>(this ILogger<T> logger, Exception? ex, FormattableString? message) =>
WriteInterpolated<T>(logger, ex, message, Information);
public static void WriteInterpolated<T>(this ILogger<T> logger, Exception? ex, FormattableString? message, Serilog.Events.LogEventLevel logEventLevel)
{
var contextedLogger = Log.ForContext<T>();
WriteInterpolated(contextedLogger, ex, message, logEventLevel);
}
ILogger 来自Microsoft.Extensions.Logging
命名空间,Serilog 好像没有。但我不是这方面的专家,因此愿意接受建议。