bc-telemetry-generator
Skill28 starsChanged 7 months agoMITView on GitHub
Instruments Business Central AL codeunits with Application Insights telemetry using the System Application Telemetry codeunit. Analyzes an existing codeunit supplied by the user, generates a dedicated Feature Usage Telemetry codeunit (or extends an existing one) with helper procedures for LogStart/LogEnd with automatic duration, LogError with call stack, LogFeatureUsage, and LogPerformanceWarning. Adds Telemetry.LogMessage calls with consistent event IDs (PREFIX-NNN), meaningful custom dimensions (Dictionary of [Text, Text]), proper Verbosity levels (Normal, Warning, Error, Critical), correct DataClassification (SystemMetadata, CustomerContent, EndUserIdentifiableInformation), and TelemetryScope::ExtensionPublisher. Covers five telemetry categories — lifecycle events (started/completed), error tracking (validation/posting failures), performance monitoring (slow operation warnings with threshold comparison), feature usage analytics (discount types, payment methods, order size distribution), and contextual telemetry (environment, version, anonymized user). Generates KQL queries for Application Insights analysis. Use when adding telemetry to codeunits, instrumenting AL code with Application Insights, tracking feature usage, monitoring performance, logging errors with custom dimensions, creating telemetry helper codeunits, or implementing observability for BC extensions.
In this repository38 other files it gives its agents.
- bc-agent-instructions-debuggerSkill
- bc-al-bug-fixSkill
- bc-al-code-reviewerSkill
- bc-al-project-contextSkill
- bc-api-page-generatorSkill
- bc-api-query-generatorSkill
- bc-approval-workflow-generatorSkill
- bc-attachments-generatorSkill
- skill-batch-processingSkill
- bc-business-events-generatorSkill
- bc-cds-page-generatorSkill
- bc-dataverse-entity-generatorSkill
- bc-dataverse-mapping-generatorSkill
- bc-field-propagationSkill
- bc-install-codeunit-generatorSkill
- bc-isolated-storage-generatorSkill
- bc-job-queueSkill
- bc-manifest-handoff-generatorSkill
- bc-matrix-page-generatorSkill
- bc-number-series-generatorSkill
- bc-pricing-refactorSkill
- bc-report-selection-generatorSkill
- bc-reportsSkill
- bc-setup-table-generatorSkill
- bc-setup-wizard-generatorSkill
- bc-table-dimensions-generatorSkill
- bc-test-codeunit-generatorSkill
- bc-upgrade-codeunit-generatorSkill
- documentation-bc-analysis-generatorSkill
- documentation-bc-architecture-generatorSkill
- documentation-bc-ccn-generatorSkill
- documentation-bc-md-to-docx-converterSkill
- documentation-bc-phase-plan-generatorSkill
- documentation-bc-release-note-generatorSkill
- documentation-bc-technical-spec-generatorSkill
- documentation-bc-user-story-generatorSkill
- onprem-remote-deploySkill
- skill-contribution-assistantSkill
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 7 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Ask the user which codeunit to instrument.
- Distinctive: line 48
Check if a telemetry helper already exists in the workspace.
- Very specific: line 144
Use CustomerContent classification label for business data (order no, customer no, amounts)
- Very specific: line 145
Use SystemMetadata for technical data (duration, counts, operation names)
- Very specific: line 146
Use EndUserIdentifiableInformation for user references — anonymize when possible
- Distinctive: line 147
Never log passwords, API keys, credit card numbers, or PII
- Distinctive: line 148
Keep dimension count under 15 per event for readability
- Distinctive: line 152
Add telemetry calls to the target codeunit using the helper:
- Very specific: line 219
Run al_build to verify compilation
- Very specific: line 220
Check @problems for errors
- Distinctive: line 221
Verify no sensitive data is logged
- Distinctive: line 233
Keep the AREA tag short (4-8 chars)
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
BC Telemetry Generator
Instruments Business Central AL codeunits with Application Insights telemetry. Analyzes a target codeunit, creates or extends a dedicated telemetry helper codeunit, and adds Telemetry.LogMessage calls following Microsoft best practices.
Reference: alguidelines.dev — Adding Telemetry
Prerequisites
- Target codeunit to instrument (user provides the codeunit)
- Available object ID for telemetry helper codeunit
- Extension prefix established (e.g., BCS)
- Application Insights configured in extension (or environment)
Workflow
Step 1: Read the Target Codeunit
Ask the user which codeunit to instrument. Read the file and identify:
- Public procedures — entry points needing start/end tracking
- Validation procedures — needing warning-level telemetry on failure
- Error-prone operations — posting, external calls, database writes
- Performance-sensitive paths — loops, bulk operations, external HTTP calls
- Feature decision points — discount type selection, payment method, routing logic
Step 2: Plan Telemetry Strategy
For each identified procedure, determine:
| Category | Verbosity | When to Log |
| Lifecycle (start/end) | Normal | Entry points, key milestones |
| Error | Error | Catch blocks, posting failures, validation errors |
| Warning | Warning | Validation failures, degraded paths |
| Performance | Warning | Operations exceeding threshold |
| Feature usage | Normal | Business decisions, option selections |
Event ID scheme: [PREFIX]-[AREA][NNN] for info, [PREFIX]-[AREA]E[NNN] for errors, [PREFIX]-[AREA]W[NNN] for warnings, [PREFIX]-[AREA]P[NNN] for performance.
Example: BCS-SALES001, BCS-SALESE001, BCS-SALESW001, BCS-SALESP001
Step 3: Create or Extend Telemetry Helper Codeunit
Check if a telemetry helper already exists in the workspace. If so, add new procedures to it. If not, create one.
File location: Same feature folder as the target codeunit, or Codeunit/ folder.
Naming: [Prefix] [Feature] Telemetry (e.g., BCS Sales Telemetry)
Telemetry Helper Structure
codeunit [ID] "[Prefix] [Feature] Telemetry"
{
Access = Internal;
SingleInstance = true;
var
Telemetry: Codeunit Telemetry;
procedure LogOperationStarted(EventId: Text; Message: Text; CustomDimensions: Dictionary of [Text, Text])
begin
Telemetry.LogMessage(
EventId, Message,
Verbosity::Normal, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
procedure LogOperationCompleted(EventId: Text; Message: Text; StartTime: DateTime; CustomDimensions: Dictionary of [Text, Text])
var
DurationMs: Duration;
begin
DurationMs := CurrentDateTime - StartTime;
CustomDimensions.Set('DurationMs', Format(DurationMs));
Telemetry.LogMessage(
EventId, Message,
Verbosity::Normal, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
procedure LogError(EventId: Text; Message: Text; CustomDimensions: Dictionary of [Text, Text])
begin
CustomDimensions.Set('ErrorMessage', GetLastErrorText());
CustomDimensions.Set('ErrorCallStack', GetLastErrorCallStack());
Telemetry.LogMessage(
EventId, Message,
Verbosity::Error, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
procedure LogWarning(EventId: Text; Message: Text; CustomDimensions: Dictionary of [Text, Text])
begin
Telemetry.LogMessage(
EventId, Message,
Verbosity::Warning, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
procedure LogFeatureUsage(EventId: Text; FeatureArea: Text; FeatureAction: Text; CustomDimensions: Dictionary of [Text, Text])
begin
CustomDimensions.Set('FeatureArea', FeatureArea);
CustomDimensions.Set('FeatureAction', FeatureAction);
Telemetry.LogMessage(
EventId, FeatureArea + ' - ' + FeatureAction,
Verbosity::Normal, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
procedure LogPerformanceWarning(EventId: Text; OperationName: Text; DurationMs: Duration; ThresholdMs: Integer; CustomDimensions: Dictionary of [Text, Text])
begin
if DurationMs <= ThresholdMs then
exit;
CustomDimensions.Set('Operation', OperationName);
CustomDimensions.Set('DurationMs', Format(DurationMs));
CustomDimensions.Set('ThresholdMs', Format(ThresholdMs));
Telemetry.LogMessage(
EventId,
StrSubstNo('Slow operation detected: %1 (%2 ms, threshold %3 ms)', OperationName, DurationMs, ThresholdMs),
Verbosity::Warning, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, CustomDimensions);
end;
}Step 4: Add Dimension Builder Procedures
For each entity involved, create a dimension builder that collects standard fields:
local procedure AddOrderDimensions(var Dims: Dictionary of [Text, Text]; SalesHeader: Record "Sales Header")
begin
Dims.Add('OrderNo', SalesHeader."No.");
Dims.Add('CustomerNo', SalesHeader."Sell-to Customer No.");
Dims.Add('DocumentType', Format(SalesHeader."Document Type"));
end;Rules for custom dimensions:
- Use
CustomerContentclassification label for business data (order no, customer no, amounts) - Use
SystemMetadatafor technical data (duration, counts, operation names) - Use
EndUserIdentifiableInformationfor user references — anonymize when possible - Never log passwords, API keys, credit card numbers, or PII
- Keep dimension count under 15 per event for readability
Step 5: Instrument the Target Codeunit
Add telemetry calls to the target codeunit using the helper:
Lifecycle Events (Start/End)
procedure ProcessOrder(var SalesHeader: Record "Sales Header"): Boolean
var
BCStelemetry: Codeunit "BCS Sales Telemetry";
CustomDimensions: Dictionary of [Text, Text];
StartTime: DateTime;
begin
StartTime := CurrentDateTime;
AddOrderDimensions(CustomDimensions, SalesHeader);
BCStelemetry.LogOperationStarted('BCS-SALES001', 'Order processing started', CustomDimensions);
// ... existing logic ...
Clear(CustomDimensions);
AddOrderDimensions(CustomDimensions, SalesHeader);
BCStelemetry.LogOperationCompleted('BCS-SALES002', 'Order processing completed', StartTime, CustomDimensions);
exit(true);
end;Error Tracking
if not PostOrder(SalesHeader) then begin
Clear(CustomDimensions);
AddOrderDimensions(CustomDimensions, SalesHeader);
BCStelemetry.LogError('BCS-SALESE001', 'Order posting failed', CustomDimensions);
exit(false);
end;Validation Warnings
if Customer.Blocked <> Customer.Blocked::" " then begin
Clear(CustomDimensions);
CustomDimensions.Add('CustomerNo', SalesHeader."Sell-to Customer No.");
CustomDimensions.Add('BlockedReason', Format(Customer.Blocked));
BCStelemetry.LogWarning('BCS-SALESW001', 'Order validation failed: Customer blocked', CustomDimensions);
Error('Customer %1 is blocked.', Customer."No.");
end;Performance Monitoring
StartTime := CurrentDateTime;
ValidateOrder(SalesHeader);
Duration := CurrentDateTime - StartTime;
BCStelemetry.LogPerformanceWarning(
'BCS-SALESP001', 'ValidateOrder', Duration, 1000, CustomDimensions);Feature Usage
BCStelemetry.LogFeatureUsage(
'BCS-FEAT001', 'Discounts', 'Line Discount Applied', CustomDimensions);Step 6: Build and Validate
- Run
al_buildto verify compilation - Check
@problemsfor errors - Verify no sensitive data is logged
Event ID Convention
| Pattern | Meaning | Example |
PREFIX-AREA### | Informational | BCS-SALES001 |
PREFIX-AREAE### | Error | BCS-SALESE001 |
PREFIX-AREAW### | Warning | BCS-SALESW001 |
PREFIX-AREAP### | Performance | BCS-SALESP001 |
PREFIX-FEAT### | Feature usage | BCS-FEAT001 |
- Keep the AREA tag short (4-8 chars)
- Number sequentially within a category
- Maintain an event ID registry comment at the top of the telemetry codeunit
DataClassification Rules
| Data Type | Classification | Examples |
| Technical metrics | SystemMetadata | Duration, counts, operation name |
| Business identifiers | CustomerContent | Order No., Customer No., amounts |
| User references | EndUserIdentifiableInformation | User ID (anonymize!) |
| Sensitive data | NEVER LOG | Passwords, API keys, credit cards |
Best Practices
- Don't over-log — log entry/exit of key operations, not every line
- Use consistent event IDs — prefix + area + sequential number
- Include helpful dimensions — enough to diagnose issues, not everything
- Clear dimensions before reuse — call
Clear(CustomDimensions)between events - Log at appropriate verbosity — Normal for info, Warning for degraded paths, Error for failures
- Always use TelemetryScope::ExtensionPublisher — routes to your Application Insights
- Keep dimension values short — Application Insights truncates at ~8 KB per event
- Never log PII — anonymize user IDs, never log passwords or tokens
- Add duration to completion events — essential for performance analysis
- Leave telemetry helper body empty for feature usage — just add dimensions and call helper
Advanced Patterns
- Telemetry wrapper codeunit: See references/telemetry-reference.md
- Contextual telemetry (environment, version): See references/telemetry-reference.md
- KQL queries for Application Insights: See references/kql-queries.md
External References
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

