03.06.2018, 09:15 | #1 |
Administrator
|
Стек вызовов в инфологе в D365FO
Всем добрый день!
На этом форуме уже несколько раз пролетала мысль про добавлении стека вызовов в инфолог (об этом упоминали разные авторы, и даже когда-то я в древности), но до версии D365FO еще не доходили. Я помню, как стек вызовов прикрутил к инфологу еще в 3.0, затем пришлось модификацию немного поменять, т.к. в 4.0 ввели упаковку данных инфолога в контейнер. Но зато в 2009 и особенно в 2012 модификация перетекла достаточно легко. Главной ее сложностью (в моем исполнении) была необходимость правки формы инфолога и класса Info, в результате чего при неаккуратной правке могло поломаться приложение. Это в общем-то основная причина, по которой я не выкладывал (и не выкладываю) ее на форум. Однако в версии D365FO, в связи с появлением понятия модели и пакета (Package), в котором создается модель – стало возможно эту модификацию сделать достаточно безопасной для инсталляции, хотя, к сожалению и пришлось немного пожертвовать удобством использования (в связи с запретом оверлеинга). Соответственно, получилось нечто, что в целом (лично для меня) приносит больше пользы, чем вреда ). Ее еще можно дошлифовывать, но в неком «грубом представлении» вполне уже можно использовать в работе. Вполне вероятно – ошибки будут – поэтому просьба сообщать – буду править по мере сил и возможностей. Сразу скажу – разработка по времени еще не много обкатывалась, поэтому возможны какие-то недочеты, соответственно, тех, кто будут пользоваться прошу выдавать замечания – будем исследовать что можно будет сделать в разных ситуациях. Для начала хочу сказать, что Microsoft решил «развести» уровни отображения сообщений и поэтому часть сообщений выводится на полоске при форме (в контексте формы), а часть – в верхнем меню системы. И даже об этом целых 2 странички написал в документации https://docs.microsoft.com/en-us/dyn...er-bar-details https://docs.microsoft.com/en-us/dyn...messaging-user Microsoft всем рекомендует использовать функции класса Message со словами, что старые добрые методы info/warning/error «Все еще поддерживаются». Логично – эти методы чуть ли не в каждом объекте, содержащем X++ написаны. Памятуя историю с устареванием RunBase в 2012 и его «возрождением» в D365FO )) – надеюсь, что в ближайшее время метод \Info\add (ну или любой его аналог, как центр сбора сообщений) не исчезнет, метод xSession::xppCallStack (или любой его аналог) тоже пока останется – ну и значит какое-то время мы сможем воспользоваться их интеграцией. Чтобы было понятно - приведу текст класса Message (он небольшой) X++: public static class Message { static int64 Add(MessageSeverity severity, SysInfoLogStr txt) { return infolog.insertMessage(severity, txt); } static int64 Remove(int64 messageId) { return infolog.removeMessage(messageId); } } X++: int64 insertMessage( MessageSeverity severity, str _txt, str label = '') { int actionClassId; container packedAction; Exception exception; switch(severity) { case MessageSeverity::Informational: exception = Exception::Info; break; case MessageSeverity::Warning: exception = Exception::Warning; break; default: exception = Exception::Error; break; } if (!this.shouldAdd(exception)) { return 0; } // Raise the message event if there are consumers and the event capturing is enabled if (enableMinimumLevelInfologRaiseMessageEvent && (exception >= minimumLevelInfologRaiseMessageEvent)) { this.onMessageAdd(exception, _txt); } return super(severity, getprefix()+_txt, this.GetLabelContext(_txt)); } На него можно подписаться и т.о. получить информацию о сообщении. Правда этот делегат был сделан исключительно для запуска тестов и для того, чтобы воспользоваться надо в классе Info включить режим сбора событий (можно посмотреть ссылки на этот метод). Но этот режим влияет исключительно только на возможность подписки на этот делегат (опять-таки- смотрим код), поэтому в целом мы для себя вполне можем его использовать. Соответственно, при реализации стека вызовов в инфологе глобально была применена идея включения режима перехвата событий, перехват событий и запись их с добавлением информации по стеку вызовов (стек вызовов я не очищал от вызова непосредственно перехватчика – лично меня эта строчка не напрягает, а все желающие могут если захотят сами это доделать). Заодно решилась проблема чтения длинных соообщений в инфологе, текст которых в полоске на форме был неудобочитаем (по крайней мере для меня). Соответственно, как работает моя модификация: 1. В параметры пользователя добавлен флажок «Стек вызовов». Включение флажка включает режим логирования сообщений инфолога. Логируется только то, что проходит через \Info\add. Соответственно, бывают ситуации, когда сообщения не залогировались, -но я пока не отловил эти ситуации. Выключение флажка очищает лог текущего пользователя. В роли лога выступает обычная таблица в БД. Пользователи разделяются в ней по полю CreatedBy. 2. При помощи делегата OnMessageAdd сообщения собираются в таблицу лога (Лог чистится только при выключении флажка у пользователя. Я пытался его очищать на событии OnClear у инфолога – пока это не дало результата. Соответственно, если будут какие-нибудь предложения / мысли на эту тему – с интересом ознакомлюсь). 3. Данные таблицы лога отображаются на форме. Форма вызывается с вкладки OPTIONS (ПАРАМЕТРЫ), которая является общей для почти всех форм в D365FO (за исключением диалоговых и может еще каких-нибудь сильно специализированных). При отключенном флажке у пользователя – вызов формы стека вызовов не показывается на этой вкладке (чтобы не смущать пользователей системы), поэтому после включения флажка в параметрах пользователя – нужно открыть какую-нибудь форму с вкладкой ПАРАМЕТРЫ для вызова формы лога стека вызовов. 4. Делегат OnMessageAdd работает только для роли «Системный администратор», поэтому для возможности собрать стек вызовов для пользователя без этой роли я добавил в модификацию специальную роль CallStack, а в коде пришлось временно (в момент включения режима сбора сообщений) обмануть функцию Global::isSystemAdministrator(), заставив временно ее вернуть истину на момент включения режима и «вернуть как было» после момента включения режима. Меточный файл не делал, хватило стандартных существующих меток. Прикладываю .axmodel-файл и .axpp-файл CallStack-VSUH.axmodel CallStack.axpp
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 03.06.2018 в 13:41. |
|
|
За это сообщение автора поблагодарили: skuull (2), raz (10), EVGL (10), AlexSD (4), trud (5), mazzy (10), axotnik88 (1), Logger (15), Jorj (1), gl00mie (10), ice321i (1). |
04.06.2018, 01:49 | #2 |
Microsoft Dynamics
|
У меня есть пара мыслей.
1. Добавить периодическую операцию по очистке старых сообщений. Что бы можно было бы включить постоянный лог для пользователей, под которыми работают интеграции 2. Добавить фильтр по типу сообщений, какие сохранять в лог, какие игнорировать. |
|
|
За это сообщение автора поблагодарили: mazzy (2), sukhanchik (2). |
04.06.2018, 08:04 | #3 |
Участник
|
Добавляйте, мы вам спасибо скажем. И на гитхаб!
|
|
|
За это сообщение автора поблагодарили: sukhanchik (2). |
05.06.2018, 01:40 | #4 |
Microsoft Dynamics
|
Метод SysSystemDefinedButtonsCallStack_Extension.getFormRunExt() может вернуть null, но нигде это не проверяется.
Хотя, я смотрю в SysSystemDefinedButtons... там та же история. Код был оттуда скопирован. Не уделяют должного внимания ревью кода в Microsoft. Видимо, комитменты поменялись. "При Балмере такого не было" |
|
|
За это сообщение автора поблагодарили: sukhanchik (2). |
08.06.2018, 20:13 | #5 |
Administrator
|
Цитата:
Цитата:
Сообщение от AlexSD
Метод SysSystemDefinedButtonsCallStack_Extension.getFormRunExt() может вернуть null, но нигде это не проверяется.
Хотя, я смотрю в SysSystemDefinedButtons... там та же история. Код был оттуда скопирован. Не уделяют должного внимания ревью кода в Microsoft. Видимо, комитменты поменялись. "При Балмере такого не было" В общем - я рад, что идея нашла поддержку в сообществе. Значит - есть потребность ) Спасибо.
__________________
Возможно сделать все. Вопрос времени |
|
24.09.2021, 19:28 | #6 |
Участник
|
С некоторыми изменениями добавил в свой список утилит и выложил на гитхаб
https://denistrunin.com/xpptools-devinfocallstack/
Замечания и предложения приветствуются |
|
|
За это сообщение автора поблагодарили: sukhanchik (6), Logger (1), S.Kuskov (5). |
26.10.2023, 11:53 | #7 |
Участник
|
Денис, заметил одну мелочь.
При использовании try catch retry инфолог ошибок внутри блока try catch удаляется с экрана пользователя. Но при этом попадает в журнал инфолога. Хотелось бы и в журнале не видеть этот инфолог. https://learn.microsoft.com/en-us/dy...try-statements The retry statement erases all messages that have been written to the Infolog since program control entered the try block
__________________
Дмитрий Последний раз редактировалось Damn; 26.10.2023 в 12:07. |
|
26.10.2023, 13:53 | #8 |
Administrator
|
Цитата:
Сообщение от Damn
При использовании try catch retry инфолог ошибок внутри блока try catch удаляется с экрана пользователя. Но при этом попадает в журнал инфолога.
Хотелось бы и в журнале не видеть этот инфолог. https://learn.microsoft.com/en-us/dy...try-statements The retry statement erases all messages that have been written to the Infolog since program control entered the try block Что происходит здесь: 1. Отрабатывает вывод сообщения (info / warning / error) внутри try. 2. При выводе сообщения срабатывает делегат по сохранению этого сообщения вместе со стеком вызовов (xSession::xppCallStack) в БД в специальную табличку. Т.е. классно конечно, что Цитата:
The retry statement erases all messages that have been written to the Infolog since program control entered the try block
В этом механизме нет какой-то завершающей обработки - это по сути условное логирование инфолога. И даже если кто-то удалил из временной таблицы инфолога (tmpInfologTable) какие-то записи - то механизм стека вызовов об этом не узнает. Вешать на условный tmpInfologTable.delete() какой-нибудь триггер по очистке стека вызовов - неправильно, ибо основная суть стека вызовов и состоит в том, что когда уже все сообщения потёрлись - он остался
__________________
Возможно сделать все. Вопрос времени |
|
26.10.2023, 18:03 | #9 |
Участник
|
Примерно в 2010 году в версии 4.0 сделал себе сохранение стека вызовов в табличку БД, чтобы каждый вызов из стека был в отдельной записи, и все они имели общий идентификатор, связывающий их также с инфологом. Также в этой табличке у меня были userid, номер сессии, дата-время и тип инфолога (info / warning / error). Но включал я запись параметром не у пользователя, а в системе в целом - задача была не только отловить источник проблемы, но и понять у каких пользователей и как часто она возникает.
На другие проекты на более высокие версии это не переносил. |
|
27.10.2023, 11:01 | #10 |
Участник
|
Я реализовывал хранение стеков вызовов в реляционном виде для ах2012 и d365 :
https://github.com/d-tolstov/D365-CallStackTable https://github.com/d-tolstov/Ax2012-CallStackTable Позволяет собирать статистику ошибок и в разрезе стека целиком и в разрезе отдельных его строк. Иногда очень выручает. Ну и экономит место при хранении стека вызовов в журнале инфолога например. Вместо контейнера хранится ссылка по RecId.
__________________
Дмитрий |
|
|
За это сообщение автора поблагодарили: sukhanchik (6). |
27.10.2023, 15:16 | #11 |
Участник
|
Стеки вызовов имеют свойство повторяться и занимать много места. Так что можно и на этом сэкономить. Хранить хеш и по нему ссылаться.
|
|
27.10.2023, 15:53 | #12 |
Участник
|
Я практически так и делаю. Только ссылаюсь по RecId (он весит в два раза меньше чем guid). По хешу осуществляю поиск ранее созданного стека вызовов.
__________________
Дмитрий |
|