Re[10]: Куда помещать код логирования?
От: abibok  
Дата: 05.03.12 19:56
Оценка: 108 (3)
S>1. К сожалению, в дотнете нет способа перевыбросить исключение, не исказив его стек. Поэтому вариантов для конкретного фрагмента, в общем-то, нет.

static void Rethrow(Exception ex)
{
    if (ex == null)
    {
        return;
    }

    if (ex.GetType().IsSerializable)
    {
        BinaryFormatter formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.CrossAppDomain));
        MemoryStream stream = new MemoryStream();
        formatter.Serialize(stream, ex);
        stream.Position = 0;

        throw (Exception)formatter.Deserialize(stream);
    }
            
    FieldInfo remoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
    remoteStackTraceString.SetValue(ex, ex.StackTrace + Environment.NewLine);

    throw ex;
}
Re: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.02.12 10:57
Оценка: 9 (2)
Здравствуйте, stomsky, Вы писали:

S>Доброго времени суток!

S>Пишу сейчас один сервис, который будет круглосуточно выполнять всякие полезные действия.
S>Надо вести подробный лог.
S>Сейчас кодирую и вижу как буквально на глазах "полезный" код засоряется кодом логирования.
S>Подскажите, плиз, как вы боритесь с этой проблемной?
Имхо, достаточно буквально трёхстрочной "библиотеки", чтобы превратить вашу лапшу в:
void DoAnything()
  { 
    Trace(()=>{
      Trace(()=>DoAction1());
      Trace(()=>DoAction2());
      Trace(()=>DoAction3());
    });
  }

Ещё десять строчек — и можно добавить в трейс значения интересных вам переменных. DRY.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Куда помещать код логирования?
От: Nuseraro Россия  
Дата: 29.02.12 09:27
Оценка: 7 (2)
Здравствуйте, stomsky, Вы писали:

S>Слабое утешение... Потом код читать сложно...


Я вот честно говоря не нашел в литературе подтверждение своих наработок, но давно считаю, что трассировка начала и конца функции — это плохая практика. Такое трассирование само по себе мусор, поэтому и код замусоривается. Я ниже написал какую-то конкретику. Мб она для вас тоже не подойдет. Но ключевая идея — не трассируйте тогда, когда практически очевидно, что все 3 трейса например или пройдут одновременно или не пройдут, кроме случая очевидной описки. Каждый трейс должен быть индивидуально полезен, особенно если вы его пишете вручную, а не юзаете модные библиотеки.


Наиболее полезные трэйсы/логи:
1) утверждения на предусловия
        public bool IsNeedToPayBonus(Context context)
        {
            if (context == null)
            {
                Warning("Я имел в виду что тут контекст всегда задан");
                return;
            }

            if (context.CurrentOrder == null)
            {
                Warning("Я имел в виду что тут у контекста есть ордер");
                return;
            }

            return context.CurrentOrder.Price > 1000;
        }

2) условная логика
        public bool IsNeedToPayBonus(Context context)
        {
            //...
            if (context.CurrentOrder.IsPremium)
            {
                Trace("Используется алгоритм премиального рассчета");
                return context.CurrentOrder.Price > 100;
            }
            else
            {
                Trace("Используется алгоритм обычного рассчета");
                return context.CurrentOrder.Price > 1000;
            }            
        }

3) Логирование ошибки
        public bool IsNeedToPayBonus(Context context)
        {
            try
            {
                //...
            }
            catch (Exception e)
            {
                Error(e.Message + e.StackTrace);
                throw;
            }
        }

4) Трассировка конкретных значений, например, при взаимодействии с источниками данных. Короче тех значений, которые потом можно как-то где-то посмотреть
        public bool IsNeedToPayBonus(Context context)
        {    
            //...
            Save(context.CurrentOrder);
            Trace("Сохранил в базу ордер {0}. Цена - {1}", context.CurrentOrder.Id, context.CurrentOrder.Price);
            //...
        }
Homo Guglens
Re[8]: Куда помещать код логирования?
От: abibok  
Дата: 29.02.12 22:58
Оценка: 1 (1) +1
A>И что вы предлагаете-то? Не пользоваться throw?

Вы читали то, что я написал? Какой смысл пытаться что-то объяснить, придумывать красивые примеры, рассказывать о своем опыте наступания на грабли, если все это перечеркивается вот таким "И чо?"
Re[9]: Куда помещать код логирования?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.02.12 23:01
Оценка: -2
Здравствуйте, abibok, Вы писали:

A>>И что вы предлагаете-то? Не пользоваться throw?

A>Вы читали то, что я написал? Какой смысл пытаться что-то объяснить, придумывать красивые примеры, рассказывать о своем опыте наступания на грабли, если все это перечеркивается вот таким "И чо?"

Из вашего примера следует (впрочем это давно известная истина), что throw; лучше чем throw e;, потому что не происходит потеря информации.
В сообщении на которое вы отвечали и так написано throw; и вы написали так не делать, потому что происходит потеря информации.
Итого, вы написали два сообщения противоречащих друг другу.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[8]: Куда помещать код логирования?
От: AlexNek  
Дата: 02.03.12 17:43
Оценка: -1 :)
Здравствуйте, Sinclair, Вы писали:

S> AN>Делать код хорошо пригодный для определенного способа трассировки???


S> Я не понимаю ваш вопрос. Сформулируйте его так, чтобы на него можно было ответить.

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

S> S>> А в чём именно тут вопрос? Какую проблему вы хотите решить?


S> AN>Только прояснить данное сообщение

S> AN>здесь
Автор: Sinclair
Дата: 01.03.12

S> AN>"Не делайте так. Происходит потеря информации о месте возникновения исходного исключения."
S> AN>Елинственная связь с этим
S> AN>здесь
Автор: Sinclair
Дата: 01.03.12

S> AN>это "throw;"

S> В сообщении, на которое вы ссылаетесь, нет цитаты, которую вы приводите.

Сорри ссылки не проверил и забыл что здесь нужно ссылки на сообщения по другому "красть"
Вот эти должны быть правильнее.
http://www.rsdn.ru/forum/dotnet/4641286.1.aspx
Автор: abibok
Дата: 29.02.12

http://www.rsdn.ru/forum/dotnet/4641442.1.aspx
Автор: abibok
Дата: 01.03.12
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[6]: Куда помещать код логирования?
От: abibok  
Дата: 29.02.12 21:41
Оценка: 1 (1)
a>> Не делайте так. Происходит потеря информации о месте возникновения исходного исключения.
AN>А можно пояснить, что то мысль про место не совсем понятна. И как нужно правильно?

It is very important to collect as much information about failure as it is possible. It is not enough to know that something wrong has happened. We need to know how it happened, what was done before the failure, and what the state of the system was. In other words, we need history.

One of the most valuable parts of the history is call stack. Misuse of try-catch construction in our code may lead to call stack cut or even loss. Here I will try to demonstrate several examples of such misuse.

Example 1:

try
{
    // some logic here
}
catch
{
    // Simply re-throwing all exceptions
    // in order to show that the base class catches the exceptions and
    // fails appropriately.
    throw;
}



What’s wrong? Consider the following program.

 1: class Program
 2: {
 3:    static void f(bool b)
 4:    {
 5:        if (b)
 6:            throw new ApplicationException();
 7:    }
 8:
 9:    static void RunTest()
10:    {
11:        try
12:        {
13:            f(false);
14:            f(true);
15:            f(false);
16:        }
17:        catch
18:        {
19:            throw;
20:        }
21:    }
22:    
23:    static void Main(string[] args)
24:    {
25:        try
26:        {
27:            RunTest();
28:        }
29:        catch (Exception e)
30:        {
31:            string s = e.ToString();
32:        }
33:    }
34: }


