For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Sign inTry it free
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
  • Tutorials
    • The AI Iteration Loop for Deploying Reliable Agents with LangGraph
    • Using LaunchDarkly feature flags and Experimentation with Wordpress
    • Migrate a Hardcoded LangGraph Agent to LaunchDarkly AgentControl in 20 Minutes
    • Offline Evaluation of RAG-Grounded Answers in AgentControl
    • Beyond n8n for Workflow Automation: Agent Graphs as Your Universal Agent Harness
    • Catch your first silent AI failure with Vega AI in under 10 minutes
    • Evaluate LLM code generation with LLM-as-judge evaluators
    • OpenTelemetry for LLM Applications: A Practical Guide with LaunchDarkly and Langfuse
    • Use LaunchDarkly Agent Skills in Claude Code and Cursor
    • Detection to Resolution: Real World Debugging with Rage Clicks and Session Replay
    • Compare AI orchestrators: LangGraph vs Strands vs OpenAI Swarm
    • Building a data extraction pipeline with LaunchDarkly
    • Day 12 | 🎊 New Year, New Observability
    • Day 11 | ✉️ Letters to Santa: What engineering teams really want from Observability in 2026
    • Day 10 | Why observability and feature flags go together like milk and cookies
    • Day 9 | 👻 The Three Ghosts Haunting Your AI This Holiday Season
    • Day 7 | 🎄✨The Rockefeller tree in NYC: SLOs that actually drive decisions
    • Day 6 | 💸 The famous green character that stole your cloud budget: the cardinality problem
    • Day 5 | 🧹 Using a Popular Tidying Method to Consolidate Your Observability Stack
    • Day 4 | ❄️ Tracing the impact of holiday styling in your Node.js app
    • Day 8 | 🎁 Observable Multi-Modal Agentic Systems
    • Day 3 | 🔔 Jingle All the Way to Zero-Config Observability
    • Day 2 | 🎅 He knows if you have been bad or good... But what if he gets it wrong?
    • Collecting user feedback in your app with feature flags
    • Day 1 | 🎄 Observability Under the Tree: What Changed in 2025
    • Build a User Frustration Detection & Response System
    • When to Add Online Evals to Your AgentControl
    • Detecting User Frustration: Understanding Rage Clicks and Session Replay
    • AgentControl config CI/CD Pipeline: Automated Quality Gates and Safe Deployment
    • A Deeper Look at LaunchDarkly Architecture: More than Feature Flags
    • Add Observability to Your React Native App in 5 minutes
    • Smart AI Agent Targeting with MCP Tools
    • Build a LangGraph Multi-Agent System in 20 Minutes with LaunchDarkly AgentControl
    • Snowflake Cortex Completion API + LaunchDarkly SDK Integration
    • Using AgentControl to review database changes
    • How to implement WebSockets and kill switches in a Python application
    • 4 hacks to turbocharge your Cursor productivity
    • Create a feature flag in your IDE in 5 minutes with LaunchDarkly's MCP server
    • Observability for Your Go ORM: OpenTelemetry Integration with GORM
    • The complete guide to OpenTelemetry in Next.js
    • How to instrument your React Native app with OpenTelemetry
    • The complete guide to OpenTelemetry in Python
    • Monitoring Browser Applications with OpenTelemetry
    • How to Use OpenTelemetry to Monitor Next.js Applications
    • What is OpenTelemetry and Why Should I Care?
    • Distributed Tracing in Next.js Apps
    • Tracing Distributed Systems in Next.js
    • Real-time Monitoring in Django: Essential Tools and Techniques
    • DeepSeek vs Qwen: local model showdown featuring LaunchDarkly AgentControl
    • Application Tracing in .NET for Performance Monitoring
    • The Ultimate Guide to Ruby Logging: Best Libraries and Practices
    • Using Materialized Views in ClickHouse (vs. Postgres)
    • Filtering and Sampling LaunchDarkly Ingest
    • How to Set Up Your Production AWS MSK Kafka Cluster
    • Publishing an NPM Package with Private pnpm Monorepo Dependencies
    • How To Use The Chrome Inspector & Debugger
    • 3 Levels of Data Validation in a Full Stack Application With React
    • The power of the monorepo: Keep your fullstack app in sync!
    • Compression: The simple, powerful upgrade for your web stack
    • Video tutorials
