Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 67

Application Insights: Custom Instrumentation for .NET

Recommended resources

Welcome back! In our last lesson, we saw how to enable Application Insights for an App Service using the "codeless" autoinstrumentation approach. This gives us a fantastic baseline of telemetry out-of-the-box—requests, dependencies, exceptions, and performance counters.

While this automatic data is essential for understanding operational health, it doesn't tell the whole story. It doesn't know about your specific business logic. This is where you, as a developer, can significantly enrich the monitoring data.

Today's lesson addresses exactly that. We'll move from configuration to coding to instrument a .NET application with custom events, metrics, and telemetry using the Application Insights SDK. You'll learn how to send application-specific data that bridges the gap between system performance and business outcomes. Since this involves working with a .NET SDK and dependency injection, the patterns will be very familiar to you.

1. The Key to Custom Telemetry: TelemetryClient

All custom telemetry in Application Insights is sent via the TelemetryClient class. In a modern ASP.NET Core application, the framework manages the lifecycle of this client for you.

As we touched on in the last lesson, once you've installed the Microsoft.ApplicationInsights.AspNetCore NuGet package and registered the service in Program.cs with builder.Services.AddApplicationInsightsTelemetry(), a singleton instance of TelemetryClient becomes available in the dependency injection container.

You can then inject it into any controller, service, or other class where you need to send custom telemetry.

public class MyController : ControllerBase
{
    private readonly TelemetryClient _telemetryClient;

    // Inject TelemetryClient via the constructor
    public MyController(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient;
    }

    // ... your methods will use _telemetryClient to send data
}

This is the standard and recommended practice. Creating your own instances of TelemetryClient is discouraged as it can lead to incorrect configuration and data loss, especially in short-lived applications like Azure Functions.


2. Tracking Custom Events

The automatically collected data tells you what happened (e.g., a request failed), but custom events tell you why in the context of your business logic. A custom event is a record of a discrete action occurring in your application.

Think of events like:

  • User Signed Up
  • Product Added To Cart
  • Payment Failed
  • Report Generated

These are far more meaningful for understanding user behavior and business flows than a simple HTTP request count.

To get a practical walkthrough of implementing custom events, let's watch a detailed video.

Custom Events and Metrics :: Application Insights (5 of 6)

This video from Kevin Griffin provides an excellent developer-focused guide to custom telemetry in .NET. He starts with the core concepts and then moves into a live coding demonstration.

First, watch the concept of events to understand what custom events are and how TelemetryClient is used. Then, watch the practical demonstration from the live coding demo. Pay close attention to how he first tracks a simple event and then enriches it with a dictionary of custom properties.

As the video demonstrates, you send events using the TrackEvent method. While you can send just the event name, the real power comes from adding context through properties and measurements.

Here’s a concise example, similar to the one in the video, but focused on a common e-commerce scenario.

[HttpPost]
public async Task<IActionResult> PlaceOrder([FromBody] OrderRequest request)
{
    // ... logic to create the order ...

    // Define properties (string values) for context
    var eventProperties = new Dictionary<string, string>
    {
        { "PaymentMethod", request.PaymentMethod },
        { "ShippingRegion", request.ShippingRegion }
    };

    // Define measurements (numeric values) associated with the event
    var eventMetrics = new Dictionary<string, double>
    {
        { "ItemCount", order.Items.Count },
        { "OrderTotal", (double)order.Total }
    };

    // Track the event with its context
    _telemetryClient.TrackEvent("OrderPlaced", eventProperties, eventMetrics);

    return Ok();
}
  • Properties (customDimensions in Application Insights) are string key-value pairs used for filtering and segmenting your data. ShippingRegion is a perfect example.
  • Measurements (customMeasurements in Application Insights) are numeric values associated with the event. They are useful for analysis (e.g., calculating the average OrderTotal for all OrderPlaced events).

A key best practice is to use consistent, PascalCase naming for your events and to avoid high-cardinality values (like User IDs or Order IDs) as property keys or values if you intend to group by them, as this can negatively impact query performance and cost.


