Profiler and Snapshot Debugging in Business Central 2021 Wave 2 (v19)

In this video, I take a look at the new profiler in BC version 19. It’s part of the snapshot debugger, so this is almost a quick primer into snapshot debugging.

https://youtu.be/6rIqnxVi0YY

In this video, Erik walks through two powerful diagnostic features available in Business Central 2021 Wave 2 (version 19): Snapshot Debugging and the Profiler. He demonstrates how to set up and use snapshot debugging to record and replay code execution on a production environment, and then shows how to generate a profiler output from the recorded snapshot. Along the way, he clears up some common misconceptions from the official documentation and shares practical tips for getting better results.

Clarifying the Documentation

Before diving into the demo, Erik addresses an important point about the official documentation. Microsoft’s docs state that snapshot debugging is for delegated admins. However, Erik demonstrates that he is not a delegated admin — he’s a regular super user on his own tenant without a CSP partner. And it works just fine.

The documentation also refers to the required permission as a “permission group,” but it’s actually a permission set: D365 SNAPSHOT DEBUG. Any user involved in snapshot debugging needs to have this permission set assigned to them.

What Is Snapshot Debugging?

Snapshot debugging is a two-step operation:

  1. Record — You record the execution of code on a production environment. This is significant because you normally cannot attach a debugger to production. During recording, the code runs normally without interruption — nothing breaks or pauses.
  2. Replay — After the recording is complete, you go back into VS Code and replay the recorded session offline. You can step through the code, inspect variables, and examine the call stack.

This distinction is crucial: you are not debugging live. You are capturing a snapshot and then analyzing it after the fact.

Understanding Snap Points

When recording, you control what data gets captured through breakpoints in VS Code. During a snapshot session, these breakpoints become snap points. At each snap point, the full state — stack trace, variable values, etc. — is recorded.

If you don’t set any breakpoints, only the sequence of executed code lines is recorded. To actually inspect variable values and the call stack during replay, you must place breakpoints at the locations you care about before initiating the recording.

The Demo Extension

For this demo, Erik created a simple page extension on the Customer List with an action called “Heavy Stuff” that loops through customers, their ledger entries, and detailed ledger entries — three nested loops spread across separate procedures:

pageextension 50111 "Heavy Code" extends "Customer List"
{
    actions
    {
        addfirst(processing)
        {
            action(Test)
            {
                Caption = 'Heavy Stuff';
                ApplicationArea = all;
                PromotedIsBig = true;
                Promoted = true;
                PromotedCategory = Process;
                PromotedOnly = true;
                trigger OnAction()
                var
                    Cust: Record Customer;
                begin
                    if Cust.FindSet() then
                        repeat
                            Heavy2(Cust);
                        until Cust.Next() = 0;
                end;
            }
        }
    }

    local procedure Heavy2(var Cust: Record Customer)
    var
        Ledger: Record "Cust. Ledger Entry";
    begin
        Ledger.Setrange("Customer No.", Cust."No.");
        if Ledger.findset() then
            repeat
                Heavy3(Ledger);
            until Ledger.Next() = 0;
    end;

    local procedure Heavy3(var Ledger: Record "Cust. Ledger Entry")
    var
        Dtl: Record "Detailed Cust. Ledg. Entry";
        X: Decimal;
    begin
        Dtl.Setrange("Entry No.", Ledger."Entry No.");
        if Dtl.findset() then
            repeat
                x += Dtl."Amount (LCY)";
            until Dtl.Next() = 0;
    end;
}

This provides a realistic scenario with nested procedure calls and measurable execution time — perfect for both snapshot debugging and profiling.

Setting Up the launch.json

To configure snapshot debugging, you add a configuration to your launch.json file. In VS Code, use Add Configuration and select the option to initialize a snapshot debugging session on the cloud. Key settings include:

  • environmentName — set to your production environment
  • tenant — your tenant ID
  • breakOnNext — set to "WebClient" (this means “initiate on the next web client session,” not literally “break”)
  • executionContext — set to "DebugAndProfile" to capture both snapshot and profiler data

