Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Getting started with log4net, система ведения логов 
:(
    Опции темы
HalkaR
Дата 28.6.2007, 12:27 (ссылка) |    (голосов:6) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пуфыстый назгул
****


Профиль
Группа: Экс. модератор
Сообщений: 2132
Регистрация: 8.12.2002
Где: В Москве

Репутация: 14
Всего: 42



Очень часто в приложение приходится сохранять логи происходящего. Сохранять информацию об обработанных исключених, о действиях пользователя. Вся эта информация нужна для обнаружения потенциальных проблем и для облегчения решения проблем существующих.
Для данных целей хорошо подходит библиотека log4net (имеющая реализации на множестве других языков).
Как выяснилось у многих с этой простой библиотечкой проблемы. Постараюсь написать краткий док по тому как начать им пользоваться. Так сказать Get Started. Прошу сильно не бить если что не понравится, написал по просьбе трудящихся краткий гайд. В будущем постараюсь расширить и дополнить.

1. Layout

Для начал самое простое - форматирование вывода.
Вообще log4net предоставляет множетсво паттернов. Но мы разберем самый удобный и общий из них - PatternLayout. 
Код

PatternLayout layout = new PatternLayout(@"[%d] %5p [%t] (%M@%F:%L) - %m%n");

Этот пример вывоводит следующую информацию:
%d - дата
%p - тип сообщения (пятерка в записи %5p означает максимальную длинну - 5 символов)
%t - поток из которого была произведена запись
%M - метод
%F - файл
%L - строка
%m - сообщение
%n - символ перехода на новую строку
Все остальные символ используются только для форматирования. Собственно говоря - вот и все. Из других полезных паттернов могу назвать следующие
%a или %appdomain - выводит название домена из которого была произведена запись.
%C или %class - класс из ктогорого была запись.
%exception - выводит исключение если оно было передано.
Остальные паттерны можно найти на http://logging.apache.org/log4net/release/...ternLayout.html

2. Appenders

Для вывода данных в log4net изспользуются Appender'ы (как перевести не знаю). Их в поставке очень много и каждый найдет нужный себе. Я постарюсь в кратце рассказать о 3-х.

Все аппендеры являются потомками класса AppenderSkeleton. Из важных полей этого класса опишу следующие:
Свойство Layout - используется для установки формата вывода.
Метод AddFilter - используется для добавления фильтра.
Метод ClearFilters - используется для очистки всех устанволенных фильтров.
Метод ActivateOptions - используется для активации настроек аппендера.
Более подробно опишу эти свойства и методы позже.

Некоторые аппендеры являются наследниками класса BufferedAppenderSkeleton, отличающегося тем, что запись происходит не мнгновенно, а по мере заполнения буфера.
Специальные свойства BufferedAppenderSkeleton:
BufferSize - размер буфера сообщений (устанавливает максимальное количество сообщений). Если значение установлено в 1 или менее, то буфер записывает сообщения синхронно.
Lossy, Evaluator, LossyEvaluator - отвечают за возможность потери событий из списка (не пользовался, поэтому описывать не буду).


ConsoleAppender - используется для вывода данных на консоль. Имеет только одно особое свойство Target, которое отвечает за поток вывода (имеет два значения "Console.Out" или "Console.Error"). Удобно использовать данный аппендер для отладки в Visual Studio - вся логируемая информация попадает в Output окно IDE.

FileAppender - используется для вывода сообщений в файл. Имеет множество своих свойств:
AppendToFile - флаг, определяющий пересоздается ли файл при инициализации конфигурации или каждый раз данные дописываются.
Encoding - кодировка вывода.
File - имя фала (и путь до него) в который будет выводится информация.
LockingModel - модель блокировки.

AdoNetAppender - аппендер записывающий сообщения в базу данных. Достаточно простой аппендер. ИЗ свойств отличаются CommandText, CommandType, ConnectionString, ConnectionType, ReconnectOnError и UseTransactions и метод AddParameter - отвечающие за подключение к базе и внесение данных.
Соответственно единственный сложный момент - это создание запроса на вставку данных в базу.
Простейший пример:
Код

            AdoNetAppender adoAppender = new AdoNetAppender();
            adoAppender.CommandType = System.Data.CommandType.Text;
            adoAppender.CommandText =
                "INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)";
            AdoNetAppenderParameter paramDate = new AdoNetAppenderParameter();
            paramDate.ParameterName = @"@log_date";
            paramDate.DbType = System.Data.DbType.DateTime;
            paramDate.Layout = new Layout2RawLayoutAdapter(new PatternLayout(@"%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}"));
            adoAppender.AddParameter(paramDate);
            // и т.д.


Теперь собираем все это вместе:
Код

            //создаем паттерн, по которому будет производиться вывод
            PatternLayout layout = new PatternLayout(@"[%d] %5p [%t] (%M@%F:%L) - %m%n");
            //создаем консольный аппендер для вывода в консоль
            ConsoleAppender consoleAppender = new ConsoleAppender();
            //опредлеляем для аппендера layout
            consoleAppender.Layout = layout;
            //создаем файловый аппендер
            FileAppender appender = new FileAppender();
            //определяем файл в который будут выводиться данные
            appender.File = "back-log.log";
            //опредлеляем для аппендера layout
            appender.Layout = layout;
            //устанавлием два аппендера в конфигурацию - теперь они будут использоваться для вывода данных
            BasicConfigurator.Configure(consoleAppender);
            BasicConfigurator.Configure(appender);
            // активируем настройки обоих аппендеров
            appender.ActivateOptions();
            consoleAppender.ActivateOptions();
    
Класс BasicConfiguration используется для простейшего способа конфигурации логгера.  Существуют альтернативные способы, но этот самый простой.
Как видите все предельно просто. Теперь наш логгер настроен и будет выводить все сообщения в консоль и в файл.
Теперь попытаемся им воспользоваться.
Код

    public class Test
    {
        private static readonly ILog LOG = LogManager.GetLogger(typeof(Test));
        static TestMethod()
        {
            LOG.Info("This is test!");
        }
        
    }        

Таким образом для каждого класса мы можем определить свой логгер или создать глобальный логгер для всей программы.
Интерфейс Ilog выглядит следующим образом:
Код

namespace log4net
{
    public interface ILog
    {
        /* Test if a level is enabled for logging */
        bool IsDebugEnabled { get; }
        bool IsInfoEnabled { get; }
        bool IsWarnEnabled { get; }
        bool IsErrorEnabled { get; }
        bool IsFatalEnabled { get; }
        
        /* Log a message object */
        void Debug(object message);
        void Info(object message);
        void Warn(object message);
        void Error(object message);
        void Fatal(object message);
        
        /* Log a message object and exception */
        void Debug(object message, Exception t);
        void Info(object message, Exception t);
        void Warn(object message, Exception t);
        void Error(object message, Exception t);
        void Fatal(object message, Exception t);
        
        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(string format, params object[] args);
        void InfoFormat(string format, params object[] args);
        void WarnFormat(string format, params object[] args);
        void ErrorFormat(string format, params object[] args);
        void FatalFormat(string format, params object[] args);
        
        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(IFormatProvider provider, string format, params object[] args);
        void InfoFormat(IFormatProvider provider, string format, params object[] args);
        void WarnFormat(IFormatProvider provider, string format, params object[] args);
        void ErrorFormat(IFormatProvider provider, string format, params object[] args);
        void FatalFormat(IFormatProvider provider, string format, params object[] args);
    }
}

Методы Debug, Info, Warn, Error, Fatal используются для создания сообщений с разрым уровнем критичности. Каждому из этих методов передается сообщение и исключение (опционально).
За сим на первый раз все.
PM MAIL   Вверх
stab
Дата 29.6.2007, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



закреплю тему на недельку, пусть народ почитает. интересно.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
HalkaR
Дата 29.6.2007, 13:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пуфыстый назгул
****


Профиль
Группа: Экс. модератор
Сообщений: 2132
Регистрация: 8.12.2002
Где: В Москве

Репутация: 14
Всего: 42



По просьбе некоторых участников форума - краткое продолжение (сожалею не получилось побольше написать - не успел).

В прошлый раз я разобрал написал как просто начать работать с log4net. Теперь давайте пойдем не вглубь а в ширь.

1. Layout

В прошлый раз я описал layout PatterLayout.

Теперь опишем остальные:
log4net.Layout.ExceptionLayout    Выводит только текст исключения.
log4net.Layout.RawTimeStampLayout    Выводит timestamp.
log4net.Layout.RawUtcTimeStampLayout    Выводит timestamp в универсальном времени.
log4net.Layout.SimpleLayout    Простой layout? выводит данные в формате: [level] - [message].
log4net.Layout.XmlLayout    Выводит текст сообщений в виде XML.
log4net.Layout.XmlLayoutSchemaLog4j    Также выводит текст сообщений в виде XML, но используем схему характерную для log4j.

2. Фильтры.

В прошлый раз фильтров я не коснулся.
Аппендеры используют фильтры для выборки сообщений. По умолчанию аппендеры записывают все сообщения.

log4net.Filter.DenyAllFilter     Данный фильтр не пропускает не одного сообщения, используется исключительно с другими фильтрами.
log4net.Filter.LevelMatchFilter    Данный фильтр позволяет жестко задать разрешение на вывод сообщений определенного уровня (конструктор принимает уровень и флаг, показывающий будут ли выводится сообщения данного уровня или нет).
log4net.Filter.LevelRangeFilter    Работает аналогично предыдущему фильтру только позволяет задавать промежуток уровней (от и до).
log4net.Filter.LoggerMatchFilter    Выводит сообщения только от определнного логгера (фильтрация по имени логгера).
log4net.Filter.PropertyFilter    Фильтрует по значениям свойств сообщения (по подстроке).
log4net.Filter.StringMatchFilter    Фильтрует по тексту сообщения (по подстроке).

Это сообщение отредактировал(а) HalkaR - 29.6.2007, 13:22
PM MAIL   Вверх
stab
Дата 29.6.2007, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



HalkaR, как вы отнесётесь к внесению вашего творчества в FAQ, после недельного висения на "доске почёта"? smile


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
HalkaR
Дата 29.6.2007, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пуфыстый назгул
****


Профиль
Группа: Экс. модератор
Сообщений: 2132
Регистрация: 8.12.2002
Где: В Москве

Репутация: 14
Всего: 42



cully, если людям пригодится, то только за. Постараюсь в выходные еще дописать.
PM MAIL   Вверх
Blazkovicz
Дата 21.11.2007, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 21.11.2007

Репутация: нет
Всего: нет



Appender и Layout также можно настраивать не в коде а в конфиг файле
может быть это будет более удобно?
могу написать про это
PM MAIL   Вверх
thomas
Дата 21.11.2007, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент... почти
***


Профиль
Группа: Завсегдатай
Сообщений: 1385
Регистрация: 3.10.2006
Где: " Сказочное королевство"

Репутация: 6
Всего: 65



Blazkovicz
Конечно напиши. Вещь, по любому, нужная.

HalkaR
Отдельный респект.  smile 

Ведение логов крайне необходимо для сопровождения и поддержки программы у клиента, а не только на стадии тестирования.

Это сообщение отредактировал(а) thomas - 21.11.2007, 14:54


--------------------
Крепко жму горло, искренне ваш Thomas. (С)vingrad
Некоторые сорта флоры буквально за одно мгновение превращают нас в фауну!
Проблемы негров шерифа не волнуют.
PM MAIL   Вверх
Blazkovicz
Дата 21.11.2007, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 21.11.2007

Репутация: нет
Всего: нет



В файле конфигурации заводим секцию:

Код

<configSections>
 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>


затем вставляем информацию про аппендеры, категории, фильтры, рендереры:

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

Код

<log4net debug="true">
    <appender name="LogFile" type="log4net.Appender.FileAppender">
        <file value="TestLog.xls" />
        <appendToFile value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%n%-21d{dd.MM.yy HH:mm:ss.fff}    %-5p    %-60m    ...%-20.20F    %-20.40c{1}    %-10M    %-3.4L"/>
        </layout>
    </appender>

    <category name="TestClassName">
        <level value="Debug"/>
        <appender-ref ref="LogFile"/>
    </category>
</log4net>


в коде программы в main процедуре инициализируем настройки;
эта процедура должна проработать перед какой либо записью в лог

Код

XmlConfigurator.Configure();


в классе ClassName, где используем запись в лог нужно завести статическую переменную:

Код

private static readonly ILog logger = LogManager.GetLogger(typeof (ClassName));


собственно использование в нужных местах:

Код

...
logger.Debug("сообщение в лог");
...
catch(Exception exception)
            {
                logger.Error(exception.ToString());
                
            }
...


Надеюсь, написала понятно

Добавлено через 4 минуты и 6 секунд
В свою очередь, возникает вопрос:
Как в приложении различать уровни сообщений debug и info, error и fatal?
есть ли какие-нибудь статьи на эту тему?

Добавлено через 12 минут и 26 секунд
Да, кстати в примере использовались библиотеки log4net, log4net.config, NUnit.Framework
PM MAIL   Вверх
GalSys
Дата 15.1.2008, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 15.1.2008

Репутация: нет
Всего: нет



Вы писали:
Цитата

Таким образом для каждого класса мы можем определить свой логгер или создать глобальный логгер для всей программы.

Можете на примере показать как это делается ?
Допустим есть многопоточное приложение, требуется записывать логи в отдельные файлы для каждого потока.
Как можно все это програмно реализовать.
Заранее спасибо.
PM MAIL   Вверх
vee312
Дата 16.1.2008, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 16.1.2008

Репутация: нет
Всего: нет



Цитата

Можете на примере показать как это делается ?
Допустим есть многопоточное приложение, требуется записывать логи в отдельные файлы для каждого потока.
Как можно все это програмно реализовать.
Заранее спасибо.


Сегодня столкнулся с подобной проблемой. Вот найденное мною решение:

Код

            FileAppender appender = new FileAppender();

            appender.AppendToFile = true;
            appender.File = "someLog.log";
            appender.ImmediateFlush = true;
            appender.LockingModel = new FileAppender.MinimalLock();

            appender.Name = "MyAppender";

            PatternLayout layout = new PatternLayout("%date [%thread] %-5level - %message%newline");
            layout.Header = "------ New session ------" + Environment.NewLine;
            layout.Footer = "------ End session ------" + Environment.NewLine;
            appender.Layout = layout;
            appender.ActivateOptions();

            ILoggerRepository repository = log4net.LogManager.CreateRepository("MyRepository");

            log4net.Config.BasicConfigurator.Configure(repository, appender);
            ILog logger = log4net.LogManager.GetLogger(repository.Name, "MyLog");


Вся фишка в создании нового Repository. Это приводит к формированию новой иерархии appender'ов и их не нужно конфигурировать фильтрами и левелами, дабы избежать пересечения в логировании.
Если найдете другие варианты - отпишите пожалуйста ))

Это сообщение отредактировал(а) vee312 - 16.1.2008, 14:13
PM MAIL   Вверх
Kosya4ok
Дата 14.11.2008, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 23.7.2007

Репутация: нет
Всего: нет



А как быьб с передачей параметров из C# кода логгеру определенному в конфиг файле?
PM MAIL   Вверх
Mihanya
Дата 21.10.2009, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 20.10.2009

Репутация: нет
Всего: нет



У меня вопрос такой:  log4net протоколирует в том же потоке, в котором был вызван метод this.logger.Info("Чего нибудь")? или в отдельном?
PM MAIL   Вверх
HalkaR
Дата 21.10.2009, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пуфыстый назгул
****


Профиль
Группа: Экс. модератор
Сообщений: 2132
Регистрация: 8.12.2002
Где: В Москве

Репутация: 14
Всего: 42



AFAIK в том же.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1012 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.