Ngôn ngữ
Lưu ý
Cần có ủy quyền mới truy nhập được vào trang này. Bạn có thể thử đăng nhập hoặc thay đổi thư mục.
Cần có ủy quyền mới truy nhập được vào trang này. Bạn có thể thử thay đổi thư mục.
In .NET 11 and later, the Microsoft.Extensions.Diagnostics.Tracing APIs let you register ActivityListener instances and use rules to select the ActivitySource and Activity instances that each listener receives. Define rules in code or load them from IConfiguration.
Important
Tracing rules affect only listeners registered through this tracing infrastructure. They don't affect unrelated ActivityListener instances, including listeners that telemetry exporters create and manage. Configure those listeners or exporters separately.
Register tracing
The APIs are available in the Microsoft.Extensions.Diagnostics package. Apps that reference the Microsoft.AspNetCore.App shared framework already include the assembly.
Call AddTracing on an IServiceCollection. In the callback:
- Call AddListener to register each listener. The listener name identifies the listener in configuration rules.
- Configure the listener's sampling and notification delegates through ActivityListenerBuilder. The tracing infrastructure owns
ShouldListenTo, source subscriptions, and the listener lifetime. - Call AddConfiguration with the configuration section that contains the rules. For a section named
Tracing, passconfiguration.GetSection("Tracing").
The complete sample shows all three calls. A .NET host activates tracing subscriptions when the host starts. If you use dependency injection without a host, resolve the registered ActivitySourceFactory to construct the listeners and activate their subscriptions. The complete sample resolves the factory directly.
Configure tracing
Set tracing rules through configuration or in code. If no rule matches a listener, source, operation, and scope, tracing remains disabled for that combination.
Configure tracing without code
For apps that use configuration, add a Tracing section to appsettings.json or another configuration provider. Then pass that section to AddConfiguration:
tracing.AddConfiguration(configuration.GetSection("Tracing"));
The following example shows the supported rule sections and rule levels:
{
"Tracing": {
"EnabledTracing": {
"Default": false,
"Contoso": true,
"Contoso.Orders": {
"Default": true,
"HealthCheck": false
},
"Contoso.*.Storage": true
},
"EnabledGlobalTracing": {
"System.Net.Http": true
},
"EnabledLocalTracing": {
"Contoso.Workers": true
},
"Console": {
"EnabledLocalTracing": {
"Contoso.Orders": {
"Submit": false
}
}
}
}
}
Add rules directly under an EnabledTracing, EnabledGlobalTracing, or EnabledLocalTracing section. Don't add a Rules level.
Rule sections
Choose a rule section based on the source scope and whether the rule targets one listener:
| Section | Matching listeners | Matching activity sources |
|---|---|---|
EnabledTracing |
All registered listeners. | Global and local sources. |
EnabledGlobalTracing |
All registered listeners. | Global sources only. |
EnabledLocalTracing |
All registered listeners. | Local sources only. |
{Listener}:EnabledTracing |
The named listener. | Global and local sources. |
{Listener}:EnabledGlobalTracing |
The named listener. | Global sources only. |
{Listener}:EnabledLocalTracing |
The named listener. | Local sources only. |
Listener names match the names passed to AddListener. Section names and listener names aren't case-sensitive.
Rule levels
Under any rule section, use one of the following key forms:
| Key form | Rule level | Match |
|---|---|---|
Default |
Default. | Every source and operation. |
{SourceName} |
Activity source. | Every operation from matching sources. |
{SourceName}:Default |
Activity source. | Every operation from matching sources. This form lets a source also contain operation rules. |
{SourceName}:{OperationName} |
Operation. | The named operation from matching sources. |
Set each leaf value to true to enable the match or false to disable it. For example, the preceding configuration:
- Disables tracing by default.
- Enables sources whose names start with
Contoso. - Enables
Contoso.Orders, but disables itsHealthCheckoperation. - Enables a source pattern that starts with
Contoso.and ends with.Storage. - Adds rules that apply only to global sources, local sources, or the listener named
Console.
Use Default as a Boolean leaf. If Default contains operation children, the configuration treats Default as a literal activity-source name.
Configure tracing with code
Call EnableTracing and DisableTracing on the ITracingBuilder passed to AddTracing.
tracing.EnableTracing(sourceName: "Contoso");
tracing.DisableTracing(
sourceName: "Contoso.Orders",
operationName: "HealthCheck");
Omit sourceName, operationName, or listenerName to match all values at that level. By default, a programmatic rule applies to both global and local sources. Pass Global, Local, or both through the scopes argument to narrow the rule.
Configuration rules and programmatic rules form one ordered rule set. If equally specific rules conflict, the rule added last wins. The order of calls in the AddTracing callback therefore matters when AddConfiguration, EnableTracing, and DisableTracing add equally specific rules.
Match activity-source names
Source names, operation names, and listener names use case-insensitive ordinal comparison. Source-name rules support these match forms:
- An empty source name matches every source.
- A source name without a wildcard matches by prefix. For example,
ContosomatchesContoso.OrdersandContosoPayments; the matcher doesn't require a separator after the prefix. - A source name with one
*wildcard matches a prefix and suffix. For example,Contoso.*.StoragematchesContoso.Orders.Storage, but notContoso.Orders.Api. - A source name of
*matches every source.
Operation names match exactly. They don't use prefix or wildcard matching.
Apply rule precedence
For each listener, source, operation, and scope combination, the tracing infrastructure chooses one matching rule. It compares matching rules in this order:
- A listener-specific rule takes precedence over a rule for all listeners.
- A source rule takes precedence over a default rule. If two source expressions match, the longer expression takes precedence. The comparison uses the expression length, including a
*wildcard. - An operation rule takes precedence over a source-level rule.
- A global-only or local-only rule takes precedence over a rule that covers both scopes.
- The last rule takes precedence when all preceding factors are equal.
The comparison stops at the first difference. For example, a listener-specific default rule takes precedence over a source-specific rule that applies to all listeners because listener specificity is evaluated first.
Operation rules also control source subscriptions. A listener subscribes to a source that's disabled by default when an operation rule enables at least one operation from that source. The listener then returns None and skips its callbacks for disabled operations.
Choose global or local activity sources
The tracing infrastructure distinguishes two activity-source scopes:
- A global source is an
ActivitySourcecreated through its constructor.EnabledGlobalTracingrules apply to these sources. - A local source is an
ActivitySourcecreated by theActivitySourceFactoryresolved from dependency injection.EnabledLocalTracingrules apply to sources created by that factory.
Use Create when you want the dependency injection container to manage the source and its tracing listeners. A factory's listeners ignore local sources created by a different factory. Rules in EnabledTracing apply to both source types.
These scopes restrict only the listeners that AddTracing registers. An independent ActivityListener uses its own ShouldListenTo and sampling callbacks, even for an activity source created by ActivitySourceFactory.
Reload tracing configuration
AddConfiguration subscribes to the change token from the supplied configuration. When a configuration provider supports reload and reports a change, the tracing infrastructure:
- Rebuilds the rule set.
- Refreshes each registered listener's source subscriptions.
- Applies the updated rules to subsequent activities.
The app can keep using the same ActivitySource instances after a reload. Subsequent activities use the updated rules.
For a mutable provider that doesn't report changes automatically, update the configuration and call Reload. The complete sample uses this approach with the in-memory configuration provider.
Handle invalid configuration
Tracing configuration parses values with TryParse. It accepts true and false without regard to case and permits surrounding whitespace. It doesn't accept 1, 0, yes, or on.
The configuration loader silently ignores a leaf value that isn't a valid Boolean. It also ignores unknown or malformed sections that don't match the supported schema. Check key names carefully because these cases don't produce an exception.
A source expression can contain at most one * wildcard. A rule with more than one wildcard throws an ArgumentException when the rule is materialized, either during app startup or after configuration reload. For programmatic rules, None also causes an ArgumentOutOfRangeException.
Run the sample
The following .NET 11 console app creates one enabled operation and one disabled operation. It then updates the disabled operation's rule, calls Reload, and starts the operation again through the same local ActivitySource.
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Tracing;
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Tracing:EnabledTracing:Default"] = "false",
["Tracing:EnabledTracing:Contoso.Orders:Default"] = "true",
["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "false",
})
.Build();
ServiceCollection services = new();
services.AddTracing(tracing =>
{
tracing.AddListener("Console", listener =>
{
listener.Sample = static (ref ActivityCreationOptions<ActivityContext> _) =>
ActivitySamplingResult.AllData;
listener.SampleUsingParentId = static (ref ActivityCreationOptions<string> _) =>
ActivitySamplingResult.AllData;
listener.ActivityStarted = activity =>
Console.WriteLine($"Listener started: {activity.OperationName}");
});
tracing.AddConfiguration(configuration.GetSection("Tracing"));
});
using ServiceProvider serviceProvider = services.BuildServiceProvider();
ActivitySourceFactory factory =
serviceProvider.GetRequiredService<ActivitySourceFactory>();
using ActivitySource source = factory.Create("Contoso.Orders");
Console.WriteLine("Before reload:");
WriteResult(source, "EnabledOperation");
WriteResult(source, "DisabledOperation");
configuration["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "true";
configuration.Reload();
Console.WriteLine("After reload:");
WriteResult(source, "DisabledOperation");
static void WriteResult(ActivitySource source, string operationName)
{
using Activity? activity = source.StartActivity(operationName);
string state = activity is null ? "disabled" : "enabled";
Console.WriteLine($"{operationName}: {state}");
}
Imports System.Diagnostics
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Diagnostics.Tracing
Module Program
Sub Main()
Dim initialData As New Dictionary(Of String, String) From {
{"Tracing:EnabledTracing:Default", "false"},
{"Tracing:EnabledTracing:Contoso.Orders:Default", "true"},
{"Tracing:EnabledTracing:Contoso.Orders:DisabledOperation", "false"}
}
Dim configuration As IConfigurationRoot =
New ConfigurationBuilder().AddInMemoryCollection(initialData).Build()
Dim services As New ServiceCollection()
services.AddTracing(
Sub(tracing)
tracing.AddListener(
"Console",
Sub(listener)
listener.Sample = AddressOf SampleActivity
listener.SampleUsingParentId = AddressOf SampleActivityUsingParentId
listener.ActivityStarted =
Sub(activity) Console.WriteLine(
$"Listener started: {activity.OperationName}")
End Sub)
tracing.AddConfiguration(configuration.GetSection("Tracing"))
End Sub)
Using serviceProvider As ServiceProvider = services.BuildServiceProvider()
Dim factory As ActivitySourceFactory =
serviceProvider.GetRequiredService(Of ActivitySourceFactory)()
Using source As ActivitySource = factory.Create("Contoso.Orders")
Console.WriteLine("Before reload:")
WriteResult(source, "EnabledOperation")
WriteResult(source, "DisabledOperation")
configuration(
"Tracing:EnabledTracing:Contoso.Orders:DisabledOperation") = "true"
configuration.Reload()
Console.WriteLine("After reload:")
WriteResult(source, "DisabledOperation")
End Using
End Using
End Sub
Private Function SampleActivity(
ByRef options As ActivityCreationOptions(Of ActivityContext)
) As ActivitySamplingResult
Return ActivitySamplingResult.AllData
End Function
Private Function SampleActivityUsingParentId(
ByRef options As ActivityCreationOptions(Of String)
) As ActivitySamplingResult
Return ActivitySamplingResult.AllData
End Function
Private Sub WriteResult(source As ActivitySource, operationName As String)
Using activity As Activity = source.StartActivity(operationName)
Dim state As String = If(activity Is Nothing, "disabled", "enabled")
Console.WriteLine($"{operationName}: {state}")
End Using
End Sub
End Module
The C# and Visual Basic samples produce the same result:
Before reload:
Listener started: EnabledOperation
EnabledOperation: enabled
DisabledOperation: disabled
After reload:
Listener started: DisabledOperation
DisabledOperation: enabled