After run s =
System.ApplicationException: Error in the application.
at Program.f(Boolean b) in c:\test\Program.cs:line 6
at Program.RunTest() in c:\test\Program.cs:line 19
at Program.Main(String[] args) in c:\test\Program.cs:line 27

What was the reason for exception? That information was lost. We don’t know what part of the code caused the error – the first f-function, the second or the third.

Here we can have 3 different errors with the same stack. To get the root of the problem we need to do manual investigation, what is difficult and is not always possible.

Example 2:

try
{
    // some logic here
}
catch (Exception e)
{
    throw e;
}


Pretty similar to example 1, note that we use “throw e” instead “throw” here. Look how it works:

 1: class Program
 2: {
 3:    static void f(bool b)
 4:    {
 5:        if (b)
 6:            throw new ApplicationException();
 7:    }
 8:
 9:    static void RunTest()
10:    {
11:        try
12:        {
13:            f(false);
14:            f(true);
15:            f(false);
16:        }
17:        catch
18:        {
19:            throw e;
20:        }
21:    }
22:    
23:    static void Main(string[] args)
24:    {
25:        try
26:        {
27:            RunTest();
28:        }
29:        catch (Exception e)
30:        {
31:            string s = e.ToString();
32:        }
33:    }
34: }


After run s =
System.ApplicationException: Error in the application.
at Program.RunTest() in c:\test\Program.cs:line 19
at Program.Main(String[] args) in c:\test\Program.cs:line 27

Here even more information was lost. We only know that something has happened somewhere in try-catch block. Manual investigation is required.

Summary:

Do not use try-catch where it is not necessary. If you are not sure about that then it is not necessary, let the base class do its work.
At catch be as specific as possible, catch only expected exceptions, do not catch all exceptions (System.Exception) unless it is required by code logic.
If you really need to throw your own exception in a catch block, the best way to do this is to throw a new exception and include the old one as the inner exception:

try
{
    // some logic here
}
catch (SomeException e)
{
    // log some more info here
    throw new SomeException("descriptive message", e);
}
Re: Куда помещать код логирования?
От: ksg71 Германия  
Дата: 29.02.12 07:46
Оценка: +1
Здравствуйте, stomsky, Вы писали:


S>В первом варианте, вроде бы логирование более централизованно, но код уж больно замусорен.

S>Во втором случае код логирования слишком размазан...

S>Или все-таки на аспекты смотреть? Кто-нибудь этот функционал из BlToolkit пробовал? Я его для доступа к данным использую...


что логируем, там и пишем,в данном случае первый вариант, аспекты нужны, но не для трассировки, а в примерах именно она (никаких "бизнес" задач не решается)
"замусоривание" трейсами — вполне нормальное явление, взгляните на код, ну например System.Net.SmtpClient
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[3]: Куда помещать код логирования?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.02.12 10:56
Оценка: -1
Здравствуйте, stomsky, Вы писали:

S>Здравствуйте, adontz, Вы писали:


A>>Первый вариант не позволит настраивать журналирование по классам.

S>Не понял, что значит словосочетание "журналирование по классам"... По классам чего? Или по классам каким?

По классам которые "class". И log4net, и NLog при правильном использовании позволяют фильтровать сообщения по классам.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[11]: Куда помещать код логирования?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 01.03.12 00:29
Оценка: -1
Здравствуйте, abibok, Вы писали:

A>Я все же настоятельно советую прочитать мой пример до конца, а не пытаться угадывать.


Причём тут пример? Мой вопрос был, что вы предлагаете делать? Есть конкретное предложение по улучшению кода?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[3]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.03.12 04:06
Оценка: +1
Здравствуйте, stomsky, Вы писали:
S>Тока скажите честно, ВЫ САМИ такое стали бы использовать????
Сам — стал бы. А зачем полагаться на какие-то внешние библиотеки и DSL, которые работают непрозрачным образом?
Только когда такой код станет некрасивым, имеет смысл пойти по пути дальнейшего улучшения.

Вообще, вынужден предупредить: я промышленный код не пишу уже много лет, и на практике подобные идеи не проверял. Возможно, в реальных проектах всплывут неожиданные грабли.
Вы можете попробовать такую технику на небольшом фрагменте. Код функции Trace должен быть достаточно очевиден.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.03.12 12:55
Оценка: +1
Здравствуйте, AlexNek, Вы писали:
AN>А что сама .NET полностью прозрачна?
AN>Библиотека должна работать без ощибок и я должен понимать как ее использовать, все остальное не должно волновать.
Я не очень понимаю, к чему ваш вопрос. В коде, который я привёл, есть недостаток — в нём всё ещё явно указано, что именно будет трассироваться.
Зато я знаю, почему в этом коде трассируются 1 и 3, и не трассируется 2:
void DoAnything()
  { 
    Trace(()=>{
      Trace(()=>DoAction1());
      DoAction2();
      Trace(()=>DoAction3());
    });
  }


AN>Давайте все же возвратимся к "задетой" части кода и даже теоретически обсудим что же там неправильного в свете вышесказанного и как

AN>должен выглядет "правильный" код? (Для теории — считаем этот метод частью библиотеки.)
AN>
AN>        public bool IsNeedToPayBonus(Context context)
AN>        {
AN>            try
AN>            {
AN>                //...
AN>            }
AN>            catch (Exception e)
AN>            {
AN>                Error(e.Message + e.StackTrace);
AN>                throw;
AN>            }
AN>        }
AN>

А в чём именно тут вопрос? Какую проблему вы хотите решить?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 07:22
Оценка:
Доброго времени суток!
Пишу сейчас один сервис, который будет круглосуточно выполнять всякие полезные действия.
Надо вести подробный лог.
Сейчас кодирую и вижу как буквально на глазах "полезный" код засоряется кодом логирования.
Подскажите, плиз, как вы боритесь с этой проблемной?
Про аспекты я, конечно, слышал, но не хочется под это дело сторонние библиотеки привлекать.
И, кстати, какой вариант код по-вашему предпочтительнее (на осмысленность сообщений пожалуйста внимания не обращайте):

class MyClass
{
  ILogger _logger;
  ...
  void DoAnything()
  {
    _logger.Info("Начато выполнение действия...");

    _logger.Info("Выполняется DoAction1...");
    DoAction1();
    _logger.Info("DoAction1 выполнено успешно");

    _logger.Info("Выполняется DoAction2...");
    DoAction2();
    _logger.Info("DoAction2 выполнено успешно");

    _logger.Info("Выполняется DoAction3...");
    DoAction3();
    _logger.Info("DoAction3 выполнено успешно")

    _logger.Info("Действие выполнено успешно");
  }
  void DoAction1()
  { ... }
  void DoAction2()
  { ... }
  void DoAction3()
  { ... }
}


или такой:

class MyClass
{
  ILogger _logger;
  ...
  void DoAnything()
  {
    _logger.Info("Начато выполнение действия...");

    DoAction1();
    DoAction2();
    DoAction3();

    _logger.Info("Действие выполнено успешно");
  }
  void DoAction1()
  {
    _logger.Info("Выполняется DoAction2...");
    ...
    _logger.Info("DoAction1 выполнено успешно");
  }
  void DoAction2()
  {
    _logger.Info("Выполняется DoAction2...");
    ...
    _logger.Info("DoAction1 выполнено успешно");
  }
  void DoAction3()
  {
    _logger.Info("Выполняется DoAction3...");
    ...
    _logger.Info("DoAction3 выполнено успешно");
  }
}

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

Или все-таки на аспекты смотреть? Кто-нибудь этот функционал из BlToolkit пробовал? Я его для доступа к данным использую...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[2]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 08:38
Оценка:
Здравствуйте, ksg71, Вы писали:

