Re[6]: Передача контекста через множество уровней абстракции приложения
От: Sinix  
Дата: 31.07.16 08:50
Оценка: +1
Здравствуйте, Vladek, Вы писали:

S>>У топикстартера как раз одна из проблем — как этот контейнер по всей цепочке вызовов протащить. Есть какие-нибудь идеи?


V>Его не нужно никуда протаскивать. Достаточно воспользоваться механизмом событий — у компонента будет набор релевантных событий, а логгер будет на них подписан.

Такие советы в 100% случаев означают, что человек или не использовал логирование, или привык давать советы, не задумываясь о последствиях.

Если подобное предлагается абсолютно всерьёз на реальном проекте и намёков человек не понимает, то лечится просто. Поступаем точно так же, как и с полезным предложением. Даётся реальный код с парой сотен вызовов логгера (это очень мало) из которых половина — в static-методах, а ещё треть — в await | итераторах и предлагается оценить трудозатраты по переводу на модель событий. Также расписать возможные косяки (если не назовёт утечку памяти / вызов обработчиков событий в "неправильном" порядке и взаимные side-эффекты от подписчиков — ещё один минус в бюджет предложения) и стоимость мер по их исправлению.

Если по итогам человек не проникся, то дальше вариантов полно. Или подсаживаем в команду с хорошим лидом на переобучение, или перекидываем на проект, где от кипучей деятельности будет польза, или расстаёмся с хорошими рекомендациями, пусть конкуренты берут. Человек, способный из любви к абстрактным идеям протащить их в проект, в итоге навредит так что любая сознательная диверсия детским утренником покажется.
Re[7]: Передача контекста через множество уровней абстракции приложения
От: Vladek Россия Github
Дата: 31.07.16 10:50
Оценка:
Здравствуйте, Sinix, Вы писали:

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


S>>>У топикстартера как раз одна из проблем — как этот контейнер по всей цепочке вызовов протащить. Есть какие-нибудь идеи?


V>>Его не нужно никуда протаскивать. Достаточно воспользоваться механизмом событий — у компонента будет набор релевантных событий, а логгер будет на них подписан.

S>Такие советы в 100% случаев означают, что человек или не использовал логирование, или привык давать советы, не задумываясь о последствиях.

S>Если подобное предлагается абсолютно всерьёз на реальном проекте и намёков человек не понимает, то лечится просто. Поступаем точно так же, как и с полезным предложением. Даётся реальный код с парой сотен вызовов логгера (это очень мало) из которых половина — в static-методах, а ещё треть — в await | итераторах и предлагается оценить трудозатраты по переводу на модель событий. Также расписать возможные косяки (если не назовёт утечку памяти / вызов обработчиков событий в "неправильном" порядке и взаимные side-эффекты от подписчиков — ещё один минус в бюджет предложения) и стоимость мер по их исправлению.


Ты уж потрудись, сам распиши косяки. Желательно с примерами. Что мне толку с твоего гонора?
Re[8]: Передача контекста через множество уровней абстракции приложения
От: Sinix  
Дата: 31.07.16 11:59
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Ты уж потрудись, сам распиши косяки. Желательно с примерами. Что мне толку с твоего гонора?


Ну так это не гонор, эт стандартная реакция на рекомендации в стиле "мыши станьте ёжиками". Не, серьёзно, ну как можно советовать очевиднейшую ерунду?
Самый простейший пример (реальный код, имена понятное дело изменены):
static async Task DoAsync(string uri, ILogger logger)
{
  try
  {
    await DoAsyncCore(uri);
  }
  catch(Exception ex)
  {
    logger.Log("Do async failed, bla-bla-bla", ex);
    throw;
  }
}


Попробуйте изобразить то же самое на событиях. Только плиз не чтоб было, а как бы вы написали для реального кода, который в продакшн пойдёт.
Re[9]: Передача контекста через множество уровней абстракции приложения
От: Vladek Россия Github
Дата: 31.07.16 12:47
Оценка:
Здравствуйте, Sinix, Вы писали:

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


Вот тут
Автор: rm822
Дата: 31.07.16
и без меня дали вариант.

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

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

var commandName = command.GetType().Name + "(" + command.GetHashCode() + ")";
var stopwatch = new Stopwatch();
try
{
    Debug.WriteLine("{0} executing {1}", this.dispatcherName, commandName);
    Debug.WriteLine("{0} {1} is {2}", this.dispatcherName, commandName, command.ToString());
    stopwatch.Start();

    await this.dispatcher.ExecuteAsync(command);
}
catch (Exception x)
{
    Debug.WriteLine("{0} caught error: {1}", this.dispatcherName, x);
    throw;
}
finally
{
    stopwatch.Stop();
    Debug.WriteLine("{0} executed {1} ({2} ms)", this.dispatcherName,
        commandName, stopwatch.ElapsedMilliseconds);
}


