Ninject.Extensions.Logging.Log4net 意外行为

发布于 2024-12-02 06:42:49 字数 1269 浏览 1 评论 0 原文

我通过 Ninject 的 (2.2.1.4) Extensions.Logging.Log4net (2.2.0.4) 使用 Log4Net (1.2.10) 时遇到问题,通过 NuGet 安装。

当我直接访问 Log4Net 时:

var logger = log4net.LogManager.GetLogger("Log4NetLoggerTest");
logger.Debug("foo { bar");

结果是:

2011-08-29 10:02:02,071 [9] DEBUG Log4NetLoggerTest foo { bar

但是,当通过 Ninject 访问记录器时:

using (IKernel kernel = new StandardKernel())
{
    var ninjectLogger = kernel.Get<NinjectLoggerTest>();
    ninjectLogger.Log.Debug("foo { bar");
}

其中 NinjectLoggerTest 只是这样:

using Ninject.Extensions.Logging;
namespace TestApp
{
    public class NinjectLoggerTest
    {
        public NinjectLoggerTest(ILogger log)
        {
            Log = log;
        }
        public ILogger Log;
    }
}

有点出乎意料的是,结果是:

2011-08-29 10:29:27,114 [10] DEBUG TestApp.NinjectLoggerTest <log4net.Error>Exception during StringFormat: Input string was not in a correct format. <format>foo { bar</format><args>{}</args></log4net.Error>

更糟糕的是,当使用 ILogger 的 Trace 方法时,存在 type 的第一次机会异常mscorlib.dll 中的“System.FormatException”

我做错了什么吗?我该如何解决这个问题?

TIA

I am having a problem using Log4Net (1.2.10) through Ninject's (2.2.1.4) Extensions.Logging.Log4net (2.2.0.4), as installed through NuGet.

When I access Log4Net directly:

var logger = log4net.LogManager.GetLogger("Log4NetLoggerTest");
logger.Debug("foo { bar");

The result is:

2011-08-29 10:02:02,071 [9] DEBUG Log4NetLoggerTest foo { bar

However, when the logger is accessed through Ninject:

using (IKernel kernel = new StandardKernel())
{
    var ninjectLogger = kernel.Get<NinjectLoggerTest>();
    ninjectLogger.Log.Debug("foo { bar");
}

Where NinjectLoggerTest is simply this:

using Ninject.Extensions.Logging;
namespace TestApp
{
    public class NinjectLoggerTest
    {
        public NinjectLoggerTest(ILogger log)
        {
            Log = log;
        }
        public ILogger Log;
    }
}

Somewhat unexpectedly, the result is:

2011-08-29 10:29:27,114 [10] DEBUG TestApp.NinjectLoggerTest <log4net.Error>Exception during StringFormat: Input string was not in a correct format. <format>foo { bar</format><args>{}</args></log4net.Error>

Even worse, when using the ILogger's Trace method there is a first chance exception of type 'System.FormatException' in mscorlib.dll

Am I doing something wrong? How may I fix this?

TIA

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷弦 2024-12-09 06:42:49

解决方案是创建一个简单的记录器外观,将 Ninject 与应用程序的其余部分完全解耦。步骤是:

1) 将 Ninject 的 ILogger 接口复制/粘贴到应用程序的命名空间中(不要只是继承,否则您最终会依赖 Ninject 的程序集,因为通过 Ninject 的 ILogger 公开的类型)。

2) 创建自定义 Logger、LoggerFactory 和 LoggerModule 类。

3) 将 LoggerModule 传递给 Ninject 的 StandardKernel

为了完整起见,代码是:

Ninject 的 ILogger - 复制/粘贴 ILogger 接口,将其命名空间更改为 MyAppNamespace.Logger 并添加以下方法:

void Debug(string message);
void Info(string message);
void Trace(string message);
void Warn(string message);
void Error(string message);
void Fatal(string message);

Logger.cs

namespace MyAppNamespace.Logger
{
    using System;
    class Logger : Ninject.Extensions.Logging.Log4net.Infrastructure.Log4NetLogger, ILogger
    {
        private const string DumpVerbatimFormat = "{0}";

        public Logger(Type type)
            : base(type)
        {
        }

        public void Debug(string message)
        {
            base.Debug(DumpVerbatimFormat, message);
        }

        public void Info(string message)
        {
            base.Info(DumpVerbatimFormat, message);
        }

        public void Trace(string message)
        {
            base.Trace(DumpVerbatimFormat, message);
        }

        public void Warn(string message)
        {
            base.Warn(DumpVerbatimFormat, message);
        }

        public void Error(string message)
        {
            base.Error(DumpVerbatimFormat, message);
        }

        public void Fatal(string message)
        {
            base.Fatal(DumpVerbatimFormat, message);
        }
    }
}

LoggerFactory.cs

namespace MyAppNamespace.Logger
{
    using System;
    using System.Collections.Generic;

    static class LoggerFactory
    {
        public static ILogger GetLogger(Ninject.Activation.IContext context)
        {
            return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType);
        }

        private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>();

        private static ILogger GetLogger(Type type)
        {
            lock (TypeToLoggerMap)
            {
                if (TypeToLoggerMap.ContainsKey(type))
                    return TypeToLoggerMap[type];

                ILogger logger = new Logger(type);
                TypeToLoggerMap.Add(type, logger);

                return logger;
            }
        }
    }
}

