Log4net: как настроить данные для хранения

У меня есть несколько различных веб-сервисов, открытых на моем веб-сайте. Вот цели, которые я хочу достичь:

  • Хранить все данные в БД в одной таблице;
  • Каждая запись должна иметь текстовое поле с именем "service/component";
  • Необходимо сохранять все параметры дохода при вызове любого метода;
  • Необходимо сохранить все параметры результата и сообщения об ошибках, если возникло какое-либо исключение.

Мое первоначальное намерение состояло в том, чтобы использовать log4net. Но из этих проходов (http://sadi02.wordpress.com/2008/09/15/how-to-store-log-in-database-using-log4net/, http://logging.apache.org/log4net/release/config-examples.html) Я не вижу простого способа добавления пользовательских данных в таблицу журналов.

Можно ли использовать log4net для таких целей? Как я могу изменить схему таблицы ведения журнала для хранения пользовательских данных? Должен ли я изменить исходный код библиотеки log4net? Вероятно, было бы лучше написать пользовательскую функциональность для хранения таких данных?

Спасибо.

Ответ 1

Ни один из предложенных ответов не работает для меня. Проблема в том, что мне нужно иметь несколько настраиваемых полей. Для меня кажется слишком сложным создавать разные экземпляры журнала или настраивать значения столбцов каждый раз через "свойства".

Я поеду (фактически, уже реализованный) пользовательский логгер, который поместил данные в БД.

Ответ 2

В соответствии с этим обсуждение процесс довольно прост.

Первым шагом является обновление текста команды в объявлении appender в файле конфигурации:

<commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception,@MyColumn)"/>        

Следующим шагом является добавление нового параметра для настраиваемого столбца:

<parameter>
   <parameterName value="@MyColumn "/>
   <dbType value="String" />
   <size value="255" />
   <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{MyColumn}" />
   </layout>
</parameter>

Наконец, вы можете получить доступ к значению через свойства GlobalContext log4net:

log4net.GlobalContext.Properties["MyColumn"] = "MyValue";
log.Debug("My message");

Вы можете сделать это для столько полей, сколько вам нужно.

Ответ 3

Рассматривая документацию log4net, вы можете выяснить, как получить свои пользовательские данные в файле? Если это так, вы также сможете получить те же данные, которые зарегистрированы в базе данных. Просто добавьте в таблицу больше столбцов, больше столбцов в <command text> node AdoNetAppender и больше узлов <parameter>.

Я думаю, что у вас будет какая-то работа, чтобы выполнить входные и исходящие параметры. Вам нужно, чтобы они вошли в отдельные столбцы (возможно, это было непросто сделать чисто)? Это нормально, если они записываются вместе с сообщением?

Например, если у вас есть следующий метод, который вы хотите ввести в журнал:

public void DoSomething(int x, int y)
{
  log.Info("Inside DoSomething");
}

Как вы хотите, чтобы ваш вывод выглядел? Вы хотите, чтобы "стандартная" информация log4net отображалась в отдельных столбцах (timestamp, loggername, level, message)? Как насчет параметров? Если x и y появляются в отдельных столбцах (возможно, не очень легко сделать, если каждый метод не имеет одинакового количества параметров), или было бы нормально, если бы параметры были зарегистрированы следующим образом:

public void DoSomething(int x, int y)
{
  ILog log = LogManager.GetLogger("abc");
  log.InfoFormat("Parameters: x = {0}, y = {1}", x, y);
  log.Info("Inside DoSomething");
}

Операторы журнала будут генерировать сообщения, которые будут выглядеть примерно так:

11/29/2010 16:36:00 | abc | INFO | Parameters: x = 10, y = 20
11/29/2010 16:36:00 | abc | INFO | Inside DoSomething

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

Глядя на решение AOP, например PostSharp, может помочь вам, потому что вы можете относительно легко добавлять входные/выходные регистрации без "загрязнения" вашего исходного кода приложения с отчетами о регистрации. Внутри аспекта ведения журнала вы должны иметь доступ к параметрам метода.

Мне может быть что-то упущено, но я подозреваю, что если вы хотите сохранить свои параметры метода как отдельные столбцы в базе данных, вам будет трудно это сделать. Если вы удовлетворены объединением всех параметров (вручную) для каждого метода в виде одного столбца (по существу, форматированной строки), то это будет проще. Одна цена, которую вам придется заплатить, заключается в том, что вам придется явно регистрировать все параметры (если вы не отправляете маршрут AOP).

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

[EDIT]

Чтобы получить "имя компонента", зарегистрированное в log4net, вы должны назвать свои регистраторы для своих компонентов. Когда вы вызываете LogManager.GetLogger(имя), вы можете передать любое имя (или тип). Общий шаблон - иметь такой код в каждом классе:

public class MyClass
{
  private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

  public void DoSomething(int x)
  {
    logger.InfoFormat("Inside DoSomething.  x = {0}", x);
  }
}

Это получит регистратор с полным именем класса (namespace + имя класса). Если вы делаете это в каждом классе, вы можете контролировать ведение журнала (уровень, к которому это приложение добавляется и т.д.) Для каждого класса. Таким образом, вы можете легко включить регистрацию для Class1 в Info и выполнить регистрацию для Class2 Off и т.д. Это даст вам максимальную степень контроля за протоколированием.

Теперь, в вашем файле конфигурации, вы не обязаны перечислять каждый регистратор (т.е. каждое полное имя класса) явно. Вы можете просто настроить корневой журнал, а затем эти настройки будут применены к каждому регистратору. Вы можете управлять ведением журнала по пространству имен. Например, если вы работаете в CompanyX и имеете явные правила пространства имен, ваши пространства имен могут выглядеть так:

CompanyX
CompanyX.DataAccess
CompanyX.DataAccess.Read
CompanyX.DataAccess.Write
CompanyX.GUI
CompanyX.Forms
CompanyX.Controls

В каждом пространстве имен у вас может быть разный класс (например, несколько разных считывателей данных, вспомогательные классы, авторы данных и т.д.). С такими классами, как это, и с вашими классами, регистрирующими журналы, как описано выше, вы можете легко настроить ведение журнала для всех классов в CompanyX или всех регистраторов в CompanyX.DataAccess или CompanyX.DataAccess.Read и т.д. Вы даже можете отключить все протоколирования, но включите его для этого трудного класса, который дает вам проблемы.

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

ILog logger = LogManager.GetLogger("DataAccess");
ILog logger = LogManager.GetLogger("Performance");
ILog logger = LogManager.GetLogger("UI");

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

Другое слово на NLog... NLog очень похож на log4net. У этого есть полезная функция, позволяющая автоматически возвращать регистратор для текущего класса:

Logger logger = NLog.LogManager.GetCurrentClassLogger();

Это, по крайней мере, экономит некоторую типизацию с вашей стороны. NLog также просто вышел с новой версией (в настоящее время в бета-версии).

Не знаю, помогло ли это, но я надеюсь, что это было!

Удачи!