3. Tracking Custom Metrics

While events track occurrences, custom metrics track numeric measurements over time. They are optimized for aggregation (sum, average, min, max, count) and are ideal for performance indicators or business KPIs.

Good examples of metrics include:

  • Queue depth
  • Cache hit rate
  • Batch processing time in milliseconds
  • Number of active user sessions

How to Track Custom Events and Metrics in Azure Application Insights

This article from OneUptime provides a very clear and concise distinction between events and metrics.

Read the section "Custom Events vs Custom Metrics" to solidify your understanding of when to use one over the other.

As you'll see in the next video segment, Application Insights supports both single-dimensional and multi-dimensional metrics. A single-dimensional metric is a simple value, like "ProcessingTime." A multi-dimensional metric allows you to slice that value by different attributes, such as "ProcessingTime by BatchType."

Custom Events and Metrics :: Application Insights (5 of 6)

Let's return to Kevin Griffin's video for a deep dive into metrics. He covers both the theory and the implementation.

First, watch the metric concepts section where he explains single vs. multi-dimensional metrics and the importance of pre-aggregation. Next, see a practical example of a single-dimensional metric (AverageDelay). Notice how he aggregates the values over a minute before sending a single point to Application Insights. This is a crucial efficiency pattern. Finally, watch the powerful demonstration of multi-dimensional metrics (ApiHits by State and City). This shows how you can analyze your data from different perspectives in the Azure portal.

The video highlights two key points:

  1. Pre-aggregation is vital: You should not call TrackMetric for every single occurrence in a high-frequency scenario. Instead, collect values over an interval (e.g., one minute), calculate an aggregate (like an average or sum), and send that single data point. The GetMetric(...).TrackValue(...) API helps with this by handling the aggregation for you, making it the preferred method for high-throughput metrics.
  2. Multi-dimensional metrics are powerful: By adding dimensions, you can easily filter and split your metric charts in the Azure portal without writing complex queries. For example, you could track a FileSize metric with a FileType dimension (.jpg, .pdf, .zip).

4. Other Useful Telemetry Types

The Application Insights SDK provides a few other Track* methods for specific scenarios that are good to be aware of.

Custom Events and Metrics :: Application Insights (5 of 6)

The final segment of the video briefly covers other common telemetry types you might need.

Watch the quick overview from other tracking methods.

Here is a quick summary of those methods:

  • TrackException(): Use this inside a catch block to log exceptions that you handle gracefully but still want to record in Application Insights. Unhandled exceptions are logged automatically, but handled ones are not.
  • TrackTrace(): Sends a custom log message, similar to using ILogger. These appear in the traces table in Application Insights and are useful for diagnostic "breadcrumb" style logging.
  • TrackDependency(): While most dependencies (SQL, HTTP calls) are tracked automatically, you might use this to manually time and record calls to a dependency that isn't auto-detected, such as a call to a TCP service or a local file system.

Conclusion

In this lesson, you've learned how to elevate your application monitoring from the generic to the specific. By instrumenting your .NET code with custom telemetry, you can capture the business-critical signals that autoinstrumentation alone cannot provide.

Key Takeaways:

  • Custom telemetry is sent using an instance of TelemetryClient, which should be acquired via dependency injection in ASP.NET Core.
  • TrackEvent is used for discrete business occurrences. Use properties (string dictionaries) and measurements (double dictionaries) to add rich context.
  • TrackMetric is used for numeric values that you want to aggregate and analyze over time. Use the GetMetric().TrackValue() API for efficient pre-aggregation.
  • Metrics can be multi-dimensional, allowing you to easily slice and dice the data in the Azure portal.
  • Methods like TrackException and TrackTrace provide further control for logging handled errors and diagnostic messages.

You now have the tools to generate incredibly rich data about your application's behavior. But generating data is only half the battle. The next step is to analyze it. In our next lesson, we will dive into the Kusto Query Language (KQL) to write queries that filter, aggregate, and visualize the custom events and metrics you've just learned how to create.