使用 Serilog 的模式(通过 ILogger 与使用静态 Serilog.Log) [英] Pattern to use Serilog (pass ILogger vs using static Serilog.Log)

查看:241
本文介绍了使用 Serilog 的模式(通过 ILogger 与使用静态 Serilog.Log)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

在选择 Serilog 作为记录器的新项目中,我自动开始传递 ILogger 接口.代码访问 Log.Logger 一次,然后需要记录的类通过构造函数注入接受 ILogger.

In a new project where Serilog was chosen as the logger I automatically started passing around ILogger interface. The code accesses Log.Logger once and from then the classes that desire logging accept ILogger via constructor injection.

我在这种做法上遇到了挑战,建议是在 Log 类上使用静态方法,例如Serilog.Log.Debug(...).争论是在 Log.Logger 上有一个 set; 所以模拟很容易.

I was challenged on this practice and the advice was to use the static methods on the Log class, e.g. Serilog.Log.Debug(...). The argument is that there is a set; on Log.Logger so mocking is easy.

查看 api 我可以看到传递 ILogger 的好处之一是 ForContext 方法.

Looking at the api I can see that one of the benefits of passing ILogger are the ForContext methods.

我在网络和 Serilog 的文档上花了一些时间,但我找不到有关在整个应用程序代码中访问日志的规范方式的信息.

I spent some time on the webs and in the Serilog's documentation but I could not find information about a canonical way to access the log throughout the application code.

问题

是否有一种规范的,即在大多数情况下更好的方法来访问/传递 Serilog 记录器,如果有,它是否传递了 ILogger 或在 Serilog.Log 类上使用静态 api?

Is there a canonical, i.e. better-in-most-cases, way to access/pass around the Serilog logger and if there is, is it passing ILogger or using the static api on the Serilog.Log class?

推荐答案

Log.Logger 上还有一个 ForContext,所以我不会在此基础上做出决定.如果您正在模拟/测试日志记录,您不想通过单个全局实例来执行此操作.相反,任何进行日志记录的库代码都应该接受一个 ILogger 参数作为输入,使调用者能够检测和/或只在他们认为合适的时候传入 Log.Logger(不要在内部为 Log.Logger 添加默认值,出于同样的原因,使用默认构造函数自动构建您正在寻求解耦的依赖项是一个坏主意).如果你不这样做,你将无法有意义地测试日志输出是否正确(因为任何最终并行运行的并发测试都将写入完全相同的记录器实例),这是一件大事

There is also a ForContext on Log.Logger, so I would not decide on that basis. If you're doing mocking/testing of logging, you don't want to do that via the single global instance. Instead, any library code that will do logging should admit an ILogger parameter as input, enabling the caller to instrument and/or just pass in Log.Logger as they see fit (don't add defaulting to Log.Logger internally, for the same reasons that having a default constructor that auto-constructs dependencies that you're seeking to decouple from is a bad idea). If you don't do this, you won't be able to meaningfully test logging outputs are correct (because any concurrent tests that end up running in parallel will be writing to the exact same logger instance), which is a big thing to give up.

对我来说,主要的权衡实际上是您是否愿意使用 Enrich.FromLogContextLogContext.* 接口,它们将状态挂在 .NET 之外 ExecutionContext,你需要小心不要疯狂.(是的,可以说您可以使用隔离在 ExecutionContext 中的收集器来破解我之前的观点,但甚至不要去那里.)

For me, the main tradeoff is actually whether you're willing to use Enrich.FromLogContext and the LogContext.* interfaces, which hang state off the .NET ExecutionContext, which you need to be careful to not go crazy with. (Yes, arguably you can use a collector sequestered in the ExecutionContext to hack around my previous point, but don't even go there.)

根据您的 DI 是如何操纵的,您可能希望在您的输入中使用 ILogger,但同样,除非有人需要能够检测到信息,有一个static ILogger _logger = Log.ForContext() 没问题,只要 Log 连接得足够早.

Depending on how your DI is rigged, you may want to take an ILogger<T> in your inputs, but again, unless someone needs to be able to instrument to grab the info, having a static ILogger _logger = Log.ForContext<MyClass>() is fine as long as the Log is wired up early enough.

这篇关于使用 Serilog 的模式(通过 ILogger 与使用静态 Serilog.Log)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