Возможно ли пассивное ведение журнала в .NET? - PullRequest
8 голосов
/ 27 марта 2009

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

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

public void MyProcess(int a, string b, object c)
{
  log(
    String.Format(
      "Entering process MyProcess with arguments: [a] = [{0}]; [b] = [{1}]; [c] = [{2}]",
      a.ToString(),
      b,
      c.ToString()
  );

  try
  {
    int d = DoStuff(a)
    log(
      String.Format(
        "DoStuff({0}) returned value {1}",
        a.ToString(),
        d.ToString()
      )
    );
  }
  catch (Exception ex)
  {
    log(
      String.Format("An exception occurred during process DoStuff({0})\nException:\n{1}",
      a.ToString(),
      ex.ToString())
    )
  }
}

Что было бы замечательно, если бы я мог сказать своему регистратору:

Monitor(MyClass.MyMethod)

Затем он будет отслеживать все, что происходит внутри этого метода, включая передаваемые в аргументах вместе с вызовами методов и значениями, передаваемыми в эти методы, возникающими исключениями и т. Д.

Кто-нибудь реализовывал что-то подобное в прошлом? Может ли быть реализованным? Вход в эту моду - несбыточная мечта?

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

Любые предложения будут с благодарностью приняты ...

Редактировать: Я подумал, что прокомментирую ответ, в котором запрашивается уровень детализации, требуемый в журнале. Часто требуется обеспечить настраиваемые уровни ведения журнала таким образом, чтобы, если в конфигурации указана подробная запись в журнал, все регистрировалось, тогда как если настроено критическое ведение журнала, то регистрируется только определенная информация вместе с исключениями. Если фатальное ведение журнала настроено, будет регистрироваться только та информация, которая приводит к смерти приложения. Будет ли что-то подобное настраиваться или AOP потребует 3 или 4 разных сборок в зависимости от количества уровней ведения журнала?

Я часто использую 4 уровня: Фатальный, Критический, Информация, Подробный

Ответы [ 6 ]

9 голосов
/ 27 марта 2009

Вы можете использовать PostSharp для входа "вокруг" метода. Это именно то, что хорошо АОП хорошо. Возможно, вы захотите начать с Log4PostSharp - плагин специально для регистрации.

4 голосов
/ 27 марта 2009

Это один из учебников (не уверен, в каком учебнике есть AoP, но вы поняли) примеры AoP - ведения журнала: где вы хотите вставить что-то до и после метода.

Возможно, вы захотите изучить маршрут AoP, PostSharp - один из самых популярных, наряду с Microsoft Unity (также IoC), Castle.

Одним из упрощенных примеров AoP является добавление кода до и после методов вместо добавления вызовов методов внутри реальных методов. Поскольку вы пометили вопрос с помощью C #, вы можете просто захотеть создать метод расширения для его регистрации, который уже находится в этом вопросе .

Я бы выбрал практический подход: сколько реальных журналов вы делаете? Можете ли вы обойтись просто с помощью метода расширения вместо того, чтобы просто ослеплять человека, читающего ваш код. Ведение журнала , встроенного в .NET Framework , уже достаточно прилично.

4 голосов
/ 27 марта 2009

Это классический пример из аспектно-ориентированного программирования. См. PostSharp для очень хорошей библиотеки на основе CLR.

1 голос
/ 27 марта 2009

В дополнение к методам регистрации, упомянутым Джоном, вероятно, стоит также отметить еще одну полезную функцию в VS для отслеживания потока программы, и это возможность иметь неразрывные точки останова, которые будут просто выводить сообщение или запускать макрос при хит (обратите внимание, что вы также можете распечатать значения переменных)

Щелкните правой кнопкой мыши по точке останова и выберите пункт контекстного меню «При попадании ...».

И, конечно, еще одна очень полезная функция - это объект трассировки и списки трассировки в System.Diagnostics.

0 голосов
/ 28 октября 2009

Я использую OpenSource Apache log4net во всех моих проектах. Это очень простая реализация со всеми видами расширений, которые позволяют вам регистрироваться в базах данных, zip-файлах, обновляемых лог-файлах, каналах RRS, клиентах telnet и т. Д. Ведение журнала в основном так же просто, как

'Will print stack trace after message'
log.err(ex.message,ex)

log.warn("warn")
log.info("info")
log.debug("debug")

Параметры регистрации, такие как формат вывода и уровень журнала для вывода, считываются в режиме реального времени, пока ваше приложение находится во время выполнения.

0 голосов
/ 21 октября 2009

Недавно я написал библиотеку журналов, которая использует интерфейс IDisposable для переноса областей в контекст журналирования. По сути, есть одноразовый объект LogSite, который вы используете следующим образом:

using(var logger = new LogSite("methodName", new object[] { p1, p2, p3 })
{
    // code that does stuff goes here
}

Объект LogSite имеет несколько удобных перегрузок для конструктора, таких как MethodBase, поэтому вы можете просто использовать MethodBase.GetCurrentMethod () и использовать отражение, чтобы получить фактическое имя метода и параметров (вместо жестко закодированных строк). ,

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

При утилизации он также проверяет Marshal.GetExceptionCode () на ненулевое значение, чтобы увидеть, выдал ли код внутри объекта исключение или нормально завершился. Это не дает вам исключения, так что это должно будет быть явно зарегистрировано в обработчике перехвата, но это указывает «пройти / не пройти» для этого региона. Это позволяет вашей области ведения журнала быть более конкретным, чем просто метод, поскольку вы можете иметь множество этих блоков в одном методе и точно знать, какой из них выдает исключение.

Кроме того, поскольку теперь доступен объект "logger", ваш обработчик catch выглядит так:

try { ... } 
catch (Exception ex)
{ 
    logger.LogException(ex);
}

Регистратор уже знает имя метода, информацию о параметрах и все такое и имеет внутренние методы для форматирования информации об исключении.

Попав в архитектуру ниже этого высокоуровневого объекта, есть концепция «LogDisposition», которая обрабатывает «проход / неудача», которую мы определили ранее, и есть концепция «LogEntryType», которая представляет собой фильтр (реализованный с помощью перечисления Flags ), который указывает, какой тип записи журнала передается (ошибка, трассировка и т. д.).

То, что фактически делает ведение журнала, это просто шаблон издателя / слушателя. Издатель принимает переданную в журнале запись и во многом похож на многоадресного делегата, ведет реестр экземпляров LogListener (должен быть установлен в начале программы или добавляется динамически по мере необходимости) и передает запись журнала в эти экземпляры. ,

LogListeners, в свою очередь, отфильтровывают, какие записи журнала им нужны. Так что, если вы не хотите, чтобы точки входа и выхода метода находились в условиях отсутствия ошибок, они не должны отображаться в журнале. , Это можно контролировать во время выполнения, чтобы пользователь мог по своему усмотрению включать и выключать детальную регистрацию. Поскольку издатель может выполнять запись в различные списки журналирования, вы можете подключить что-либо, что записывает в файл или записывает в базу данных, или отображает уведомления об ошибках в графическом интерфейсе ... и т. Д.

Это довольно хорошая система и требует относительно небольшого количества кода для получения относительно богатых журналов.

Я мог бы дать вам пример кода, если вы хотите ... Вы можете связаться со мной через мой (почти полностью неактивный) блог (см. Мой профиль учетной записи).

Надеюсь, это поможет.

...