Sign inTry it free
LogoLogo
On this page
  • Introduction
  • The Role of Tracing in .NET Applications
  • Utilizing Built-in .NET Tracing Capabilities
  • Advanced Tracing with DiagnosticSource in .NET Core
  • Leveraging Third-Party Tools for Tracing
  • Application Insights for Comprehensive Telemetry
  • LaunchDarkly for Open Source Telemetry via OpenTelemetry
  • NLog for Flexible and Structured Logging
  • Conclusion
Tutorials

Application Tracing in .NET for Performance Monitoring

Was this page helpful?
Previous

The Ultimate Guide to Ruby Logging: Best Libraries and Practices

Next
Built with

Published February 10, 2024

portrait of Vadim Korolik.

by Vadim Korolik

Introduction

Application tracing is a critical aspect of software development and maintenance, especially in complex .NET environments. It involves monitoring and recording application activities, providing insights into application behavior and performance. This guide will delve into the essential tools and techniques for effective application tracing in .NET, ensuring that developers and administrators can efficiently troubleshoot and optimize their applications.

The Role of Tracing in .NET Applications

In .NET, application tracing provides a window into the running state of applications, helping identify bottlenecks, errors, and performance issues. It’s not only about finding problems; tracing also offers valuable data for optimizing and refining application functionality.

Utilizing Built-in .NET Tracing Capabilities

.NET Framework and .NET Core offer built-in tracing capabilities that are robust and easy to implement. Let’s explore a basic example of how to implement tracing in a .NET application:

1using System.Diagnostics;
2
3Trace.Listeners.Add(new TextWriterTraceListener("logfile.log"));
4Trace.AutoFlush = true;
5Trace.WriteLine("Starting application tracing");
6
7// Your application logic here
8
9Trace.WriteLine("Ending application tracing");

This code snippet demonstrates how to set up a simple trace listener that writes trace output to a file. This is fundamental for any .NET application requiring basic logging and tracing capabilities.

Advanced Tracing with DiagnosticSource in .NET Core

For more advanced scenarios, especially in .NET Core, System.Diagnostics.DiagnosticSource provides a powerful way to collect rich telemetry data. Here’s an example:

1using System.Diagnostics;
2
3var source = new DiagnosticListener("MyApplicationSource");
4
5if (source.IsEnabled("StartRequest"))
6{
7 source.Write("StartRequest", new { RequestId = Guid.NewGuid(), Timestamp = DateTime.UtcNow });
8}
9
10// Application logic here
11
12if (source.IsEnabled("EndRequest"))
13{
14 source.Write("EndRequest", new { RequestId = Guid.NewGuid(), Timestamp = DateTime.UtcNow });
15}

This code creates a DiagnosticListener that emits custom events, making it a versatile tool for complex tracing requirements.

Leveraging Third-Party Tools for Tracing

Application Insights for Comprehensive Telemetry

Application Insights, a feature of Azure Monitor, is an extensible Application Performance Management (APM) service for developers. It can be easily integrated into .NET applications:

1using Microsoft.ApplicationInsights;
2using Microsoft.ApplicationInsights.Extensibility;
3
4var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
5telemetryConfiguration.InstrumentationKey = "your_instrumentation_key_here";
6var telemetryClient = new TelemetryClient(telemetryConfiguration);
7
8telemetryClient.TrackTrace("Application trace message");

This snippet shows how to send trace messages to Application Insights, which provides analytics and actionable insights on application performance and usage.

LaunchDarkly for Open Source Telemetry via OpenTelemetry

Setting up OpenTelemetry tracing for a .NET application involves a few key steps. OpenTelemetry is a set of APIs, libraries, agents, and instrumentation that allow you to create and manage telemetry data (metrics, logs, and traces) for your applications. Here’s how you can set up tracing in a .NET application:

  1. Install Necessary NuGet Packages

First, you need to add the OpenTelemetry packages to your project. You can do this via the NuGet package manager. The primary package you’ll need is OpenTelemetry. Depending on the specific needs of your application, you may also need exporters (like Zipkin, Jaeger, etc.) and instrumentation for specific libraries.