LoggerModule.cs

namespace MyAppNamespace.Logger
{
    public class LoggerModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            log4net.Config.XmlConfigurator.Configure();
            Bind<ILogger>().ToMethod(LoggerFactory.GetLogger);
        }
    }
}

将整个混乱放入一个单独的类库中,使其成为唯一依赖于 Ninject 日志扩展和具体记录器的部分。现在,您可以在整个应用程序中使用 MyAppNamespace.ILogger,如下所示:

LoggerTest.cs

namespace MyAppNamespace.Whatever
{
    using Logger;
    public class LoggerTest
    {
        public LoggerTest(ILogger log)
        {
            Log.Info("Logger starting up");
        }
    }
}

Main.cs Main 中某处的

using (IKernel kernel = new StandardKernel(new Logger.LoggerModule()))
{
    kernel.Get<LoggerTest>();
}

最终取决于 Ninject,但不取决于日志扩展以及您使用的任何记录器(该代码适用于 Log4Net,您需要调整NLog 的一点)。应用程序的其他部分依赖于 MyAppNamespace.ILogger。就是这样。

The solution is to create a simple logger façade to completely decouple Ninject from the rest of the app. The steps are:

1) Copy/paste Ninject's ILogger interface into the app's namespace (do not just inherit or you end up depending on Ninject's assembly because of the types exposed through Ninject's ILogger).

2) Create custom Logger, LoggerFactory and LoggerModule classes.

3) Pass LoggerModule to Ninject's StandardKernel

For completeness the code is:

Ninject's ILogger - copy/paste the ILogger interface, change it's namespace to MyAppNamespace.Logger and add the following methods:

void Debug(string message);
void Info(string message);
void Trace(string message);
void Warn(string message);
void Error(string message);
void Fatal(string message);

Logger.cs

namespace MyAppNamespace.Logger
{
    using System;
    class Logger : Ninject.Extensions.Logging.Log4net.Infrastructure.Log4NetLogger, ILogger
    {
        private const string DumpVerbatimFormat = "{0}";

        public Logger(Type type)
            : base(type)
        {
        }

        public void Debug(string message)
        {
            base.Debug(DumpVerbatimFormat, message);
        }

        public void Info(string message)
        {
            base.Info(DumpVerbatimFormat, message);
        }

        public void Trace(string message)
        {
            base.Trace(DumpVerbatimFormat, message);
        }

        public void Warn(string message)
        {
            base.Warn(DumpVerbatimFormat, message);
        }

        public void Error(string message)
        {
            base.Error(DumpVerbatimFormat, message);
        }

        public void Fatal(string message)
        {
            base.Fatal(DumpVerbatimFormat, message);
        }
    }
}

LoggerFactory.cs

namespace MyAppNamespace.Logger
{
    using System;
    using System.Collections.Generic;

    static class LoggerFactory
    {
        public static ILogger GetLogger(Ninject.Activation.IContext context)
        {
            return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType);
        }

        private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>();

        private static ILogger GetLogger(Type type)
        {
            lock (TypeToLoggerMap)
            {
                if (TypeToLoggerMap.ContainsKey(type))
                    return TypeToLoggerMap[type];

                ILogger logger = new Logger(type);
                TypeToLoggerMap.Add(type, logger);

                return logger;
            }
        }
    }
}

LoggerModule.cs

namespace MyAppNamespace.Logger
{
    public class LoggerModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            log4net.Config.XmlConfigurator.Configure();
            Bind<ILogger>().ToMethod(LoggerFactory.GetLogger);
        }
    }
}

Tuck this whole mess away into a separate class library making it the only piece dependent on Ninject's logging extension and the concrete logger. You can now use MyAppNamespace.ILogger throughout your app, like this:

LoggerTest.cs

namespace MyAppNamespace.Whatever
{
    using Logger;
    public class LoggerTest
    {
        public LoggerTest(ILogger log)
        {
            Log.Info("Logger starting up");
        }
    }
}

somewhere in Main.cs

using (IKernel kernel = new StandardKernel(new Logger.LoggerModule()))
{
    kernel.Get<LoggerTest>();
}

Main ends up depending on Ninject but not the logging extension and whatever logger you use (the code works with Log4Net, you will need to tweak a bit for NLog). Other parts of the app depend on MyAppNamespace.ILogger. That's about it.

菊凝晚露 2024-12-09 06:42:49

根据官方问题跟踪器,此问题已在版本中修复Ninject.Extensions.Logging 的 3.0.2,因此更新该库将解决该问题。

According to official issue tracker, this was fixed in version 3.0.2 of Ninject.Extensions.Logging, so updating that library will solve the issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文