Debugging in AL used to be a disaster for me
I've always been annoyed by how AL (Application Language) is structured, and how the event based system makes it horrible to debug and trace your program. However, even tho the underlying system has some undeniable flaws, our gods from above (Microsoft) have done everything they could to make the best of it, giving us access to an entire toolkit of debugging methods, some of which, you might not be aware of.
Breakpoints
I'm sure everyone and their grandma has heard about breakpoints, and uses them all the time in their day to day AL programming routine. Its a tool in visual studio code that lets you set a red dot on a specific line, forcing the BC server to stop execution of the code, and letting you inspect the surrounding context.
In the debug panel (at the left side of visual studio code), you can also inspect global and local variables.
Depending on your preferences, you also might find it annoying that the debugger breaks on errors and/or on changes to records. To enable/disable this behavior, you can alter your launching profile found in .vscode/launch.json
.
{
"configurations": [
{
"breakOnError": true,
"breakOnRecordWrite": true
}
]
}
Event recorder
One of the biggest question I always had while debugging with breakpoints was: "what caused SomeFunctionA to be called?". In the case of normal procedures, the answer can quickly be found with a simple project scoped ctrl + f on the query SomeFunctionA\(
However in the case of events (which is common, since AL is an event based programming language). The answer to this question is often much more difficult to answer. What events are called when? and to what should I subscribe? what is the order of events being called?
However, recently I found a very nice way to debug this: the build in 'event record'. This is a tool that is used within the business central web application, and can be opened by searching for the Event Recorder
page. When you open it, you will be presented by something like this:
When you click Record Events > Start
, BC will start keeping track of any custom, or trigger event, that is being activated. make sure to not close the event recorder page, instead open new pages, by searching for them using the search glass, else the recording will be canceled.
You can then perform all your actions that you want to inspect, and then click Record Events > Stop
, to stop the recording and display the list of activated custom/trigger events.
Most of the time this will result in hundreds, if not thousands of entries, however just like any BC table, you can filter it on any property.
This gives you a nice overview of what events are triggered, however, what if you wanted to subscribe a function to one of the events that you found using the event debugger? You could very easily scroll to the right of the event recorder table, until you find the Get AL Snippet
column, where you can click a link to give you automatically generated code.
This is often a huge timesaver since you dont need to dig trough documentation to find the event's arguments.
Callstack
This one is a bit more known then the BC event recorder, but still deserves much love. It is a tool within the VSCode AL debugger, just like the local/global variable inspector. It appears when you are stuck on a breakpoint and looks like this:
As you might notice when trying this out, the top row contains the name of the function you are currently in, with the file and location of the function displayed on the right of that same row.
But what if you wanted to know from what location the current function was called? maybe its only called in some condition, or maybe its called from some binding to an event.
The most intuitive way to figure this out is by spamming breakpoints on all places that calls the current function, however there is a much more efficient way:
The callstack can be used for this exact purpose, see from what function, the current function has been called. In the image above, you can see that the current function named Code
was called from the function PostSplitJnlLine
which was in turn called from RunWithCheck
. You can also double click these rows to directly jump to that function call.
Watches
Another debugging scenario, is when you want to keep track of the value of a variable when stepping trough breakpoints. Maybe you have an integer value named MyNumber
that incremented in different locations within the code, and you want to know how MyNumber ends up being a certain value.
Instead of having to scroll back down to the variable section of the codeunit, to hover over the variable to inspect it, you could try adding it to the Watch
list in the debugger. Whenever you add a variable here, it will show it along sides its value during your debugging session.
This way it will always be visible on your screen and you dont need to spam your code with Message(Format(MyNumber));
Good luck debugging
This is the end of the article, I hope i taught you at least one helpful way of debugging that you didn't know was possible, Maybe I've even helped you prevent hours of debugging.
Make use of these functionalities as much as you can, and have fun debugging your code!
Top comments (0)