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

Simple Injector and a Logging Abstraction Using Log4net

为了尝试使用 Log4net 获得良好的日志记录抽象,我采用了 this SO post and the adapter from 的抽象并试图让它们一起工作。

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

我试过的配置是

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>();
    }
}

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

我用那个配置得到的ActivationException是:

The constructor of type LogImpl contains the parameter with name 'logger' and type ILogger that is not registered. Please ensure ILogger is registered, or change the constructor of LogImpl.

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

编辑

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

container.RegisterPerWebRequest<ILog>(() => LogManager.GetLogger(typeof(LoginController)));

您指向的 假设应用程序中的每个组件都有一个记录器,而您希望有一个特定的记录器 'knows' 关于它的消费者,因此它可以关联将消息记录到原始 class.

虽然这似乎是使用 log4net 和 NLog 等工具时非常常见的做法,但根据我的经验,这种要求通常来自于日志记录在代码中的太多地方完成的事实。请阅读 this Whosebug q/a 了解更多信息。

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

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);
    }
}

使用此通用 class,您可以进行以下 conditional/contextual 注册:

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