【问题标题】:Implement ILogger interface the right way以正确的方式实现 ILogger 接口
【发布时间】:2017-01-15 22:51:30
【问题描述】:

给定几种类型的类构造函数注入,即;

public class DataService :IDataService
{
    public DataService(ILogger logger) { ... }
}

和,

public class Logger
{
     public Logger(IDataService service) { ... }
}

或者,我应该这样做;

public class DataService : IDataService, ILogger, IDisposable
{
    public DataService() { ... }
}

但是,我实际上不喜欢在每个存储库类或其他需要同时进行数据服务和日志记录的类上执行此操作;

public class SomeRepository : IRepostiory
{
    public SomeRepository (IDataService service, ILogger logger) { ... }
}

我对这个模型很好;

public interface IRepository : ILogger { ... }

或者,

public interface IDataService : ILogger { ... }

哪一个更适合作为最佳实践设计?另外,我们如何确定是否要记录数据服务进程,同时我们还要记录注入 ILogger 服务或使用存储库的其他组件?

【问题讨论】:

  • 为什么您的记录器需要 idataservice?只是问,因为那是一个循环引用.. 讨厌!:(另外,我假设记录器实现 ilogger,可能是错的!
  • 您能否详细说明DataService 的目的,我感觉您选择了低效设计。
  • 通常,你注入到构造函数,或者注入到需要你注入的任何东西的方法中。
  • @ChrisWatts,啊,好吧。我需要将日志保存到数据库的数据服务。不,它不是循环引用,问题是选择哪个更好。项目中只有一种类型。我知道我可以直接在数据库的记录器中执行此操作,这就是为什么我想知道如何执行此操作。
  • @OrelEraki,当然,我需要为我的存储库提供数据服务。数据服务可以是任何存储连接器。可能这里的命名不合适。无论如何,如果我也想在数据服务中记录某些内容,那么问题的上下文是哪个更好以及如何使用数据库实现日志记录。

标签: c# logging dependency-injection architecture


【解决方案1】:

这是一个开玩笑的答案,但没有“正确”的方式来实现 ILogger。您可能应该使用现有的框架来构建一个ILogger,或者将其交给 NLog、log4net 或 Serilog。除非您计划构建自己的日志框架,否则不应直接实现 ILogger。您应该使用日志库的扩展方法来连接ILogger 这是关于此的article

这是一个如何让控制台登录并运行的最小示例:

var hostBuilder = Host.CreateDefaultBuilder().
ConfigureLogging((builderContext, loggingBuilder) =>
{
    loggingBuilder.AddConsole((options) =>
    {
        //This displays arguments from the scope
        options.IncludeScopes = true;
    });
});
var host = hostBuilder.Build();
var logger = host.Services.GetRequiredService<ILogger<LogTest>>();
//This specifies that every time a log message is logged, the correlation id will be logged as part of it
using (logger.BeginScope("Correlation ID: {correlationID}", 123))
{
    logger.LogInformation("Test");
    logger.LogInformation("Test2");
}

【讨论】:

    【解决方案2】:

    我想补充一点,BeginScope 方法可以接受任何类型的对象,而不仅仅是字符串。您可以传递一个更复杂的对象,它可以更好地表示上下文/范围,例如 User Id、HostName、CorrelationId、Tennant Id ...

    在我的情况下,我创建了一个外部 Api Logger 服务,从而创建了我自己的 ILogger,其中带有这些值的 BeginScope 更有意义。

    public IDisposable BeginScope<TState>(TState state)
    {
        _scopeContextManager = state as ScopeContextManager;
        return default!;
    }
    
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, 
         Exception exception, Func<TState, Exception, string> formatter)
    {
        // use _scopeContextManager 
    }
    

    我挣扎了很久才弄明白。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2017-12-13
      • 2016-05-24
      相关资源
      最近更新 更多