Filter OpenTelemetry for .NET, Java, Node.js, and Python applications

Note

For .NET, Node.js, and Python applications:

For Java applications, use the Azure Monitor OpenTelemetry Distro.

Use this guide to filter OpenTelemetry (OTel) data in Azure Monitor Application Insights. Filtering helps you exclude unnecessary telemetry and prevent collection of sensitive data to optimize performance and support compliance.

Use the Microsoft OpenTelemetry Distro for .NET, Node.js, and Python. Java continues to use the Azure Monitor OpenTelemetry Distro. First, enable the distro for your language. The examples that initialize the distro replace the basic initialization; don't initialize a second distro or provider for the same signal.

For Node.js, enable instrumentation before loading application libraries. ESM applications must preload the Microsoft OpenTelemetry Distro loader. Set APPLICATIONINSIGHTS_CONNECTION_STRING before running examples that don't set it in code.

Reasons to filter out telemetry include:

  • Filtering out health check telemetry to reduce noise.
  • Ensuring personal data and credentials aren't collected.
  • Filtering out low-value telemetry to optimize performance.

To learn more about OpenTelemetry concepts, review the OpenTelemetry overview.

Note

For Azure Function Apps, see Use OpenTelemetry with Azure Functions.

Filter OpenTelemetry using instrumentation libraries

For the instrumentation libraries included with each distro, review Automatic data collection and resource detectors.

Many instrumentation libraries provide a filter option. For guidance, review the corresponding readme files:

Note

The Microsoft OpenTelemetry Distro for .NET includes a copy of the SqlClient instrumentation source code while the upstream library remains experimental.

Options on a separately installed SqlClient instrumentation package don't configure the bundled copy. To use that package for custom filtering, disable the bundled instrumentation with options.Instrumentation.EnableSqlClientInstrumentation = false, then register your configured instrumentation once.

See Microsoft OpenTelemetry Distro instrumentation customization.

Filter telemetry using span processors

Use a span processor to filter spans before the exporter sends them to Application Insights.

  1. Use a custom processor:

    Tip

    Add the processor shown here before adding Azure Monitor.

    Filter telemetry using span processors
    // Import the Microsoft OpenTelemetry Distro and supporting APIs.
    using Microsoft.OpenTelemetry;
    using OpenTelemetry.Trace;
    
    // Create the application builder.
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddOpenTelemetry()
      .WithTracing(tracing => tracing
    
        // Collect spans from the application activity source.
        .AddSource("ActivitySourceName")
    
        // Run the custom processor before exporting spans.
        .AddProcessor(new ActivityFilteringProcessor()))
    
      // Configure the Microsoft OpenTelemetry Distro.
      .UseMicrosoftOpenTelemetry(options =>
      {
        options.Exporters = ExportTarget.AzureMonitor;
      });
    
    // Build the application with the configured telemetry services.
    var app = builder.Build();
    
    // Run the application and its telemetry providers.
    app.Run();
    
  2. Add ActivityFilteringProcessor.cs to your project with the following code:

    using System.Diagnostics;
    using OpenTelemetry;
    
    public class ActivityFilteringProcessor : BaseProcessor<Activity>
    {
        // The OnStart method is called when an activity is started. This is the ideal place
        // to filter activities.
        public override void OnStart(Activity activity)
        {
            // prevents all exporters from exporting internal activities
            if (activity.Kind == ActivityKind.Internal)
            {
                activity.IsAllDataRequested = false;
            }
        }
    }
    

If a particular source isn't explicitly added by using AddSource("ActivitySourceName"), then none of the activities created by using that source are exported.

Filter telemetry at ingestion using data collection rules

Reduce noise or standardize telemetry before Azure Monitor stores it in a Log Analytics workspace. To achieve that goal, use ingestion-time transformations in a data collection rule (DCR) to filter or modify telemetry after Azure Monitor receives it.

Transformations use a Kusto Query Language (KQL) statement that runs on each ingested record.

