Ninject.Extensions.Logging.Log4net непредвиденное поведение - PullRequest
6 голосов
/ 29 августа 2011

У меня проблема с использованием Log4Net (1.2.10) через Ninject's (2.2.1.4) Extensions.Logging.Log4net (2.2.0.4), установленного через 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>

Что еще хуже, при использовании метода Trace в ILogger существует первое исключение типа «System.FormatException» в mscorlib.dll

Я что-то не так делаю? Как я могу это исправить?

ТИА

Ответы [ 2 ]

5 голосов
/ 30 августа 2011

Решение состоит в том, чтобы создать простой фасад регистратора, чтобы полностью отделить Ninject от остальной части приложения. Шаги:

1) Скопируйте / вставьте интерфейс Ninject ILogger в пространство имен приложения (не просто наследуйте, или вы в конечном итоге зависите от сборки Ninject из-за типов, предоставляемых через ILogger Ninject).

2) Создание пользовательских классов Logger, LoggerFactory и LoggerModule.

3) Передайте LoggerModule в StandardKernel Ninject

Для полноты код:

Ninject's 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

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

Main заканчивается в зависимости от Ninject, но не от расширения журналирования и от того, какой регистратор вы используете (код работает с Log4Net, вам нужно немного настроить NLog). Другие части приложения зависят от MyAppNamespace.ILogger. Вот и все.

0 голосов
/ 09 сентября 2016

В соответствии с официальным средством отслеживания ошибок , это было исправлено в версии 3.0.2 Ninject.Extensions.Logging, поэтому обновление этой библиотеки решит проблему.

...