Как мне спроектировать логирование в моем приложении? - PullRequest
5 голосов
/ 15 июля 2011

Итак, я провел много исследований по этому вопросу и не нашел ответов, где я сказал: «Да, ЭТО». Я надеюсь, что вечно эрудированная толпа StackOverflow поможет мне.

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

public class MyClass
{
    ... 

    public void ImportantMethod()
    {
        DoInterestingThing();

        var result = SomethingElseImportant();
        if (result == null)
        {
            logger.Log("I wasn't expecting that. No biggie.");
            return;
        }

        MoreInterestingStuff(); 
}

Меня интересует где взять logger из .

На мой взгляд, у меня есть несколько вариантов.

  1. Добавьте его в MyClass в конструкторе.
  2. Получите его, используя глобально доступный сервисный локатор.
  3. Используйте декораторы методов и AOP, чтобы сделать мою регистрацию для меня.

Ни один из этих вариантов не кажется отличным вариантом. # 3 выглядит невозможным, поскольку я регистрирую прямо в середине своей бизнес-логики, а не просто выполняю простую трассировку своих вызовов методов, входных параметров и / или выданных исключений. № 2, хотя простой кажется, что было бы очень трудно провести модульное тестирование. Конечно, я хотел бы проверить все. # 1, хотя он и работал бы нормально, загромождает всю мою бизнес-логику регистрационными объектами , которые не имеют ничего общего с самими бизнес-объектами.

Есть альтернативные идеи или мысли по поводу одного из вариантов выше? Большое спасибо!

РЕДАКТИРОВАТЬ: просто чтобы быть ясно, я уже знаю, как сделать DI (я использую Unity), и я уже знаю хорошую структуру ведения журналов (я использую log4net). Просто интересно, как использовать логирование в смысле архитектуры в приложении самым умным способом.


* РЕДАКТИРОВАТЬ *

Я отметил ответ Марка Симана как решение. Я просмотрел свое приложение и обнаружил, что большинство моих вызовов в журнале делали то же самое, что мог сделать декоратор. А именно, зарегистрируйте запись в методе, любые исключенные исключения и выйдите из возвращаемых значений.

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

private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));

LogProviderFactory имеет метод SetProvider, который позволяет заменять синглтон. Итак, в модульном тестировании я могу сделать:

// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);

Декоратор ведения журнала использует тот же LogProvider, что и синглтон (который он получает путем внедрения), поэтому ведение журнала объединяется во всей системе.

Так что на самом деле конечным решением был в основном вариант № 3 и гибрид № 2 (где это шаблон локатора службы, но служба «вводится» в локатор).

АОП

Что касается «аспектно-ориентированного программирования», я был немного разочарован ограничениями языка. Надеемся, что АОП будет рассматриваться как первоклассный гражданин в будущих выпусках.

  • Я попробовал PostSharp, но не смог правильно запустить его на моей машине. Кроме того, это было большим ограничением, что вы должны были установить PostSharp в вашей системе, чтобы использовать его (в отличие от простого вызова dll, который поставляется с решением или что-то подобное).
  • Я использовал LinFu и смог заставить его работать частично. Однако в нескольких случаях он взорвался. Новый выпуск 2.0 едва документирован, так что это было препятствием.
  • Интерфейсный перехват с Unity, однако, кажется, работает хорошо из коробки. Мне повезло, что большинство вещей, которые я хотел записать, были в классах, реализующих интерфейсы.

Ответы [ 3 ]

4 голосов
/ 15 июля 2011
2 голосов
/ 15 июля 2011

Два бита:

(1) - встроенная структура ведения журнала.

Некоторым людям нравится Log4Net, но я фанат EntLibs.Это делает тяжелую работу с точки зрения фактической регистрации.Такие инструменты, как EntLibs, позволят вам входить в различные типы репозиториев (база данных, очередь сообщений, текстовый файл и т. Д.).Они также позволят вам входить в различные экземпляры на основе категорий и так далее.Они обычно легко конфигурируются.

(2) - Пользовательские классы, которые обертывают каркас журналирования.

Итак, «регистратор» - это то, что вы пишете, и этовызывает структуру ведения журнала для фактического ведения журнала.

Мне нравится этот подход по нескольким причинам:

  • Вы отделяете структуру ведения журнала (# 1) от остальной части вашего приложения какПользовательские оболочки помещаются в отдельную сборку.
  • Написав свой собственный API ведения журнала, вы можете определить сигнатуры методов, соответствующие вашим потребностям, и расширить их.
  • Если вы работаете в команде, вы можете сделать сигнатуры методов очень простыми в использовании, чтобы никто не имел оснований утверждать, что использование журналирования было слишком сложным.
  • Оно ведет журналированиепоследовательны.Это также облегчает поиск кода для «незаконного» кода, который записывает в файлы, консоль или журнал событий, так как их не будет как часть вашей регистрации (это все в рамках).
  • Путем написания определенных пользовательских классов для каждого уровня вы можете предварительно заполнить большой объем данных за кулисами, упрощая жизнь тому, кто пишет настоящий код приложения.Вы можете установить серьезность, приоритет, идентификаторы событий по умолчанию, категории и т. Д.
  • Хорошо масштабируется с точки зрения сложности и роста приложения;это может показаться сложным для небольших приложений, но у вас будет много свободного места, если он начнет расти со временем.

Вот пример класса ведения журнала для информации в проекте I 'мы работали надОн имеет несколько простых для вызова открытых методов и один закрытый метод, который вызывает платформу (ConcreteLogInformation).

public static void LogInformation(string title, string message)

public static void LogInformation(string title, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, int eventId, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, int eventId)

public static void LogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, int eventId, string category)

public static void LogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties, string category)

private static void ConcreteLogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties, string category)
1 голос
/ 15 июля 2011

В Использование контекста запроса в Фабричном или Фабричном методе для выполнения контекстной привязки раздела Документы Ninject Contexttual Binding У меня есть пример использования вашего контейнера для ввода соответствующегорегистратор для вашего класса, выполнив (на ниндзектезе):

Bind<ILog>().ToMethod( context => LogFactory.CreateLog( context.Request.Target.Type ) );

Для отслеживания типа материала в статье перехвата Марка описан лучший подход.

И могу ли я снова попросить вас прочитать @Mark SeemannГлубоко процитировал статьи, прежде чем просто отбросить их без лишних голосов.

...