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)
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:
- Call AddHeader to set the module name, event ID, and message text.
- Call Add one or more times to attach key-value custom dimensions.
- 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
Instrumenting an Application for Telemetry (Microsoft Learn)