K>что логируем, там и пишем,в данном случае первый вариант, аспекты нужны, но не для трассировки, а в примерах именно она (никаких "бизнес" задач не решается)

Ну в случае сервиса, если надо не просто знать нормально или НЕ нормально отработало, но еще и иметь возможность выяснить "почему отработало так, а не иначе" (я в том числе и о бизнес-логике говорю), разница между трассировкой и логами ИМХО невелика. Логи шибко подробные должны быть...

K>"замусоривание" трейсами — вполне нормальное явление, взгляните на код, ну например System.Net.SmtpClient

Слабое утешение... Потом код читать сложно...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[3]: Куда помещать код логирования?
От: ksg71 Германия  
Дата: 29.02.12 08:47
Оценка:
Здравствуйте, stomsky, Вы писали:

S>Здравствуйте, ksg71, Вы писали:


K>>что логируем, там и пишем,в данном случае первый вариант, аспекты нужны, но не для трассировки, а в примерах именно она (никаких "бизнес" задач не решается)

S>Ну в случае сервиса, если надо не просто знать нормально или НЕ нормально отработало, но еще и иметь возможность выяснить "почему отработало так, а не иначе" (я в том числе и о бизнес-логике говорю), разница между трассировкой и логами ИМХО невелика. Логи шибко подробные должны быть...

K>>"замусоривание" трейсами — вполне нормальное явление, взгляните на код, ну например System.Net.SmtpClient

S>Слабое утешение... Потом код читать сложно...

ну почему так отработало, а не иначе, надо не логами выяснять, а тестами (я о бизнес логике)
а для диагностики — трейсы, и AOP тут, кмк, ни к чему
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[4]: Куда помещать код логирования?
От: ksg71 Германия  
Дата: 29.02.12 08:59
Оценка:
Здравствуйте, ksg71, Вы писали:

K>Здравствуйте, stomsky, Вы писали:


S>>Здравствуйте, ksg71, Вы писали:


K>>>что логируем, там и пишем,в данном случае первый вариант, аспекты нужны, но не для трассировки, а в примерах именно она (никаких "бизнес" задач не решается)

S>>Ну в случае сервиса, если надо не просто знать нормально или НЕ нормально отработало, но еще и иметь возможность выяснить "почему отработало так, а не иначе" (я в том числе и о бизнес-логике говорю), разница между трассировкой и логами ИМХО невелика. Логи шибко подробные должны быть...

K>>>"замусоривание" трейсами — вполне нормальное явление, взгляните на код, ну например System.Net.SmtpClient

S>>Слабое утешение... Потом код читать сложно...

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

K>а для диагностики — трейсы, и AOP тут, кмк, ни к чему

хотя, конечно, согласен — всех ситуаций не отловить,
но и аспектами можно код усложнить и замусорить
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[4]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 09:57
Оценка:
Здравствуйте, ksg71, Вы писали:

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

Тестирование не прокатит. Попробую изложить подробности вкратце...
Мой сервис занимается перекачкой данных из одной базы данных (древнючей-древнючей), назовем ее "Источник", в другую (MS SQL), назовем "Приемник".
Если в "Источнике" появилась новая запись, то она через некоторое время T должна оказаться в "Приемнике".
И в "Источнике" и в "Приемнике" постоянно работают пользователи.
В идеале, после копирования строки в "Приемник", пользователи не должны вносить изменения в "Источнике".
Но технически реализовать такое невозможно.
Единственный разумный выход — пометить измененную строку в "Приемнике", а GUI приложения, работающего с БД "Приемника", просигнализирует пользователю о недопустимой ситуации, чтобы дальше включился "генератор докладных записок" (ну т.е. пусть пользователи, работающие с "Приемником" предъявляют претензии пользователям, работающим с "Источником").
Так вот, в логе хотелось бы отразить обнаружение факта изменения скопированной строки.
И таких "мелочей", которых быть не должно, но они есть, потому что недопустить их возникновения НЕ возможно, много.
Поэтому лог должен быть подробный.
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[5]: Куда помещать код логирования?
От: ksg71 Германия  
Дата: 29.02.12 10:21
Оценка:
Здравствуйте, stomsky, Вы писали:

S>Здравствуйте, ksg71, Вы писали:


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

S>Тестирование не прокатит. Попробую изложить подробности вкратце...
S>Мой сервис занимается перекачкой данных из одной базы данных (древнючей-древнючей), назовем ее "Источник", в другую (MS SQL), назовем "Приемник".
S>Если в "Источнике" появилась новая запись, то она через некоторое время T должна оказаться в "Приемнике".
S>И в "Источнике" и в "Приемнике" постоянно работают пользователи.
S>В идеале, после копирования строки в "Приемник", пользователи не должны вносить изменения в "Источнике".
S>Но технически реализовать такое невозможно.
S>Единственный разумный выход — пометить измененную строку в "Приемнике", а GUI приложения, работающего с БД "Приемника", просигнализирует пользователю о недопустимой ситуации, чтобы дальше включился "генератор докладных записок" (ну т.е. пусть пользователи, работающие с "Приемником" предъявляют претензии пользователям, работающим с "Источником").
S>Так вот, в логе хотелось бы отразить обнаружение факта изменения скопированной строки.
S>И таких "мелочей", которых быть не должно, но они есть, потому что недопустить их возникновения НЕ возможно, много.
S>Поэтому лог должен быть подробный.

почему не прокатит?

сервис получает строку из источника, проверяет есть ли версия в приемнике, если есть — помечает и бросает исключение, нет — сохраняет в приемнике,
вся эта логика легко юнит-тестируется (при должном дизайне сервиса), а логирование сводится к минимуму
имхо и с остальными "мелочами" можно также поступить
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[6]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 10:29
Оценка:
Здравствуйте, ksg71, Вы писали:

K>почему не прокатит?


K>сервис получает строку из источника, проверяет есть ли версия в приемнике, если есть — помечает и бросает исключение, нет — сохраняет в приемнике,

K>вся эта логика легко юнит-тестируется (при должном дизайне сервиса), а логирование сводится к минимуму
K>имхо и с остальными "мелочами" можно также поступить
Да я не об этом!
Просто в "Приемнике" есть битовый флаг "Запись изменена в 'Источнике'".
Но что именно изменилось? Какое именно поле?
Вот в лог я и напишу, что у платежного поручения изменилась, например, сумма.
В моем случае лог ведется не только и не столько для отладки и технической диагностики, но и с целью выявления неких обстоятельств в сфере бизнес-логики.
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[7]: Куда помещать код логирования?
От: ksg71 Германия  
Дата: 29.02.12 10:42
Оценка:
Здравствуйте, stomsky, Вы писали:

S>Здравствуйте, ksg71, Вы писали:


K>>почему не прокатит?


K>>сервис получает строку из источника, проверяет есть ли версия в приемнике, если есть — помечает и бросает исключение, нет — сохраняет в приемнике,

K>>вся эта логика легко юнит-тестируется (при должном дизайне сервиса), а логирование сводится к минимуму
K>>имхо и с остальными "мелочами" можно также поступить
S>Да я не об этом!
S>Просто в "Приемнике" есть битовый флаг "Запись изменена в 'Источнике'".
S>Но что именно изменилось? Какое именно поле?
S>Вот в лог я и напишу, что у платежного поручения изменилась, например, сумма.
S>В моем случае лог ведется не только и не столько для отладки и технической диагностики, но и с целью выявления неких обстоятельств в сфере бизнес-логики.


ну и какие после этого вопросы, куда помещать код логирования?
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[4]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 10:45
Оценка:
Здравствуйте, Nuseraro, Вы писали:

