Ведение журнала сделано правильно - PullRequest
8 голосов
/ 02 декабря 2011

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

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

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

Регистрация может бытьнастраивается с помощью xmls, inCode или в некоторых настройках и т. д., но это не решает проблему построения строк.

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

Все дерево создается только для того, чтобы этот оператор ведения журнала отображался в файле журнала

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

public void SomeMethod(){
    logger.Debug(someObject.GetHeavyDescriptionFromLazyTree());
}

Метод someObject.GetHeavyDescriptionFromLazyTree() всегда вызывается, даже если ведение журнала отключено, поэтому существуют некоторые общие решения этой проблемы, такие как:

public void SomeMethod(){
#if DEBUG
    logger.Debug(someObject.GetHeavyDescriptionFromLazyTree());
#endif       
}

public void SomeMethod(){
    if(logger.DoLogDebug())
        logger.Debug(someObject.GetHeavyDescriptionFromLazyTree());
}

Iдумаю, ясно, что флаг компилятора #if DEBUG не является решением для производительного кода.Если я использую logger.DoLogDebug(), будет слишком много кода для проверки, включено ли ведение журнала ... так что это тоже не может быть решением.

Я думал, что ConditionalAttribute может помочь, но он также связанна флаги компилятора, и он не деактивирует вызов GetHeavyDescriptionFromLazyTree

[Conditional("DEBUG")]  
public void Debug(string debugMessage) 
{ 
    Console.WriteLine(debugMessage); 
} 

Так что я ищу решение для ведения журнала, которое

  • не чрезмерно обрезает мой источниккод с операторами отладки
  • , где уровень ведения журнала определяется во время выполнения, а не во время компиляции
  • , где операторы разрешаются только в случае необходимости (logLevel >finedLogLevel)

Extraloglines для лучшего ответа; -)

Отредактировано: я ищу решение в .NET 2.0

Ответы [ 3 ]

6 голосов
/ 02 декабря 2011

Один из подходов к «ленивому ведению журнала» заключается в использовании выражения (для создания делегата функции, который возвращает сообщение), а не в использовании прямой оценки:

logger.Debug(() => someObject.GetHeavyDescriptionFromLazyTree());

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

4 голосов
/ 02 декабря 2011

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

Не совсем верно. Смотрите здесь:

if (Log.IsDebugEnabled)
{
    StackFrame f = new StackFrame(2);
    Log.Debug("Very expensive message to put together and stuff." + f.GetMethod().Name);
}

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

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

Редактировать2:

Если я использую logger.DoLogDebug (), будет слишком много кода для проверки, включено ли ведение журнала ... так что это тоже не может быть решением.

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

Ключевой идеей здесь является то, что log4net имеет пять уровней ведения журнала, каждый из которых может рассматриваться совершенно независимо от других. Таким образом, у вас может быть IsDebugEnabled в одном месте и IsInfoEnabled в другом месте. Вы не получите этого с условной компиляцией очень легко, и это окажется даже больше громоздким. Этот сценарий довольно часто встречается в коде, над которым я работал:

if (Log.IsDebugEnabled)
{
    StackFrame f = new StackFrame(2);
    Log.Debug("Very expensive message to put together and stuff." + f.GetMethod().Name);
}
if (Log.IsInfoEnabled)
{
    StackFrame f = new StackFrame(2);
    Log.Debug("Very expensive message to put together and stuff." + f.GetMethod().Name);
}
if (Log.IsErrorEnabled)
{
    StackFrame f = new StackFrame(2);
    Log.Debug("Very expensive message to put together and stuff." + f.GetMethod().Name);
}

Если вы хотите иметь возможность настраивать выходные данные журнала по уровню ведения журнала и по классам, или даже по целым пространствам имен, то это путь.

0 голосов
/ 02 декабря 2011

Вы можете сделать это настраиваемым через web.config или app.config.Добавьте элемент с именем EnableLogging (<add key="EnableLogging" value="false"/>).Затем создайте статический метод, который получает значение из .config и использует его для проверки.

...