Всем добрый день!
На этом форуме уже несколько раз пролетала мысль про добавлении стека вызовов в инфолог (об этом упоминали разные авторы, и даже когда-то я в древности), но до версии 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-файл
CallStack-VSUH.axmodel
CallStack.axpp