Тут диспетчер dispatcher — занимается передачей команды нужному обработчику. Вот этот вот код — точно такой же диспетчер-обёртка с журналом (в данном случае это обычный отладочный вывод). Обработчики команд тоже могут иметь свои журналы, работающие похожим образом. Код, собственно выполняющий работу, не замусорен вызовами журнала или обращениями к каким-то контекстам.
Re[10]: Передача контекста через множество уровней абстракции приложения
От: Sinix  
Дата: 31.07.16 13:52
Оценка:
Здравствуйте, Vladek, Вы писали:

V>В продакшен пойдёт код, который не будет загромождать журнал мусором.

V>Вернёмся к методу из примера. В нём не будет журнала вообще.

Я ж говорю — вы не используете логгинг, что обсуждать-то?
Какой нафиг "Debug.WriteLine"? Вы в продакшне на живой сервер будете отладочные сборки подсовывать??? Или у вас любая ситуация всегда локально воспроизводится, без завязки на пользовательские данные?

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


Угу-угу. Вы это товарищам внедренцам расскажите в ситуации, когда человек за 10k километров от вас и у него уже рабочий день заканчивается, у вас меньше половины дня на починить систему (т.е. минимум часов 5 — не ваши, а QA и внедренцев), удалённый отладчик вы подключить не можете ибо прав на сервер у вас нет, да и не получите, ибо допуск оформлять ещё надо. Абсолютно типовая ситуация в любом более-менее крупном продукте, минимум раз в квартал встречается.

Удачи, что ещё сказать.

Лечится не менее стандартно, инструкцией вида "ставим галочку "всё пропало, помогииите", воспроизводим, оставляем контактные данные, ждём звонка/письма". Если у людей паранойя и доступ к интернету перекрыт, то придётся ещё самим отправить файлы с итогами трассировки по указанному адресу, да.


V>Вернёмся к методу из примера.

V>this.dispatcher
Ну, т.е. простой static-метод внезапно становится членом класса и начинает подгребать зависимости, которые в оригинале спокойно передавались в параметрах.
При этом исходная задача — скинуть сообщение об ошибке в конкретный логгер, а не в общий журнал — не решена. Ну и самих событий, ради которых мы и начали изобретать велосипед, тоже внезапно нет.
И это мы делаем для того, чтобы _упростить_ тестирование / сопровождение, ничего не упустил?
Re[11]: Передача контекста через множество уровней абстракции приложения
От: Vladek Россия Github
Дата: 31.07.16 15:13
Оценка:
Здравствуйте, Sinix, Вы писали:

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


V>>В продакшен пойдёт код, который не будет загромождать журнал мусором.

V>>Вернёмся к методу из примера. В нём не будет журнала вообще.

S>Я ж говорю — вы не используете логгинг, что обсуждать-то?

S>Какой нафиг "Debug.WriteLine"? Вы в продакшне на живой сервер будете отладочные сборки подсовывать??? Или у вас любая ситуация всегда локально воспроизводится, без завязки на пользовательские данные?

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

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


S>Угу-угу. Вы это товарищам внедренцам расскажите в ситуации, когда человек за 10k километров от вас и у него уже рабочий день заканчивается, у вас меньше половины дня на починить систему (т.е. минимум часов 5 — не ваши, а QA и внедренцев), удалённый отладчик вы подключить не можете ибо прав на сервер у вас нет, да и не получите, ибо допуск оформлять ещё надо. Абсолютно типовая ситуация в любом более-менее крупном продукте, минимум раз в квартал встречается.


S>Удачи, что ещё сказать.


Это вам удачи, со мной такого давно не происходило. Любой конкретный пример из своего опыта тут ни при чём. В самом деле, какой смысл обсуждать косяки в своей работе? Косяки придётся исправлять как придётся, раз уж они случились. Мы обсуждаем как не допускать косяков, а не как их исправлять. Если косяк становится типичной ситуацией — надо что-то менять в консерватории. Брут-форс не поможет.

S>Лечится не менее стандартно, инструкцией вида "ставим галочку "всё пропало, помогииите", воспроизводим, оставляем контактные данные, ждём звонка/письма". Если у людей паранойя и доступ к интернету перекрыт, то придётся ещё самим отправить файлы с итогами трассировки по указанному адресу, да.



V>>Вернёмся к методу из примера.

