AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 03.06.2018, 09:15   #1  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,309 / 3546 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Стек вызовов в инфологе в 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);
    }
}
И метод insertMessage (я пока вырезал закомментаренный код)
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));
    }
Ну т.е. мы видим, что класс Message хоть и обходит в явном виде \Info\add - все равно есть возможность встроиться в делегат OnMessageAdd, который также вызывается и из \Info\add.

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

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

Соответственно, как работает моя модификация:
1. В параметры пользователя добавлен флажок «Стек вызовов». Включение флажка включает режим логирования сообщений инфолога. Логируется только то, что проходит через \Info\add. Соответственно, бывают ситуации, когда сообщения не залогировались, -но я пока не отловил эти ситуации. Выключение флажка очищает лог текущего пользователя. В роли лога выступает обычная таблица в БД. Пользователи разделяются в ней по полю CreatedBy.
2. При помощи делегата OnMessageAdd сообщения собираются в таблицу лога (Лог чистится только при выключении флажка у пользователя. Я пытался его очищать на событии OnClear у инфолога – пока это не дало результата. Соответственно, если будут какие-нибудь предложения / мысли на эту тему – с интересом ознакомлюсь).
3. Данные таблицы лога отображаются на форме. Форма вызывается с вкладки OPTIONS (ПАРАМЕТРЫ), которая является общей для почти всех форм в D365FO (за исключением диалоговых и может еще каких-нибудь сильно специализированных). При отключенном флажке у пользователя – вызов формы стека вызовов не показывается на этой вкладке (чтобы не смущать пользователей системы), поэтому после включения флажка в параметрах пользователя – нужно открыть какую-нибудь форму с вкладкой ПАРАМЕТРЫ для вызова формы лога стека вызовов.
4. Делегат OnMessageAdd работает только для роли «Системный администратор», поэтому для возможности собрать стек вызовов для пользователя без этой роли я добавил в модификацию специальную роль CallStack, а в коде пришлось временно (в момент включения режима сбора сообщений) обмануть функцию Global::isSystemAdministrator(), заставив временно ее вернуть истину на момент включения режима и «вернуть как было» после момента включения режима.
Меточный файл не делал, хватило стандартных существующих меток.
Прикладываю .axmodel-файл и .axpp-файл

Нажмите на изображение для увеличения
Название: SNAG_Program-0058.png
Просмотров: 622
Размер:	32.8 Кб
ID:	11934

Нажмите на изображение для увеличения
Название: SNAG_Program-0054.png
Просмотров: 590
Размер:	44.1 Кб
ID:	11935

Нажмите на изображение для увеличения
Название: SNAG_Program-0056.png
Просмотров: 596
Размер:	47.1 Кб
ID:	11936

Нажмите на изображение для увеличения
Название: SNAG_Program-0057.png
Просмотров: 578
Размер:	63.2 Кб
ID:	11937

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  
AlexSD is offline
AlexSD
Microsoft Dynamics
Сотрудники Microsoft Dynamics
 
257 / 302 (11) ++++++
Регистрация: 14.10.2003
У меня есть пара мыслей.

1. Добавить периодическую операцию по очистке старых сообщений. Что бы можно было бы включить постоянный лог для пользователей, под которыми работают интеграции
2. Добавить фильтр по типу сообщений, какие сохранять в лог, какие игнорировать.
За это сообщение автора поблагодарили: mazzy (2), sukhanchik (2).
Старый 04.06.2018, 08:04   #3  
skuull is offline
skuull
Участник
Most Valuable Professional
Лучший по профессии 2014
 
700 / 752 (27) +++++++
Регистрация: 08.03.2013
Адрес: ХЗ
Цитата:
Сообщение от AlexSD Посмотреть сообщение
У меня есть пара мыслей.

1. Добавить периодическую операцию по очистке старых сообщений. Что бы можно было бы включить постоянный лог для пользователей, под которыми работают интеграции
2. Добавить фильтр по типу сообщений, какие сохранять в лог, какие игнорировать.
Добавляйте, мы вам спасибо скажем. И на гитхаб!
За это сообщение автора поблагодарили: sukhanchik (2).
Старый 05.06.2018, 01:40   #4  
AlexSD is offline
AlexSD
Microsoft Dynamics
Сотрудники Microsoft Dynamics
 
257 / 302 (11) ++++++
Регистрация: 14.10.2003
Метод SysSystemDefinedButtonsCallStack_Extension.getFormRunExt() может вернуть null, но нигде это не проверяется.
Хотя, я смотрю в SysSystemDefinedButtons... там та же история. Код был оттуда скопирован. Не уделяют должного внимания ревью кода в Microsoft. Видимо, комитменты поменялись. "При Балмере такого не было"
За это сообщение автора поблагодарили: sukhanchik (2).
Старый 08.06.2018, 20:13   #5  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,309 / 3546 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от AlexSD Посмотреть сообщение
У меня есть пара мыслей.