N>Я вот честно говоря не нашел в литературе подтверждение своих наработок, но давно считаю, что трассировка начала и конца функции — это плохая практика. Такое трассирование само по себе мусор, поэтому и код замусоривается.

Гм... Об этом я, честно говоря, не задумывался... Надо посмотреть на проблему с этой стороны. Уже спасибо, за свежую мысль!

N>
N>        public bool IsNeedToPayBonus(Context context)
N>        {
N>            if (context == null)
N>            {
N>                Warning("Я имел в виду что тут контекст всегда задан");
N>                return;
N>            }

N>            if (context.CurrentOrder == null)
N>            {
N>                Warning("Я имел в виду что тут у контекста есть ордер");
N>                return;
N>            }

N>            return context.CurrentOrder.Price > 1000;
N>        }
N>

А я в таких случаях ArgumentNullException'ы выбрасываю. Потому как "context == null" — в данном случае ИМХО откровенный косяк.

А здесь:
N>2) условная логика
N>
N>        public bool IsNeedToPayBonus(Context context)
N>        {
N>            //...
N>            if (context.CurrentOrder.IsPremium)
N>            {
N>                Trace("Используется алгоритм премиального рассчета");
N>                return context.CurrentOrder.Price > 100;
N>            }
N>            else
N>            {
N>                Trace("Используется алгоритм обычного рассчета");
N>                return context.CurrentOrder.Price > 1000;
N>            }            
N>        }
N>

и здесь:
N>4) Трассировка конкретных значений, например, при взаимодействии с источниками данных. Короче тех значений, которые потом можно как-то где-то посмотреть
N>
N>        public bool IsNeedToPayBonus(Context context)
N>        {    
N>            //...
N>            Save(context.CurrentOrder);
N>            Trace("Сохранил в базу ордер {0}. Цена - {1}", context.CurrentOrder.Id, context.CurrentOrder.Price);
N>            //...
N>        }
N>


как раз и есть тот мусор от которого хотелось бы избавиться!!! (это я про "Trace")
Это как лишние комментарии: из кода и так понятно что там делается! Только код читать мешают.
Но в лог-то вывести надо...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re: Куда помещать код логирования?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.02.12 10:46
Оценка:
Здравствуйте, stomsky, Вы писали:

Первый вариант не позволит настраивать журналирование по классам.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[8]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 10:52
Оценка:
Здравствуйте, ksg71, Вы писали:

K>ну и какие после этого вопросы, куда помещать код логирования?


Да я вообще от него избавиться хочу, от кода этого!
Или поместить его в такое место, чтобы он был подальше отделен от бизнес-логики и не мешал читать код, относящийся к ней...

Ну ладно... уговорили: я, как обычно, сам не знаю чего хочу!
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[2]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 10:54
Оценка:
Здравствуйте, adontz, Вы писали:

A>Первый вариант не позволит настраивать журналирование по классам.

Не понял, что значит словосочетание "журналирование по классам"... По классам чего? Или по классам каким?
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[2]: Куда помещать код логирования?
От: stomsky Россия  
Дата: 29.02.12 11:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>
S>void DoAnything()
S>  { 
S>    Trace(()=>{
S>      Trace(()=>DoAction1());
S>      Trace(()=>DoAction2());
S>      Trace(()=>DoAction3());
S>    });
S>  }
S>

УАУ!!! ВОТ ЭТО КРУТО!!!
Я серьезно: каждый раз убеждаюсь, что этот форум — кладезь оригинальных и красивых решений!
Спасибо большое!

Тока скажите честно, ВЫ САМИ такое стали бы использовать???? Нет, это ПРАВДА красиво на мой взгляд! Но, по-моему, какой-то огород на ровном месте... Хотя, я, конечно, сам просил чего-нибудь эдакого в рамках стандартного фреймворка...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re: Куда помещать код логирования?
От: AlexNek  
Дата: 29.02.12 18:32
Оценка:
Здравствуйте, stomsky, Вы писали:

s> Доброго времени суток!

s> Пишу сейчас один сервис, который будет круглосуточно выполнять всякие полезные действия.
s> Надо вести подробный лог.
s> Сейчас кодирую и вижу как буквально на глазах "полезный" код засоряется кодом логирования.
...
s> Или все-таки на аспекты смотреть? Кто-нибудь этот функционал из BlToolkit пробовал? Я его для доступа к данным использую...
Вообще то вначале нужен ответ на вопрос для чего это мне нужно?
Если нужно просто разобраться с какой то проблемой в реальной работе, то лучше делать индивидуальные логи в тексте которые можно отключать через препроцессор, если важно время. У нас в каждом проекте есть файл с описанием отладочных директив. Можно например трассировать передачу данных и/или прием и/или конвертирование. Спец. трассировка "спрятана" в регионах. Аспектами было бы сложно, так как в данном случае почти каждый метод имеет индивидуальных подход логирования наиболее удобный для поставленной задачи.
Если же нужен просто глобальный обзор одинаковый для многих, то постшапр с аспектами довольно хорошее решение. Буквально недавно только пробовал. Достаточно одной строки в ассебли инфо (ну и аспект), чтобы получить в логе вход, выход, параметры и возможное исключение для всех классов и методов в библиотеке. Мусора конечно полно, но зато бывают видны "интересные вещи".
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[4]: Куда помещать код логирования?
От: abibok  
Дата: 29.02.12 19:47
Оценка:
N>3) Логирование ошибки
N>
N>        public bool IsNeedToPayBonus(Context context)
N>        {
N>            try
N>            {
N>                //...
N>            }
N>            catch (Exception e)
N>            {
N>                Error(e.Message + e.StackTrace);
N>                throw;
N>            }
N>        }
N>


Не делайте так. Происходит потеря информации о месте возникновения исходного исключения.
Re[5]: Куда помещать код логирования?
От: AlexNek  
Дата: 29.02.12 19:56
Оценка:
Здравствуйте, abibok, Вы писали:

a> N>3) Логирование ошибки

a> N>
a> N>        public bool IsNeedToPayBonus(Context context)
a> N>        {
a> N>            try
a> N>            {
a> N>                //...
a> N>            }
a> N>            catch (Exception e)
a> N>            {
a> N>                Error(e.Message + e.StackTrace);
a> N>                throw;
a> N>            }
a> N>        }
a> N>


a> Не делайте так. Происходит потеря информации о месте возникновения исходного исключения.

А можно пояснить, что то мысль про место не совсем понятна. И как нужно правильно?
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[7]: Куда помещать код логирования?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.02.12 22:30
Оценка:
Здравствуйте, abibok, Вы писали:

И что вы предлагаете-то? Не пользоваться throw?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[10]: Куда помещать код логирования?
От: abibok  
Дата: 29.02.12 23:20
Оценка:
A>Из вашего примера следует (впрочем это давно известная истина), что throw; лучше чем throw e;, потому что не происходит потеря информации.

Я все же настоятельно советую прочитать мой пример до конца, а не пытаться угадывать.
Re[7]: Куда помещать код логирования?
От: AlexNek  
Дата: 29.02.12 23:24
Оценка:
Здравствуйте, abibok, Вы писали:

a> a>> Не делайте так. Происходит потеря информации о месте возникновения исходного исключения.


a> AN>А можно пояснить, что то мысль про место не совсем понятна. И как нужно правильно?


По моему, слишком академично.

a> It is very important to collect as much information about failure as it is possible.

Ну да еще и фото пользователя присобачить.
It is not enough to know that something wrong has happened. We need to know how it happened, what was done before the failure, and what the state of the system was. In other words, we need history.
Да это все хотят, но непонятно как получить. История обычно следующая — нажимали кнопочки она и вылетела.

a> One of the most valuable parts of the history is call stack.