V>>this.dispatcher
S>Ну, т.е. простой static-метод внезапно становится членом класса и начинает подгребать зависимости, которые в оригинале спокойно передавались в параметрах.
S>При этом исходная задача — скинуть сообщение об ошибке в конкретный логгер, а не в общий журнал — не решена. Ну и самих событий, ради которых мы и начали изобретать велосипед, тоже внезапно нет.

Пример с событиями был в другом посте, я давал ссылку. Мой код — пример моего подхода (без событий). С событиями нет особых проблем — есть замечательная библиотека Rx, которая поможет справиться с перенаправлением событий по журналам. Ещё проще, иметь отдельного слушателя на каждый класс компонентов.

S>И это мы делаем для того, чтобы _упростить_ тестирование / сопровождение, ничего не упустил?


Это надо у автора первого поста спрашивать, зачем ему такая система логов. Мы же предлагаем простые способы решить проблему без привлечения грубой силы.
Re[12]: Передача контекста через множество уровней абстракции приложения
От: Sinix  
Дата: 31.07.16 16:06
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Пользовательские данные будут в журнале — запись его действий. А дальше уже можно анализировать локально что происходит с программой после ввода этих данных. Если там есть БД, которая нужна для воспроизведения проблемы, то к ней можно подключиться в режиме чтения или использовать копию.


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

Базы вам в 90% случаев не отдадут ни при каких условиях. Максимум — разрешат перекинуть сисадмину отдельные запросы (только select, разумеется), он их проверит, выполнит и перекинет обратно результат (при этом ещё, бывает, допускается только проверять наличие записей/значений в полях, но не вытаскивать сами данные). Содержимое логов точно так же согласовывается (даже абсолютные пути/url-ы обычно запрещены), копия отправленных данных сохраняется у заказчика для возможных разбирательств.


V>Это вам удачи, со мной такого давно не происходило.

А, ну так это комнатные условия, серьёзно. Любая попытка внедрить боль-менее сложную систему у нового клиента очень часто приводит к выявлению каких-либо косяков. Необязательно это именно ошибки в коде (их как раз ловят быстро). Чаще всего это сочетание неверной настройки и частных случаев нескольких бизнес-правил, которые по отдельности формально верны, но вместе приводят к неочевидным результатам. И хорошо если это заметные вещи типа годовой премии в десятикратном размере (угу, внедренцы по запарке поменяли 10% на 10x), которые легко воспроизводятся и диагностируются. Хуже, когда подобные мелкие ошибки приходится править постфактум. Вот тогда действительно веселуха.


V>Если косяк становится типичной ситуацией — надо что-то менять в консерватории. Брут-форс не поможет.

В любой крупной системе всегда есть что чинить/исправлять, это текучка как обновления в win. Менять в консерватории надо, если рутина в подвиг превращается. Тот же "полдня на исправить" как правило занимает часа четыре до момента поставки фикса клиенту. Ну или, всё те же 4 часа на диагностику "исправление нетривиальное, вот вам костыль, нормально починим с плановой рассылкой обновлений".


V>>>Вернёмся к методу из примера.

V> Мой код — пример моего подхода (без событий). С событиями нет особых проблем — есть замечательная библиотека Rx, которая поможет справиться с перенаправлением событий по журналам. Ещё проще, иметь отдельного слушателя на каждый класс компонентов.

Всё замечательно, только оно никак не относится к поставленному вопросу: как быть с реальным кодом, который в 99% случаев на событийную модель ложится преотвратно?
Особенно с приседаниями в виде Rx, которая требует досконального знания матчасти для того, чтобы корректно управлять временем жизни подписки.
Re[13]: Передача контекста через множество уровней абстракции приложения
От: Vladek Россия Github
Дата: 31.07.16 17:11
Оценка: +1
Здравствуйте, Sinix, Вы писали:

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


V>>Пользовательские данные будут в журнале — запись его действий. А дальше уже можно анализировать локально что происходит с программой после ввода этих данных. Если там есть БД, которая нужна для воспроизведения проблемы, то к ней можно подключиться в режиме чтения или использовать копию.


S>Так как они в журнале будут, если вы только для отладочных сборок информацию пишете?


Это зависит от конфигурации программы. В простом случае всё пишется в файл.

S>Базы вам в 90% случаев не отдадут ни при каких условиях. Максимум — разрешат перекинуть сисадмину отдельные запросы (только select, разумеется), он их проверит, выполнит и перекинет обратно результат (при этом ещё, бывает, допускается только проверять наличие записей/значений в полях, но не вытаскивать сами данные). Содержимое логов точно так же согласовывается (даже абсолютные пути/url-ы обычно запрещены), копия отправленных данных сохраняется у заказчика для возможных разбирательств.


Это решаемо, обычно и БД не нужна (проблема проявляется при записи новой информации), если всё-таки надо — её обфусцируют.