$# Copy code
$dotnet add package OpenTelemetry
$dotnet add package OpenTelemetry.Exporter.Console
$dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
$dotnet add package OpenTelemetry.Instrumentation.AspNetCore
  1. Configure Services in Startup.cs

In the Startup.cs file of your .NET application, you need to configure the OpenTelemetry services. This includes setting up the tracing pipeline with any necessary exporters and instrumentations.

Here is an example code block for setting up a basic OpenTelemetry tracing with a console exporter and ASP.NET Core instrumentation:

1using OpenTelemetry.Trace;
2
3public class Startup
4{
5public void ConfigureServices(IServiceCollection services)
6{
7// Other service configurations ...
8
9 // Configure OpenTelemetry Tracing
10 services.AddOpenTelemetryTracing(builder =>
11 {
12 builder
13 .AddAspNetCoreInstrumentation()
14 .AddConsoleExporter(); // Using console exporter for demonstration
15 });
16 }
17
18 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
19 {
20 // Existing configuration code...
21
22 // Ensure to use the appropriate middleware if needed
23 app.UseOpenTelemetry();
24 }
25}
  1. Instrumenting Your Code

To create custom traces or to add additional information to the automatic traces, you can use the OpenTelemetry API in your application code:

1using System.Diagnostics;
2using OpenTelemetry.Trace;
3
4public class MyService
5{
6private static readonly ActivitySource ActivitySource = new ActivitySource("highlight-dot-net-example");
7
8 public void DoWork()
9 {
10 using (var activity = ActivitySource.StartActivity("DoingWork"))
11 {
12 // Your logic here
13 // You can add custom tags or events to 'activity' as needed
14 }
15 }
16}

The configuration and code above set up a basic tracing pipeline for a .NET application. This will set up a console exporter to debug traces to the console log, but you can change to an OTLP exporter to send traces to a remote collector.

  1. Update the code block to send traces to highlight