Можно было голосование устроить как часто его получают и насколько он практически полезен. И самое интересное сколько % будет иметь номер строки и кто будет ее искать в данном релизе.
Misuse of try-catch construction in our code may lead to call stack cut or even loss. Here I will try to demonstrate several examples of such misuse.

a> Example 1:


a>
a> try
a> {
a>     // some logic here
a> }
a> catch
a> {
Кстати, именно здесь и был лог, насколько я помню, в предыдущем примере
a>     // Simply re-throwing all exceptions
a>     // in order to show that the base class catches the exceptions and
a>     // fails appropriately.
a>     throw;
a> }
a>


Что то об этой конструкции забыто
try
{
 ...
}
catch
{
  // по барабану
}

a> What’s wrong? Consider the following program.

a>
a>  1: class Program
a>  2: {
a>  3:    static void f(bool b)
a>  4:    {
a>  5:        if (b)
a>  6:            throw new ApplicationException();
Давайте всегда и везде кидать просто ApplicationException :)
a>  7:    }
...
a>


a> After run s =

a> System.ApplicationException: Error in the application.
a> at Program.f(Boolean b) in c:\test\Program.cs:line 6
a> at Program.RunTest() in c:\test\Program.cs:line 19
a> at Program.Main(String[] args) in c:\test\Program.cs:line 27

a> What was the reason for exception? That information was lost.

Она теряется автоматом как только программа уходит наружу.
We don’t know what part of the code caused the error – the first f-function, the second or the third.
Почти ненужная инфа в реале. Гораздо важнее знать больше, что именно, где и как делал пользователь, а также отчего могло бы быть конкретное исключение.

a> If you really need to throw your own exception in a catch block, the best way to do this is to throw a new exception and include the old one as the inner exception:


a>
a> try
a> {
a>     // some logic here
a> }
a> catch (SomeException e)
a> {
a>     // log some more info here
a>     throw new SomeException("descriptive message", e);
a> }
a>

Ну это вроде и так ясно, хотя вот так сразу вспомнить программы для обычных пользователей, где можно глянуть все вложенные исключения как то не вспомню.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[4]: Куда помещать код логирования?
От: AlexNek  
Дата: 01.03.12 08:35
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, stomsky, Вы писали:

S>>Тока скажите честно, ВЫ САМИ такое стали бы использовать????
S>Сам — стал бы. А зачем полагаться на какие-то внешние библиотеки и DSL, которые работают непрозрачным образом?
А что сама .NET полностью прозрачна?
Библиотека должна работать без ощибок и я должен понимать как ее использовать, все остальное не должно волновать.
S>Только когда такой код станет некрасивым, имеет смысл пойти по пути дальнейшего улучшения.
Зачем продуцировать "некрасивый код". Решение нужно принять до того как.

S>Вообще, вынужден предупредить: я промышленный код не пишу уже много лет, и на практике подобные идеи не проверял.

Тут у нас похоже наоборот. Теория интересует именно с точки зрения применения на практике.

Давайте все же возвратимся к "задетой" части кода и даже теоретически обсудим что же там неправильного в свете вышесказанного и как
должен выглядет "правильный" код? (Для теории — считаем этот метод частью библиотеки.)

        public bool IsNeedToPayBonus(Context context)
        {
            try
            {
                //...
            }
            catch (Exception e)
            {
                Error(e.Message + e.StackTrace);
                throw;
            }
        }
Re: Куда помещать код логирования?
От: debugx Россия http://oignatov.blogspot.com
Дата: 01.03.12 11:32
Оценка:
Здравствуйте, stomsky, Вы писали:

S>Доброго времени суток!


Пара полезных статей на хабре про то, как правильно использовать логгеры:
http://habrahabr.ru/blogs/net/98638/
http://habrahabr.ru/blogs/net/135242/
Re: Куда помещать код логирования?
От: elw00d Россия http://elwood.su
Дата: 01.03.12 13:38
Оценка:
Здравствуйте, stomsky, Вы писали:

S>Доброго времени суток!

S>Пишу сейчас один сервис, который будет круглосуточно выполнять всякие полезные действия.
S>Надо вести подробный лог.
S>Сейчас кодирую и вижу как буквально на глазах "полезный" код засоряется кодом логирования.
S>Подскажите, плиз, как вы боритесь с этой проблемной?
S>Про аспекты я, конечно, слышал, но не хочется под это дело сторонние библиотеки привлекать.

Я вот тут на днях послушал Радио-Т, и там обсуждали концепцию just in time logging, согласно которой настроить уровни логирования недостаточно для локализации ошибок. Ну положим, у вас есть много Trace, Info, Debug сообщений на сервере, который обрабатывает постоянно новые данные. И вы поступаете обычно так — либо разрешаете писать в лог все-все-все, либо ограничиваете мин. левел Warn и Error. Проблема первого способа — избыточность логируемой инфы. Проблема второго — недостаточность (например, произошла ошибка, сообщение о ней записано в лог, но разобраться, ПОЧЕМУ эта ошибка произошла — без записей Trace, Debug и Info, относящихся к последней выполненной операции, сложно. А вы их заблаговременно отключили).

Вот здесь http://pragprog.com/magazines/2011-12/justintime-logging автор предлагает использовать концепцию, в которой мы можем определить логический "кусок" программы, который занимается некоторой операцией. Мы наваливаем туда все, что можно — Trace, Debug, Info итд, но пока операция не завершится, эта штука не будет записана в лог, она просто хранится в памяти. И после завершения операции мы должны определить, нужно ли целиком все это богатство записать на диск (например в случае ошибки) или можно с чистой совестью выкинуть детали происшедшего. Таким образом, сохраняется баланс между количеством и качеством логируемой информации. Предложенная реализация, конечно, там скудновата, я вот как раз собираюсь для NLog сделать адаптер с более широкой функциональностью. Но идея вот такая. Я бы от себя добавил, что лучше конечно сделать это не в хешмапе, а в древовидной структуре, где узел дерева определяет "область видимости" текущего лог-узла. Ну и сделать эти "узлы" IDisposable, чтобы обязать юзера завершать эти "блоки" логов. Подход мне кажется достаточно перспективным именно в местах, где происходит циклическая обработка потока данных, где важно уметь именно расследовать причины ошибок. В остальных местах можно пользоваться старыми способами, не требующими мозговых затрат на продумывания дерева scope'ов.
Re[6]: Куда помещать код логирования?
От: AlexNek  
Дата: 01.03.12 17:41
Оценка:
Здравствуйте, Sinclair, Вы писали:

S> AN>А что сама .NET полностью прозрачна?

S> AN>Библиотека должна работать без ошибок и я должен понимать как ее использовать, все остальное не должно волновать.

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


Это не вопрос а просто комментарий к данной фразе
"S>Сам — стал бы. А зачем полагаться на какие-то внешние библиотеки и DSL, которые работают непрозрачным образом?"
S> Зато я знаю, почему в этом коде трассируются 1 и 3, и не трассируется 2:
S>
S> void DoAnything()
S>   {
S>     Trace(()=>{
S>       Trace(()=>DoAction1());
S>       DoAction2();
S>       Trace(()=>DoAction3());
S>     });
S>   }
S>


Делать код хорошо пригодный для определенного способа трассировки???
S> AN>Давайте все же возвратимся к "задетой" части кода и даже теоретически обсудим что же там неправильного в свете вышесказанного и как
S> AN>должен выглядет "правильный" код? (Для теории — считаем этот метод частью библиотеки.)
S> AN>
S> AN>        public bool IsNeedToPayBonus(Context context)
S> AN>        {
S> AN>            try
S> AN>            {
S> AN>                //...
S> AN>            }
S> AN>            catch (Exception e)
S> AN>            {
S> AN>                Error(e.Message + e.StackTrace);
S> AN>                throw;
S> AN>            }
S> AN>        }
S> AN>


