How to: Add telemetry to your extension

This topic explains how to add structured telemetry signals to a Business Central AL extension using the LS Telemetry framework. The framework is published on AppSource and must be listed as a dependency in your extension's app.json file. Your extension also needs an Application Insights connection string—either configured in the extension's app.json file or set in the environment—for the signals to appear in Azure Application Insights.

In this article

Step 1: Declare the dependency

Step 2: Define your telemetry events

Step 3: Implement the send-event codeunit

Step 4: Add an app-specific trace level (optional)

Step 5: Send telemetry events in your code

Step 6: Use the Trace Logger for performance measurement (optional)

See also

Step 1: Declare the dependency

Add the LS Telemetry framework as a dependency in your extension's app.json file. Contact your LS Retail partner or check AppSource for the current publisher, name, and version values.

You must also add an applicationInsightsConnectionString or an applicationInsightsKey entry to your app.json file so that Business Central routes the signals to your own Application Insights instance.

Note: Without a valid Application Insights connection string in your app's app.json file (or configured in the environment), calls to the telemetry framework will not produce any signals in Application Insights.

Step 2: Define your telemetry events

Create an enum extension that extends the base LSCTM Telemetry Event enum. Each value in your extension represents one telemetry event. Every value must implement the LSCTM ISendEvent interface and point to the codeunit you create in Step 3.

enumextension 50100 "My App Telemetry Event" extends "LSCTM Telemetry Event"
{
    value(50100; "Company Open")
    {
        Caption = 'MyApp - Company open';
        Implementation = "LSCTM ISendEvent" = "My App Send Telemetry";
    }
    value(50101; "Item Sold")
    {
        Caption = 'MyApp - Item sold';
        Implementation = "LSCTM ISendEvent" = "My App Send Telemetry";
    }
}

By convention, captions use the pattern ModuleName - EnumValueID.

Note: Assign object IDs and enum values from your extension's registered object range. Do not use IDs that overlap with other extensions.

Step 3: Implement the send-event codeunit

Create a codeunit that implements the LSCTM ISendEvent interface. This codeunit is the bridge between the framework and your extension's Application Insights connection string. Its SendEvent procedure calls Session.LogMessage, and its ReturnTraceLevel procedure returns the trace level configured for your app.

codeunit 50100 "My App Send Telemetry" implements "LSCTM ISendEvent"
{
    Access = Internal;

    procedure SendEvent(
        EventID: Text; Message: Text;
        CustomDimensions: Dictionary of [Text, Text];
        Verbosity: Verbosity; Scope: TelemetryScope)
    begin
        Session.LogMessage(
            EventID, Message, Verbosity,
            DataClassification::SystemMetadata, Scope, CustomDimensions);
    end;

    procedure ReturnTraceLevel(var OverwriteDefault: Boolean): Enum "LSCTM Telemetry Verbosity"
    var
        TelemetrySetup: Record "LSCTM Telemetry Setup";
    begin
        OverwriteDefault := true;
        if not TelemetrySetup.Get() then
            exit("LSCTM Telemetry Verbosity"::Normal);

        exit(TelemetrySetup."My App Trace Level");
    end;
}

If you do not want to override the default trace level, set OverwriteDefault to false in ReturnTraceLevel. The framework then uses the Default Trace Level from the Telemetry Setup page.

Step 4: Add an app-specific trace level (optional)

To let administrators control the verbosity of your extension's signals independently of other extensions, add a trace-level field to the LSCTM Telemetry Setup table and expose it on the Telemetry Setup page. Use a table extension and a page extension for this purpose.

Table extension example:

tableextension 50100 "My App Telemetry Setup Ext" extends "LSCTM Telemetry Setup"
{
    fields
    {
        field(50100; "My App Trace Level"; Enum "LSCTM Telemetry Verbosity")
        {
            Caption = 'My App Trace Level';
            DataClassification = CustomerContent;
            ToolTip = 'My App Trace Level specifies which trace level is used for
                telemetry events triggered by My App. Telemetry events with a Verbosity
                equal to or above this level will be sent. Events from other extensions
                are controlled by their own trace level or by the Default Trace Level.';
        }
    }
}

Page extension example:

pageextension 50100 "My App Telemetry Setup Ext" extends "LSCTM Telemetry Setup"
{
    layout
    {
        addafter("Default Trace Level")
        {
            field("My App Trace Level"; Rec."My App Trace Level")
            {
                ApplicationArea = All;
            }
        }
    }
}

After you add the field, reference it from the ReturnTraceLevel procedure in your send-event codeunit as shown in Step 3.

Step 5: Send telemetry events in your code

Use the LSCTM Telemetry Msg codeunit to build and send events. The general pattern is:

  1. Call AddHeader to set the module name, event ID, and message text.
  2. Call Add one or more times to attach key-value custom dimensions.
  3. Call SendEvent to send the event at the desired verbosity level.

Simple event example:

var
    Telemetry: Codeunit "LSCTM Telemetry Msg";
begin
    Telemetry.AddHeader('MyApp', "LSCTM Telemetry Event"::"Item Sold", 'Item sold');
    Telemetry.Add('ItemNo', Format(ItemNo));
    Telemetry.Add('Quantity', Format(Quantity));
    Telemetry.SendEvent(Verbosity::Normal);
end;

When you call AddHeader, the module name is automatically added as a custom dimension named ModuleName. The framework also prefixes the event ID with an underscore and the module name to produce a qualified event ID (for example, AL_LSC-MyApp-50101) that is unique across extensions.

To send a sales-context event—for example, at the end of a transaction—use AddSalesHeader to include store, terminal, and receipt information as standard custom dimensions:

Telemetry.AddHeader('MyApp', "LSCTM Telemetry Event"::"Item Sold", 'Item sold');
Telemetry.AddSalesHeader(ReceiptNo, StoreID, TerminalID, TransactionID);
Telemetry.SendEvent(Verbosity::Normal);

Note: The framework automatically redacts values for keys that match a built-in list of personally identifiable fields, including CustomerName, Address, Email, Phone, IBAN, and others. You cannot remove these redactions. If you want to protect additional fields specific to your extension, call the Add(BlockedKeys) overload before adding dimensions.

Step 6: Use the Trace Logger for performance measurement (optional)

When you need to measure how long an operation takes, use the LSCTM Trace Logger codeunit. Call StartTrace before the operation and LogEvent after it. The framework calculates the elapsed time in milliseconds and attaches it as the LapsedTimeMs custom dimension.

var
    TraceLogger: Codeunit "LSCTM Trace Logger";
    CorrelationID: Text;
begin
    CorrelationID := CreateGuid();
    TraceLogger.StartTrace(CorrelationID);

    // ... perform the operation ...

    TraceLogger.LogEvent(
        CorrelationID,
        'MyApp',
        "LSCTM Telemetry Event"::"Item Sold",
        'ITEM-SOLD-001',
        'Sales',
        'Item sold successfully',
        Verbosity::Normal);
end;

If the start and end of an operation span different Business Central sessions—for example, an asynchronous job—call UseIsolatedStorage on the LSCTM Trace Logger codeunit before StartTrace. This stores the start time in Isolated Storage so it is accessible across session boundaries.

Tip: The Trace Logger uses in-memory storage by default, which is appropriate for same-session operations. Isolated Storage is required only when start and end times occur in different sessions.

See also

Telemetry Framework for LS Retail Solutions

Telemetry Setup page

Instrumenting an Application for Telemetry (Microsoft Learn)