# Bc Telemetry Generator

> 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…

- **Type:** Skill
- **Install:** `agentstack add skill-fernandoartalf-al-copilot-skills-collection-bc-telemetry-generator`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [fernandoartalf](https://agentstack.voostack.com/s/fernandoartalf)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [fernandoartalf](https://github.com/fernandoartalf)
- **Source:** https://github.com/fernandoartalf/AL-Copilot-Skills-Collection/tree/main/skills/bc-telemetry-generator
- **Website:** https://alcopilotskills.com/

## Install

```sh
agentstack add skill-fernandoartalf-al-copilot-skills-collection-bc-telemetry-generator
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 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](https://alguidelines.dev/docs/agentic-coding/gettingmore/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

```al
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  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

```al
StartTime := CurrentDateTime;
ValidateOrder(SalesHeader);
Duration := CurrentDateTime - StartTime;

BCStelemetry.LogPerformanceWarning(
  'BCS-SALESP001', 'ValidateOrder', Duration, 1000, CustomDimensions);
```

#### Feature Usage

```al
BCStelemetry.LogFeatureUsage(
  'BCS-FEAT001', 'Discounts', 'Line Discount Applied', CustomDimensions);
```

### Step 6: Build and Validate

- Run `al_build` to verify compilation
- Check `@problems` for 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

1. **Don't over-log** — log entry/exit of key operations, not every line
2. **Use consistent event IDs** — prefix + area + sequential number
3. **Include helpful dimensions** — enough to diagnose issues, not everything
4. **Clear dimensions before reuse** — call `Clear(CustomDimensions)` between events
5. **Log at appropriate verbosity** — Normal for info, Warning for degraded paths, Error for failures
6. **Always use TelemetryScope::ExtensionPublisher** — routes to your Application Insights
7. **Keep dimension values short** — Application Insights truncates at ~8 KB per event
8. **Never log PII** — anonymize user IDs, never log passwords or tokens
9. **Add duration to completion events** — essential for performance analysis
10. **Leave telemetry helper body empty for feature usage** — just add dimensions and call helper

## Advanced Patterns

- **Telemetry wrapper codeunit**: See [references/telemetry-reference.md](references/telemetry-reference.md#telemetry-wrapper-pattern)
- **Contextual telemetry** (environment, version): See [references/telemetry-reference.md](references/telemetry-reference.md#contextual-telemetry)
- **KQL queries for Application Insights**: See [references/kql-queries.md](references/kql-queries.md)

## External References

- [alguidelines.dev — Adding Telemetry](https://alguidelines.dev/docs/agentic-coding/gettingmore/telemetry/)
- [Microsoft Docs — Telemetry Codeunit](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-instrument-application-for-telemetry)
- [Microsoft Docs — Custom Telemetry Signals](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/telemetry-custom-signal-trace)
- [Microsoft Docs — Application Insights for Extensions](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-application-insights-for-extensions)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [fernandoartalf](https://github.com/fernandoartalf)
- **Source:** [fernandoartalf/AL-Copilot-Skills-Collection](https://github.com/fernandoartalf/AL-Copilot-Skills-Collection)
- **License:** MIT
- **Homepage:** https://alcopilotskills.com/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-fernandoartalf-al-copilot-skills-collection-bc-telemetry-generator
- Seller: https://agentstack.voostack.com/s/fernandoartalf
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
