diff --git a/content/docs/analyzers/ApplicationCop/AC0034.md b/content/docs/analyzers/ApplicationCop/AC0034.md index 1af9294..a1d41e0 100644 --- a/content/docs/analyzers/ApplicationCop/AC0034.md +++ b/content/docs/analyzers/ApplicationCop/AC0034.md @@ -1,33 +1,37 @@ +++ -title = 'Telemetry requires a Telemetry Logger implementation' +title = 'Register a Telemetry Logger in this app' linkTitle = 'AC0034' [params] id = 'AC0034' - severity = 'Warning' + severity = 'Hidden' category = 'Design' codeAction = false ignoreObsolete = true +++ -`Codeunit Telemetry` and `Codeunit "Feature Telemetry"` do not call `Session.LogMessage` for the calling app. They look up the `"Telemetry Logger"` registered for the calling app's publisher and hand the message to it. A logger is registered by a subscriber to the `OnRegisterTelemetryLogger` event of `Codeunit "Telemetry Loggers"`. +Enable this rule when you want every app to carry its own Telemetry Logger, regardless of which other apps from your publisher are installed. + +`Codeunit Telemetry` and `Codeunit "Feature Telemetry"` do not call `Session.LogMessage` for the calling app. On every call they look up the `"Telemetry Logger"` registered for the calling app's publisher and hand the message to it. A logger is registered by a subscriber to the `OnRegisterTelemetryLogger` event of `Codeunit "Telemetry Loggers"`. The event is raised on every telemetry call, and any installed app from the same publisher can register the logger. It does not have to be a dependency of the calling app. The first registration for a publisher wins. > Every publisher needs to have an implementation of the "Telemetry Logger" interface and a subscriber to "Telemetry Loggers".OnRegisterTelemetryLogger event in one of their apps in order for this codeunit to work as expected — [Codeunit Telemetry](https://learn.microsoft.com/en-us/dynamics365/business-central/application/system-application/codeunit/system.telemetry.telemetry) on Microsoft Learn -When no logger is registered for the publisher, `"Telemetry Loggers Impl."` logs warning `0000G7K` and discards the message. The publisher's Application Insights resource never receives the event: +The logger runs `Session.LogMessage` inside its own app, so the `applicationInsightsConnectionString` of the logger app receives the event. The calling app is visible only in the `CallerAppName` custom dimension. When no logger is registered for the publisher, `"Telemetry Loggers Impl."` logs warning `0000G7K` and discards the message: > An app from publisher %1 is sending telemetry, but there is no registered telemetry logger for this publisher. — `NoPublisherErr` label in [`"Telemetry Loggers Impl."`](https://github.com/microsoft/BCApps/blob/main/src/System%20Application/App/Telemetry/src/Logging/TelemetryLoggersImpl.Codeunit.al) in the System Application -Implement `"Telemetry Logger"` in the app and register it in an `OnRegisterTelemetryLogger` subscriber. +With the rule enabled, each app that uses the telemetry codeunits implements `"Telemetry Logger"` and registers it in an `OnRegisterTelemetryLogger` subscriber, so its telemetry does not depend on a logger in another app. A logger in every app is safe: since BC 25.0 a second registration for the same publisher is ignored without a warning, and no message is dropped. + +BC 25.0 removed the duplicate-logger warning `0000G7J`. Older community posts that quote it describe behaviour before BC 25.0. ### Example {{< highlight al "hl_lines=1" >}} -codeunit 50101 "Sales Order Telemetry" // Telemetry requires a Telemetry Logger implementation [AC0034] +codeunit 50101 "Sales Order Telemetry" // Register a Telemetry Logger in this app [AC0034] { procedure LogOrderReleased() var @@ -60,7 +64,7 @@ codeunit 50111 "App Telemetry Logger" implements "Telemetry Logger" } {{< /highlight >}} -The registration is per publisher, not per app: the System Application expects exactly one `"Telemetry Logger"` implementation registered per app publisher. AC0034 only checks that the app contains an implementation. It does not check that the implementation is registered. +AC0034 only checks that the app contains an implementation. It does not check that the implementation is registered. ### When the diagnostic is reported @@ -73,30 +77,29 @@ The registration is per publisher, not per app: the System Application expects e Test codeunits (`Subtype = Test` or `TestRunner`) and obsolete objects are not reported. -Only codeunits in the app being compiled count as an implementation. Because the logger is registered per publisher, a logger in a dependency app from the same publisher, such as a shared foundation app, serves every app of that publisher, but AC0034 does not see it. Suppress the diagnostic on the object: +### Why the rule is disabled by default + +Microsoft documents one logger per app publisher, and that logger can live in any installed app from the publisher, such as a shared foundation app. Microsoft Learn describes this as "exactly one implementation of the "Telemetry Logger" interface registered per app publisher". The Base Application uses the telemetry codeunits in many files and implements no logger of its own. AC0034 counts only codeunits in the app being compiled, so it does not see a logger in another app and would report every app that relies on a shared one. Leave the rule off in that topology. + +### Enable the rule -{{< highlight al >}} -// The "Telemetry Logger" for this publisher is implemented and registered in the -// foundation app, a dependency from the same publisher: one logger per publisher. -#pragma warning disable AC0034 -codeunit 50101 "Sales Order Telemetry" -#pragma warning restore AC0034 +Add AC0034 to your project's ruleset file. Use `Info` to show it as a suggestion, or `Warning` to make it stand out: + +```json { - procedure LogOrderReleased() - var - FeatureTelemetry: Codeunit "Feature Telemetry"; - begin - FeatureTelemetry.LogUsage('0000ABC', 'Sales Order Release', 'Sales order released'); - end; + "id": "AC0034", + "action": "Warning", + "justification": "Each app carries its own Telemetry Logger" } -{{< /highlight >}} - -For an app that relies on a shared logger throughout, disable the rule in the ruleset instead. +``` [AC0033](../ac0033/) applies the same check to `Codeunit "Rest Client"` and `"Http Client Handler"`. ### See also - [Interface "Telemetry Logger"](https://learn.microsoft.com/en-us/dynamics365/business-central/application/system-application/interface/system.telemetry.telemetry-logger) on Microsoft Learn +- [Feature telemetry](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/telemetry-feature-telemetry) on Microsoft Learn +- [Codeunit "Telemetry Loggers"](https://learn.microsoft.com/en-us/dynamics365/business-central/application/system-application/codeunit/system.telemetry.telemetry-loggers) on Microsoft Learn +- [FeatureTelemetry sample](https://github.com/microsoft/BCTech/tree/master/samples/AppInsights/AL/FeatureTelemetry) in BCTech on GitHub - [Codeunit "Feature Telemetry"](https://learn.microsoft.com/en-us/dynamics365/business-central/application/system-application/codeunit/system.telemetry.feature-telemetry) on Microsoft Learn - [Prefer the Rest Client module over the native HttpClient](https://github.com/ALCops/Analyzers/discussions/405) on GitHub Discussions diff --git a/content/docs/analyzers/ApplicationCop/_index.md b/content/docs/analyzers/ApplicationCop/_index.md index 987851a..0daeeec 100644 --- a/content/docs/analyzers/ApplicationCop/_index.md +++ b/content/docs/analyzers/ApplicationCop/_index.md @@ -43,6 +43,6 @@ ApplicationCop inspects how objects are modeled: tables, fields, pages, enums, l | [AC0031](ac0031/) | Table data access requires explicit object permissions | Info | ✓ | ✓ | | [AC0032](ac0032/) | Unused permission declared | Info | ✓ | ✓ | | [AC0033](ac0033/) | Send Rest Client requests through an Http Client Handler in this app | Info | — | | -| [AC0034](ac0034/) | Telemetry requires a Telemetry Logger implementation | Warning | ✓ | | +| [AC0034](ac0034/) | Register a Telemetry Logger in this app | Info | — | | **Note:** Rules marked with "—" in the Enabled column are disabled by default and must be explicitly enabled in your project's ruleset file.