V>>Это вам удачи, со мной такого давно не происходило.

S>А, ну так это комнатные условия, серьёзно. Любая попытка внедрить боль-менее сложную систему у нового клиента очень часто приводит к выявлению каких-либо косяков. Необязательно это именно ошибки в коде (их как раз ловят быстро). Чаще всего это сочетание неверной настройки и частных случаев нескольких бизнес-правил, которые по отдельности формально верны, но вместе приводят к неочевидным результатам. И хорошо если это заметные вещи типа годовой премии в десятикратном размере (угу, внедренцы по запарке поменяли 10% на 10x), которые легко воспроизводятся и диагностируются. Хуже, когда подобные мелкие ошибки приходится править постфактум. Вот тогда действительно веселуха.


V>>Если косяк становится типичной ситуацией — надо что-то менять в консерватории. Брут-форс не поможет.

S>В любой крупной системе всегда есть что чинить/исправлять, это текучка как обновления в win. Менять в консерватории надо, если рутина в подвиг превращается. Тот же "полдня на исправить" как правило занимает часа четыре до момента поставки фикса клиенту. Ну или, всё те же 4 часа на диагностику "исправление нетривиальное, вот вам костыль, нормально починим с плановой рассылкой обновлений".

Да. подвигов быть не должно.

V>>>>Вернёмся к методу из примера.

V>> Мой код — пример моего подхода (без событий). С событиями нет особых проблем — есть замечательная библиотека Rx, которая поможет справиться с перенаправлением событий по журналам. Ещё проще, иметь отдельного слушателя на каждый класс компонентов.

S>Всё замечательно, только оно никак не относится к поставленному вопросу: как быть с реальным кодом, который в 99% случаев на событийную модель ложится преотвратно?


Как же не ложится? Автор указал набор событий, которые происходят в программе и влияют на работу с журналом (аутентификация, публикация команд, запуск параллельных операций). Только у него эти события в коде не имеют чёткого представления — вот и надо оформить их явно — в виде обычных дотнетовских событий или ещё как.

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


Матчасть надо знать в любом случае. Жизнь компонентов тоже должна быть абсолютно ясна из кода: вот тут компонент рождается, вот тут мы от него избавляемся. Компонент сам может сообщать о своей скорой смерти отдельным событием и журнал будет удалять свою подписку.
Re: Передача контекста через множество уровней абстракции приложения
От: UberPsychoSvin  
Дата: 01.08.16 11:40
Оценка:
У меня простой вариант.
* Давать тредам имена в стиле VasyanVasyanov.SESSION14.PC123.CMDID123.THREAD111 .
* Всё писать в один лог и парсить по имени треда .
Re: Передача контекста через множество уровней абстракции приложения
От: VladCore  
Дата: 01.08.16 12:50
Оценка:
Здравствуйте, LWhisper, Вы писали:

LW>Спасибо за внимание.


1.
У вас тум куча логеров в одном процессе что ли? Это не правильно. Или это не логеры.

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

3.
В Trace.Listeners свой writer не пробовали подсунуть?

Кстати, писать в один файл их разных потоков никто не запрещает.
Re[2]: Передача контекста через множество уровней абстракции приложения
От: UberPsychoSvin  
Дата: 01.08.16 13:46
Оценка:
Здравствуйте, VladCore, Вы писали:
VC>У вас тум куча логеров в одном процессе что ли? Это не правильно. Или это не логеры.
А как же .NET'овская практика, создавать по логгеру на класс?
class Some
{
    public Some()
    {
        _log = LogFactory.Get(GetType().Name);
    }
}
Re[3]: Передача контекста через множество уровней абстракции приложения
От: VladCore  
Дата: 02.08.16 14:10
Оценка:
Здравствуйте, UberPsychoSvin, Вы писали:

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

VC>>У вас тум куча логеров в одном процессе что ли? Это не правильно. Или это не логеры.
UPS>А как же .NET'овская практика, создавать по логгеру на класс?
UPS>
UPS>class Some
UPS>{
UPS>    public Some()
UPS>    {
UPS>        _log = LogFactory.Get(GetType().Name);
UPS>    }
UPS>}
UPS>


LW>Возьмём, для примера, логирование.

LW>Вот запускается приложение и моментально начинает писать лог. Имя лога спускается в аргументах командой строки.
LW>Окей, от этого трудно отказаться (хотя и можно), но пока терпимо.
LW>Происходит аутентификация пользователя. Теперь лог пишется уже в каталог этого горемычного юзера.

выделил для тех кто не читал вопрос.

кстати, эта порочная практика с функцией _log = function(type_name) {....} пришла из явы. Когда-то было круто. Её не надо использовать. см. вопрос топик-стартера.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.