1using System.Diagnostics;
2using OpenTelemetry;
3using OpenTelemetry.Exporter;
4using OpenTelemetry.Logs;
5using OpenTelemetry.Metrics;
6using OpenTelemetry.Resources;
7using OpenTelemetry.Trace;
8using Serilog.Context;
9using Serilog.Core;
10using Serilog.Events;
11using Serilog.Sinks.OpenTelemetry;
12
13namespace dotnet;
14
15public class HighlightTraceProcessor : BaseProcessor<Activity>
16{
17 public override void OnStart(Activity data)
18 {
19 var ctx = HighlightConfig.GetHighlightContext();
20 foreach (var entry in ctx)
21 {
22 data.SetTag(entry.Key, entry.Value);
23 }
24
25 base.OnStart(data);
26 }
27}
28
29public class HighlightLogProcessor : BaseProcessor<LogRecord>
30{
31 public override void OnStart(LogRecord data)
32 {
33 var ctx = HighlightConfig.GetHighlightContext();
34 var attributes = ctx.Select(entry => new KeyValuePair<string, object?>(entry.Key, entry.Value)).ToList();
35 if (data.Attributes != null)
36 {
37 attributes = attributes.Concat(data.Attributes).ToList();
38 }
39
40 data.Attributes = attributes;
41 base.OnStart(data);
42 }
43}
44
45public class HighlightLogEnricher : ILogEventEnricher
46{
47 public void Enrich(LogEvent logEvent, ILogEventPropertyFactory pf)
48 {
49 var ctx = HighlightConfig.GetHighlightContext();
50 foreach (var entry in ctx)
51 {
52 logEvent.AddOrUpdateProperty(pf.CreateProperty(entry.Key, entry.Value));
53 }
54 }
55}
56
57public class HighlightConfig
58{
59 // Replace with the highlight endpoint. For highlight.io cloud, use https://otel.highlight.io:4318
60 public static readonly String OtlpEndpoint = "https://otel.highlight.io:4318";
61
62 // Replace with your project ID and service name.
63 public static readonly String ProjectId = "<YOUR_PROJECT_ID>";
64 // This must match the ServiceName used by the ActivitySource to ensure traces are sent.
65 public static readonly String ServiceName = "highlight-dot-net-example";
66
67 public static readonly String TracesEndpoint = OtlpEndpoint + "/v1/traces";
68 public static readonly String LogsEndpoint = OtlpEndpoint + "/v1/logs";
69 public static readonly String MetricsEndpoint = OtlpEndpoint + "/v1/metrics";
70
71 public static readonly OtlpProtocol Protocol = OtlpProtocol.HttpProtobuf;
72 public static readonly OtlpExportProtocol ExportProtocol = OtlpExportProtocol.HttpProtobuf;
73 public static readonly String HighlightHeader = "x-highlight-request";
74
75 public static readonly Dictionary<string, object> ResourceAttributes = new()
76 {
77 ["highlight.project_id"] = ProjectId,
78 ["service.name"] = ServiceName,
79 };
80
81 public static Dictionary<string, string> GetHighlightContext()
82 {
83 var ctx = new Dictionary<string, string>
84 {
85 { "highlight.project_id", ProjectId },
86 };
87
88 var headerValue = Baggage.GetBaggage(HighlightHeader);
89 if (headerValue == null) return ctx;
90
91 var parts = headerValue.Split("/");
92 if (parts.Length < 2) return ctx;
93
94 ctx["highlight.session_id"] = parts[0];
95 ctx["highlight.trace_id"] = parts[1];
96 return ctx;
97 }
98
99 public static void EnrichWithHttpRequest(Activity activity, HttpRequest httpRequest)
100 {
101 var headerValues = httpRequest.Headers[HighlightHeader];
102 if (headerValues.Count < 1) return;
103 var headerValue = headerValues[0];
104 if (headerValue == null) return;
105 var parts = headerValue.Split("/");
106 if (parts?.Length < 2) return;
107 activity.SetTag("highlight.session_id", parts?[0]);
108 activity.SetTag("highlight.trace_id", parts?[1]);
109 Baggage.SetBaggage(new KeyValuePair<string, string>[]
110 {
111 new(HighlightHeader, headerValue)
112 });
113 }
114
115 public static void Configure(WebApplicationBuilder builder)
116 {
117 builder.Logging.AddOpenTelemetry(options =>
118 {
119 options
120 .SetResourceBuilder(ResourceBuilder.CreateDefault().AddAttributes(ResourceAttributes))
121 .AddProcessor(new HighlightLogProcessor())
122 .AddOtlpExporter(exporterOptions =>
123 {
124 exporterOptions.Endpoint = new Uri(LogsEndpoint);
125 exporterOptions.Protocol = ExportProtocol;
126 });
127 });
128
129 builder.Services.AddOpenTelemetry()
130 .ConfigureResource(resource => resource.AddAttributes(ResourceAttributes))
131 .WithTracing(tracing => tracing
132 .AddSource(ServiceName)
133 .AddProcessor(new HighlightTraceProcessor())
134 .AddAspNetCoreInstrumentation(options =>
135 {
136 options.RecordException = true;
137 options.EnrichWithHttpRequest = EnrichWithHttpRequest;
138 })
139 .AddOtlpExporter(options =>
140 {
141 options.Endpoint = new Uri(TracesEndpoint);
142 options.Protocol = ExportProtocol;
143 }))
144 .WithMetrics(metrics => metrics
145 .AddMeter(ServiceName)
146 .AddAspNetCoreInstrumentation()
147 .AddOtlpExporter(options =>
148 {
149 options.Endpoint = new Uri(MetricsEndpoint);
150 options.Protocol = ExportProtocol;
151 }));
152 }
153}

Get started today with our OpenTelemetry instrumentation for .NET that gives you flexibility with your data destination.

NLog for Flexible and Structured Logging

NLog is a versatile logging tool for .NET, allowing for structured logging, which is crucial in modern application tracing. Here’s a basic setup:

1var config = new NLog.Config.LoggingConfiguration();
2var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "file.txt" };
3var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
4
5config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
6config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);
7
8NLog.LogManager.Configuration = config;

This configuration sets up NLog to log messages to both a file and the console, providing a flexible approach to logging.

Conclusion

Effective tracing in .NET applications is key to understanding and improving application behavior and performance. This guide has introduced various tools and techniques, from basic built-in .NET tracing to advanced tools like Application Insights and NLog. By choosing the right combination of these tools, developers can gain valuable insights and maintain robust, high-performance applications.

Explore these tracing techniques in your .NET projects. Share your experiences and insights in the comments below. For more in-depth information, check out our additional resources.