Use a workspace transformation DCR for Application Insights tables. A Log Analytics workspace supports one workspace transformation DCR. Put all transformations for that workspace in the same DCR.

Activation can take up to 60 minutes after an update.

Use these resources to learn more:

Map OpenTelemetry signals to Log Analytics tables

Application Insights stores common OpenTelemetry (OTel) signals in these tables:

  • AppTraces (logs)
  • AppRequests (incoming requests)
  • AppDependencies (outgoing dependencies)
  • AppExceptions (exceptions)
  • AppMetrics (metrics)

In a workspace transformation DCR, use the stream name format Microsoft-Table-<TableName> for each table. For example, use Microsoft-Table-AppRequests for the AppRequests table.

Note

A workspace transformation DCR applies to all data ingested into the selected tables in that Log Analytics workspace. If multiple applications share the same workspace, scope each transformation by using a filter such as AppRoleName or ResourceGUID.

Use workspace transformation DCR samples

The following samples show JSON for a Microsoft.Insights/dataCollectionRules resource with kind set to WorkspaceTransforms. They aren't complete ARM templates or standalone deployment commands. For creation and workspace association, follow the workspace transformation tutorial.

The first example shows a DCR resource request body. The remaining examples are objects or arrays of objects for its properties.dataFlows array. Use one transformation per table and keep each transformKql value on one line.

When updating an existing workspace transformation DCR:

  • If a flow already targets the table, edit that flow's transformKql instead of adding a second flow for the same table. Combine the example with any existing filtering or redaction requirements.
  • Add a data-flow object only for a table that doesn't already have a flow. An array example contains individual flows to add or update; it doesn't replace the entire properties.dataFlows array.
  • Preserve other data flows, destinations, and resource settings. The laDest destination name must match the workspace destination in properties.destinations.logAnalytics.

Define a workspace transformation DCR request body

This resource-body excerpt defines an unchanged-data transformation for AppRequests. It isn't independently deployable. Use it as the starting resource definition for a new workspace transformation DCR, not as a replacement for an existing DCR. In an ARM template, insert these fields inside the Microsoft.Insights/dataCollectionRules resource declaration in the resources array. Retain its type, apiVersion, and name fields and any other existing resource settings.

{
  "kind": "WorkspaceTransforms",
  "location": "<Location>",
  "properties": {
    "dataSources": {},
    "destinations": {
      "logAnalytics": [
        {
          "workspaceResourceId": "/subscriptions/<SubscriptionId>/resourceGroups/<ResourceGroupName>/providers/Microsoft.OperationalInsights/workspaces/<WorkspaceName>",
          "name": "laDest"
        }
      ]
    },
    "dataFlows": [
      {
        "streams": ["Microsoft-Table-AppRequests"],
        "destinations": ["laDest"],
        "transformKql": "source"
      }
    ]
  }
}
Drop a telemetry type by dropping a table

Use this sample to block an entire telemetry type, such as all traces or all requests.

Add or update one object in properties.dataFlows for each table whose incoming records you want to drop. Keep flows for other tables. These transformations discard incoming records; they don't delete the tables or previously stored data.

[
  {
    "streams": ["Microsoft-Table-AppTraces"],
    "destinations": ["laDest"],
    "transformKql": "source | where 1 == 0"
  },
  {
    "streams": ["Microsoft-Table-AppRequests"],
    "destinations": ["laDest"],
    "transformKql": "source | where 1 == 0"
  },
  {
    "streams": ["Microsoft-Table-AppDependencies"],
    "destinations": ["laDest"],
    "transformKql": "source | where 1 == 0"
  },
  {
    "streams": ["Microsoft-Table-AppExceptions"],
    "destinations": ["laDest"],
    "transformKql": "source | where 1 == 0"
  },
  {
    "streams": ["Microsoft-Table-AppMetrics"],
    "destinations": ["laDest"],
    "transformKql": "source | where 1 == 0"
  }
]
Drop health check requests

