diff --git a/BASE/README.md b/BASE/README.md index d5a82a4acc..0e5dc20b0b 100644 --- a/BASE/README.md +++ b/BASE/README.md @@ -4,38 +4,7 @@ [![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights/) # Application Insights for .NET - Core SDK - -This repository contains the core .NET SDK for Application Insights. [Application Insights][AILandingPage] is a service that monitors the availability, performance, and usage of your applications. The `Microsoft.ApplicationInsights` package provides the foundational `TelemetryClient` API for sending telemetry from any .NET application. - -> **For platform-specific scenarios:** If you're building an ASP.NET Core application, see the [ASP.NET Core SDK documentation](../NETCORE/Readme.md). For Worker Services, background tasks, or console applications, see the [Worker Service SDK documentation](../NETCORE/WorkerService.md). These packages provide automatic telemetry collection and simplified configuration. - -## What's New in Version 3.x - -Version 3.x represents a major architectural shift in the Application Insights SDK: - -- **Built on OpenTelemetry**: The SDK now uses [OpenTelemetry](https://opentelemetry.io/) as the underlying telemetry collection framework with the [Azure Monitor Exporter](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter) for transmission. -- **TelemetryClient as Shim**: The familiar `TelemetryClient` API is preserved as a compatibility layer that translates calls into OpenTelemetry primitives (Activity, ActivityEvent, LogRecord). -- **OpenTelemetry Extensibility**: You can extend telemetry collection using standard OpenTelemetry patterns (Activity Processors, Resource Detectors, custom instrumentation). -- **Unified Observability**: Seamlessly integrates with the broader OpenTelemetry ecosystem, allowing you to send telemetry to multiple backends. - -**Breaking Changes from 2.x:** -- `ITelemetryInitializer` and `ITelemetryProcessor` are deprecated in favor of OpenTelemetry's Activity Processors and Log Processors -- Configuration model has changed to use OpenTelemetry's builder pattern -- Some context properties are now populated differently through OpenTelemetry Resource Detectors - -See the [Migration Guide](#migrating-from-2x-to-3x) for detailed upgrade instructions. - -## Quick Start: Choose Your Path - -Select the option that best describes your situation: - -- **📦 Building an ASP.NET Core web application?** → Use the [ASP.NET Core SDK](../NETCORE/Readme.md) for automatic instrumentation -- **⚙️ Building a Worker Service, console app, or background service?** → Use the [Worker Service SDK](../NETCORE/WorkerService.md) for simplified configuration -- **🔧 Need the core TelemetryClient API for custom scenarios?** → Continue reading this document -- **🔄 Migrating from Application Insights 2.x?** → Jump to the [Migration Guide](#migrating-from-2x-to-3x) -- **🎓 Want to understand how it works under the hood?** → Start with [OpenTelemetry Integration](#opentelemetry-integration) - ---- + The `Microsoft.ApplicationInsights` package provides the foundational `TelemetryClient` API for sending telemetry from any .NET application to ApplicationInsights. ## Table of Contents @@ -44,10 +13,6 @@ Select the option that best describes your situation: - [Installation](#installation) - [Get a Connection String](#get-a-connection-string) - [Basic Configuration](#basic-configuration) -- [OpenTelemetry Integration](#opentelemetry-integration) - - [Architecture Overview](#architecture-overview) - - [Accessing OpenTelemetry APIs](#accessing-opentelemetry-apis) - - [Custom Instrumentation](#custom-instrumentation) - [Using TelemetryClient](#using-telemetryclient) - [Tracking Events](#tracking-events) - [Tracking Metrics](#tracking-metrics) @@ -59,20 +24,8 @@ Select the option that best describes your situation: - [Tracking Page Views](#tracking-page-views) - [Configuration](#configuration) - [TelemetryConfiguration](#telemetryconfiguration) -- [Setting Context Properties](#setting-context-properties) + - [Setting Context Properties](#setting-context-properties) - [Dependency Injection](#dependency-injection) -- [Advanced Scenarios](#advanced-scenarios) - - [Enriching Telemetry with Activity Processors](#enriching-telemetry-with-activity-processors) - - [Filtering Telemetry](#filtering-telemetry) - - [Custom Resource Attributes](#custom-resource-attributes) - - [Sampling](#sampling) -- [Migrating from 2.x to 3.x](#migrating-from-2x-to-3x) - - [Configuration Changes](#configuration-changes) - - [Replacing ITelemetryInitializer](#replacing-itelemetryinitializer) - - [Replacing ITelemetryProcessor](#replacing-itelemetryprocessor) -- [Troubleshooting](#troubleshooting) -- [SDK Layering](#sdk-layering) -- [Contributing](#contributing) ## Getting Started @@ -103,7 +56,7 @@ To use the Application Insights SDK, you need a **Connection String** from your 2. In the "Overview" section, copy the Connection String 3. The Connection String format is: `InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://...` -For more details, see [how to obtain a connection string][AIKey]. +For more details, see [how to obtain a connection string](https://learn.microsoft.com/en-us/azure/azure-monitor/app/create-workspace-resource?tabs=portal#get-the-connection-string). ### Basic Configuration @@ -115,10 +68,8 @@ Initialize `TelemetryConfiguration` and `TelemetryClient` in your application: using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.Extensibility; -var configuration = new TelemetryConfiguration -{ - ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://..." -}; +var configuration = TelemetryConfiguration.CreateDefault(); +configuration.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://..."; var telemetryClient = new TelemetryClient(configuration); @@ -126,42 +77,6 @@ var telemetryClient = new TelemetryClient(configuration); telemetryClient.TrackEvent("ApplicationStarted"); ``` -#### Configuration with Dependency Injection - -For applications using dependency injection (console apps, worker services): - -```csharp -using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -var host = Host.CreateDefaultBuilder(args) - .ConfigureServices((context, services) => - { - services.AddSingleton(sp => - { - var config = new TelemetryConfiguration - { - ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000;..." - }; - return config; - }); - - services.AddSingleton(sp => - { - var config = sp.GetRequiredService(); - return new TelemetryClient(config); - }); - }) - .Build(); - -var telemetryClient = host.Services.GetRequiredService(); -telemetryClient.TrackEvent("ApplicationStarted"); - -await host.RunAsync(); -``` - #### Ensure Telemetry is Sent Telemetry is batched and sent asynchronously by the OpenTelemetry SDK. When your application exits, call `Flush()` to ensure all telemetry is transmitted: @@ -171,197 +86,11 @@ telemetryClient.Flush(); ``` -## OpenTelemetry Integration - -Before diving into the `TelemetryClient` API, it's important to understand the architecture of Application Insights 3.x. This SDK is built on **OpenTelemetry**, an industry-standard observability framework. Understanding this foundation will help you make better decisions about when to use `TelemetryClient` versus native OpenTelemetry APIs. - -### Architecture Overview - -Application Insights 3.x is built on OpenTelemetry: - -``` -┌─────────────────────────────────────────────────────────┐ -│ Your Application Code │ -├─────────────────────────────────────────────────────────┤ -│ TelemetryClient API (Compatibility Layer) │ -│ ↓ Translates to OpenTelemetry primitives │ -├─────────────────────────────────────────────────────────┤ -│ OpenTelemetry SDK │ -│ • Activity (Traces/Spans) │ -│ • LogRecord (Logs) │ -│ • Metrics │ -├─────────────────────────────────────────────────────────┤ -│ Activity Processors / Log Processors │ -│ • Enrichment │ -│ • Filtering │ -│ • Sampling │ -├─────────────────────────────────────────────────────────┤ -│ Azure Monitor Exporter │ -│ ↓ Converts to Application Insights schema │ -├─────────────────────────────────────────────────────────┤ -│ Azure Monitor / Application Insights │ -└─────────────────────────────────────────────────────────┘ -``` - -**Key Mappings:** -- `TrackEvent()` → `LogRecord` with custom event marker -- `TrackDependency()` → `Activity` with `ActivityKind.Client` (outbound calls to external services) -- `TrackRequest()` → `Activity` with `ActivityKind.Server` (inbound requests) -- `TrackException()` → `LogRecord` with exception -- `TrackTrace()` → `LogRecord` -- `TrackMetric()` → OpenTelemetry Histogram - -**When using OpenTelemetry Activity directly, choose the appropriate ActivityKind:** -- `ActivityKind.Client` - Outbound synchronous calls (HTTP requests, database queries, cache calls) -- `ActivityKind.Server` - Inbound synchronous requests (API endpoints, RPC handlers) -- `ActivityKind.Producer` - Outbound asynchronous messages (publishing to queue/topic) -- `ActivityKind.Consumer` - Inbound asynchronous messages (consuming from queue/topic) -- `ActivityKind.Internal` - Internal operations within your application (not crossing process boundaries) - -### Accessing OpenTelemetry APIs - -You can use OpenTelemetry APIs directly alongside TelemetryClient. This gives you access to the full power of OpenTelemetry while maintaining compatibility with Application Insights. - -> **Important:** If you haven't already, read [Understanding ActivitySource](#understanding-activitysource) in the Configuration section to learn about ActivitySource registration. - -**Example: Combining OpenTelemetry and TelemetryClient** - -```csharp -using System.Diagnostics; -using OpenTelemetry; -using OpenTelemetry.Resources; -using OpenTelemetry.Trace; - -public class OrderService -{ - // Create an ActivitySource for this service - private static readonly ActivitySource ActivitySource = new("MyApp.OrderService"); - private readonly TelemetryClient _telemetryClient; - - public OrderService(TelemetryClient telemetryClient) - { - _telemetryClient = telemetryClient; - } - - public async Task ProcessOrderAsync(string orderId) - { - // Option 1: Use OpenTelemetry Activity for distributed tracing - // This creates a span that appears as a dependency in Application Insights - using var activity = ActivitySource.StartActivity("ProcessOrder"); - activity?.SetTag("order.id", orderId); - - try - { - await ProcessPaymentAsync(orderId); - await ShipOrderAsync(orderId); - - activity?.SetStatus(ActivityStatusCode.Ok); - - // Option 2: Use TelemetryClient for business events - // This creates a custom event in Application Insights - _telemetryClient.TrackEvent("OrderProcessed", new Dictionary - { - { "OrderId", orderId } - }); - } - catch (Exception ex) - { - activity?.SetStatus(ActivityStatusCode.Error, ex.Message); - activity?.RecordException(ex); - throw; - } - } -} -``` - -**Don't forget to register your ActivitySource:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - // Wildcards supported - this registers all ActivitySources starting with "MyApp." - builder.AddSource("MyApp.*"); -}); -``` - -**Key Differences:** - -| Aspect | OpenTelemetry Activity | TelemetryClient | -|--------|----------------------|-----------------| -| **Use Case** | Distributed tracing (spans, dependencies) | Events, metrics, compatibility | -| **Shows As** | Dependency or Request in App Insights | Event, Metric, or custom telemetry type | -| **Registration** | Requires `AddSource()` registration | Works immediately | -| **Child Spans** | Automatic parent-child relationships | Manual correlation | - -### Custom Instrumentation - -You can create custom distributed trace spans using OpenTelemetry's `ActivitySource`. This is useful for tracking operations within your application that aren't automatically instrumented. - -> **Note:** Before using `ActivitySource`, make sure you understand the concept. See [Understanding ActivitySource](#understanding-activitysource) in the Configuration section. - -**Example: Custom instrumentation for a data service** - -```csharp -using System.Diagnostics; - -public class DataService -{ - // 1. Create a static ActivitySource with a descriptive name - private static readonly ActivitySource ActivitySource = new("MyApp.DataService"); - - public async Task GetUserAsync(string userId) - { - // 2. Start an Activity to track this operation - using var activity = ActivitySource.StartActivity("GetUser"); - - // 3. Add tags (attributes) to provide context - activity?.SetTag("user.id", userId); - activity?.SetTag("db.system", "postgresql"); - - var user = await _database.GetUserAsync(userId); - - activity?.SetTag("user.found", user != null); - - return user; - } -} -``` - -**Register the ActivitySource in TelemetryConfiguration:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - // Register by exact name - builder.AddSource("MyApp.DataService"); - - // Or use wildcards to register multiple sources at once - builder.AddSource("MyApp.*"); -}); -``` - -**What gets sent to Application Insights?** - -When you call `StartActivity()`, OpenTelemetry creates a span that: -- Appears as a **Dependency** in Application Insights (if started within a request context) -- Includes all tags as **Custom Properties** -- Captures duration automatically -- Links to parent operations for end-to-end tracing - -**Naming Conventions:** - -Use hierarchical naming for your ActivitySources to make wildcard registration easier: -- `MyCompany.OrderService` ✓ -- `MyCompany.OrderService.Validation` ✓ -- `MyCompany.InventoryService` ✓ - -Then register with: `builder.AddSource("MyCompany.*")` - --- ## Using TelemetryClient -Now that you understand how Application Insights 3.x is built on OpenTelemetry, let's explore the `TelemetryClient` API. This familiar API from Application Insights 2.x is preserved as a compatibility layer, making it easy to track custom telemetry without directly interacting with OpenTelemetry primitives. +Let's explore the `TelemetryClient` API. This familiar API from Application Insights 2.x is preserved as a compatibility layer, making it easy to track custom telemetry without directly interacting with OpenTelemetry primitives. The `TelemetryClient` class provides methods for tracking different types of telemetry. @@ -413,12 +142,7 @@ telemetryClient.TrackMetric( }); // Using MetricTelemetry object -var metric = new MetricTelemetry -{ - Name = "RequestDuration", - Value = 123.45 -}; -metric.Properties["Endpoint"] = "/api/users"; +var metric = new MetricTelemetry("RequestDuration", 123.45); telemetryClient.TrackMetric(metric); ``` @@ -447,13 +171,16 @@ try catch (Exception ex) { // Track failed dependency - telemetryClient.TrackDependency( - dependencyTypeName: "HTTP", - dependencyName: "GET /data", - data: "https://api.example.com/data", - startTime: startTime, - duration: timer.Elapsed, - success: false); + var failedDependency = new DependencyTelemetry + { + Type = "HTTP", + Name = "GET /data", + Data = "https://api.example.com/data", + Timestamp = startTime, + Duration = timer.Elapsed, + Success = false + }; + telemetryClient.TrackDependency(failedDependency); throw; } @@ -481,6 +208,7 @@ catch (Exception ex) throw; } ``` +For more examples of sending exception telemetry, please reference the [ExceptionTelemetryExamples](../examples/BasicConsoleApp/ExceptionTelemetryExamples.cs). ### Tracking Requests @@ -504,12 +232,15 @@ try } catch (Exception ex) { - telemetryClient.TrackRequest( - name: "ProcessMessage", - startTime: startTime, - duration: timer.Elapsed, - responseCode: "500", - success: false); + var failedRequest = new RequestTelemetry + { + Name = "ProcessMessage", + Timestamp = startTime, + Duration = timer.Elapsed, + ResponseCode = "500", + Success = false + }; + telemetryClient.TrackRequest(failedRequest); telemetryClient.TrackException(ex); throw; @@ -536,6 +267,7 @@ telemetryClient.TrackTrace( { "ValidationErrors", "Missing required field: CustomerEmail" } }); ``` +For more examples of sending Application Insights traces, please see the [BasicConsoleApp example](../examples/BasicConsoleApp/Program.cs). **Severity Levels:** - `Verbose` - Detailed diagnostic information @@ -569,6 +301,7 @@ catch (Exception ex) message = ex.Message; } +// Syntax 1 - with AvailabilityTelemetry object var availability = new AvailabilityTelemetry { Name = "Health Check", @@ -580,6 +313,15 @@ var availability = new AvailabilityTelemetry }; telemetryClient.TrackAvailability(availability); + +// Syntax 2 - with individual parameters +telemetryClient.TrackAvailability( + name: "Health Check", + timeStamp: startTime, + duration: timer.Elapsed, + runLocation: Environment.MachineName, + success: success, + message: message); ``` ### Tracking Page Views @@ -618,13 +360,8 @@ Now that you've seen how to track telemetry with `TelemetryClient`, let's explor The `TelemetryConfiguration` class controls SDK behavior: ```csharp -var configuration = new TelemetryConfiguration -{ - ConnectionString = "InstrumentationKey=...;IngestionEndpoint=...", - - // Disable telemetry collection (useful for testing) - DisableTelemetry = false -}; +var configuration = TelemetryConfiguration.CreateDefault(); +configuration.ConnectionString = "InstrumentationKey=...;IngestionEndpoint=..."; ``` #### Telemetry Configuration Properties @@ -642,27 +379,25 @@ var configuration = new TelemetryConfiguration *Storage directory defaults: Windows: `%LOCALAPPDATA%\Microsoft\AzureMonitor`, Linux/macOS: `$TMPDIR/Microsoft/AzureMonitor` -> **⚠️ Sampling Configuration:** Configure **either** `SamplingRatio` **or** `TracesPerSecond`, not both. Use `SamplingRatio` for percentage-based sampling (e.g., keep 50% of telemetry). Use `TracesPerSecond` for rate-limited sampling (e.g., keep at most 5 traces per second regardless of load). +> **⚠️ Sampling Configuration:** Configure **either** `SamplingRatio` **or** `TracesPerSecond`, not both. Use `SamplingRatio` for percentage-based sampling (e.g., keep 50% of telemetry). Use `TracesPerSecond` for rate-limited sampling (e.g., keep at most 5 OpenTelemetry traces per second regardless of load). **Example:** ```csharp -var configuration = new TelemetryConfiguration -{ - ConnectionString = "InstrumentationKey=...;IngestionEndpoint=...", - - // Sampling: Choose ONE of these approaches - SamplingRatio = 0.5f, // Keep 50% of telemetry - // TracesPerSecond = 5.0, // OR: Keep max 5 traces/second - - // Offline storage - StorageDirectory = @"C:\AppData\MyApp\Telemetry", - DisableOfflineStorage = false, - - // Features - EnableLiveMetrics = true, - EnableTraceBasedLogsSampler = true -}; +var configuration = TelemetryConfiguration.CreateDefault(); +configuration.ConnectionString = "InstrumentationKey=...;IngestionEndpoint=..."; + +// Sampling: Choose ONE of these approaches +configuration.SamplingRatio = 0.5f; // Keep 50% of telemetry +// configuration.TracesPerSecond = 5.0; // OR: Keep max 5 traces/second + +// Offline storage +configuration.StorageDirectory = @"C:\AppData\MyApp\Telemetry"; +configuration.DisableOfflineStorage = false; + +// Features +configuration.EnableLiveMetrics = true; +configuration.EnableTraceBasedLogsSampler = true; ``` #### Configuring OpenTelemetry Integration @@ -673,92 +408,76 @@ In version 3.x, you can extend the SDK using OpenTelemetry's extensibility model configuration.ConfigureOpenTelemetryBuilder(builder => { // Add custom ActivitySources (explained below) - builder.AddSource("MyApp.*"); + builder.WithTracing(tracing => tracing.AddSource("MyApp.*")); // Add processors - builder.AddProcessor(); + builder.WithTracing(tracing => tracing.AddProcessor()); }); ``` Note: Setting an OpenTelemetry Sampler via `builder.SetSampler()` is currently unsupported and will lead to unexpected sampling behavior. -#### Understanding ActivitySource -**What is an ActivitySource?** -An `ActivitySource` is OpenTelemetry's mechanism for creating distributed trace spans (called `Activity` in .NET). Think of it as a factory that creates telemetry for a specific component or subsystem in your application. +### Setting Context Properties -**Why do I need to register ActivitySources?** +In version 3.x, the following properties remain publicly settable on telemetry items: -By default, OpenTelemetry only collects Activities from sources you explicitly register. When you create a custom `ActivitySource` in your code, you must register its name (or name pattern) so the SDK knows to collect telemetry from it. +**Available Context Properties:** +| Context | Properties | Notes | +|---------|-----------|-------| +| `User` | `Id`, `AuthenticatedUserId`, `UserAgent` | Be mindful of PII | +| `Operation` | `Name`| | +| `Location` | `Ip` | | +| `GlobalProperties` | (dictionary) | Custom key-value pairs | -**Example: Creating and Registering an ActivitySource** +**Example: Setting context on a telemetry item** ```csharp -// 1. Create an ActivitySource in your service class -public class OrderService +var request = new RequestTelemetry { - // Define a static ActivitySource with a unique name - private static readonly ActivitySource ActivitySource = new ActivitySource("MyCompany.OrderService"); - - public async Task ProcessOrderAsync(string orderId) - { - // 2. Use the ActivitySource to create Activities (spans) - using var activity = ActivitySource.StartActivity("ProcessOrder"); - activity?.SetTag("order.id", orderId); - - // Your business logic here - await ValidateOrderAsync(orderId); - await ChargePaymentAsync(orderId); - - activity?.SetStatus(ActivityStatusCode.Ok); - } -} -``` - -```csharp -// 3. Register the ActivitySource when configuring TelemetryConfiguration -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - // Option 1: Register specific source by exact name - builder.AddSource("MyCompany.OrderService"); - - // Option 2: Use wildcard patterns to register multiple sources - builder.AddSource("MyCompany.*"); // Captures MyCompany.OrderService, MyCompany.InventoryService, etc. -}); -``` - -**When to use ActivitySource vs TelemetryClient:** - -- **Use `ActivitySource`** for distributed tracing (requests, dependencies, operations that span multiple services) -- **Use `TelemetryClient`** for events, metrics, and when you need the Application Insights 2.x compatibility API + Name = "ProcessOrder", + Timestamp = DateTimeOffset.UtcNow, + Duration = TimeSpan.FromMilliseconds(150), + ResponseCode = "200", + Success = true +}; -See [Custom Instrumentation](#custom-instrumentation) for detailed examples. +// Set user context (be mindful of PII) +request.Context.User.Id = userId; +request.Context.User.AuthenticatedUserId = authenticatedUserId; -### Setting Context Properties +// Set operation context +request.Context.Operation.Name = "ProcessOrder"; -Set properties that apply to all telemetry: +// Set location context +request.Context.Location.Ip = clientIpAddress; -```csharp -// Set cloud role name (appears as "Cloud role" in Azure) -telemetryClient.Context.Cloud.RoleName = "OrderProcessingService"; +// Set custom properties via GlobalProperties +request.Context.GlobalProperties["Environment"] = "Production"; +request.Context.GlobalProperties["DataCenter"] = "WestUS"; -// Set application version -telemetryClient.Context.Component.Version = "1.2.3"; +telemetryClient.TrackRequest(request); +``` -// Set user context (be mindful of PII) -telemetryClient.Context.User.Id = userId; -telemetryClient.Context.Session.Id = sessionId; +**Recommended: Use OpenTelemetry Resource Attributes** -// Set device context -telemetryClient.Context.Device.OperatingSystem = Environment.OSVersion.ToString(); +For service-level context (cloud role, version, environment), the recommended approach in 3.x is to use OpenTelemetry Resource attributes, which apply to all telemetry automatically: -// Set custom properties -telemetryClient.Context.GlobalProperties["Environment"] = "Production"; -telemetryClient.Context.GlobalProperties["DataCenter"] = "WestUS"; +```csharp +configuration.ConfigureOpenTelemetryBuilder(builder => +{ + builder.ConfigureResource(r => r + .AddService( + serviceName: "OrderProcessingService", // Maps to Cloud.RoleName + serviceVersion: "1.2.3", // Maps to Application Version + serviceInstanceId: Environment.MachineName) // Maps to Cloud.RoleInstance + .AddAttributes(new Dictionary + { + ["deployment.environment"] = "Production" + })); +}); ``` -**Important:** In version 3.x, many context properties are populated through OpenTelemetry Resource Detectors. See [Custom Resource Attributes](#custom-resource-attributes) for the recommended approach. - ### Dependency Injection In applications using Microsoft.Extensions.DependencyInjection: @@ -773,16 +492,8 @@ var services = new ServiceCollection(); // Register TelemetryConfiguration services.AddSingleton(sp => { - var config = new TelemetryConfiguration - { - ConnectionString = "InstrumentationKey=...;IngestionEndpoint=..." - }; - - // Configure OpenTelemetry - config.ConfigureOpenTelemetryBuilder(builder => - { - builder.AddSource("MyApp.*"); - }); + var config = TelemetryConfiguration.CreateDefault(); + config.ConnectionString = "InstrumentationKey=...;IngestionEndpoint=..."; return config; }); @@ -813,426 +524,4 @@ public class OrderService } } ``` - ---- - -## Advanced Scenarios - -With the fundamentals of configuration in place, let's explore advanced scenarios for enriching, filtering, and optimizing your telemetry collection. These techniques leverage OpenTelemetry's extensibility model to give you fine-grained control over what telemetry is collected and how it's processed. - -### Enriching Telemetry with Activity Processors - -Activity Processors replace `ITelemetryInitializer` from version 2.x. They enrich or modify telemetry before export: - -```csharp -using System.Diagnostics; -using OpenTelemetry; - -public class CustomEnrichmentProcessor : BaseProcessor -{ - public override void OnEnd(Activity activity) - { - // Add custom tags to all activities - activity?.SetTag("app.environment", "Production"); - activity?.SetTag("app.version", "1.2.3"); - - // Conditionally enrich - if (activity?.OperationName == "ProcessOrder") - { - activity?.SetTag("business.critical", "true"); - } - - // Add resource information - activity?.SetTag("host.name", Environment.MachineName); - } -} -``` - -**Register the processor:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.AddProcessor(); -}); -``` - -### Filtering Telemetry - -Filter out unwanted telemetry to reduce volume and costs: - -```csharp -public class FilteringProcessor : BaseProcessor -{ - public override void OnEnd(Activity activity) - { - // Filter out health check requests - if (activity?.DisplayName?.Contains("/health") == true) - { - activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; - return; - } - - // Filter out specific dependencies - if (activity?.Kind == ActivityKind.Client && - activity?.GetTagItem("http.url")?.ToString()?.Contains("internal-service") == true) - { - activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; - } - } -} -``` - -**Register the processor:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.AddProcessor(); -}); -``` - -### Custom Resource Attributes - -Resource Detectors add contextual information to all telemetry: - -```csharp -using OpenTelemetry.Resources; - -public class CustomResourceDetector : IResourceDetector -{ - public Resource Detect() - { - var attributes = new Dictionary - { - { "service.name", "OrderProcessingService" }, - { "service.version", "1.2.3" }, - { "deployment.environment", "Production" }, - { "service.instance.id", Environment.MachineName }, - { "custom.datacenter", "WestUS" } - }; - - return new Resource(attributes); - } -} -``` - -**Register the detector:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.ConfigureResource(resourceBuilder => - { - resourceBuilder.AddDetector(new CustomResourceDetector()); - }); -}); -``` - -### Sampling - -Sampling reduces telemetry volume while maintaining statistical accuracy: - -```csharp -using OpenTelemetry.Trace; - -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - // Sample 10% of traces - builder.SetSampler(new TraceIdRatioBasedSampler(0.1)); - - // Or use parent-based sampling (respects upstream sampling decisions) - builder.SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(0.1))); -}); -``` - -For more sophisticated sampling (e.g., sample errors at 100%, successful requests at 10%): - -```csharp -public class AdaptiveSampler : Sampler -{ - private readonly TraceIdRatioBasedSampler _defaultSampler = new(0.1); - - public override SamplingResult ShouldSample(in SamplingParameters samplingParameters) - { - // Always sample errors - var tags = samplingParameters.Tags; - if (tags?.Any(t => t.Key == "error" && (bool)t.Value) == true) - { - return new SamplingResult(SamplingDecision.RecordAndSample); - } - - // Sample other requests at 10% - return _defaultSampler.ShouldSample(samplingParameters); - } -} -``` - ---- - -## Migrating from 2.x to 3.x - -If you're upgrading from Application Insights 2.x, this section will guide you through the key changes and help you adapt your existing code to the new OpenTelemetry-based architecture. - -### Configuration Changes - -**2.x Configuration:** - -```csharp -// Old way (2.x) -var configuration = new TelemetryConfiguration -{ - InstrumentationKey = "your-instrumentation-key", - TelemetryInitializers = { new CustomInitializer() }, - TelemetryProcessors = { new CustomProcessor() } -}; -``` - -**3.x Configuration:** - -```csharp -// New way (3.x) -var configuration = new TelemetryConfiguration -{ - ConnectionString = "InstrumentationKey=...;IngestionEndpoint=..." -}; - -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - // Use Activity Processors instead of ITelemetryInitializer/ITelemetryProcessor - builder.AddProcessor(); - builder.AddProcessor(); -}); -``` - -### Replacing ITelemetryInitializer - -`ITelemetryInitializer` is replaced by Activity Processors: - -**2.x ITelemetryInitializer:** - -```csharp -// Old way (2.x) -public class CustomInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - telemetry.Context.Cloud.RoleName = "OrderService"; - - if (telemetry is RequestTelemetry request) - { - request.Properties["CustomProperty"] = "CustomValue"; - } - } -} -``` - -**3.x Activity Processor:** - -```csharp -// New way (3.x) -public class CustomEnrichmentProcessor : BaseProcessor -{ - public override void OnEnd(Activity activity) - { - // Set service name (equivalent to Cloud.RoleName) - activity?.SetTag("service.name", "OrderService"); - - // Add custom properties - if (activity?.Kind == ActivityKind.Server) - { - activity?.SetTag("CustomProperty", "CustomValue"); - } - } -} -``` - -**Register the processor:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.AddProcessor(); - - // Also set service name via Resource - builder.ConfigureResource(r => r.AddService( - serviceName: "OrderService", - serviceVersion: "1.0.0")); -}); -``` - -### Replacing ITelemetryProcessor - -`ITelemetryProcessor` is replaced by filtering Activity Processors: - -**2.x ITelemetryProcessor:** - -```csharp -// Old way (2.x) -public class FilteringProcessor : ITelemetryProcessor -{ - private ITelemetryProcessor _next; - - public FilteringProcessor(ITelemetryProcessor next) - { - _next = next; - } - - public void Process(ITelemetry item) - { - // Filter out health checks - if (item is RequestTelemetry request && request.Name.Contains("/health")) - { - return; // Don't pass to next processor - } - - _next.Process(item); - } -} -``` - -**3.x Activity Processor:** - -```csharp -// New way (3.x) -public class FilteringProcessor : BaseProcessor -{ - public override void OnEnd(Activity activity) - { - // Filter out health checks - if (activity?.DisplayName?.Contains("/health") == true) - { - // Mark as not recorded to prevent export - activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; - } - } -} -``` - -**Register the processor:** - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.AddProcessor(); -}); -``` - ---- - -## Troubleshooting - -### Telemetry Not Appearing in Portal - -1. **Verify Connection String**: Ensure the connection string is correct and includes the IngestionEndpoint. - -2. **Check Network Connectivity**: Verify your application can reach the ingestion endpoint (typically `https://*.in.applicationinsights.azure.com`). - -3. **Call Flush()**: Telemetry is batched. Call `Flush()` and wait a few seconds before application exit. - -4. **Enable Diagnostic Logging**: Configure OpenTelemetry diagnostic logging: - -```csharp -using OpenTelemetry; -using System.Diagnostics; - -// Enable detailed logging -AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); -Sdk.CreateTracerProviderBuilder() - .AddSource("Microsoft.ApplicationInsights.*") - .AddConsoleExporter() - .Build(); -``` - -5. **Check Sampling**: If sampling is enabled, only a percentage of telemetry is sent. - -6. **Verify Processors**: Ensure Activity Processors aren't filtering out your telemetry. - -### High Telemetry Volume - -1. **Enable Sampling**: Use TraceIdRatioBasedSampler to reduce volume: - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.SetSampler(new TraceIdRatioBasedSampler(0.1)); // 10% sampling -}); -``` - -2. **Filter Unnecessary Telemetry**: Use Activity Processors to filter out health checks, internal calls, etc. - -3. **Reduce Trace Verbosity**: Avoid tracking trace telemetry at `Verbose` level in production. - -### Performance Issues - -1. **Reuse TelemetryClient**: Don't create new instances for each operation. - -2. **Avoid Blocking on Flush()**: Telemetry is sent asynchronously. Only call `Flush()` at application shutdown. - -3. **Optimize Activity Processors**: Keep processor logic fast and non-blocking. - -4. **Use Async APIs**: Prefer async patterns in your application code. - -### Missing Context Properties - -In 3.x, many context properties are set via Resource Detectors: - -```csharp -configuration.ConfigureOpenTelemetryBuilder(builder => -{ - builder.ConfigureResource(resourceBuilder => - { - resourceBuilder.AddService(serviceName: "MyService", serviceVersion: "1.0.0"); - resourceBuilder.AddAttributes(new[] - { - new KeyValuePair("deployment.environment", "Production") - }); - }); -}); -``` - -## SDK Layering - -The Application Insights SDK is composed of multiple layers: - -| Layer | Description | Extensibility | -|-------|-------------|---------------| -| **TelemetryClient API** | High-level API for tracking telemetry (events, metrics, dependencies, etc.) | Track custom telemetry using `TelemetryClient.Track*()` methods | -| **OpenTelemetry Shim** | Translates `TelemetryClient` calls to OpenTelemetry primitives (Activity, LogRecord, Metrics) | Use OpenTelemetry APIs directly (`ActivitySource`, `ILogger`, `Meter`) | -| **OpenTelemetry SDK** | Collects, processes, and exports telemetry using industry-standard OpenTelemetry | Add custom instrumentation, processors, samplers, exporters | -| **Activity Processors** | Enrich, filter, or modify telemetry before export | Implement `BaseProcessor` | -| **Resource Detectors** | Add contextual information (service name, version, environment, etc.) | Implement `IResourceDetector` | -| **Azure Monitor Exporter** | Converts OpenTelemetry signals to Application Insights schema and sends to Azure Monitor | Configure exporter options (endpoint, retry policy, etc.) | - -### Platform-Specific Packages - -The core `Microsoft.ApplicationInsights` package provides the foundational `TelemetryClient` API. Platform-specific packages build on this foundation: - -- **[Microsoft.ApplicationInsights.AspNetCore](../NETCORE/Readme.md)**: Automatic instrumentation for ASP.NET Core applications (requests, dependencies, exceptions, performance counters). Includes middleware, filters, and automatic context propagation. - -- **[Microsoft.ApplicationInsights.WorkerService](../NETCORE/WorkerService.md)**: Optimized for Worker Services, background tasks, and console applications. Provides automatic dependency tracking and integrates with `ILogger`. - -- **Microsoft.ApplicationInsights.Web**: Legacy package for ASP.NET Framework applications (not covered in this documentation). - -These packages configure OpenTelemetry instrumentation libraries and the Azure Monitor Exporter automatically, eliminating most manual configuration. - -> **Note:** For classic Application Insights SDK (version 2.x), refer to the [2.x branch documentation](https://github.com/microsoft/ApplicationInsights-dotnet/tree/2.x). - -## Contributing - -We strongly welcome and encourage contributions to this project. Please read the general [contributor's guide][ContribGuide] located in the ApplicationInsights-Home repository and the [contributing guide](https://github.com/Microsoft/ApplicationInsights-dotnet/blob/develop/.github/CONTRIBUTING.md) for this SDK. If making a large change we request that you open an [issue][GitHubIssue] first. We follow the [Git Flow][GitFlow] approach to branching. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -[AILandingPage]: https://azure.microsoft.com/services/application-insights/ -[api-overview]: https://learn.microsoft.com/azure/azure-monitor/app/api-custom-events-metrics -[ContribGuide]: https://github.com/Microsoft/ApplicationInsights-Home/blob/master/CONTRIBUTING.md -[GitFlow]: http://nvie.com/posts/a-successful-git-branching-model/ -[GitHubIssue]: https://github.com/Microsoft/ApplicationInsights-dotnet/issues -[master]: https://github.com/Microsoft/ApplicationInsights-dotnet/tree/master -[develop]: https://github.com/Microsoft/ApplicationInsights-dotnet/tree/development -[NuGetCore]: https://www.nuget.org/packages/Microsoft.ApplicationInsights -[WebGetStarted]: https://learn.microsoft.com/azure/azure-monitor/app/asp-net -[WinAppGetStarted]: https://learn.microsoft.com/azure/azure-monitor/app/windows-desktop -[DesktopGetStarted]: https://learn.microsoft.com/azure/azure-monitor/app/windows-desktop -[AIKey]: https://learn.microsoft.com/azure/azure-monitor/app/create-workspace-resource#copy-the-connection-string +--- \ No newline at end of file diff --git a/BreakingChanges.md b/BreakingChanges.md index 1b12178d7d..70ead4a7fe 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -106,11 +106,13 @@ This applies to all dimension combinations (1D, 2D, 3D, 4D). - ❌ `TelemetryConfiguration(string instrumentationKey)` - ❌ `TelemetryConfiguration(string instrumentationKey, ITelemetryChannel channel)` +#### Methods +- ❌ **`CreateFromConfiguration(string config)`** - Static method that created a TelemetryConfiguration from XML configuration string. Use `CreateDefault()` or the parameterless constructor and set properties directly. + ### Properties with Changed Behavior - ✅ **`ConnectionString`** - Still exists but behavior differs - **2.x**: String property - **3.x**: Setting this calls OpenTelemetry configuration internally -- ✅ **`DisableTelemetry`** - Still exists but does not disable flow of telemetry (will be fixed later) ### Methods with changed Behavior - CreateDefault() returns an internal static configuration instead of a new TelemetryConfiguration() @@ -139,11 +141,8 @@ Most TelemetryContext modules have now been marked internal or removed. The prop ### Properties Retained The following remain **public**: -- ✅ `Cloud` (RoleName, RoleInstance) - - Note: These are settable via resource attributes (service.name & service.instance.id) in OpenTelemetry; we are working on fixing functionality for setting the same via CloudContext. - ✅ `User` (Id, AuthenticatedUserId, UserAgent) -- ✅ `Operation` (Name, SyntheticSource) - - Note: A future work item is to make sure SyntheticSource can be read from properly and emitted in the telemetry item. +- ✅ `Operation` (Name) - ✅ `Location` (Ip) - ✅ `GlobalProperties` @@ -197,6 +196,11 @@ The following extension methods remain with identical signatures: - ❌ **`ExceptionTrackingMiddleware`** - Middleware class removed - ❌ **`HostingDiagnosticListener`** - Diagnostic listener removed - ❌ **`HostingStartupOptions`** - Configuration class removed +- ❌ **`Resources`** - Internal resource class removed from public API + - `Resources.Culture` (get/set) + - `Resources.JavaScriptAuthSnippet` (get) + - `Resources.JavaScriptSnippet` (get) + - `Resources.ResourceManager` (get) ### TelemetryInitializers Removed (All 7) - ❌ `AspNetCoreEnvironmentTelemetryInitializer` @@ -218,13 +222,13 @@ The following extension methods remain with identical signatures: - ❌ **`RequestCollectionOptions`** - Removed (non-functional, use OpenTelemetry instrumentation options) - ❌ **`DependencyCollectionOptions`** - Removed (non-functional, use OpenTelemetry instrumentation options) - ❌ `EnableAdaptiveSampling`** - Removed, rate limited sampling is now the default. +- ❌ **`EnableDebugLogger`** - Removed ### Properties Retained - ✅ **`ConnectionString`** - Primary configuration method - ✅ **`ApplicationVersion`** - ✅ **`AddAutoCollectedMetricExtractor`** - ✅ **`EnableQuickPulseMetricStream`** -- ✅ **`EnableDebugLogger`** - Retained but has no effect - ✅ **`EnableAuthenticationTrackingJavaScript`** - JavaScript auth tracking config - ✅ **`EnableDependencyTrackingTelemetryModule`** - Dependency tracking toggle - ✅ **`EnablePerformanceCounterCollectionModule`** - Performance counter toggle @@ -234,6 +238,7 @@ The following extension methods remain with identical signatures: - ✅ **`Credential`** (Azure.Core.TokenCredential) - Enables Azure Active Directory (AAD) authentication - ✅ **`TracesPerSecond`** (double?) - Gets or sets the number of traces per second for rate-limited sampling (default sampling mode). Replaces `EnableAdaptiveSampling`. - ✅ **`SamplingRatio`** (float?) - Gets or sets the sampling ratio for traces (0.0 to 1.0). A value of 1.0 means all telemetry is sent. Replaces `EnableAdaptiveSampling`. +- ✅ **`EnableTraceBasedLogsSampler`** (bool?) - Gets or sets whether trace-based log sampling is enabled (default: true). When enabled, logs are sampled based on the sampling decision of the associated trace. ### JavaScriptSnippet Constructor Change **2.x:** @@ -286,6 +291,7 @@ The following extension methods remain with identical signatures: - ❌ **`EndpointAddress`** - No longer configurable (`ConnectionString` contains endpoints) - ❌ **`DependencyCollectionOptions`** - Removed (non-functional, use OpenTelemetry instrumentation options) - ❌ **`EnableAdaptiveSampling`** - Removed, rate limited sampling is now the default. +- ❌ **`EnableDebugLogger`** - Removed ### Properties Retained - ✅ **`ConnectionString`** - Primary configuration method (maps to `AzureMonitorExporterOptions.ConnectionString`) @@ -293,13 +299,13 @@ The following extension methods remain with identical signatures: - ✅ **`EnableDependencyTrackingTelemetryModule`** - Still configurable - ✅ **`EnablePerformanceCounterCollectionModule`** - Still configurable - ✅ **`EnableQuickPulseMetricStream`** - Maps to `AzureMonitorExporterOptions.EnableLiveMetrics` -- ✅ **`EnableDebugLogger`** - Still configurable though has no effect - ✅ **`AddAutoCollectedMetricExtractor`** - Still configurable ### New Properties Added in 3.x - ✅ **`Credential`** (Azure.Core.TokenCredential) - Enables Azure Active Directory (AAD) authentication - ✅ **`TracesPerSecond`** (double?) - Gets or sets the number of traces per second for rate-limited sampling (default sampling mode). Replaces `EnableAdaptiveSampling`. - ✅ **`SamplingRatio`** (float?) - Gets or sets the sampling ratio for traces (0.0 to 1.0). A value of 1.0 means all telemetry is sent. Replaces `EnableAdaptiveSampling`. +- ✅ **`EnableTraceBasedLogsSampler`** (bool?) - Gets or sets whether trace-based log sampling is enabled (default: true). When enabled, logs are sampled based on the sampling decision of the associated trace. ## Migration Impact - Any code depending on `InstrumentationKey` must migrate to `ConnectionString` diff --git a/LOGGING/README.md b/LOGGING/README.md index 075acc054d..e9216cb63d 100644 --- a/LOGGING/README.md +++ b/LOGGING/README.md @@ -1,35 +1,10 @@ ![Build](https://mseng.visualstudio.com/DefaultCollection/_apis/public/build/definitions/96a62c4a-58c2-4dbb-94b6-5979ebc7f2af/2637/badge) ## Nuget packages - -- For ILogger: - [Microsoft.Extensions.Logging.ApplicationInsights](https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.Extensions.Logging.ApplicationInsights.svg)](https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights/) - For NLog: [Microsoft.ApplicationInsights.NLogTarget](http://www.nuget.org/packages/Microsoft.ApplicationInsights.NLogTarget/) [![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.NLogTarget.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.NLogTarget/) -- For Log4Net: [Microsoft.ApplicationInsights.Log4NetAppender](http://www.nuget.org/packages/Microsoft.ApplicationInsights.Log4NetAppender/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.Log4NetAppender.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.Log4NetAppender/) -- For System.Diagnostics: [Microsoft.ApplicationInsights.TraceListener](http://www.nuget.org/packages/Microsoft.ApplicationInsights.TraceListener/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.TraceListener.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.TraceListener/) -- [Microsoft.ApplicationInsights.DiagnosticSourceListener](http://www.nuget.org/packages/Microsoft.ApplicationInsights.DiagnosticSourceListener/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.DiagnosticSourceListener.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.DiagnosticSourceListener/) -- [Microsoft.ApplicationInsights.EtwCollector](http://www.nuget.org/packages/Microsoft.ApplicationInsights.EtwCollector/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.EtwCollector.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.EtwCollector/) -- [Microsoft.ApplicationInsights.EventSourceListener](http://www.nuget.org/packages/Microsoft.ApplicationInsights.EventSourceListener/) -[![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.EventSourceListener.svg)](https://www.nuget.org/packages/Microsoft.ApplicationInsights.EventSourceListener/) - -Application Insights logging adapters. -============================== - -If you use NLog, log4Net or System.Diagnostics.Trace for diagnostic tracing in your application, you can have your logs sent to Application Insights, where you can explore and search them. Your logs will be merged with the other telemetry coming from your application, so that you can identify the traces associated with servicing each user request, and correlate them with other events and exception reports. -Read more: -- [Microsoft Docs: "Explore .NET trace logs in Application Insights"](https://docs.microsoft.com/azure/application-insights/app-insights-asp-net-trace-logs) -- [Microsoft Docs: "Diagnose sudden changes in your app telemetry"](https://docs.microsoft.com/azure/application-insights/app-insights-analytics-diagnostics#trace) - -## ILogger -See [this](src/ILogger/Readme.md). ## NLog @@ -78,7 +53,7 @@ For more information, see the [Azure.Identity documentation](https://learn.micro - Your_Resource_Key + InstrumentationKey=YOUR_IKEY;IngestionEndpoint=https://YOUR_REGION.in.applicationinsights.azure.com/ @@ -91,7 +66,7 @@ For more information, see the [Azure.Identity documentation](https://learn.micro NLog allows you to configure conditional configs: ```xml -${configsetting:APPINSIGHTS.INSTRUMENTATIONKEY:whenEmpty=${environment:APPINSIGHTS_INSTRUMENTATIONKEY}} +${configsetting:APPLICATIONINSIGHTS_CONNECTION_STRING:whenEmpty=${environment:APPLICATIONINSIGHTS_CONNECTION_STRING}} ``` For more information see: @@ -99,17 +74,6 @@ For more information see: - https://github.com/nlog/nlog/wiki/Environment-Layout-Renderer - https://github.com/nlog/nlog/wiki/WhenEmpty-Layout-Renderer - - -```csharp -// You need this only if you did not define InstrumentationKey in ApplicationInsights.config (Or in the NLog.config) -TelemetryConfiguration.Active.InstrumentationKey = "Your_Resource_Key"; - -Logger logger = LogManager.GetLogger("Example"); - -logger.Trace("trace log message"); -``` - * **Configure ApplicationInsightsTarget using NLog Config API** : If you configure NLog programmatically with the [NLog Config API](https://github.com/nlog/NLog/wiki/Configuration-API), then create Application Insights target in code and add it to your other targets: @@ -117,8 +81,7 @@ If you configure NLog programmatically with the [NLog Config API](https://github var config = new LoggingConfiguration(); ApplicationInsightsTarget target = new ApplicationInsightsTarget(); -// You need this only if you did not define InstrumentationKey in ApplicationInsights.config or want to use different instrumentation key -target.InstrumentationKey = "Your_Resource_Key"; +target.ConnectionString = "InstrumentationKey=....;IngestionEndpoint=..."; LoggingRule rule = new LoggingRule("*", LogLevel.Trace, target); config.LoggingRules.Add(rule); @@ -130,79 +93,3 @@ Logger logger = LogManager.GetLogger("Example"); logger.Trace("trace log message"); ``` -## Log4Net - -Application Insights Log4Net adapter nuget modifies web.config and adds Application Insights Appender. - -For more information, see [Log4Net Configuration](https://logging.apache.org/log4net/release/manual/configuration.html) - -```csharp -// You do not need this if you have instrumentation key in the ApplicationInsights.config -TelemetryConfiguration.Active.InstrumentationKey = "Your_Resource_Key"; - -log4net.Config.XmlConfigurator.Configure(); -var logger = LogManager.GetLogger(this.GetType()); - -logger.Info("Message"); -logger.Warn("A warning message"); -logger.Error("An error message"); -``` - -## System.Diagnostics - -Microsoft.ApplicationInsights.TraceListener nuget package modifies web.config and adds application insights listener. - -For more information, see ["Microsoft Docs: "Tracing and Instrumenting Applications"](https://docs.microsoft.com/dotnet/framework/debug-trace-profile/tracing-and-instrumenting-applications) - -```xml - - - - - - - - - -``` - -If your application type does not have web.config, add listener programmatically or in the configuration file appropriate to your application type - -```csharp -// You do not need this if you have instrumentation key in the ApplicationInsights.config -TelemetryConfiguration.Active.InstrumentationKey = "Your_Resource_Key"; -System.Diagnostics.Trace.TraceWarning("Slow response - database01"); - -``` - - -## EventSource - -`EventSourceTelemetryModule` allows you to configure EventSource events to be sent to Application Insights as traces. - -For more information, see [Microsoft Docs: "Using EventSource Events"](https://docs.microsoft.com/azure/application-insights/app-insights-asp-net-trace-logs#using-eventsource-events). - - -## ETW - -`EtwCollectorTelemetryModule` allows you to configure events from ETW providers to be sent to Application Insights as traces. - -For more information, see [Microsoft Docs: "Using ETW Events"](https://docs.microsoft.com/azure/application-insights/app-insights-asp-net-trace-logs#using-etw-events). - - -## DiagnosticSource - -You can configure `System.Diagnostics.DiagnosticSource` events to be sent to Application Insights as traces. - -For more information, see [CoreFX: "Diagnostic Source Users Guide"](https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/DiagnosticSourceUsersGuide.md). - -To enable, edit the `TelemetryModules` section of the ApplicationInsights.config file: - -```xml - - - - - - ``` - diff --git a/NETCORE/Readme.md b/NETCORE/Readme.md index d6d0693fb4..582cc15d26 100644 --- a/NETCORE/Readme.md +++ b/NETCORE/Readme.md @@ -39,12 +39,11 @@ The Microsoft.ApplicationInsights.AspNetCore package is built on top of OpenTele #### Logs - Logs created with `Microsoft.Extensions.Logging`. See [Logging in .NET Core and ASP.NET Core](https://learn.microsoft.com/aspnet/core/fundamentals/logging) for more details on how to create and configure logging. -- [Azure SDK logs](https://learn.microsoft.com/dotnet/azure/sdk/logging) are recorded as a subset of `Microsoft.Extensions.Logging`. + #### Resource Detectors - **Azure App Service Resource Detector**: Adds resource attributes for applications running in Azure App Service. - **Azure VM Resource Detector**: Adds resource attributes for applications running in an Azure Virtual Machine. -- **Azure Container Apps Resource Detector**: Adds resource attributes for applications running in Azure Container Apps. - **ASP.NET Core Environment Resource Detector**: Adds resource attributes from the ASP.NET Core environment configuration. > **Note**: Resource attributes are used to set the cloud role and role instance. Most other resource attributes are currently ignored. @@ -137,16 +136,6 @@ In your `appsettings.json`: ## Configuration -### Connection String - -The connection string can be configured in multiple ways (listed in order of precedence): - -1. `ApplicationInsightsServiceOptions.ConnectionString` property set in code -2. `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable -3. `ApplicationInsights:ConnectionString` configuration setting - -> **Important**: Version 3.x uses **ConnectionString** instead of InstrumentationKey. InstrumentationKey-based configuration is deprecated. - ### ApplicationInsightsServiceOptions The following options are available when configuring Application Insights in version 3.x: @@ -157,13 +146,46 @@ builder.Services.AddApplicationInsightsTelemetry(options => // Connection string for the Application Insights resource options.ConnectionString = "InstrumentationKey=..."; + // AAD authentication credential (optional) + // options.Credential = new DefaultAzureCredential(); + + // Application version reported with telemetry + // options.ApplicationVersion = "1.0.0"; + // Enable or disable Live Metrics (default: true) options.EnableQuickPulseMetricStream = true; + + // Rate-limited sampling: maximum traces per second (default: 5) + // Use this for rate-based sampling to limit telemetry volume + options.TracesPerSecond = 5.0; + + // Percentage-based sampling: ratio of telemetry to collect (0.0 to 1.0) + // Use this instead of TracesPerSecond for percentage-based sampling + // options.SamplingRatio = 0.5f; // 50% of telemetry + + // Enable or disable Application Insights Standard Metrics (default: true) + options.AddAutoCollectedMetricExtractor = true; + + // Enable or disable performance counter collection (default: true) + options.EnablePerformanceCounterCollectionModule = true; + + // Enable or disable dependency tracking (default: true) + // When false, outbound HTTP, SQL, and other dependency calls are not tracked + options.EnableDependencyTrackingTelemetryModule = true; + + // Enable or disable request tracking (default: true) - ASP.NET Core only + // When false, incoming HTTP requests are not tracked + options.EnableRequestTrackingTelemetryModule = true; + + // Enable JavaScript snippet for authenticated user tracking (default: false) + options.EnableAuthenticationTrackingJavaScript = false; + + // Enable or disable trace-based log sampling (default: true) + // When true, logs are sampled based on the sampling decision of the associated trace + options.EnableTraceBasedLogsSampler = true; }); ``` -> **Note**: In version 3.x, many properties from `ApplicationInsightsServiceOptions` in 2.x are no longer functional because they related to telemetry modules, processors, and channels that have been replaced by OpenTelemetry components. The properties shown above are the ones that are actively used in the 3.x OpenTelemetry-based implementation. - ## Advanced Configuration ### Using TelemetryClient for Custom Telemetry @@ -351,17 +373,6 @@ builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => }); ``` -#### Disabling Live Metrics - -By default, Live Metrics is enabled. To disable it: - -```csharp -builder.Services.AddApplicationInsightsTelemetry(options => -{ - options.EnableQuickPulseMetricStream = false; -}); -``` - #### Dropping Specific Metrics Instruments To exclude specific instruments from being collected: @@ -410,554 +421,12 @@ using (logger.BeginScope(scope)) } ``` -## Migration from 2.x to 3.x - -Version 3.x of the Application Insights SDK represents a significant architectural change. The SDK is now built on top of OpenTelemetry, which means many of the Application Insights-specific concepts and APIs have been replaced with OpenTelemetry equivalents. - -### Breaking Changes - -#### What Has Been Removed - -The following features are **no longer available** in version 3.x: - -1. **Telemetry Modules** - All telemetry modules have been removed. Telemetry collection is now handled by OpenTelemetry instrumentation libraries. - -2. **Telemetry Initializers** - Telemetry initializers are no longer supported. Use OpenTelemetry processors or resource detectors instead. - -3. **Telemetry Processors** - Custom telemetry processors are not supported. Use OpenTelemetry processors. - -4. **ITelemetryChannel** - Custom telemetry channels are not supported. The Azure Monitor OpenTelemetry Exporter handles telemetry transmission. - -5. **TelemetryConfiguration Builder Pattern** - Direct configuration of `TelemetryConfiguration` through builder pattern is no longer supported. Use `ApplicationInsightsServiceOptions` and OpenTelemetry configuration APIs. - -6. **RequestCollectionOptions properties** - Most properties in `RequestCollectionOptions` have been removed. Use OpenTelemetry instrumentation options instead (e.g., `AspNetCoreTraceInstrumentationOptions`). - -7. **InstrumentationKey** - Configuration via InstrumentationKey is deprecated. Use ConnectionString instead. - -8. **PerformanceCollectorModule** - Performance counter collection works differently in 3.x. Set `EnablePerformanceCounterCollectionModule = true` in options. - -9. **AutoCollectMetricExtractor** - Metric extraction has changed. Use `AddAutoCollectedMetricExtractor` option. - -10. **JavaScript Snippet Injection** - The way JavaScript snippet is injected has changed. Use `IJavaScriptSnippet` service. - -#### What Has Changed - -1. **AddApplicationInsightsTelemetry()** - Still the primary way to add Application Insights, but now configures OpenTelemetry under the hood. - -2. **TelemetryClient** - Still available for backward compatibility, but is now a shim layer over OpenTelemetry APIs. For new code, consider using OpenTelemetry APIs directly (`ActivitySource`, `Meter`, `ILogger`). - -3. **Configuration** - Connection strings are now configured via `ApplicationInsightsServiceOptions.ConnectionString` or `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable. - -5. **Live Metrics** - Still supported via the `EnableQuickPulseMetricStream` option. - -### Migration Steps - -#### Step 1: Update Package Reference - -Update your package reference to version 3.x: - -```xml - -``` - -#### Step 2: Update Connection String Configuration - -Replace InstrumentationKey with ConnectionString: - -**Before (2.x):** -```csharp -services.AddApplicationInsightsTelemetry(options => -{ - options.InstrumentationKey = "00000000-0000-0000-0000-000000000000"; -}); -``` - -**After (3.x):** -```csharp -builder.Services.AddApplicationInsightsTelemetry(options => -{ - options.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://..."; -}); -``` - -#### Step 3: Replace Telemetry Initializers and Processors with OpenTelemetry Processors - -**Important Difference:** In 2.x, ITelemetryInitializer and ITelemetryProcessor applied to **all telemetry types** (requests, dependencies, traces, events, metrics, exceptions). In 3.x, OpenTelemetry uses **separate mechanisms for different signal types**: - -- **Activity Processors** (`BaseProcessor`) - Apply to traces (requests, dependencies, and custom activities) -- **Log Processors** (`BaseProcessor`) - Apply to logs (traces, events, exceptions logged via ILogger) -- **Metric Views** - Transform/filter metrics (OpenTelemetry doesn't use processors for metrics; use `AddView()` instead) - -Here are common migration patterns: - -**Example: Adding Custom Properties to All Telemetry** - -**Before (2.x) - Using ITelemetryInitializer:** -```csharp -public class MyTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - telemetry.Context.GlobalProperties["Environment"] = "Production"; - telemetry.Context.GlobalProperties["CustomerId"] = GetCustomerId(); - } -} - -// Registration -services.AddApplicationInsightsTelemetry(); -services.AddSingleton(); -``` - -**After (3.x) - Using OpenTelemetry Processor:** -```csharp -using System.Diagnostics; -using OpenTelemetry; - -public class MyActivityProcessor : BaseProcessor -{ - public override void OnStart(Activity activity) - { - activity.SetTag("Environment", "Production"); - activity.SetTag("CustomerId", GetCustomerId()); - } - - private string GetCustomerId() - { - // Your logic here - return "12345"; - } -} +### Custom OpenTelemetry Processor Registration +Register any custom processors with: -// Registration -builder.Services.AddApplicationInsightsTelemetry(); +```C# builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => { builder.AddProcessor(); }); -``` - -**Example: Filtering Telemetry** - -**Before (2.x) - Using ITelemetryProcessor:** -```csharp -public class MyTelemetryProcessor : ITelemetryProcessor -{ - private ITelemetryProcessor Next { get; set; } - - public MyTelemetryProcessor(ITelemetryProcessor next) - { - Next = next; - } - - public void Process(ITelemetry item) - { - // Filter out requests to health check endpoint - if (item is RequestTelemetry request && - request.Url.AbsolutePath.Contains("/health")) - { - return; // Don't send - } - - Next.Process(item); - } -} - -// Registration -services.Configure(config => -{ - var builder = config.DefaultTelemetrySink.TelemetryProcessorChainBuilder; - builder.Use(next => new MyTelemetryProcessor(next)); - builder.Build(); -}); -``` - -**After (3.x) - Using OpenTelemetry Processor:** -```csharp -using System.Diagnostics; -using OpenTelemetry; - -public class FilteringActivityProcessor : BaseProcessor -{ - public override void OnEnd(Activity activity) - { - // Filter out requests to health check endpoint - if (activity.DisplayName.Contains("/health") || - activity.GetTagItem("url.path")?.ToString()?.Contains("/health") == true) - { - // Mark as not recorded to prevent export - activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; - } - } -} - -// Registration -builder.Services.AddApplicationInsightsTelemetry(); -builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => -{ - builder.AddProcessor(); -}); -``` - -> **Note**: For filtering, also consider using instrumentation options like `AspNetCoreTraceInstrumentationOptions.Filter` for better performance. - -**Example: Enriching with User Context** - -**Before (2.x) - Using ITelemetryInitializer:** -```csharp -public class UserTelemetryInitializer : ITelemetryInitializer -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public UserTelemetryInitializer(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public void Initialize(ITelemetry telemetry) - { - var context = _httpContextAccessor.HttpContext; - if (context?.User?.Identity?.IsAuthenticated == true) - { - telemetry.Context.User.AuthenticatedUserId = context.User.Identity.Name; - } - } -} -``` - -**After (3.x) - Using OpenTelemetry Processor:** -```csharp -using System.Diagnostics; -using Microsoft.AspNetCore.Http; -using OpenTelemetry; - -public class UserActivityProcessor : BaseProcessor -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public UserActivityProcessor(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public override void OnStart(Activity activity) - { - var context = _httpContextAccessor.HttpContext; - if (context?.User?.Identity?.IsAuthenticated == true) - { - activity.SetTag("enduser.id", context.User.Identity.Name); - } - } -} - -// Registration (processor with dependencies) -builder.Services.AddHttpContextAccessor(); -builder.Services.AddApplicationInsightsTelemetry(); -builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => -{ - var httpContextAccessor = sp.GetRequiredService(); - builder.AddProcessor(new UserActivityProcessor(httpContextAccessor)); -}); -``` - -**Example: Processing Logs (Traces, Events, Exceptions)** - -**Before (2.x) - Using ITelemetryInitializer (applies to all types):** -```csharp -public class MyTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - // Applied to requests, dependencies, traces, events, exceptions, etc. - telemetry.Context.GlobalProperties["Version"] = "1.0.0"; - - if (telemetry is TraceTelemetry trace) - { - trace.Properties["ProcessedBy"] = "MyInitializer"; - } - - if (telemetry is EventTelemetry evt) - { - evt.Properties["ProcessedBy"] = "MyInitializer"; - } - } -} -``` - -**After (3.x) - Using Enrichment at Log Time:** -```csharp -using Microsoft.Extensions.Logging; - -// Define compile-time logging methods with structured properties -internal static partial class LoggerExtensions -{ - [LoggerMessage(LogLevel.Information, "Processing request for CustomerId: `{customerId}`, Version: `{version}`")] - public static partial void LogProcessingRequest(this ILogger logger, string customerId, string version); -} - -// Usage -_logger.LogProcessingRequest(GetCustomerId(), "1.0.0"); -``` - -**Alternative - Using Log Scopes for Context:** -```csharp -using Microsoft.Extensions.Logging; -using OpenTelemetry.Logs; - -// Enable scopes -builder.Services.Configure(options => -{ - options.IncludeScopes = true; -}); - -// Use scopes to add context to all logs -List> scope = -[ - new("Version", "1.0.0"), - new("ProcessedBy", "MyLogProcessor") -]; - -// Define logging methods -internal static partial class LoggerExtensions -{ - [LoggerMessage(LogLevel.Information, "This log will include scope properties")] - public static partial void LogWithScopeInfo(this ILogger logger); - - [LoggerMessage(LogLevel.Warning, "This log will also include scope properties")] - public static partial void LogWithScopeWarning(this ILogger logger); -} - -// Usage -using (_logger.BeginScope(scope)) -{ - _logger.LogWithScopeInfo(); - _logger.LogWithScopeWarning(); -} -``` - -> **Migration Tip**: If your 2.x initializer/processor handled multiple telemetry types, you'll need to create separate processors in 3.x: -> - Activity Processor for Request/Dependency telemetry -> - Log Processor for Trace/Event/Exception telemetry (logged via ILogger) -> - Use TelemetryClient shim for backward compatibility with TrackEvent(), TrackTrace(), TrackException() -``` - -#### Step 4: Replace RequestCollectionOptions - -**Before (2.x):** -```csharp -services.AddApplicationInsightsTelemetry(options => -{ - options.RequestCollectionOptions.TrackExceptions = true; - options.RequestCollectionOptions.InjectResponseHeaders = true; -}); -``` - -**After (3.x):** - -Use OpenTelemetry instrumentation options: - -```csharp -builder.Services.AddApplicationInsightsTelemetry(); - -builder.Services.Configure(options => -{ - options.RecordException = true; - options.Filter = (httpContext) => - { - // Custom filtering logic - return true; - }; -}); -``` - -#### Step 5: Update Custom Telemetry Code - -For new code, consider using OpenTelemetry APIs instead of TelemetryClient: - -**Custom Traces:** - -**Before (2.x):** -```csharp -_telemetryClient.TrackTrace("My trace message"); -``` - -**After (3.x) - Using TelemetryClient (backward compatible):** -```csharp -_telemetryClient.TrackTrace("My trace message"); -``` - -**After (3.x) - Using OpenTelemetry (recommended for new code):** -```csharp -// Define compile-time logging method -internal static partial class LoggerExtensions -{ - [LoggerMessage(LogLevel.Information, "My trace message")] - public static partial void LogMyTrace(this ILogger logger); -} - -// Usage -_logger.LogMyTrace(); -``` - -**Custom Metrics:** - -**Before (2.x):** -```csharp -_telemetryClient.TrackMetric("MyMetric", 42); -``` - -**After (3.x) - Using TelemetryClient (backward compatible):** -```csharp -_telemetryClient.TrackMetric("MyMetric", 42); -``` - -**After (3.x) - Using OpenTelemetry (recommended for new code):** -```csharp -// Create a Meter -private static readonly Meter MyMeter = new Meter("MyCompany.MyProduct"); -private static readonly Counter MyCounter = MyMeter.CreateCounter("MyMetric"); - -// Use it -MyCounter.Add(42); -``` - -**Custom Activities/Spans:** - -**Before (2.x):** -```csharp -var operation = _telemetryClient.StartOperation("MyOperation"); -try -{ - // Do work -} -finally -{ - _telemetryClient.StopOperation(operation); -} -``` - -**After (3.x) - Using TelemetryClient (backward compatible):** -```csharp -var operation = _telemetryClient.StartOperation("MyOperation"); -try -{ - // Do work -} -finally -{ - _telemetryClient.StopOperation(operation); -} -``` - -**After (3.x) - Using OpenTelemetry (recommended for new code):** -```csharp -// Create an ActivitySource -private static readonly ActivitySource MyActivitySource = new ActivitySource("MyCompany.MyProduct"); - -// Register it with OpenTelemetry -builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => -{ - builder.AddSource("MyCompany.MyProduct"); -}); - -// Use it -using var activity = MyActivitySource.StartActivity("MyOperation"); -// Do work -``` - -#### Step 6: Test Thoroughly - -After migrating, thoroughly test your application to ensure: -- Telemetry is being collected and sent to Azure Monitor -- Custom telemetry is working as expected -- Performance is acceptable -- All required telemetry signals (traces, metrics, logs) are being captured - -### Migration Checklist - -- [ ] Update package reference to 3.x -- [ ] Replace InstrumentationKey with ConnectionString -- [ ] Remove all ITelemetryInitializer implementations -- [ ] Remove all ITelemetryProcessor implementations -- [ ] Remove all custom ITelemetryModule implementations -- [ ] Replace RequestCollectionOptions with AspNetCoreTraceInstrumentationOptions -- [ ] Test all custom telemetry collection -- [ ] Verify Live Metrics is working (if enabled) -- [ ] Verify all expected telemetry appears in Azure Monitor -- [ ] Consider migrating custom telemetry to OpenTelemetry APIs for new code - -## Troubleshooting - -### Self-Diagnostics - -OpenTelemetry provides a [self-diagnostics feature](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/README.md#troubleshooting) to collect internal logs. - -To enable self-diagnostics, create a configuration file at your application's directory: - -**OTEL_DIAGNOSTICS.json** -```json -{ - "LogDirectory": ".", - "FileSize": 1024, - "LogLevel": "Warning" -} -``` - -### Azure SDK Instrumentation - -Azure SDK instrumentation is supported under the experimental feature flag which can be enabled using one of the following ways: - -* Set the `AZURE_EXPERIMENTAL_ENABLE_ACTIVITY_SOURCE` environment variable to `true`. - -* Set the Azure.Experimental.EnableActivitySource context switch to true in your app's code: - ```csharp - AppContext.SetSwitch("Azure.Experimental.EnableActivitySource", true); - ``` - -* Add the RuntimeHostConfigurationOption setting to your project file: - ```xml - - - - ``` - -## Repository Structure - -``` -NETCORE\ - ApplicationInsights.AspNetCore.sln - Main Solution - - src\ - Microsoft.ApplicationInsights.AspNetCore - Application Insights for ASP.NET Core - Microsoft.ApplicationInsights.WorkerService - Application Insights for Worker Services - Shared - Shared code between packages - - test\ - Microsoft.ApplicationInsights.AspNetCore.Tests - Unit tests - FunctionalTestUtils - Test utilities for functional tests - MVCFramework.FunctionalTests - Functional tests for MVC applications - WebApi.FunctionalTests - Functional tests for Web API applications - EmptyApp.FunctionalTests - Functional tests for empty applications - PerfTest - Performance tests -``` - -## Contributing - -See [CONTRIBUTING.md](https://github.com/microsoft/ApplicationInsights-dotnet/blob/main/CONTRIBUTING.md) for details on contribution process. - -## Additional Resources - -- [Application Insights Documentation](https://docs.microsoft.com/azure/azure-monitor/app/asp-net-core) -- [OpenTelemetry .NET Documentation](https://github.com/open-telemetry/opentelemetry-dotnet) -- [Azure Monitor OpenTelemetry Exporter](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter) -- [Migration Guide for OpenTelemetry](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-dotnet-migrate?tabs=aspnetcore) - -## Support - -If you encounter any issues or have questions: -- Check the [troubleshooting guide](https://learn.microsoft.com/azure/azure-monitor/app/asp-net-core#troubleshooting) -- Review [GitHub Issues](https://github.com/microsoft/ApplicationInsights-dotnet/issues) -- Consult [Microsoft Q&A](https://learn.microsoft.com/answers/tags/azure-monitor/) - --- - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/NETCORE/WorkerService.md b/NETCORE/WorkerService.md index b30474787e..f7a68e84fd 100644 --- a/NETCORE/WorkerService.md +++ b/NETCORE/WorkerService.md @@ -112,13 +112,29 @@ The connection string can be configured in multiple ways (listed in order of pre ### ApplicationInsightsServiceOptions -The same configuration options available in ASP.NET Core apply to Worker Services: +Most configuration options available in ASP.NET Core also apply to Worker Services, except for request-specific options: + +- `EnableRequestTrackingTelemetryModule` +- `EnableAuthenticationTrackingJavaScript` +- `RequestCollectionOptions` ```csharp builder.Services.AddApplicationInsightsTelemetryWorkerService(options => { options.ConnectionString = "InstrumentationKey=..."; options.EnableQuickPulseMetricStream = true; + + // Rate-limited sampling: maximum traces per second (default: 5) + // Use this for rate-based sampling to limit telemetry volume + options.TracesPerSecond = 5.0; + + // Percentage-based sampling: ratio of telemetry to collect (0.0 to 1.0) + // Use this instead of TracesPerSecond for percentage-based sampling + // options.SamplingRatio = 0.5f; // 50% of telemetry + + // Enable or disable trace-based log sampling (default: true) + // When true, logs are sampled based on the sampling decision of the associated trace + options.EnableTraceBasedLogsSampler = true; }); ``` @@ -174,22 +190,11 @@ All advanced configuration options from ASP.NET Core are available for Worker Se For detailed examples and guidance, see the [ASP.NET Core Advanced Configuration documentation](Readme.md#advanced-configuration). -## Migration from 2.x to 3.x - -The migration guidance for ASP.NET Core also applies to Worker Services. The key difference is the method name: - -- **2.x**: `AddApplicationInsightsTelemetryWorkerService()` -- **3.x**: `AddApplicationInsightsTelemetryWorkerService()` (same name, but now OpenTelemetry-based) - -For complete migration steps, breaking changes, and examples, see the [ASP.NET Core Migration Guide](Readme.md#migration-from-2x-to-3x). - ## Examples Complete working examples are available in the repository: - [Worker Service Example](../examples/WorkerService/) -- [Background Tasks with Hosted Service Example](../examples/BackgroundTasksWithHostedService/) -- [Console Application Example](../examples/ConsoleApp/) ## Key Differences from ASP.NET Core @@ -201,24 +206,4 @@ Complete working examples are available in the repository: | HTTP Client Instrumentation | ✅ Included | ✅ Included | | SQL Client Instrumentation | ✅ Included | ✅ Included | | Live Metrics | ✅ Supported | ✅ Supported | -| Custom Telemetry | ✅ TelemetryClient + OTel APIs | ✅ TelemetryClient + OTel APIs | - -## Troubleshooting - -For troubleshooting guidance including self-diagnostics and Azure SDK instrumentation, see the [ASP.NET Core Troubleshooting section](Readme.md#troubleshooting). - -## Additional Resources - -- [ASP.NET Core Documentation](Readme.md) - Most documentation applies to Worker Services as well -- [Application Insights Documentation](https://docs.microsoft.com/azure/azure-monitor/app/worker-service) -- [OpenTelemetry .NET Documentation](https://github.com/open-telemetry/opentelemetry-dotnet) -- [Azure Monitor OpenTelemetry Exporter](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter) - -## Support - -If you encounter any issues or have questions: -- Check the [ASP.NET Core troubleshooting guide](Readme.md#troubleshooting) -- Review [GitHub Issues](https://github.com/microsoft/ApplicationInsights-dotnet/issues) -- Consult [Microsoft Q&A](https://learn.microsoft.com/answers/tags/azure-monitor/) - ---- \ No newline at end of file +| Custom Telemetry | ✅ TelemetryClient + OpenTelemetry APIs | ✅ TelemetryClient + OpenTelemetry APIs | diff --git a/Readme.md b/Readme.md index 5374283ab0..b509d3ad60 100644 --- a/Readme.md +++ b/Readme.md @@ -3,18 +3,25 @@ This is the .NET SDK for sending data to [Azure Monitor](https://docs.microsoft.com/azure/azure-monitor/overview) & [Application Insights](https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview). -## Getting Started -Please review our How-to guides to review which packages are appropriate for your project: +- **Built on OpenTelemetry**: The SDK now uses [OpenTelemetry](https://opentelemetry.io/) as the underlying telemetry collection framework with the [Azure Monitor Exporter](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter) for transmission. +- **OpenTelemetry Extensibility**: You can extend telemetry collection using standard OpenTelemetry patterns (Activity Processors, Resource Detectors, custom instrumentation). +- **Unified Observability**: Seamlessly integrates with the broader OpenTelemetry ecosystem, allowing you to send telemetry to multiple backends. -* [Console App](https://docs.microsoft.com/azure/azure-monitor/app/console) -* [ASP.NET](https://docs.microsoft.com/azure/azure-monitor/app/asp-net) -* [ASP.NET Core](https://docs.microsoft.com/azure/azure-monitor/app/asp-net-core) -* [WorkerService](https://docs.microsoft.com/azure/azure-monitor/app/worker-service) +See [breaking changes](BreakingChanges.md) for more information on what has changed between versions 2.x and 3.x. + +## Quick Start: Choose Your Path + +Select the option that best describes your situation: + +- **Building an ASP.NET Core web application?** → Use the [ASP.NET Core SDK](../NETCORE/Readme.md) for automatic instrumentation +- **Building a Worker Service, console app, or background service?** → Use the [Worker Service SDK](../NETCORE/WorkerService.md) for simplified configuration +- **Need the core TelemetryClient API for custom scenarios?** → Use the [base SDK](../BASE/README.md) +- **Need compatibility with NLog?** -> Use the [Logging SDK](../LOGGING/README.md) ### Understanding our SDK -We've gathered a list of concepts, code examples, and links to full guides [here](docs/concepts.md). +We've gathered a list of concepts [here](docs/concepts.md). ## Contributing @@ -24,6 +31,7 @@ Please review our [Contributing guide](.github/CONTRIBUTING.md). ## Branches - [main](https://github.com/Microsoft/ApplicationInsights-dotnet/tree/master) is the default branch for all development and releases. +- [2.x] (https://github.com/microsoft/ApplicationInsights-dotnet/tree/2.x) is the branch for the previous 2.x release. ## Releases diff --git a/WEB/Readme.md b/WEB/Readme.md index e450d21f22..a8828292e0 100644 --- a/WEB/Readme.md +++ b/WEB/Readme.md @@ -39,17 +39,16 @@ See the [Migration Guide](#migrating-from-2x-to-3x) for detailed upgrade instruc - [Installation](#installation) - [Configuration](#configuration) - [Using TelemetryClient](#using-telemetryclient) + - [Recommended Pattern: Initialize in Global.asax.cs](#recommended-pattern-initialize-in-globalasaxcs) + - [Use the Shared Instance in Controllers](#use-the-shared-instance-in-controllers) - [Advanced Configuration](#advanced-configuration) - [Customizing Telemetry Collection](#customizing-telemetry-collection) - - [Adding Custom Properties](#adding-custom-properties) + - [Filtering Telemetry](#filtering-telemetry) - [Performance Counters](#performance-counters) - [Migrating from 2.x to 3.x](#migrating-from-2x-to-3x) - [Migration Steps](#migration-steps) - [Configuration Changes](#configuration-changes) - - [Replacing Telemetry Initializers](#replacing-telemetry-initializers) -- [Architecture](#architecture) -- [Troubleshooting](#troubleshooting) -- [Contributing](#contributing) + - [Replacing Telemetry Initializers and Processors](#replacing-telemetry-initializers-and-processors) ## Getting Started @@ -179,8 +178,6 @@ public class MvcApplication : System.Web.HttpApplication TelemetryClient = new TelemetryClient(configuration); // Optionally set properties that apply to all telemetry - TelemetryClient.Context.Cloud.RoleName = "MyWebApp"; - TelemetryClient.Context.Component.Version = "1.0.0"; TelemetryClient.Context.GlobalProperties["Environment"] = "Production"; // Your other startup code @@ -269,8 +266,6 @@ protected void Application_Start() var telemetry = new TelemetryClient(configuration); // Set properties that apply to all telemetry - telemetry.Context.Cloud.RoleName = "MyWebApp"; - telemetry.Context.Component.Version = "1.0.0"; telemetry.Context.GlobalProperties["Environment"] = "Production"; } ``` @@ -283,7 +278,7 @@ In version 3.x, telemetry filtering is handled through OpenTelemetry processors. To exclude specific URL patterns (like health checks), you would need to configure OpenTelemetry processors. For most ASP.NET Framework applications, the simplest approach is to handle filtering at the infrastructure level (load balancer health checks) rather than in code. -If you need custom filtering logic, see the [BASE SDK documentation](../BASE/README.md#enriching-telemetry-with-activity-processors) for details on implementing Activity Processors. +If you need custom filtering logic, see the [concepts documentation](../docs/concepts.md#filtering-telemetry) for details on implementing Activity Processors. ### Performance Counters @@ -362,9 +357,7 @@ The internal instrumentation has changed significantly. Test your application to In 2.x, `ITelemetryInitializer` and `ITelemetryProcessor` were used to enrich and filter telemetry. In 3.x, these are replaced by OpenTelemetry Activity Processors. -#### Simple Property Enrichment - -For basic property setting, use `TelemetryClient.Context` properties: +#### Cloud Role Name example **2.x Telemetry Initializer:** ```csharp @@ -386,11 +379,19 @@ using Microsoft.ApplicationInsights.Extensibility; protected void Application_Start() { var configuration = TelemetryConfiguration.CreateDefault(); + + // Set cloud role via OpenTelemetry Resource attributes BEFORE creating TelemetryClient + configuration.ConfigureOpenTelemetryBuilder(builder => + { + builder.ConfigureResource(resource => resource.AddAttributes(new[] + { + new KeyValuePair("service.name", "WebApp"), // Maps to Cloud.RoleName + })); + }); + var telemetry = new TelemetryClient(configuration); - // Set properties that apply to all telemetry - telemetry.Context.Cloud.RoleName = "WebApp"; - telemetry.Context.Component.Version = "1.0.0"; + // GlobalProperties still work for custom properties on all telemetry telemetry.Context.GlobalProperties["Environment"] = "Production"; } ``` @@ -486,8 +487,6 @@ public class MvcApplication : System.Web.HttpApplication // Create TelemetryClient with configured TelemetryConfiguration TelemetryClient = new TelemetryClient(configuration); - // Set common properties - TelemetryClient.Context.Cloud.RoleName = "MyWebApp"; } protected void Application_End() @@ -496,94 +495,4 @@ public class MvcApplication : System.Web.HttpApplication System.Threading.Tasks.Task.Delay(1000).Wait(); } } -``` - -**Required NuGet Packages:** - -The `Microsoft.ApplicationInsights.Web` package already includes the necessary OpenTelemetry dependencies. No additional packages are required for basic Activity Processor functionality. - -**Key Differences:** -- **2.x**: Used `ITelemetryProcessor` and `ITelemetryInitializer` with Application Insights SDK -- **3.x**: Uses OpenTelemetry `BaseProcessor` with Activity-based telemetry -- **Filtering**: In 2.x, return early; in 3.x, clear `ActivityTraceFlags.Recorded` flag -- **Enrichment**: In 2.x, set properties on `ITelemetry`; in 3.x, use `Activity.SetTag()` -- **Registration**: In 2.x, configured in `ApplicationInsights.config`; in 3.x, registered via OpenTelemetry SDK builder - -> **Note:** For most scenarios, simple property enrichment using `TelemetryClient.Context` is sufficient. Only implement custom Activity Processors if you need complex filtering, sampling, or dynamic enrichment logic. - -See the [BASE SDK documentation](../BASE/README.md#enriching-telemetry-with-activity-processors) for more examples of Activity Processors. - -See [BreakingChanges.md](../../BreakingChanges.md) for additional migration details. - -## Architecture - -The 3.x SDK is built on [OpenTelemetry](https://opentelemetry.io/) and uses the following architecture: - -``` -┌─────────────────────────────────────────────────────────┐ -│ ASP.NET Framework Web Application │ -├─────────────────────────────────────────────────────────┤ -│ HTTP Modules (ApplicationInsightsHttpModule) │ -│ ↓ Tracks incoming requests │ -├─────────────────────────────────────────────────────────┤ -│ TelemetryClient API (Compatibility Layer) │ -│ ↓ Translates to OpenTelemetry primitives │ -├─────────────────────────────────────────────────────────┤ -│ OpenTelemetry SDK │ -│ • Activity (Traces/Spans) │ -│ • LogRecord (Logs) │ -│ • Metrics │ -├─────────────────────────────────────────────────────────┤ -│ OpenTelemetry Instrumentation │ -│ • ASP.NET (HTTP requests) │ -│ • SqlClient (SQL dependencies) │ -│ • HttpClient (HTTP dependencies) │ -├─────────────────────────────────────────────────────────┤ -│ Activity Processors │ -│ • Enrichment (user, session, synthetic traffic) │ -│ • Filtering │ -│ • Sampling │ -├─────────────────────────────────────────────────────────┤ -│ Azure Monitor Exporter │ -│ ↓ Converts to Application Insights schema │ -├─────────────────────────────────────────────────────────┤ -│ Azure Monitor / Application Insights │ -└─────────────────────────────────────────────────────────┘ -``` - -**Key Components:** - -- **HTTP Modules**: Intercept HTTP requests and responses for automatic tracking -- **OpenTelemetry Instrumentation**: Automatically collects HTTP requests, SQL dependencies, and outgoing HTTP calls -- **Activity Processors**: Enrich telemetry with web-specific context (user ID, session ID, synthetic traffic detection) -- **Azure Monitor Exporter**: Converts OpenTelemetry signals to Application Insights format and sends to Azure Monitor -- **TelemetryClient API**: Compatibility layer for sending custom telemetry - -The SDK maintains backward compatibility with the TelemetryClient API while using OpenTelemetry internally for data collection and transmission. - -## Troubleshooting - -### Telemetry Not Appearing in Portal - -1. **Verify Connection String**: Check that ApplicationInsights.config contains the correct connection string with both InstrumentationKey and IngestionEndpoint. - -2. **Check HTTP Module Registration**: Ensure the HTTP modules are registered in web.config (should be added automatically by NuGet). - -3. **Verify Network Connectivity**: Ensure your server can reach the ingestion endpoint (typically `https://*.in.applicationinsights.azure.com`). - -4. **Check Application Pool Identity**: Ensure the application pool identity has network access to send telemetry. - -5. **Review IIS Logs**: Check IIS logs for any errors during module initialization. - -## Contributing - -We strongly welcome and encourage contributions to this project. Please read the general [contributor's guide][ContribGuide] located in the ApplicationInsights-Home repository. If making a large change we request that you open an [issue][GitHubIssue] first. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -> **Note:** For classic Application Insights SDK (version 2.x), refer to the [2.x branch documentation](https://github.com/microsoft/ApplicationInsights-dotnet/tree/2.x). - -[AILandingPage]: https://azure.microsoft.com/services/application-insights/ -[AzurePortal]: https://portal.azure.com/ -[ContribGuide]: https://github.com/Microsoft/ApplicationInsights-Home/blob/master/CONTRIBUTING.md -[GitHubIssue]: https://github.com/Microsoft/ApplicationInsights-dotnet/issues/ +``` \ No newline at end of file diff --git a/WEB/Src/Web/README.md b/WEB/Src/Web/README.md index abe3761144..4c43c45f42 100644 --- a/WEB/Src/Web/README.md +++ b/WEB/Src/Web/README.md @@ -40,4 +40,4 @@ public class Global : HttpApplication For more information, see the [Azure.Identity documentation](https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme). ### Sampling, Offline Storage, and other configuration -Other options can also be set via the TelemetryConfiguration in the `Global.asax.cs` file. See [documentation for Microsoft.ApplicationInsights](../../../BASE/README.smd#azure-monitor-exporter-options). \ No newline at end of file +Other options can also be set via the TelemetryConfiguration in the `Global.asax.cs` file. See [documentation for Microsoft.ApplicationInsights](../../../BASE/README.md#telemetry-configuration-properties). These properties are also configurable via applicationinsights.config. \ No newline at end of file diff --git a/docs/concepts.md b/docs/concepts.md index 0919f29f69..010d9b7041 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -1,62 +1,260 @@ # Application Insights DotNet SDK Concepts This lists the high level concepts of the AI DotNet SDK and links to detailed guides to help you get started. -To use the Application Insights SDK you must configure an Instrumentation Key which can be [obtained from an Application Insights resource](https://docs.microsoft.com/azure/azure-monitor/app/create-new-resource). -Or you can use a [Connection string](https://docs.microsoft.com/azure/azure-monitor/app/sdk-connection-string?tabs=net) to simplify the configuration of our endpoints. -Both an Instrumentation Key and Connection String are provided for you on the Overivew Dashboard of your Application Insights resource. +## Connection String +The connection string identifies the application insights resource to send telemetry to. Read more [here](https://learn.microsoft.com/en-us/azure/azure-monitor/app/connection-strings). ## TelemetryClient -The `TelemetryClient` object is the primary root object for the library. -Almost all functionality around telemetry sending is located on this object. +The `TelemetryClient` class provides methods for sending different types of telemetry. Read more [here](../BASE/README.md#using-telemetryclient). -### Initialization -You must initialize an instance of this object and populate it with your Instrumentation Key to identify your data. +## TelemetryConfiguration +TelemetryConfiguration provides a mechanism to configure certain settings on the telemetry client, such as: +- The connection string +- Sampling settings +- AAD authentication +- Offline storage -```C# -using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.Extensibility; +Read more [here](../BASE/README.md#configuration). +In addition, these settings are configurable via applicationinsights.config and will soon be a part of the schema for appsettings.json as well. + +## OpenTelemetry + +### OpenTelemetry vocabulary +- Traces/Spans: See [this documentation](https://opentelemetry.io/docs/concepts/signals/traces/). This is not to be confused with Application Insights traces, which are analogous to OpenTelemetry logs in ApplicationInsights 3.x. +- ActivitySource: An `ActivitySource` is OpenTelemetry's mechanism for creating distributed trace spans (called `Activity` in .NET). Think of it as a factory that creates telemetry for a specific component or subsystem in your application. By default, OpenTelemetry only collects Activities from sources you explicitly register. When you create a custom `ActivitySource` in your code, you must register its name (or name pattern) so the SDK knows to collect telemetry from it. +- [Logs](https://opentelemetry.io/docs/concepts/signals/logs/) +- [Metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) +- [Processors](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/docs/trace/extending-the-sdk#processor). These are meant to replace custom TelemetryInitializers/Modules & Filtering. +- Samplers: Allow you to configure the amount of telemetry you can send. In this SDK, we have not yet implented the ability to use [baked-in OpenTelemetry samplers](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/docs/trace/extending-the-sdk#sampler), though we provide settings via TelemetryConfiguration to use our Application Insights percentage based sampler or our custom rate-limited sampler. +- [Resource detectors](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/docs/resources/README.md) + +Application Insights 3.x is built on **OpenTelemetry**, an industry-standard observability framework. Understanding this foundation will help you make better decisions about when to use `TelemetryClient` versus native OpenTelemetry APIs. + +### Architecture Overview + +``` +┌─────────────────────────────────────────────────────────┐ +│ Your Application Code │ +├─────────────────────────────────────────────────────────┤ +│ TelemetryClient API (Compatibility Layer) │ +│ ↓ Translates to OpenTelemetry primitives │ +├─────────────────────────────────────────────────────────┤ +│ OpenTelemetry SDK │ +│ • Activity (Traces/Spans) │ +│ • LogRecord (Logs) │ +│ • Metrics │ +│ • Resource Detectors (run at startup) │ +├─────────────────────────────────────────────────────────┤ +│ Activity Processors / Log Processors │ +│ • Enrichment │ +│ • Filtering │ +│ • Sampling │ +├─────────────────────────────────────────────────────────┤ +│ Azure Monitor Exporter │ +│ ↓ Converts to Application Insights schema │ +├─────────────────────────────────────────────────────────┤ +│ Azure Monitor / Application Insights │ +└─────────────────────────────────────────────────────────┘ +``` + +**Key Mappings:** +- `TrackEvent()` → `LogRecord` with custom event marker +- `TrackDependency()` → `Activity` with `ActivityKind.Client` (outbound calls to external services) +- `TrackRequest()` → `Activity` with `ActivityKind.Server` (inbound requests) +- `TrackException()` → `LogRecord` with exception +- `TrackTrace()` → `LogRecord` +- `TrackMetric()` → OpenTelemetry Histogram + +**When using OpenTelemetry Activity directly, choose the appropriate ActivityKind:** +- `ActivityKind.Client` - Outbound synchronous calls (HTTP requests, database queries, cache calls) +- `ActivityKind.Server` - Inbound synchronous requests (API endpoints, RPC handlers) +- `ActivityKind.Producer` - Outbound asynchronous messages (publishing to queue/topic) +- `ActivityKind.Consumer` - Inbound asynchronous messages (consuming from queue/topic) +- `ActivityKind.Internal` - Internal operations within your application (not crossing process boundaries) + + +### Custom Instrumentation + +You can create custom distributed trace spans using OpenTelemetry's `ActivitySource`. This is useful for tracking operations within your application that aren't automatically instrumented. -var configuration = new TelemetryConfiguration +> **Note:** Before using `ActivitySource`, make sure you understand the concept. See [Understanding ActivitySource](#understanding-activitysource) in the Configuration section. + +**Example: Custom instrumentation for a data service** + +```csharp +using System.Diagnostics; + +public class DataService { - ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000", -}; -var tc = new TelemetryClient(configuration); + // 1. Create a static ActivitySource with a descriptive name + private static readonly ActivitySource ActivitySource = new("MyApp.DataService"); + + public async Task GetUserAsync(string userId) + { + // 2. Start an Activity to track this operation + using var activity = ActivitySource.StartActivity("GetUser"); + + // 3. Add tags (attributes) to provide context + activity?.SetTag("user.id", userId); + activity?.SetTag("db.system", "postgresql"); + + var user = await _database.GetUserAsync(userId); + + activity?.SetTag("user.found", user != null); + + return user; + } +} ``` -### Using the TelemetryClient to send telemetry -You can populate common context on the `TelemetryClient.context` property which will be automatically attached to each telemetry item sent. -You can also attach additional property data to each telemetry item sent. -The `TelemetryClient` also exposes several `Track` methods that can be used to send all telemetry types understood by the Application Insights service. Some example use cases are shown below. +**Register the ActivitySource in TelemetryConfiguration:** -Please review the full [API summary for custom events and metrics](https://docs.microsoft.com/azure/azure-monitor/app/api-custom-events-metrics) for more examples. +```csharp +configuration.ConfigureOpenTelemetryBuilder(builder => +{ + builder.WithTracing(tracing => + { + // Register by exact name + tracing.AddSource("MyApp.DataService"); + + // Or use wildcards to register multiple sources at once + tracing.AddSource("MyApp.*"); + }); +}); +``` -```C# -tc.TrackTrace(message: "Custom message."); - -tc.TrackEvent( - eventName: "PurchaseOrderSubmitted", - properties: new Dictionary() { { "CouponCode", "JULY2015" } } - ); - -try +**What gets sent to Application Insights?** + +When you call `StartActivity()`, OpenTelemetry creates a span that: +- Appears as a **Dependency** in Application Insights (if started within a request context) +- Includes all tags as **Custom Properties** +- Captures duration automatically +- Links to parent operations for end-to-end tracing + +**Naming Conventions:** + +Use hierarchical naming for your ActivitySources to make wildcard registration easier: +- `MyCompany.OrderService` ✓ +- `MyCompany.OrderService.Validation` ✓ +- `MyCompany.InventoryService` ✓ + +Then register with: `builder.WithTracing(tracing => tracing.AddSource("MyCompany.*"))` + +### Advanced Scenarios + +Let's explore advanced scenarios for enriching, filtering, and optimizing your telemetry collection. These techniques leverage OpenTelemetry's extensibility model to give you fine-grained control over what telemetry is collected and how it's processed. + +#### Enriching Telemetry with Activity Processors + +Activity Processors replace `ITelemetryInitializer` from version 2.x. They enrich or modify telemetry before export: + +```csharp +using System.Diagnostics; +using OpenTelemetry; + +public class CustomEnrichmentProcessor : BaseProcessor { - // do something + public override void OnEnd(Activity activity) + { + // Add custom tags to all activities + activity?.SetTag("app.environment", "Production"); + activity?.SetTag("app.version", "1.2.3"); + + // Conditionally enrich + if (activity?.OperationName == "ProcessOrder") + { + activity?.SetTag("business.critical", "true"); + } + + // Add resource information + activity?.SetTag("host.name", Environment.MachineName); + } } -catch(Exception ex) +``` + +**Register the processor:** + +```csharp +configuration.ConfigureOpenTelemetryBuilder(builder => +{ + builder.WithTracing(tracing => tracing.AddProcessor()); +}); +``` + +#### Filtering Telemetry + +Filter out unwanted telemetry to reduce volume and costs: + +```csharp +public class FilteringProcessor : BaseProcessor { - tc.TrackException(ex); + public override void OnEnd(Activity activity) + { + // Filter out health check requests + if (activity?.DisplayName?.Contains("/health") == true) + { + activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; + return; + } + + // Filter out specific dependencies + if (activity?.Kind == ActivityKind.Client && + activity?.GetTagItem("http.url")?.ToString()?.Contains("internal-service") == true) + { + activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; + } + } } -``` +``` + +**Register the processor:** + +```csharp +configuration.ConfigureOpenTelemetryBuilder(builder => +{ + builder.WithTracing(tracing => tracing.AddProcessor()); +}); +``` + +#### Resource Detectors -## Telemetry correlation -Application Insights supports distributed telemetry correlation, which you use to detect which component is responsible for failures or performance degradation. +Resource Detectors can add contextual information to all telemetry: -Please review our full guide on [Telemetry correlation in Application Insights](https://docs.microsoft.com/azure/azure-monitor/app/correlation). +```csharp +using OpenTelemetry.Resources; +public class CustomResourceDetector : IResourceDetector +{ + public Resource Detect() + { + var attributes = new Dictionary + { + { "service.name", "OrderProcessingService" }, + { "service.version", "1.2.3" }, + { "deployment.environment", "Production" }, + { "service.instance.id", Environment.MachineName }, + { "custom.datacenter", "WestUS" } + }; + + return new Resource(attributes); + } +} +``` -## Sampling -Sampling is the recommended way to reduce telemetry traffic, data costs, and storage costs, while preserving a statistically correct analysis of application data. +Resource detectors are typically used to enrich telemetry by detecting the specific environment an application is running in - as an example, this SDK internally implements its own resource detector that determines whether it is an aspnetcore application and will decorate the telemetry accordingly. +**Register the detector:** + +```csharp +configuration.ConfigureOpenTelemetryBuilder(builder => +{ + builder.ConfigureResource(resourceBuilder => + { + resourceBuilder.AddDetector(new CustomResourceDetector()); + }); +}); +``` +--- Please review our full guide on [Sampling in Application Insights](https://docs.microsoft.com/azure/azure-monitor/app/sampling). diff --git a/examples/BasicConsoleApp/Program.cs b/examples/BasicConsoleApp/Program.cs index 782d0c438a..e68f26a22b 100644 --- a/examples/BasicConsoleApp/Program.cs +++ b/examples/BasicConsoleApp/Program.cs @@ -32,7 +32,6 @@ static void Main(string[] args) telemetryClient.TrackEvent("SampleEvent"); telemetryClient.TrackEvent(new EventTelemetry("SampleEventObject")); - telemetryClient.TrackTrace("A trace message"); telemetryClient.TrackTrace("A warning", SeverityLevel.Warning); telemetryClient.TrackTrace("A trace with properties", new System.Collections.Generic.Dictionary { { "Key", "Value" } }); diff --git a/troubleshooting/ETW/Readme.md b/troubleshooting/ETW/Readme.md index 0ccf3670a2..1449b9eacf 100644 --- a/troubleshooting/ETW/Readme.md +++ b/troubleshooting/ETW/Readme.md @@ -116,57 +116,3 @@ StatusMonitor uses TraceEventSession to record ETW logs. - https://github.com/dotnet/roslyn/wiki/Recording-performance-traces-with-PerfView - https://github.com/microsoft/perfview/blob/master/src/TraceEvent/TraceEventSession.cs -### Self-Diagnostics - -As of version 2.18.0, this SDK ships a "self-diagnostics feature" which captures internal events and writes to a log file in a specified directory. - -The self-diagnostics feature can be enabled/changed/disabled while the process is running. -The SDK will attempt to read the configuration file every 10 seconds, using a non-exclusive read-only mode. -The SDK will create or overwrite a file with new logs according to the configuration. -This file will not exceed the configured max size and will be circularly overwritten. - -#### Configuration - -Configuration is controlled by a file named `ApplicationInsightsDiagnostics.json`. -The configuration file must be no more than 4 KiB, otherwise only the first 4 KiB of content will be read. - -**To enable self-diagnostics**, go to the [current working directory](https://en.wikipedia.org/wiki/Working_directory) of your process and create a configuration file. -In most cases, you could just drop the file along your application. -On Windows, you can use [Process Explorer](https://docs.microsoft.com/sysinternals/downloads/process-explorer), -double click on the process to pop up Properties dialog, and find "Current directory" in "Image" tab. -Internally, the SDK looks for the configuration file located in [GetCurrentDirectory](https://docs.microsoft.com/dotnet/api/system.io.directory.getcurrentdirectory), -and then [AppContext.BaseDirectory](https://docs.microsoft.com/dotnet/api/system.appcontext.basedirectory). -You can also find the exact directory by calling these methods from your code. - -**To disable self-diagnostics**, delete the configuration file. - -Example: -```json -{ - "LogDirectory": ".", - "FileSize": 1024, - "LogLevel": "Error" -} -``` - -#### Configuration Parameters - -A `FileSize`-KiB log file named as `YearMonthDay-HourMinuteSecond.ExecutableName.ProcessId.log` (e.g. `20010101-120000.foobar.exe.12345.log`) will be generated at the specified directory `LogDirectory`. -The file name starts with the `DateTime.UtcNow` timestamp of when the file was created. - -1. `LogDirectory` is the directory where the output log file will be stored. -It can be an absolute path or a relative path to the current directory. - -2. `FileSize` is a positive integer, which specifies the log file size in [KiB](https://en.wikipedia.org/wiki/Kibibyte). -This value must be between 1 MiB and 128 MiB (inclusive), or it will be rounded to the closest upper or lower limit. -The log file will never exceed this configured size, and will be circularly rewriten. - -3. `LogLevel` is the lowest level of the events to be captured. -This value must match one of the [fields](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel#fields) of the `EventLevel` enum. -Lower severity levels encompass higher severity levels (e.g. `Warning` includes the `Error` and `Critical` levels). - -**Warning**: If the SDK fails to parse any of these fields, the configuration file will be treated as invalid and self-diagnostics will be disabled. - -## References - -This document is referenced by: https://docs.microsoft.com/azure/azure-monitor/app/asp-net-troubleshoot-no-data#PerfView diff --git a/troubleshooting/Readme.md b/troubleshooting/Readme.md index 0df24cf306..e2a32e3a4b 100644 --- a/troubleshooting/Readme.md +++ b/troubleshooting/Readme.md @@ -7,17 +7,53 @@ You can do so by going online to the [Azure portal](https://portal.azure.com/) a ## SDK Internal Logs -The Application Insights .NET SDK uses ETW to expose internal exceptions. +### Self-Diagnostics -To collect these logs, please review our full guide on [ETW](ETW). +Application Insights 3.x ships a "self-diagnostics feature" which captures internal events and writes to a log file in a specified directory. -## Networking Issues +The self-diagnostics feature can be enabled/changed/disabled while the process is running. +The SDK will attempt to read the configuration file every 10 seconds, using a non-exclusive read-only mode. +The SDK will create or overwrite a file with new logs according to the configuration. +This file will not exceed the configured max size and will be circularly overwritten. -The Application Insights .NET SDK has no knowledge of the environment it's deployed in. -The SDK will send telemetry to the configured endpoint. +#### Configuration -If you suspect networking issues, please review our guide on [Troubleshooting Ingestion](Ingestion). +Configuration is controlled by a file named `ApplicationInsightsDiagnostics.json`. +The configuration file must be no more than 4 KiB, otherwise only the first 4 KiB of content will be read. -## No Data +**To enable self-diagnostics**, go to the [current working directory](https://en.wikipedia.org/wiki/Working_directory) of your process and create a configuration file. +In most cases, you could just drop the file along your application. +On Windows, you can use [Process Explorer](https://docs.microsoft.com/sysinternals/downloads/process-explorer), +double click on the process to pop up Properties dialog, and find "Current directory" in "Image" tab. +Internally, the SDK looks for the configuration file located in [GetCurrentDirectory](https://docs.microsoft.com/dotnet/api/system.io.directory.getcurrentdirectory), +and then [AppContext.BaseDirectory](https://docs.microsoft.com/dotnet/api/system.appcontext.basedirectory). +You can also find the exact directory by calling these methods from your code. -Please review our full guide on [Troubleshooting no data](https://docs.microsoft.com/azure/azure-monitor/app/asp-net-troubleshoot-no-data) +**To disable self-diagnostics**, delete the configuration file. + +Example: +```json +{ + "LogDirectory": ".", + "FileSize": 1024, + "LogLevel": "Error" +} +``` + +#### Configuration Parameters + +A `FileSize`-KiB log file named as `YearMonthDay-HourMinuteSecond.ExecutableName.ProcessId.log` (e.g. `20010101-120000.foobar.exe.12345.log`) will be generated at the specified directory `LogDirectory`. +The file name starts with the `DateTime.UtcNow` timestamp of when the file was created. + +1. `LogDirectory` is the directory where the output log file will be stored. +It can be an absolute path or a relative path to the current directory. + +2. `FileSize` is a positive integer, which specifies the log file size in [KiB](https://en.wikipedia.org/wiki/Kibibyte). +This value must be between 1 MiB and 128 MiB (inclusive), or it will be rounded to the closest upper or lower limit. +The log file will never exceed this configured size, and will be circularly rewritten. + +3. `LogLevel` is the lowest level of the events to be captured. +This value must match one of the [fields](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel#fields) of the `EventLevel` enum. +Lower severity levels encompass higher severity levels (e.g. `Warning` includes the `Error` and `Critical` levels). + +**Warning**: If the SDK fails to parse any of these fields, the configuration file will be treated as invalid and self-diagnostics will be disabled.