S> А в чём именно тут вопрос? Какую проблему вы хотите решить?

Только прояснить данное сообщение
здесь
Автор: Sinclair
Дата: 01.03.12

"Не делайте так. Происходит потеря информации о месте возникновения исходного исключения."
Елинственная связь с этим
здесь
Автор: Sinclair
Дата: 01.03.12

это "throw;"
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[7]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.03.12 02:57
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Делать код хорошо пригодный для определенного способа трассировки???

Я не понимаю ваш вопрос. Сформулируйте его так, чтобы на него можно было ответить.

S>> А в чём именно тут вопрос? Какую проблему вы хотите решить?

AN>Только прояснить данное сообщение
AN>здесь
Автор: Sinclair
Дата: 01.03.12

AN>"Не делайте так. Происходит потеря информации о месте возникновения исходного исключения."
AN>Елинственная связь с этим
AN>здесь
Автор: Sinclair
Дата: 01.03.12

AN>это "throw;"
В сообщении, на которое вы ссылаетесь, нет цитаты, которую вы приводите.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Куда помещать код логирования?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 02.03.12 04:21
Оценка:
Здравствуйте, elw00d, Вы писали:

E>Вот здесь http://pragprog.com/magazines/2011-12/justintime-logging автор предлагает использовать концепцию, в которой мы можем определить логический "кусок" программы, который занимается некоторой операцией. Мы наваливаем туда все, что можно — Trace, Debug, Info итд, но пока операция не завершится, эта штука не будет записана в лог, она просто хранится в памяти. И после завершения операции мы должны определить, нужно ли целиком все это богатство записать на диск (например в случае ошибки) или можно с чистой совестью выкинуть детали происшедшего. Таким образом, сохраняется баланс между количеством и качеством логируемой информации.


во, до этой идеи я тоже додумался, но тут есть существенный затык — если буфер хранить в памяти, то в случае аварийного завершения программы по какой-либо причине мы об этой причине вообще ничего не узнаем, т.к. весь этот буфер просто гикнется вместе с программой, а если этот буфер хранить где-то снаружи (файл, БД), то нет никакого выигрыша в производительности и основной лог и причина падения программы получается лежат в разных местах.

E>я вот как раз собираюсь для NLog сделать адаптер


с буфером в памяти?
Re[3]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.03.12 06:59
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>во, до этой идеи я тоже додумался, но тут есть существенный затык — если буфер хранить в памяти, то в случае аварийного завершения программы по какой-либо причине мы об этой причине вообще ничего не узнаем, т.к. весь этот буфер просто гикнется вместе с программой, а если этот буфер хранить где-то снаружи (файл, БД), то нет никакого выигрыша в производительности и основной лог и причина падения программы получается лежат в разных местах.

Да проблема-то скорее не в производительности программы, а в производительности анализирующего. Когда тебе надо отпарсить гигабайты логов для поиска единственного исключения — вот это дупа.
Я в своё время думал про что-то типа адаптивного логгирования, когда мы логаем вроде бы всё, но оперативно выбрасываем всё, кроме нужного куска.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Куда помещать код логирования?
От: elw00d Россия http://elwood.su
Дата: 02.03.12 08:35
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, elw00d, Вы писали:


E>>Вот здесь http://pragprog.com/magazines/2011-12/justintime-logging автор предлагает использовать концепцию, в которой мы можем определить логический "кусок" программы, который занимается некоторой операцией. Мы наваливаем туда все, что можно — Trace, Debug, Info итд, но пока операция не завершится, эта штука не будет записана в лог, она просто хранится в памяти. И после завершения операции мы должны определить, нужно ли целиком все это богатство записать на диск (например в случае ошибки) или можно с чистой совестью выкинуть детали происшедшего. Таким образом, сохраняется баланс между количеством и качеством логируемой информации.


OE>во, до этой идеи я тоже додумался, но тут есть существенный затык — если буфер хранить в памяти, то в случае аварийного завершения программы по какой-либо причине мы об этой причине вообще ничего не узнаем, т.к. весь этот буфер просто гикнется вместе с программой, а если этот буфер хранить где-то снаружи (файл, БД), то нет никакого выигрыша в производительности и основной лог и причина падения программы получается лежат в разных местах.


В дотнетовых приложениях прям совсем уж падений не бывает же (кроме падений в нативном коде или если сервер/процесс прибили), а Unhandled exceptions можно отловить и сбросить все, что находилось в буфере перед смертью. Собственно, так я и планирую делать. Ну а если есть куски, в которых это неприемлемо, то по идее можно реализовать схему с постоянным дампом на диск в виде журнала (подобно тому как это делают базы данных), но имхо это ненужное усложнение. Проще в критических местах тогда забить и использовать традиционную схему логирования.

E>>я вот как раз собираюсь для NLog сделать адаптер


OE>с буфером в памяти?


угу
Re[9]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.03.12 06:53
Оценка:
Здравствуйте, AlexNek, Вы писали:

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

Если вы хотите какого-то ответа на ваше вопросительное замечание, то, пожалуйста, сделайте его более развёрнутым. В частности, почему конкретно вы считаете такой код неприменимым на практике?

AN>Вот эти должны быть правильнее.

AN>http://www.rsdn.ru/forum/dotnet/4641286.1.aspx
Автор: abibok
Дата: 29.02.12

AN>http://www.rsdn.ru/forum/dotnet/4641442.1.aspx
Автор: abibok
Дата: 01.03.12

Не знаю, почему вы хотите пояснений мнению, высказанному abibok-ом, от меня.
Лично у меня по поводу того фрагмента мнений два:
1. К сожалению, в дотнете нет способа перевыбросить исключение, не исказив его стек. Поэтому вариантов для конкретного фрагмента, в общем-то, нет.
2. Но в целом надо понять, а зачем вообще код конкретно этого уровня заморачивается логгированием исключения? Он не доверяет вызывающему коду, думая что тот обязательно исключение проглотит? Он не доверяет вызываемому коду, думая, что тот ничего не протрассирует перед моментом выброса исключения?
Выглядит очень подозрительно. Одно дело, если бы перехват исключения был частью логики. Но тогда бы не было перевыброса. А логгированием исключений должен заниматься специальный код, отдельный от бизнес-логики.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Куда помещать код логирования?
От: AlexNek  
Дата: 03.03.12 13:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:


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

S>Если вы хотите какого-то ответа на ваше вопросительное замечание, то, пожалуйста, сделайте его более развёрнутым.
Если бы я хотел "обязательный" ответ, то это был бы вопрос.

S>В частности, почему конкретно вы считаете такой код неприменимым на практике?

Чаще всего получается, что есть уже готовый код, в котором понадобилась трассировка. При этом любая новая вставка не должна "модифицировать" существующий код. По крайнем мере, при сравнении должны быть неизменные линии старого кода и новые для трассировки. При данном способе изменяются не только линии исходного кода но и сам способ вызова. То есть происходит видоизменение существующего кода, которое непонятно как может сказаться при выполнении кода. А если бывает что даже просто вставка трассировки "убивает" ошибку, то во что выльются данные измения я не могу предсказать.

AN>>Вот эти должны быть правильнее.

AN>>http://www.rsdn.ru/forum/dotnet/4641286.1.aspx
Автор: abibok
Дата: 29.02.12

AN>>http://www.rsdn.ru/forum/dotnet/4641442.1.aspx
Автор: abibok
Дата: 01.03.12

S>Не знаю, почему вы хотите пояснений мнению, высказанному abibok-ом, от меня.
Вообще это я понял (что авторы разные) только когда искал ссылки, обычно я "вижу" форум в "плоском" виде.
S>Лично у меня по поводу того фрагмента мнений два:
S>1. К сожалению, в дотнете нет способа перевыбросить исключение, не исказив его стек. Поэтому вариантов для конкретного фрагмента, в общем-то, нет.

