使用 Log4net 的简单注入器和日志记录抽象

one*_*ill 2 c# log4net simple-injector

为了尝试使用 Log4net 获得良好的日志记录抽象,我从这篇 SO 帖子中获取了抽象,并从这篇 SO 帖子中获取了适配器,并尝试让它们一起工作。

真正剩下要做的就是配置容器,而这是我尚未成功完成的部分。

我尝试过的配置是

public static class InfrastructureRegistry
{
    public static void RegisterLoggingServices(this Container container)
    {
        container.RegisterConditional(typeof(ILog), c => LogManager.GetLogger(
            c.Consumer.ImplementationType).GetType(), 
            Lifestyle.Scoped, c => true);
        container.RegisterPerWebRequest<ILogger, Log4netAdapter>();
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您从代码中看到的,我想要一个特定的 log4net 记录器,它从注入的类中获取其类型。虽然大多数日志记录都是以包罗万象的方式完成的,但我希望在较低层中进行一些日志记录,例如当表单验证失败时。

ActivationException通过该配置得到的是:

LogImpl 类型的构造函数包含名称为“logger”且类型为 ILogger 的未注册参数。请确保ILogger已注册,或更改LogImpl的构造函数。

不太确定从这里去哪里,所以任何帮助将不胜感激。

编辑

抱歉,我应该指出,我正在尝试编写它,这样我只需编写此配置一次。以下工厂函数有效,但我不想每次要注入记录器时都手动添加更多配置:

container.RegisterPerWebRequest<ILog>(() => LogManager.GetLogger(typeof(LoginController)));
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

您指向的示例适配器假定应用程序中的每个组件都有一个记录器,而您希望有一个“了解”其使用者的特定记录器,以便它可以将日志消息与原始类相关联。

尽管在使用 log4net 和 NLog 等工具时这似乎是一种非常常见的做法,但根据我的经验,这一要求通常来自于代码中的太多地方进行日志记录这一事实。请阅读此 stackoverflow q/a以获取更多信息。

也就是说,如果您想有条件地注册记录器,则必须将适配器更改为通用类;这样你就可以使注册成为有条件的:

public class Log4netAdapter<T> : ILogger
{
    private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));

    public void Log(LogEntry entry)
    {
        if(entry.LoggingEventType == LoggingEventType.Information)
            logger.Info(entry.Message, entry.Exception);
        else if(entry.LoggingEventType == LoggingEventType.Warning)
            logger.Warn(entry.Message, entry.Exception);
        else if(entry.LoggingEventType == LoggingEventType.Error)
            logger.Error(entry.Message, entry.Exception);
        else
            logger.Fatal(entry.Message, entry.Exception);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这个通用类,您可以执行以下条件/上下文注册:

container.RegisterConditional(
    typeof(ILogger),
    c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);
Run Code Online (Sandbox Code Playgroud)