1. Добавить периодическую операцию по очистке старых сообщений. Что бы можно было бы включить постоянный лог для пользователей, под которыми работают интеграции
2. Добавить фильтр по типу сообщений, какие сохранять в лог, какие игнорировать.
Спасибо за идеи. Если найду окошко у себя - постараюсь реализовать. Ну или еще кто-то раньше меня сделает.

Цитата:
Сообщение от AlexSD Посмотреть сообщение
Метод SysSystemDefinedButtonsCallStack_Extension.getFormRunExt() может вернуть null, но нигде это не проверяется.
Хотя, я смотрю в SysSystemDefinedButtons... там та же история. Код был оттуда скопирован. Не уделяют должного внимания ревью кода в Microsoft. Видимо, комитменты поменялись. "При Балмере такого не было"
Верно. Код был скопирован без должного рефакторинга. Опять-таки - посмотрю по своей загруженности - получится - подправлю.

В общем - я рад, что идея нашла поддержку в сообществе. Значит - есть потребность )
Спасибо.
__________________
Возможно сделать все. Вопрос времени
Старый 24.09.2021, 19:28   #6  
trud is offline
trud
Участник
Лучший по профессии 2017
 
1,039 / 1630 (57) ++++++++
Регистрация: 07.06.2003
Записей в блоге: 1
С некоторыми изменениями добавил в свой список утилит и выложил на гитхаб
https://denistrunin.com/xpptools-devinfocallstack/
  • Добавил возможность фильтрации сообщений(например только Ошибки)
  • Вызов формы добавил в администрирование, оттуда ее можно например добавить в избранное
  • Добавил кнопку для удаления лога
  • Функцию для включения лога по всем пользователям
sukhanchik большое спасибо за то что поделились.
Замечания и предложения приветствуются
За это сообщение автора поблагодарили: sukhanchik (6), Logger (1), S.Kuskov (5).
Старый 26.10.2023, 11:53   #7  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Денис, заметил одну мелочь.
При использовании 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  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,309 / 3546 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от 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
Я не думаю, что это реально реализовать. Стек вызовов получается через штатную функцию xSession::xppCallStack и выдаётся в форму "как есть" без какого-либо анализа его содержимого.

Что происходит здесь:
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
но ядро об этом никак не информирует о том, какие сообщения были потёрты и в какой момент (т.е. на retry не повесить делегата).
В этом механизме нет какой-то завершающей обработки - это по сути условное логирование инфолога. И даже если кто-то удалил из временной таблицы инфолога (tmpInfologTable) какие-то записи - то механизм стека вызовов об этом не узнает.
Вешать на условный tmpInfologTable.delete() какой-нибудь триггер по очистке стека вызовов - неправильно, ибо основная суть стека вызовов и состоит в том, что когда уже все сообщения потёрлись - он остался
__________________
Возможно сделать все. Вопрос времени
Старый 26.10.2023, 18:03   #9  
ТРЕНЕР is offline
ТРЕНЕР
Участник
Аватар для ТРЕНЕР
 
599 / 50 (3) ++++
Регистрация: 11.06.2003
Адрес: Москва
Примерно в 2010 году в версии 4.0 сделал себе сохранение стека вызовов в табличку БД, чтобы каждый вызов из стека был в отдельной записи, и все они имели общий идентификатор, связывающий их также с инфологом. Также в этой табличке у меня были userid, номер сессии, дата-время и тип инфолога (info / warning / error). Но включал я запись параметром не у пользователя, а в системе в целом - задача была не только отловить источник проблемы, но и понять у каких пользователей и как часто она возникает.
На другие проекты на более высокие версии это не переносил.
Старый 27.10.2023, 11:01   #10  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Я реализовывал хранение стеков вызовов в реляционном виде для ах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  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от Damn Посмотреть сообщение
Позволяет собирать статистику ошибок и в разрезе стека целиком и в разрезе отдельных его строк. Иногда очень выручает. Ну и экономит место при хранении стека вызовов в журнале инфолога например. Вместо контейнера хранится ссылка по RecId.
Стеки вызовов имеют свойство повторяться и занимать много места. Так что можно и на этом сэкономить. Хранить хеш и по нему ссылаться.
Старый 27.10.2023, 15:53   #12  
Damn is offline
Damn
Участник
 
436 / 154 (6) ++++++
Регистрация: 28.05.2003
Адрес: в глуши
Цитата:
Сообщение от Logger Посмотреть сообщение
Хранить хеш и по нему ссылаться.
Я практически так и делаю. Только ссылаюсь по RecId (он весит в два раза меньше чем guid). По хешу осуществляю поиск ранее созданного стека вызовов.
__________________
Дмитрий
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Как программно получить стек вызовов? Bega DAX: Программирование 2 22.12.2010 18:46
aEremenko: Стек вызовов в DAX 2009 Blog bot DAX Blogs 3 08.05.2009 09:38
Как получить стек вызовов без изменения кода? Ilia# DAX: Программирование 2 24.01.2006 11:04
Как получить стек вызовов? bucken DAX: Программирование 6 03.08.2005 15:24
Как получить стек вызовов ? Dmitryus DAX: Программирование 1 26.07.2004 12:20
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 18:52.