S>2. Но в целом надо понять, а зачем вообще код конкретно этого уровня заморачивается логгированием исключения? Он не доверяет вызывающему коду, думая что тот обязательно исключение проглотит? Он не доверяет вызываемому коду, думая, что тот ничего не протрассирует перед моментом выброса исключения?

А для чего это нужно понимать? Есть код для которого нужно иметь больше информации, гораздо быстрее вставить линию трассировки и глянуть протокол, чем разбираться нужна она или нет.
S>Выглядит очень подозрительно. Одно дело, если бы перехват исключения был частью логики. Но тогда бы не было перевыброса.
Для меня выглят абсолютно натурально. Был код без трассировки, в который ее добавили.
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re[11]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.03.12 07:13
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Чаще всего получается, что есть уже готовый код, в котором понадобилась трассировка. При этом любая новая вставка не должна "модифицировать" существующий код. По крайнем мере, при сравнении должны быть неизменные линии старого кода и новые для трассировки.

Вот это требование не очень понятно, откуда взялось.
При данном способе изменяются не только линии исходного кода но и сам способ вызова.
Способ вызова остаётся тем же. Мы просто окружаем наш код "операторными скобками". То, что стек вызова будет выглядеть по-другому, в большинстве случаев неважно.
Кода, который будет чувствителен к таким нюансам, в природе очень мало.

AN>>>Вот эти должны быть правильнее.

AN>>>http://www.rsdn.ru/forum/dotnet/4641286.1.aspx
Автор: abibok
Дата: 29.02.12

AN>>>http://www.rsdn.ru/forum/dotnet/4641442.1.aspx
Автор: abibok
Дата: 01.03.12

S>>Не знаю, почему вы хотите пояснений мнению, высказанному abibok-ом, от меня.
AN>Вообще это я понял (что авторы разные) только когда искал ссылки, обычно я "вижу" форум в "плоском" виде.
Ну зачем же вы так на него смотрите. Смотрите так, чтобы было понятно, кто кому что отвечает.

AN>А для чего это нужно понимать? Есть код для которого нужно иметь больше информации, гораздо быстрее вставить линию трассировки и глянуть протокол, чем разбираться нужна она или нет.

Давайте разберёмся, какую проблему вы решаете. Если вам хочется по-быстрому воткнуться и посмотреть, то достаточно просто брекпоинта. Если не получается сделать брекпоинт, то можно втыкать какую угодно трассировку — вы же её уберёте из production, так что вопросы качества кода вообще не волнуют.

А если вы заморачиваетесь тем, как же тут правильно делать, то речь о production коде, и вот в нём такие вещи выглядят очень подозрительно.
Потом вычитывать эти тонны мусора, разбираясь, то ли это семь разных проблем, то ли один и тот же exception, залоггированный на семи уровнях — то ещё удовольствие.

S>>Выглядит очень подозрительно. Одно дело, если бы перехват исключения был частью логики. Но тогда бы не было перевыброса.

AN>Для меня выглят абсолютно натурально. Был код без трассировки, в который ее добавили.
А для меня это выглядит как абсолютно бесполезная трассировка. Исключение, если оно было, поймают и уровнями выше. И вся информация про него там будет.
Логично было бы добавить трассировку, скажем, параметров вызова, спровоцировавших исключение — которых в исключении может и не быть.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Куда помещать код логирования?
От: AlexNek  
Дата: 04.03.12 12:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:


AN>>Чаще всего получается, что есть уже готовый код, в котором понадобилась трассировка. При этом любая новая вставка не должна "модифицировать" существующий код. По крайнем мере, при сравнении должны быть неизменные линии старого кода и новые для трассировки.

S>Вот это требование не очень понятно, откуда взялось.
Откуда взялось сказать также не могу, но всегдв пользуем. По крайней мере, четко видно если что накосячено.
S>При данном способе изменяются не только линии исходного кода но и сам способ вызова.
S>Способ вызова остаётся тем же. Мы просто окружаем наш код "операторными скобками". То, что стек вызова будет выглядеть по-другому, в большинстве случаев неважно.
Если будет в одном конкретном месте, то можно вполне пренебречь, но если будет везде подобный код, то на стек будет просто невозможно смотреть. К тому же данную добавку сделать "на автомате" не так просто. Тут нужно хоть немного "подумать".
if (a())
{
 return b();
}

S>Кода, который будет чувствителен к таким нюансам, в природе очень мало.
Но совсем не хочется узнать, что вдруг нашелся подобный вариант. Да и код для меня становится гораздо хуже читаемым. Логи то видны сразу, а тут в море скобок нужно разбираться.

AN>>>>Вот эти должны быть правильнее.

AN>>>>http://www.rsdn.ru/forum/dotnet/4641286.1.aspx
Автор: abibok
Дата: 29.02.12

AN>>>>http://www.rsdn.ru/forum/dotnet/4641442.1.aspx
Автор: abibok
Дата: 01.03.12

S>>>Не знаю, почему вы хотите пояснений мнению, высказанному abibok-ом, от меня.
AN>>Вообще это я понял (что авторы разные) только когда искал ссылки, обычно я "вижу" форум в "плоском" виде.
S>Ну зачем же вы так на него смотрите.
Затем что это практически единственный форум с древовидной структурой для меня. И в Авалоне я видел только ответы.
S>Смотрите так, чтобы было понятно, кто кому что отвечает.
абсолютно неудобно, но это скорее дело привычки.

AN>>А для чего это нужно понимать? Есть код для которого нужно иметь больше информации, гораздо быстрее вставить линию трассировки и глянуть протокол, чем разбираться нужна она или нет.

S>Давайте разберёмся, какую проблему вы решаете. Если вам хочется по-быстрому воткнуться и посмотреть, то достаточно просто брекпоинта. Если не получается сделать брекпоинт, то можно втыкать какую угодно трассировку — вы же её уберёте из production, так что вопросы качества кода вообще не волнуют.

S>А если вы заморачиваетесь тем, как же тут правильно делать, то речь о production коде, и вот в нём такие вещи выглядят очень подозрительно.

S>Потом вычитывать эти тонны мусора, разбираясь, то ли это семь разных проблем, то ли один и тот же exception, залоггированный на семи уровнях — то ещё удовольствие.
Вообще то речь шла только о потери информации о стеке. А с логом разбираться в данном случае довольно просто, смотрим только на первое исключение все что дальше,будет интересовать только для случая отладки "механизма обработки иключений".

S>>>Выглядит очень подозрительно. Одно дело, если бы перехват исключения был частью логики. Но тогда бы не было перевыброса.

AN>>Для меня выглят абсолютно натурально. Был код без трассировки, в который ее добавили.
S>А для меня это выглядит как абсолютно бесполезная трассировка. Исключение, если оно было, поймают и уровнями выше. И вся информация про него там будет.
Кто это сможет гаратировать? Ну и будет как раз не вся информация о стеке.
S>Логично было бы добавить трассировку, скажем, параметров вызова, спровоцировавших исключение — которых в исключении может и не быть.
Кстати, когда игрался с постшарпом так и сделал. Оказалось практически бесполезной вещью. Хотя если лог "прийдет из другого места" будет видимо полезно.
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re[13]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.03.12 06:50
Оценка:
Здравствуйте, AlexNek, Вы писали:
AN>Откуда взялось сказать также не могу, но всегдв пользуем. По крайней мере, четко видно если что накосячено.
Я понял. В целом, мы говорим про два совершенно разных сценария использования трассировки.
Вы говорите про временную трассировку для отладки, когда нужно срочно воткнуть строки в имеющийся код, а потом убрать их.
Я говорю про перманентную трассировку в production code. К примеру, посмотрите, сколько её встроено в System.Net.
Отсюда и разногласия.

