2016-10-07 11 views
2

Я настраиваю ведение журнала для своей заявки и для ведения журнала. Я использую log4net и castle windsor для DI.Log4Net с замком windsor

Я хочу, чтобы структура каротажа была обернута внутри пользовательской реализации, поэтому ее можно изменить в будущем.

public interface ICustomLogger 
{ 
    void Debug(object message, Exception ex = null); 
    void Info(object message, Exception ex = null); 
    void Warn(object message, Exception ex = null); 
    void Error(object message, Exception ex = null); 
    void Fatal(object message, Exception ex = null); 
} 

public class CustomLogger : ICustomLogger 
{ 
    private readonly log4net.ILog _log; 
    private readonly log4net.ILog _log1; 

    public CustomLogger() 
    { 
     //approach1 
     var stack = new StackTrace(); 
     var frame = stack.GetFrame(1); 
     var method = frame.GetMethod(); 
     Type type = method.DeclaringType; 
     _log = log4net.LogManager.GetLogger(type); 

     //approach2 
     var dtype = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType; 
     _log1 = log4net.LogManager.GetLogger(dtype); 
    } 

    public CustomLogger(string name) 
    { 
     _log = log4net.LogManager.GetLogger(name); 
    } 

    public CustomLogger(Type type) 
    { 
     _log = log4net.LogManager.GetLogger(type); 
    } 

    public void Debug(object message, Exception ex = null) 
    { 
     if (_log.IsDebugEnabled) 
     { 
      if (ex == null) 
      { 
       _log.Debug(message); 
      } 
      else 
      { 
       _log.Debug(message, ex); 
      } 
     } 
    } 

    public void Info(object message, Exception ex = null) 
    { 
     if (_log.IsInfoEnabled) 
     { 
      if (ex == null) 
      { 
       _log.Info(message); 
      } 
      else 
      { 
       _log.Info(message, ex); 
      } 
     } 
    } 

    public void Warn(object message, Exception ex = null) 
    { 
     if (_log.IsWarnEnabled) 
     { 
      if (ex == null) 
      { 
       _log.Warn(message); 
      } 
      else 
      { 
       _log.Warn(message, ex); 
      } 
     } 
    } 

    public void Error(object message, Exception ex = null) 
    { 
     if (_log.IsErrorEnabled) 
     { 
      if (ex == null) 
      { 
       _log.Error(message); 
      } 
      else 
      { 
       _log.Error(message, ex); 
      } 
     } 
    } 

    public void Fatal(object message, Exception ex = null) 
    { 
     if (_log.IsFatalEnabled) 
     { 
      if (ex == null) 
      { 
       _log.Fatal(message); 
      } 
      else 
      { 
       _log.Fatal(message, ex); 
      } 
     } 
    } 
} 

Чтобы зарегистрировать собственную реализацию с DI ...

container.Register(Component.For<ICustomLogger>() 
            .ImplementedBy<CustomLogger>() 
            .LifeStyle.Transient); 

Проблема возникает, когда я прошу DI разрешить регистратор, то он всегда возвращает регистратор для Customlogger типа не класс, где я хочу использовать Это.

class ABC 
{ 
    ICustomLogger _logger; 

    public ABC(ICustomLogger logger) 
    { 
     _logger = logger; // type of this logger is CustomLogger not ABC 
    } 
} 

Оба подхода не работают, чтобы разрешить регистрацию как ABC. Может ли кто-нибудь помочь мне понять, что здесь не так, и как исправить проблему.

ответ

2

Вы можете сделать это с помощью пользовательского dependency resolver.

Сначала необходимо создать реализацию ISubDependencyResolver, которая может решить зависимости типа ICustomLogger:

public class LoggerResolver : ISubDependencyResolver 
{ 
    public bool CanResolve(
     CreationContext context, 
     ISubDependencyResolver contextHandlerResolver, 
     ComponentModel model, 
     DependencyModel dependency) 
    { 
     //We can only handle dependencies of type ICustomLogger 
     return dependency.TargetType == typeof (ICustomLogger); 
    } 

    public object Resolve(
     CreationContext context, 
     ISubDependencyResolver contextHandlerResolver, 
     ComponentModel model, 
     DependencyModel dependency) 
    { 
     //We pass the requested type, e.g. ABC, to the constructor of CustomLogger 
     return new CustomLogger(context.RequestedType); 
    } 
} 

Затем нужно зарегистрировать этот распознаватель с контейнером, как это:

container.Kernel.Resolver.AddSubResolver(new LoggerResolver()); 
1

Для вашего конкретный вопрос - в обоих подходах вы никогда не покидаете «сферу» вашего класса. С первым вы создаете новый StackTrace, а в другом объявляющий тип конструктора - это сам класс.

Но вы внедрили конструктор, который может получить тип , поэтому почему бы не использовать его. В настоящее время ваш CustomLogger зарегистрирован ваш конструктор по умолчанию:

//There is no place here that you tell castle to resolve using the constructor 
//that receives `ABS` 
container.Register(Component.For<ICustomLogger>() 
          .ImplementedBy<CustomLogger>() 
          .LifeStyle.Transient); 

См Castle Windsor passing constructor parameters, чтобы понять, как передавать параметры и таким образом вызывать конструктор вы хотите


Кроме того - Worth переосмысление :

Хотя это хорошая идея для создания такой абстракции между вашим кодом и внешним источником в этом случае я бы этого не сделал, и я объясню, почему:

  1. Из моего опыта никто не меняет структуру ведения журнала после того, как код запущен и работает. Тем более, что вы работаете со зрелой и отличной рамкой - Log4Net. Он имеет множество встроенных способностей и очень адаптирован для удовлетворения потребностей: от различного форматирования сообщений до вывода журналов в разные источники, такие как базы данных, файлы, и, если я не ошибаюсь, есть также приложения для таких вещей, как поиск эластичных изображений.
  2. Вы используете Castle Windsor, который имеет хорошую интеграцию с Log4Net и имеет для вас готовый Logging Facility до Log4Net. См. this question, как просто его добавить.
  3. Последняя точка в том, что если вы уже писать хороший SOLID код и передать свой регистратор как ILogger ко всем компонентам (а не конкретной реализации), все они, вероятно, сделать, это вызвать различные Debug/Info/Warn/Error/Fatal методы - что будет иметь любая другая зрелая структура каротажа. Поэтому в тот же день вам придется изменить (что, я думаю, не произойдет), вы можете написать интерфейс, который выглядит как интерфейс Log4Net и реализация, которая адаптирует это к вашей новой структуре ведения журнала.