Установка имени логгера log4net - PullRequest
0 голосов
/ 24 января 2011

Я использую средство регистрации Замка с log4net в моем приложении (веб-приложение MVC3). Однако вместо непосредственного использования интерфейса ILogger я абстрагировал его, создав другой интерфейс (IAuditor) с конкретной реализацией Log4NetAuditor (см. Код ниже).

Вы можете спросить, почему я это сделал, поскольку цель ILogger - абстрагировать базовую реализацию протоколирования. Я сделал это из-за строгого соблюдения принципа onion для абстрагирования всех проблем инфраструктуры.

Теперь это работает просто отлично, за исключением того, что все регистраторы имеют одинаковые имена: MyProject.Infrastructure.Log4NetAuditor:

2011-01-24 13:26:11,746 [11] DEBUG MyProject.Infrastructure.Log4NetAuditor [] - Attempting login...
2011-01-24 13:26:11,845 [11] DEBUG MyProject.Infrastructure.Log4NetAuditor [] - Authentication result is Authenticated

IAuditor предоставляется как свойство AuditableComponent, являющегося абстрактным классом, из которого происходят все компоненты, требующие ведения журнала.

public abstract class AuditableComponent
{
    private IAuditor _auditor = NullAuditor.Instance;

    public IAuditor Auditor
    {
        get { return _auditor; }
        set { _auditor = value; }
    }

    //....
}

Класс Log4NetAuditor выглядит следующим образом:

public class Log4NetAuditor : IAuditor
{
    private ILogger _logger = NullLogger.Instance;

    public ILogger Logger
    {
        get { return _logger; }
        set { _logger = value; }
    }

    public void Trace(string message)
    {
        _logger.Debug(message);
    }
}

Теперь понятно, почему все операторы журнала имеют одно и то же имя регистратора: ILogger внедряется в класс Log4NetAuditor.

Как же тогда я могу убедиться, что имя регистратора соответствует имени класса, расширяющего AuditableComponent?

1 Ответ

1 голос
/ 24 января 2011

Я сделал то же самое, что и вы, но я также включил статический класс LogManager, задачей которого было создать экземпляр вашего регистратора.Я сделал свои конструкторы внутренними в классе Logger (ваш аудиторский класс), чтобы их нельзя было создать напрямую.Это означает, что любой внешний объект должен получить свою ссылку через класс LogManager.

public static class LogManager
{
    public static readonly ILogger Log = CreateLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Creates the logger for the specified type.
    /// </summary>
    /// <param name="loggerType">Type of the logger.</param>
    /// <returns></returns>
    public static Logger CreateLogger(Type loggerType)
    {
        return new Logger(loggerType);
    }

    /// <summary>
    /// Creates the logger for the specified name.
    /// </summary>
    /// <param name="loggerName">Name of the logger.</param>
    /// <returns></returns>
    public static Logger CreateLogger(string loggerName)
    {
        return new Logger(loggerName);
    }
}

Теперь эти типы смогут создавать экземпляры вашего Auditor, передавая свой собственный тип в метод Create.

ОБНОВЛЕНИЕ -

Я использовал контейнер Unity для вставки зависимостей в этот код.Соответствующими битами является InjectionFactory.Это позволяет мне указывать статический метод локально, чтобы внедрить тип, основанный на некоторых условиях.

DependencyInjection.Container.RegisterType<IFormatter>(
    new ContainerControlledLifetimeManager(),
    new InjectionFactory(c => CreateFormatter(filename, outputType)));

...

        private static IFormatter CreateFormatter(string filename, OutputType outputType)
        {
            TextWriter textWriter = (filename.Length > 0) ? new StreamWriter(filename) : new StreamWriter(Console.OpenStandardOutput());
            var formatter = (outputType == OutputType.Xml) ? (IFormatter)new XmlFormatter(textWriter) : new CsvFormatter(textWriter);

            return formatter;
        }

...
// Calling it
using (var formatter = DependencyInjection.Container.Resolve<IFormatter>())
{
    if (timeLimit <= 1000) retval = OutputResults(results, formatter, msxQuery);
    else TimedOutputResults(results, formatter, msxQuery, timeLimit, OutputResults);
}

Ну, это как минимум для меня!

...