Use this sample to drop common health, readiness, and liveness endpoints.

{
  "streams": ["Microsoft-Table-AppRequests"],
  "destinations": ["laDest"],
  "transformKql": "source | extend url = tolower(tostring(Url)) | where not(url contains '/health' or url contains '/healthz' or url contains '/ready' or url contains '/readyz' or url contains '/live' or url contains '/livez') | project-away url"
}
Keep only failing health check requests

Use this sample to keep failing health checks and drop successful health checks.

{
  "streams": ["Microsoft-Table-AppRequests"],
  "destinations": ["laDest"],
  "transformKql": "source | extend url = tolower(tostring(Url)) | where not((url contains '/health' or url contains '/healthz' or url contains '/ready' or url contains '/readyz' or url contains '/live' or url contains '/livez') and Success == true) | project-away url"
}
Keep only failed or slow requests

Use this sample to keep requests that fail or exceed a latency threshold.

{
  "streams": ["Microsoft-Table-AppRequests"],
  "destinations": ["laDest"],
  "transformKql": "source | where Success == false or DurationMs >= 1000"
}
Keep only Warning and higher traces

Use this sample to keep trace records with SeverityLevel of Warning (2), Error (3), or Critical (4).

{
  "streams": ["Microsoft-Table-AppTraces"],
  "destinations": ["laDest"],
  "transformKql": "source | where SeverityLevel >= 2"
}
Keep only failed or slow dependencies

Use this sample to keep dependency calls that fail or exceed a latency threshold.

{
  "streams": ["Microsoft-Table-AppDependencies"],
  "destinations": ["laDest"],
  "transformKql": "source | where Success == false or DurationMs >= 500"
}
Remove SQL statements from dependency data

Use this sample to remove SQL statements stored in the Data column while keeping dependency timing and success information.

{
  "streams": ["Microsoft-Table-AppDependencies"],
  "destinations": ["laDest"],
  "transformKql": "source | extend dependencyType = tolower(tostring(DependencyType)) | extend Data = iff(dependencyType == 'sql', '', Data) | project-away dependencyType"
}
Drop synthetic traffic

Use this sample to drop records that include a SyntheticSource value.

{
  "streams": ["Microsoft-Table-AppRequests"],
  "destinations": ["laDest"],
  "transformKql": "source | where isempty(SyntheticSource)"
}
Drop cancellation exceptions

Use this sample to drop common cancellation exception types.

{
  "streams": ["Microsoft-Table-AppExceptions"],
  "destinations": ["laDest"],
  "transformKql": "source | where not(ExceptionType contains 'OperationCanceledException' or ExceptionType contains 'TaskCanceledException')"
}
Remove client IP addresses and query strings

Use this sample to remove client IP addresses and to store URLs without query strings.

[
  {
    "streams": ["Microsoft-Table-AppRequests"],
    "destinations": ["laDest"],
    "transformKql": "source | extend Url = tostring(split(tostring(Url), '?')[0]) | project-away ClientIP"
  },
  {
    "streams": ["Microsoft-Table-AppDependencies"],
    "destinations": ["laDest"],
    "transformKql": "source | extend Data = tostring(split(tostring(Data), '?')[0]) | project-away ClientIP"
  }
]
Scope a transformation to a single service

Use this sample to filter a single service when multiple applications share a workspace. Keep telemetry from other services unchanged. Apply its transformKql to the Microsoft-Table-AppRequests flow in properties.dataFlows, preserving that flow's destination and any other filtering requirements.

{
  "streams": ["Microsoft-Table-AppRequests"],
  "destinations": ["laDest"],
  "transformKql": "source | where AppRoleName != '<AppRoleName>' or Success == false or DurationMs >= 1000"
}

Troubleshooting, feedback, and support

Tip

The following sections are available across all OpenTelemetry Distro articles.

Troubleshooting

OpenTelemetry Feedback

To provide feedback:

Support

Select a tab for the language of your choice to discover support options.

Next steps