случаев неважно.
AN>Если будет в одном конкретном месте, то можно вполне пренебречь, но если будет везде подобный код, то на стек будет просто невозможно смотреть. К тому же данную добавку сделать "на автомате" не так просто. Тут нужно хоть немного "подумать".
Верно, вы правы.

S>>Кода, который будет чувствителен к таким нюансам, в природе очень мало.

AN>Но совсем не хочется узнать, что вдруг нашелся подобный вариант. Да и код для меня становится гораздо хуже читаемым. Логи то видны сразу, а тут в море скобок нужно разбираться.
AN>Затем что это практически единственный форум с древовидной структурой для меня. И в Авалоне я видел только ответы.
S>>Смотрите так, чтобы было понятно, кто кому что отвечает.
AN>абсолютно неудобно, но это скорее дело привычки.

AN>Вообще то речь шла только о потери информации о стеке.

Да не шла об этом речь. Зайдите в веб и включите древовидное представление. Это не sibmama.ru, тут не принято отвечать сразу всем.

AN>Кто это сможет гаратировать? Ну и будет как раз не вся информация о стеке.

Что значит "гарантировать"? Идём в самый-самый верх и смотрим, чем у нас unhandled exception обрабатывается. Откуда будет "не вся" информация — мне непонятно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Куда помещать код логирования?
От: AlexNek  
Дата: 05.03.12 16:59
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:

AN>>Откуда взялось сказать также не могу, но всегдв пользуем. По крайней мере, четко видно если что накосячено.
S>Я понял. В целом, мы говорим про два совершенно разных сценария использования трассировки.
S>Вы говорите про временную трассировку для отладки, когда нужно срочно воткнуть строки в имеющийся код, а потом убрать их.
S>Я говорю про перманентную трассировку в production code. К примеру, посмотрите, сколько её встроено в System.Net.
S>Отсюда и разногласия.
Для нас, трассировка в production code это просто неубранная по разным причинам, трассировка для отладки. Хотя в текущем проекте трассировка есть иключительно только в исходном коде подключаемая через препроцессор.
В любом случае, она пишется так, чтобы ее можно было убрать простым комментарием — и этот принцип еще никогда не нарушался.

S>>>Кода, который будет чувствителен к таким нюансам, в природе очень мало.

AN>>Но совсем не хочется узнать, что вдруг нашелся подобный вариант. Да и код для меня становится гораздо хуже читаемым. Логи то видны сразу, а тут в море скобок нужно разбираться.
AN>>Затем что это практически единственный форум с древовидной структурой для меня. И в Авалоне я видел только ответы.
S>>>Смотрите так, чтобы было понятно, кто кому что отвечает.
AN>>абсолютно неудобно, но это скорее дело привычки.

AN>>Вообще то речь шла только о потери информации о стеке.

S>Да не шла об этом речь. Зайдите в веб и включите древовидное представление. Это не sibmama.ru, тут не принято отвечать сразу всем.
В вебе я практически не работаю с рсдн. А если и попадается, то исключительно для прочтения темы подряд. Ну быстрее же просто колесиком мыши крутить для прокрутки текста.

Да и обычно накладок почти не было.

AN>>Кто это сможет гаратировать? Ну и будет как раз не вся информация о стеке.

S>Что значит "гарантировать"? Идём в самый-самый верх и смотрим, чем у нас unhandled exception обрабатывается.
А кто гарантирует, что данный модуль использует только одна программа? И как по быстрому найти это самый-самый верх? И у меня нет никакой уверенности что исключение туда дойдет, а не пропадет где-то по дороге.
Я бы даже сказал, что пути exception неисповедимы. Вот недавний пример. Обнаружил случайно место, где исключения просто съедались — непорядок, нужно убрать. Хорошо, что сразу протестировал, оказалось, что при этом намертво зависала splash форма. Пришлось записать в баг треккер и откатится назад.
S>Откуда будет "не вся" информация — мне непонятно.
Так именно от этого и пошел весь сыр бор — стек искажается от "внутренних" throw.
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re[14]: Куда помещать код логирования?
От: abibok  
Дата: 05.03.12 19:58
Оценка:
AN>>Кто это сможет гаратировать? Ну и будет как раз не вся информация о стеке.
S>Что значит "гарантировать"? Идём в самый-самый верх и смотрим, чем у нас unhandled exception обрабатывается. Откуда будет "не вся" информация — мне непонятно.

В том-то и дело, что если на пути от возникновения исключения к самому верхнему catch есть еще хотя бы один try-catch, который ловит и перевыбрасывает используя пустой throw или throw ex, то информация теряется. Такое исключение уже намного сложнее отлаживать.
Re[15]: Куда помещать код логирования?
От: abibok  
Дата: 05.03.12 22:04
Оценка:
Более того, сохранять в лог информацию об исключении на самом верху уже поздно, потому что к этому моменту стек раскрутился и все локальные объекты потеряны. Поэтому если мы хотим чего-то больше, чем просто стек вызовов, нужно логировать исключение непосредственно после того, как оно было брошено, но до того, как мы вошли в первый/ближайший catch.
Re[15]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.03.12 02:48
Оценка:
Здравствуйте, AlexNek, Вы писали:
AN>Для нас, трассировка в production code это просто неубранная по разным причинам, трассировка для отладки. Хотя в текущем проекте трассировка есть иключительно только в исходном коде подключаемая через препроцессор.
AN>В любом случае, она пишется так, чтобы ее можно было убрать простым комментарием — и этот принцип еще никогда не нарушался.
Я и говорю — этот сценарий сильно отличается от Production трассировки. В самом фреймворке её полно, и задач убрать её простым комментарием тоже нету.

AN>А кто гарантирует, что данный модуль использует только одна программа? И как по быстрому найти это самый-самый верх? И у меня нет никакой уверенности что исключение туда дойдет, а не пропадет где-то по дороге.

Ещё раз: если вы находитесь в процессе отладки, то у вас только одна программа — та, которую вы отлаживаете, и требований к качеству кода нет. Равно как и нет требования сохранять стек исключения для обработчиков верхнего уровня — вы только что отказались от разбирательств с этими обработчиками.
А если вы хотите вставить трассировку в production-код и отдать библиотеку для повторного использования, то всё будет устроено несколько по-другому

S>>Откуда будет "не вся" информация — мне непонятно.

AN>Так именно от этого и пошел весь сыр бор — стек искажается от "внутренних" throw.
Ещё раз: вы делаете внутренний throw оттого, что боитесь потери информации, и собственно этим её же и обеспечиваете.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Куда помещать код логирования?
От: AlexNek  
Дата: 06.03.12 18:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А если вы хотите вставить трассировку в production-код и отдать библиотеку для повторного использования, то всё будет устроено несколько по-другому

У нас бы не было никакого отличия, более того, вероятно было бы два типа либ — с подключенной трассировкой и вообще без онной. Так как совсем не хочется гонять в длинном цикле даже просто "иф". Хотя может зависеть и от других факторов, но в любом случае трассировка не будет составлять "единное целое" с кодом.
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re[17]: Куда помещать код логирования?
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.03.12 03:25
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>У нас бы не было никакого отличия, более того, вероятно было бы два типа либ — с подключенной трассировкой и вообще без онной. Так как совсем не хочется гонять в длинном цикле даже просто "иф". Хотя может зависеть и от других факторов, но в любом случае трассировка не будет составлять "единное целое" с кодом.

Я понял. Просто это совсем другой подход, чем, скажем, в FCL.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.