Implementing Non-Intrusive Telemetry Capture

Explore the implementation of non-intrusive telemetry capture in .NET.

We'll cover the following

Many years ago, many did not consider implementing baseline telemetry without the overhead of adding custom code. With the advent of platforms such as New Relic, Dynatrace, Datadog, and Application Insights, simply adding a library reference to our project and configuring connection information can enable a good amount of service and component-level telemetry without further configuration. Even with a small amount of configuration and coding, these platforms can capture and expose metrics, logs, and traces.

Custom telemetry options

Options exist beyond those platforms to capture telemetry as well. A question that we might find ourselves asking is, “Why would we want to implement this instead of using Application Insights?” On the one hand, we might want to gather this information and feed it to a platform tool within our Kubernetes cluster. We might also want more detailed control over what exactly is captured to avoid issues with bloated storage accounts or other storage media. There might be certain custom metrics that are easier to implement directly in .NET as opposed to implementing them using an Application Performance Management (APM) system’s SDK and then working additionally to format that information within the APM platform itself. Having options for implementing telemetry and reporting on it can be beneficial depending on our use case.

Features within .NET and .NET Core allow us to leverage built-in means of measuring the items we really want. To get started, we’ll look at three libraries that can add some additional value to component and service telemetry. One is the System.Diagnostics.DiagnosticSource library in .NET 7, and the other two are the OpenTelemetry meter SDKs for Prometheus and Jaeger. The OpenTelemetry framework, endorsed by the Cloud Native Computing Foundation (CNCF), is an open standard for producing and capturing values that can then be exported to reporting systems for further analysis or alerting. The SDKs for Jaeger and Prometheus demonstrate an extensibility that allows developers to integrate them with common Kubernetes platform components.

Within the System.Diagnostics.DiagnosticSource library, several object types can capture information. For our example, we’ll focus on two significant object types:

  • Meter: This class allows us to build out a collection of different counters that can be exposed using one of the meter SDKs listed previously.

  • Counter<T>: This class allows us to create a counter object, which captures information of a templatized type for aggregation and reporting. The type constraint for the template parameter is that it must be a non-nullable value type.

Meter objects have a factory method, which can create a variety of different counters. The standard syntax for creating a Meter object and an associated counter would look like the following:

Get hands-on with 1200+ tech skills courses.