Step-by-Step: Recording a Snapshot

  1. Set your breakpoints in VS Code at the locations where you want full variable/stack information captured.
  2. Run “Initialize Snapshot Debugging” from the VS Code command palette. The debug console will confirm the request succeeded.
  3. In the browser, reload the web client. You’ll see a message that a snapshot debugging session has started.
  4. Perform the scenario — navigate to the Customer List, click “Heavy Stuff,” and let it complete.
  5. Back in VS Code, run “Finish Snapshot Debugging” and select the active session. The snapshot ZIP file is downloaded.

Erik notes an important practical consideration: coordination is required. The snapshot captures the next web client session, so if you have 200 users on production, someone else might inadvertently trigger the recording. You need to coordinate with the user who will perform the scenario.

Replaying the Snapshot

Once the snapshot is downloaded, you can replay it entirely offline — you are no longer connected to the server. In the VS Code status bar, click the snapshot indicator and select which recording to replay.

The debugger starts up and stops at your snap points:

  • The first snap point hit was OnOpenPage on Page 22 (Customer List), where variable information is visible.
  • Stepping away from a snap point (e.g., into CRM Integration Management) means you can see which code executed, but variable information is no longer available.
  • Pressing F5 (Continue) jumps to the next snap point — in this case, inside the “Heavy Stuff” action, where variables and the call stack are fully visible again.
  • After the last snap point, execution ends. You can replay the same snapshot as many times as you like.

The Profiler

The profiler is essentially an add-on to the snapshot debugger. To generate a profile, use the “Generate Profile File” command from the command palette and select your recording.

The profiler output shows:

  • Which functions were called
  • How many times each was called
  • How much time was spent in each function (total and self-time)

In Erik’s demo, the profiler showed:

  • OnAction was called once, with a total of ~929 milliseconds
  • Heavy2 was called once per customer
  • Heavy3 was called for each ledger entry, consuming ~794 milliseconds
  • Heavy2 showed ~899 milliseconds total, but only ~105 milliseconds of “self time” — the rest was spent in Heavy3, which makes sense given the nesting

Dealing with Noise in the Profiler

One challenge Erik highlights is that if you record from the moment the web client loads, the profiler captures everything — including the Role Center initialization, headline rendering, and other system code. This creates a lot of noise that makes it harder to find what you care about.

Erik’s preferred approach: instead of loading the full web client, navigate directly to the page you want to profile by specifying it in the URL (e.g., ?page=22). This eliminates the Role Center noise and gives you a much cleaner profiler output focused on the scenario you’re investigating.

Profiler Accuracy Caveats

Erik notes that the profiler timing numbers don’t always add up perfectly. He’s seen profile outputs where the timings are accurate down to the decimal, and others where the numbers are inconsistent. As of version 19, this feature is still quite new, and some rough edges remain.

Practical Tips and Gotchas

  • Authentication timeouts — If you get strange authentication errors when initializing a snapshot session, try restarting VS Code. The authentication token may have expired in a way the tooling doesn’t handle gracefully.
  • Session management — You can have multiple snapshot files. The status bar shows how many sessions exist (initialized, downloaded, etc.). Keep track of which is which.
  • Finicky behavior — Snapshot debugging can sometimes be unreliable. Sessions may fail to initialize, or the web client may not pick up the session. Erik candidly notes that “sometimes it works and sometimes it doesn’t.”

Bonus: What’s Inside the Snapshot ZIP File?

Erik peeks inside the downloaded snapshot ZIP file and finds:

  • Source code files — AL source for all code units, pages, and other objects that were touched during the recording.
  • Binary frame files (with .mdc extensions) — These represent individual “frames” of the recording. Think of the snapshot as a movie: each frame captures what happened at a particular moment during execution. These files are in a binary format that Erik hasn’t reverse-engineered.

Summary

Snapshot debugging and the profiler in Business Central v19 are valuable tools for diagnosing issues on production environments where traditional debugging isn’t possible. The key takeaways:

  • Snapshot debugging is a two-phase process: record, then replay offline.
  • You don’t need to be a delegated admin — a regular user with the D365 SNAPSHOT DEBUG permission set can use it.
  • Place breakpoints (snap points) where you need full variable inspection during replay.
  • The profiler is generated from the same snapshot recording and shows execution times and call counts.
  • Navigate directly to the target page to reduce noise in the profiler output.
  • The tooling is still maturing — expect some inconsistencies in timing numbers and occasional session management quirks.