Dynamics NAV/BC – Events Stack Logging

This post shows you how I created a logging system to know when, from where and by whom an event was called.

The following solution can be used in Dynamics NAV 2017 or later because it uses TryFunctions and the GETLASTERRORCALLSTACK command.

(In Dynamics NAV 2016 TryFunction is available but I’m not sure if GETLASTERRORCALLSTACK is).

I’ve created a new table with the following structure to keep the logging information:

Table Key: Stack Entry No.,Line No.

To populate this table I’ve created a new codeunit. I could/should have two codeunits (one with the subscribers and the other one with the logging functionality) but this is just for demo purposes.

The codeunit has three methods plus as many subscribers as you want to log:

InsertStackLogging() -> To add a new stack logging record to the logging table;

[TryFunction] ErrorTryFunction() -> Local. A TryFunction to raise an error that will be used to get the error call stack. It is inside a try so it won’t stop the running transaction;

SplitLine() -> Local. Used by the InsertStackLogging to split the result from the GETLASTERRORCALLSTACK command in more that one stack field;

Then you may have as many subscribers as you want to log. You only need to have a single line in the subscriber method:

InsertStackLogging;

For testing purposes I’ve subscribed the OnBeforeInsertEvent in SalesShipmentHeader and I’ve posted a sales order ship.

Here’s the output:

Please let me know if you have any doubts.

Below the objects:

OBJECT Table 50000 Stack Logging
{
OBJECT-PROPERTIES
{
Date=13/05/19;
Time=17:57:12;
Modified=Yes;
Version List=RPM;
}
PROPERTIES
{
}
FIELDS
{
{ 1 ; ;Stack Entry No. ;Integer ;DataClassification=ToBeClassified }
{ 2 ; ;User ID ;Code50 ;TableRelation=User."User Name";
OnLookup=VAR
[email protected] : Codeunit 418;
BEGIN
UserMgt.LookupUserID("User ID");
END;

TestTableRelation=No;
DataClassification=EndUserIdentifiableInformation;
CaptionML=ENU=User ID }
{ 3 ; ;Stack 1 ;Text250 ;DataClassification=ToBeClassified }
{ 4 ; ;Stack 2 ;Text250 ;DataClassification=ToBeClassified }
{ 5 ; ;Stack 3 ;Text250 ;DataClassification=ToBeClassified }
{ 6 ; ;Stack 4 ;Text250 ;DataClassification=ToBeClassified }
{ 7 ; ;Log Date ;Date ;DataClassification=ToBeClassified }
{ 8 ; ;Log Time ;Time ;DataClassification=ToBeClassified }
{ 9 ; ;Line No. ;Integer ;DataClassification=ToBeClassified }
}
KEYS
{
{ ;Stack Entry No.,Line No. ;Clustered=Yes }
}
FIELDGROUPS
{
}
CODE
{

BEGIN
END.
}
}

 

OBJECT Codeunit 50000 Logging Codeunit
{
OBJECT-PROPERTIES
{
Date=13/05/19;
Time=17:57:19;
Modified=Yes;
Version List=RPM;
}
PROPERTIES
{
OnRun=BEGIN
END;
}
CODE
{
LOCAL PROCEDURE [email protected]();
VAR
[email protected] : Record 50000;
[email protected] : Text;
[email protected] : Text[1024];
[email protected] : Integer;
[email protected] : Integer;
BEGIN
CLEARLASTERROR;
IF NOT ErrorTryFunction THEN BEGIN

WITH StackLogging DO BEGIN
RESET;
NextStackEntryNo := 1;
IF FINDLAST THEN
NextStackEntryNo := "Stack Entry No." + 1;
END;

NextLineNo := 10000;

LastCallStack := GETLASTERRORCALLSTACK;

REPEAT

SplittedStack := SplitLine(LastCallStack,'\');

WITH StackLogging DO BEGIN
INIT;
"Stack Entry No." := NextStackEntryNo;
"Line No." := NextLineNo;
NextLineNo += 10000;

"Stack 1" := COPYSTR(SplittedStack,1,250);
"Stack 2" := COPYSTR(SplittedStack,251,250);
"Stack 3" := COPYSTR(SplittedStack,501,250);
"Stack 4" := COPYSTR(SplittedStack,751,250);

"User ID" := USERID;
"Log Date" := TODAY;
"Log Time" := TIME;
INSERT;
END;
UNTIL LastCallStack = '';
END;
END;

[TryFunction]
LOCAL PROCEDURE [email protected]();
BEGIN
ERROR('');
END;

LOCAL PROCEDURE [email protected](VAR [email protected] : Text[1024];[email protected] : Text[1]) Token : Text[1024];
VAR
[email protected] : Integer;
BEGIN
Pos := STRPOS(Text,Separator);
IF Pos > 0 THEN BEGIN
Token := COPYSTR(Text,1,Pos-1);
IF Pos+1 <= STRLEN(Text) THEN
Text := COPYSTR(Text,Pos+1)
ELSE
Text := '';
END ELSE BEGIN
Token := Text;
Text := '';
END;
END;

LOCAL PROCEDURE "-- Subscribers"@5();
BEGIN
END;

[EventSubscriber(Table,110,OnBeforeInsertEvent)]
LOCAL PROCEDURE [email protected](VAR [email protected] : Record 110;[email protected] : Boolean);
BEGIN
InsertStackLogging;
END;

BEGIN
END.
}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.