Site icon DAXRunBase

Add call stack to InfoLog messages

The main communication channel for our ERP users in case we want to tell them something is via the InfoLog messages within Microsoft Dynamics AX. In case we get an error or a warning, the technical staff does not receive the details required to troubleshoot the issue much easier. In this post I would like to show you how to send the X++ or .Net CIL call stack to InfoLog messages.
Microsoft already has an article on this for AX 2009, but that was before the AX 2012 IL code execution for server-side code, so it needs slight adjustments.

https://blogs.msdn.microsoft.com/axsupport/2010/08/02/how-to-send-the-callstack-to-the-infolog/

My changes got the following improvements:

Here is the example output:

The changes are for \Classes\Info\add() method.

Exception add(
    Exception _exception,
    str _txt,
    str _helpUrl = '',
    Object _sysInfoAction = null,
    boolean buildprefix = true)
{
    int numOfLines,i;
    int actionClassId;
    container packedAction;
    xSession session;
    System.Diagnostics.StackTrace   myStackTrace;
    System.Exception                ex;
    container                       xppCallStack    = conNull();
    str                             stackTxt        = '';
    int                             stackCnt        = 1;
    SysSQLSystemInfo                systemInfo;
    UserInfo                        userInfo;
    ;
 
    select firstOnly userInfo
        where userInfo.id   == curUserId();
 
    if (userInfo
        && (subStr(userInfo.networkAlias, 1, 3) != 'sa.'
            || userInfo.networkAlias == 'specificUserId')
        && userInfo.accountType != UserAccountType::ClaimsUser)
    {
        switch (_exception)
        {
            case Exception::Warning :
            case Exception::Error :
            case Exception::CLRError :
            case Exception::DDEerror :
            case Exception::Deadlock :
            case Exception::DuplicateKeyException :
            case Exception::DuplicateKeyExceptionNotRecovered :
            case Exception::UpdateConflict :
            case Exception::UpdateConflictNotRecovered :
                if (xSession::isCLRSession())
                {
                    try
                    {
                        myStackTrace    = new System.Diagnostics.StackTrace(true);
                        stackTxt        = myStackTrace.ToString();
                    }
                    catch
                    {
                        ex = ClrInterop::getLastException();
                        if (ex != null)
                        {
                            ex = ex.get_InnerException();
                            if (ex != null)
                            {
                                stackTxt    = ex.ToString();
                            }
                       }
                    }
                }
                else
                {
                    xppCallStack    = xSession::xppCallStack();
                    while (conPeek(xppCallStack, stackCnt))
                    {
                        stackTxt    += strFmt('\n%1 %2', conPeek(xppCallStack, stackCnt), conPeek(xppCallStack, stackCnt+1));
                        stackCnt++;
                        stackCnt++;
                    }
                }
 
                systemInfo =  SysSQLSystemInfo::construct();
 
                _txt = strLen(_txt) < 255 ? strLFix(_txt, 255, ' ') : _txt;
                _txt = _txt + strFmtLB(strFmt(@'\n(%1|%2|%3)%4',
                    systemInfo.getLoginServer(),
                    systemInfo.getloginDatabase(),
                    curUserId(),
                    stackTxt
                    ));
                break;
        }
    }
    switch (logLevel)
    {

The source code is also available on the DAXRunBase GitHub.

Exit mobile version