15.2 Custom Telemetry Signals with Session.LogMessage & KQL
Key Takeaways
- AL developers emit custom diagnostic telemetry signals using the Session.LogMessage method or the System Application Telemetry codeunit facade.
- The TelemetryScope parameter controls signal routing: TelemetryScope::ExtensionPublisher routes telemetry only to the extension's Application Insights, while TelemetryScope::All routes signals to both the extension and the environment-level Application Insights.
- Logging verbosity is governed by the Verbosity enum with levels: Verbose, Normal, Warning, Error, and Critical.
- To comply with privacy laws (GDPR/HIPAA), custom telemetry must use DataClassification::SystemMetadata; any data classified as CustomerContent or EndUserIdentifiableInformation is automatically masked by the platform before transmission.
- The System Application Feature Telemetry codeunit provides standardized patterns for tracking feature adoption and health through LogUptake, LogUsage, and LogError.
15.2 Custom Telemetry Signals with Session.LogMessage & KQL
While Business Central automatically emits platform-level telemetry for SQL queries and page rendering, enterprise extensions require custom operational telemetry to track business milestones, measure integration throughput, record feature adoption, and diagnose domain-specific validation failures. AL provides native methods and standardized System Application modules for emitting structured custom telemetry signals into Azure Application Insights.
1. Emitting Custom Telemetry: Session.LogMessage
The foundational AL method for emitting custom telemetry is Session.LogMessage(). This method allows developers to send structured event messages, assign diagnostic event IDs, define verbosity levels, set privacy classifications, and attach custom key-value dimensions.
// Syntax Signature for Session.LogMessage with Custom Dimensions Dictionary
Session.LogMessage(
EventId: Text,
Message: Text,
Verbosity: Verbosity,
DataClassification: DataClassification,
TelemetryScope: TelemetryScope,
CustomDimensions: Dictionary of [Text, Text]
);
Core Parameters of Session.LogMessage
EventId(Text): A unique, alphanumeric identifier representing the specific business event (e.g.,'CONT-001-SYNCSUCCESS','CONT-002-PAYMENTFAILED'). Follow a consistent naming convention with an ISV prefix.Message(Text): A concise, human-readable description explaining what occurred during execution.Verbosity(EnumVerbosity): Specifies the diagnostic severity level of the signal.DataClassification(EnumDataClassification): Declares the privacy classification of the telemetry payload. Must be set toDataClassification::SystemMetadatafor unmasked diagnostic transmission.TelemetryScope(EnumTelemetryScope): Controls the routing destination of the telemetry event.CustomDimensions(Dictionary of[Text, Text]): A dynamic map of custom key-value pairs providing structured context (e.g., record counts, response codes, duration, external system IDs).
TelemetryScope Routing Mechanics
The TelemetryScope enum dictates which Azure Application Insights resources receive the signal:
[ Session.LogMessage() ]
│
(TelemetryScope)
│
┌───────────────────────┴───────────────────────┐
▼ ▼
[ TelemetryScope::ExtensionPublisher ] [ TelemetryScope::All ]
│ │
▼ ┌───────┴───────┐
[ Extension App Insights ] ▼ ▼
(Configured in app.json) [ Extension AI ] [ Environment AI ]
(app.json) (BC Admin Center)
TelemetryScope::ExtensionPublisher: The telemetry event is dispatched exclusively to the Application Insights connection string declared in the extension'sapp.json. The customer's tenant administrator cannot see this event in their environment-level Application Insights.TelemetryScope::All: The telemetry event is dispatched to both the extension's Application Insights resource (fromapp.json) and the customer's environment-level Application Insights resource (from the Business Central Admin Center). Use this scope for operational events relevant to tenant administrators (e.g., batch job completion, critical integration failure).
2. The System Application Telemetry & Feature Telemetry Modules
While Session.LogMessage is the low-level runtime API, Microsoft provides high-level telemetry abstractions inside the System Application to standardize logging patterns across extensions.
1. The Telemetry Codeunit Facade
The Telemetry codeunit (Module: Telemetry in System Application) simplifies custom telemetry emission and automatically enriches every logged signal with standard contextual dimensions:
codeunit 50110 "Contoso Carrier Integration"
{
Access = Internal;
procedure ProcessShipmentSync(ShipmentNo: Code[20]; RecordCount: Integer)
var
Telemetry: Codeunit Telemetry;
CustomDimensions: Dictionary of [Text, Text];
begin
CustomDimensions.Add('ShipmentNo', ShipmentNo);
CustomDimensions.Add('TotalRecords', Format(RecordCount));
CustomDimensions.Add('CarrierCode', 'FEDEX');
Telemetry.LogMessage(
'CONT-0010',
'Carrier shipment synchronization completed successfully.',
Verbosity::Normal,
DataClassification::SystemMetadata,
TelemetryScope::All,
CustomDimensions
);
end;
}
2. The Feature Telemetry Codeunit Pattern
To track feature adoption, user onboarding, and feature health across the software lifecycle, Microsoft introduced the Feature Telemetry codeunit. This module standardizes three core telemetry events:
LogUptake: Records when a user discovers, sets up, or enables a feature (FeatureUptakeStatus::Discovered,Set up,Used).LogUsage: Records every time a user or background process actively utilizes the feature.LogError: Records expected or unexpected runtime failures occurring within the feature boundary.
local procedure PostECommerceOrder(OrderNo: Code[20])
var
FeatureTelemetry: Codeunit "Feature Telemetry";
CustomDims: Dictionary of [Text, Text];
FeatureNameLbl: Label 'Automated Shopify Connector', Locked = true;
begin
CustomDims.Add('OrderNo', OrderNo);
// 1. Log feature usage
FeatureTelemetry.LogUsage('0000-SHOP-01', FeatureNameLbl, 'Order Processing Triggered', CustomDims);
// Execute posting logic...
if not ExecuteShopifyPost(OrderNo) then begin
// 2. Log feature error if execution fails
FeatureTelemetry.LogError('0000-SHOP-02', FeatureNameLbl, 'Posting Failed', 'Gateway timeout on capture', '', CustomDims);
Error('Failed to post Shopify order %1.', OrderNo);
end;
end;
3. Verbosity Levels & Diagnostic Hierarchy
The Verbosity enum determines the operational importance of the telemetry signal. Azure Application Insights allows administrators to configure ingestion sampling and log filters based on verbosity levels to manage ingestion costs:
| Verbosity Level | Ingestion Severity | Intended Purpose | Production Recommendation |
|---|---|---|---|
Verbosity::Verbose | 0 | High-frequency diagnostic traces, step-by-step loop executions, and internal variable state dumps. | Emitted during development and troubleshooting; often filtered out in high-volume production. |
Verbosity::Normal | 1 | Informational milestones, successful batch completions, and feature usage occurrences. | Default standard for tracking routine operations and adoption. |
Verbosity::Warning | 2 | Recoverable issues, retry attempts, deprecation notices, and performance threshold warnings. | Always ingested; analyzed for proactive maintenance. |
Verbosity::Error | 3 | Handled functional errors, web service call failures, and validation blocks. | Always ingested; triggers automated partner alert rules. |
Verbosity::Critical | 4 | Fatal system-halting errors, unrecoverable data integrity failures, and core service outages. | Highest priority; triggers immediate on-call incident notifications. |
4. Privacy, Compliance & Data Classification
Under global data privacy regulations—such as the General Data Protection Regulation (GDPR) and the California Consumer Privacy Act (CCPA)—developers are legally prohibited from transmitting Personal Identifiable Information (PII) or sensitive customer transactional records into cloud telemetry logging stores.
The DataClassification Enforcement Pipeline
When AL code invokes Session.LogMessage or Telemetry.LogMessage, the runtime inspects the DataClassification parameter:
DataClassification::SystemMetadata:- Indicates that the message and custom dimensions contain only technical system identifiers, object numbers, execution durations, HTTP status codes, and non-sensitive metadata.
- The runtime transmits the payload to Azure Application Insights unaltered in plain text.
DataClassification::CustomerContent/EndUserIdentifiableInformation:- If a developer marks telemetry with
CustomerContentorEndUserIdentifiableInformation(or if telemetry contains customer-specific fields), Business Central's cloud compliance engine automatically masks the content with hashes or asterisks (***) prior to transmission. - Best Practice Rule: Never attempt to log customer names, email addresses, phone numbers, credit card numbers, or physical street addresses in custom telemetry. Always use
DataClassification::SystemMetadataand sanitize all custom dimension values to include only system codes and numeric metrics.
- If a developer marks telemetry with
5. Querying Custom Telemetry in KQL
Custom telemetry emitted via Session.LogMessage is stored in the traces table. Developers query custom dimensions by casting dynamic JSON properties into typed KQL variables using tostring(), toint(), and toreal().
// Analyze Custom Integration Sync Events
traces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith 'CONT-'
| extend
EventId = tostring(customDimensions.eventId),
CarrierCode = tostring(customDimensions.CarrierCode),
TotalRecords = toint(customDimensions.TotalRecords),
ShipmentNo = tostring(customDimensions.ShipmentNo),
ExecutionScope = tostring(customDimensions.telemetryScope)
| summarize
TotalSyncOperations = count(),
TotalRecordsProcessed = sum(TotalRecords)
by CarrierCode, bin(timestamp, 1d)
| render timechart
A developer emits a custom telemetry message using DataClassification::CustomerContent. What happens to the message and custom dimension values when they are ingested by Azure Application Insights?
Which System Application codeunit provides standardized methods (LogUptake, LogUsage, LogError) to track feature adoption, usage milestones, and errors across the extension lifecycle?
A developer passes a Dictionary of [Text, Text] containing key-value pairs (e.g., CustomDimensions.Add("SyncDurationMs", "1450")) into Session.LogMessage. How should the developer extract and convert "SyncDurationMs" to a numeric value in a Kusto Query Language (KQL) query?
An AL developer uses Session.LogMessage to emit telemetry when an external warehouse synchronization batch completes. The partner wants this telemetry event to be visible both in their own extension's Application Insights and in the customer's environment-level Application Insights. Which TelemetryScope enum value must be specified?