A code sample to show how to create new root activities that link to a previously current activity. (#4957)
This commit is contained in:
parent
2de73b2c12
commit
e454dc9dc8
|
|
@ -90,8 +90,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{E69578EB-B456-4062-A645-877CD964528B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\workflows\ci-aot.yml = .github\workflows\ci-aot.yml
|
||||
.github\workflows\ci-aot-md.yml = .github\workflows\ci-aot-md.yml
|
||||
.github\workflows\ci-aot.yml = .github\workflows\ci-aot.yml
|
||||
.github\workflows\ci-instrumentation-libraries-md.yml = .github\workflows\ci-instrumentation-libraries-md.yml
|
||||
.github\workflows\ci-instrumentation-libraries.yml = .github\workflows\ci-instrumentation-libraries.yml
|
||||
.github\workflows\ci-md.yml = .github\workflows\ci-md.yml
|
||||
|
|
@ -316,6 +316,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Metrics", "Metrics", "{1C45
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-aspnetcore", "docs\logs\getting-started-aspnetcore\getting-started-aspnetcore.csproj", "{99B4D965-8782-4694-8DFA-B7A3630CEF60}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "links-creation", "docs\trace\links-creation-with-new-activities\links-creation.csproj", "{B4856711-6D4C-4246-A686-49458D4C1301}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -590,6 +592,10 @@ Global
|
|||
{99B4D965-8782-4694-8DFA-B7A3630CEF60}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{99B4D965-8782-4694-8DFA-B7A3630CEF60}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{99B4D965-8782-4694-8DFA-B7A3630CEF60}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4856711-6D4C-4246-A686-49458D4C1301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B4856711-6D4C-4246-A686-49458D4C1301}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B4856711-6D4C-4246-A686-49458D4C1301}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B4856711-6D4C-4246-A686-49458D4C1301}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -638,6 +644,7 @@ Global
|
|||
{A0CB9A10-F22D-4E66-A449-74B3D0361A9C} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
|
||||
{1C459B5B-C702-46FF-BF1A-EE795E420FFA} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
|
||||
{99B4D965-8782-4694-8DFA-B7A3630CEF60} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
|
||||
{B4856711-6D4C-4246-A686-49458D4C1301} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
// <copyright file="Program.cs" company="OpenTelemetry Authors">
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System.Diagnostics;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace LinksCreationWithNewRootActivitiesDemo;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
private static readonly ActivitySource MyActivitySource = new("LinksCreationWithNewRootActivities");
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
||||
.AddSource("LinksCreationWithNewRootActivities")
|
||||
.AddConsoleExporter()
|
||||
.Build();
|
||||
|
||||
using (var activity = MyActivitySource.StartActivity("OrchestratingActivity"))
|
||||
{
|
||||
activity?.SetTag("foo", 1);
|
||||
await DoFanoutAsync();
|
||||
|
||||
using (var nestedActivity = MyActivitySource.StartActivity("WrapUp"))
|
||||
{
|
||||
nestedActivity?.SetTag("foo", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DoFanoutAsync()
|
||||
{
|
||||
var previous = Activity.Current;
|
||||
const int NumConcurrentOperations = 10;
|
||||
|
||||
var activityContext = Activity.Current!.Context;
|
||||
var links = new List<ActivityLink>
|
||||
{
|
||||
new ActivityLink(activityContext),
|
||||
};
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
// Fanning out to N concurrent operations.
|
||||
// We create a new root activity for each operation and
|
||||
// link it to an outer activity that happens to be the current
|
||||
// activity.
|
||||
for (int i = 0; i < NumConcurrentOperations; i++)
|
||||
{
|
||||
int operationIndex = i;
|
||||
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
// Reference: https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities
|
||||
// Since we want to create a new root activity for each of the fanned out operations,
|
||||
// this step helps us "de-parent" it from the current activity.
|
||||
// Note: At least as of Oct 2023, this is the only mechanism to create a new root
|
||||
// activity in the presence of an existing activity. This might change in the future
|
||||
// if/when issue https://github.com/open-telemetry/opentelemetry-dotnet/issues/984
|
||||
// is addressed.
|
||||
Activity.Current = null;
|
||||
|
||||
// Reference: https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Api#activity-creation-options
|
||||
// Reference: https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links
|
||||
// We create a new root activity for each of the fanned out operations and link it to the outer activity.
|
||||
using var newRootActivityForFannedOutOperation = MyActivitySource.StartActivity(
|
||||
ActivityKind.Internal, // Set this to the appropriate ActivityKind depending on your scenario
|
||||
name: $"FannedOutActivity {operationIndex + 1}",
|
||||
links: links);
|
||||
|
||||
// DO THE FANOUT WORK HERE...
|
||||
});
|
||||
|
||||
tasks.Add(task);
|
||||
}
|
||||
|
||||
// Wait for all tasks to complete
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
// Reset to the previous activity now that we are done with the fanout
|
||||
// This will ensure that the rest of the code executes in the context of the original activity.
|
||||
Activity.Current = previous;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
# Creating new root activities that link to an existing activity: A Sample
|
||||
|
||||
This sample shows how to create new root activities that
|
||||
[link](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans)
|
||||
to an existing activity. This can be useful in a fan-out or batched operation
|
||||
situation when you want to create a new trace with a new root activity
|
||||
BEFORE invoking each of the fanned out operations, and at the same time
|
||||
you want each of these new traces to be linked to the original activity.
|
||||
|
||||
To give an example, let's say that:
|
||||
|
||||
- Service A receives a request for a customer operation that impacts 1000s of
|
||||
resources. The term "resource" here means an entity that is managed by this
|
||||
service and should not be confused with the term "resource" in OpenTelemetry.
|
||||
- Service A orchestrates this overall operation by fanning out multiple
|
||||
calls to Service B, with one call for EACH of the impacted resources.
|
||||
- Let's say the number of spans generated for a single resource operation
|
||||
is in the order of several thousands of spans.
|
||||
|
||||
In the above example, if you used the same trace for the entire flow, then
|
||||
you would end up with a huge trace with more than million spans. This will
|
||||
make visualizing and understanding the trace difficult.
|
||||
|
||||
Further, it may make it difficult to do programmatic analytics at the
|
||||
*individual* resource operation level (for each of the 1000s of resource
|
||||
operations) as there would be no single trace that corresponds to each
|
||||
of the individual resource operations.
|
||||
|
||||
Instead, by creating a new trace with a new root activity before the fanout
|
||||
call, you get a separate trace for each of the resource operations. In
|
||||
addition, by using the "span links" functionality in OpenTelemetry, we link
|
||||
each of these new root activities to the original activity.
|
||||
|
||||
This enables more granular visualization and analytics.
|
||||
|
||||
## How does this example work?
|
||||
|
||||
To be able to create new root activities, we first set the Activity.Current
|
||||
to null so that we can "de-parent" the new activity from the current activity.
|
||||
|
||||
For each of the fanned out operations, this creates a new root activity. As
|
||||
part of this activity creation, it links it to the previously current activity.
|
||||
|
||||
Finally, we reset Activity.Current to the previous activity now after we are
|
||||
done with the fanout. This will ensure that the rest of the code executes
|
||||
in the context of the original activity.
|
||||
|
||||
## When should you consider such an option? What are the tradeoffs?
|
||||
|
||||
This is a good option to consider for operations that involve batched or
|
||||
fanout operations if using the same trace causes it to become huge.
|
||||
Using this approach, you can create a new trace for each of the fanned out
|
||||
operations and link them to the original activity.
|
||||
|
||||
A tradeoff is that now we will have multiple traces instead of a single trace.
|
||||
However, many Observability tools have the ability to visualize linked traces
|
||||
together, and hence it is not necessarily a concern from that perspective.
|
||||
However, this model has the potential to add some complexity to any
|
||||
programmatic analysis since now it has to understand the concept of linked
|
||||
traces.
|
||||
|
||||
## References
|
||||
|
||||
- [Links between spans](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans)
|
||||
- [Creating new root activities](https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities)
|
||||
- [Activity Creation Options](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Api#activity-creation-options)
|
||||
- [A sample where links are used in a fan-in scenario](https://github.com/PacktPublishing/Modern-Distributed-Tracing-in-.NET/tree/main/chapter6/links)
|
||||
|
||||
## Sample Output
|
||||
|
||||
You should see output such as the below when you run this example. You can see
|
||||
that EACH of the "fanned out activities" have:
|
||||
|
||||
- a new trace ID
|
||||
- an activity link to the original activity
|
||||
|
||||
```text
|
||||
Activity.TraceId: 5ce4d8ad4926ecdd0084681f46fa38d9
|
||||
Activity.SpanId: 8f9e9441f0789f6e
|
||||
Activity.TraceFlags: Recorded
|
||||
Activity.ActivitySourceName: LinksCreationWithNewRootActivities
|
||||
Activity.DisplayName: FannedOutActivity 1
|
||||
Activity.Kind: Internal
|
||||
Activity.StartTime: 2023-10-17T01:24:40.4957326Z
|
||||
Activity.Duration: 00:00:00.0008656
|
||||
Activity.Links:
|
||||
2890476acefb53b93af64a0d91939051 16b83c1517629363
|
||||
Resource associated with Activity:
|
||||
telemetry.sdk.name: opentelemetry
|
||||
telemetry.sdk.language: dotnet
|
||||
telemetry.sdk.version: 0.0.0-alpha.0.2600
|
||||
service.name: unknown_service:links-creation
|
||||
|
||||
Activity.TraceId: 16a8ad23d14a085f2a1f260a4b474d05
|
||||
Activity.SpanId: 0c3e835cfd60c604
|
||||
Activity.TraceFlags: Recorded
|
||||
Activity.ActivitySourceName: LinksCreationWithNewRootActivities
|
||||
Activity.DisplayName: FannedOutActivity 2
|
||||
Activity.Kind: Internal
|
||||
Activity.StartTime: 2023-10-17T01:24:40.5908290Z
|
||||
Activity.Duration: 00:00:00.0009197
|
||||
Activity.Links:
|
||||
2890476acefb53b93af64a0d91939051 16b83c1517629363
|
||||
Resource associated with Activity:
|
||||
telemetry.sdk.name: opentelemetry
|
||||
telemetry.sdk.language: dotnet
|
||||
telemetry.sdk.version: 0.0.0-alpha.0.2600
|
||||
service.name: unknown_service:links-creation
|
||||
|
||||
Activity.TraceId: 46f0b5b68173b4acf4f50e1f5cdb3e55
|
||||
Activity.SpanId: 42e7f4439fc2b416
|
||||
Activity.TraceFlags: Recorded
|
||||
Activity.ActivitySourceName: LinksCreationWithNewRootActivities
|
||||
Activity.DisplayName: FannedOutActivity 3
|
||||
Activity.Kind: Internal
|
||||
Activity.StartTime: 2023-10-17T01:24:40.5930378Z
|
||||
Activity.Duration: 00:00:00.0008622
|
||||
Activity.Links:
|
||||
2890476acefb53b93af64a0d91939051 16b83c1517629363
|
||||
Resource associated with Activity:
|
||||
telemetry.sdk.name: opentelemetry
|
||||
telemetry.sdk.language: dotnet
|
||||
telemetry.sdk.version: 0.0.0-alpha.0.2600
|
||||
service.name: unknown_service:links-creation
|
||||
|
||||
Activity.TraceId: 2890476acefb53b93af64a0d91939051
|
||||
Activity.SpanId: 6878c2a84d4d4996
|
||||
Activity.TraceFlags: Recorded
|
||||
Activity.ParentSpanId: 16b83c1517629363
|
||||
Activity.ActivitySourceName: LinksCreationWithNewRootActivities
|
||||
Activity.DisplayName: WrapUp
|
||||
Activity.Kind: Internal
|
||||
Activity.StartTime: 2023-10-17T01:24:40.5950683Z
|
||||
Activity.Duration: 00:00:00.0008843
|
||||
Activity.Tags:
|
||||
foo: 1
|
||||
Resource associated with Activity:
|
||||
telemetry.sdk.name: opentelemetry
|
||||
telemetry.sdk.language: dotnet
|
||||
telemetry.sdk.version: 0.0.0-alpha.0.2600
|
||||
service.name: unknown_service:links-creation
|
||||
|
||||
Activity.TraceId: 2890476acefb53b93af64a0d91939051
|
||||
Activity.SpanId: 16b83c1517629363
|
||||
Activity.TraceFlags: Recorded
|
||||
Activity.ActivitySourceName: LinksCreationWithNewRootActivities
|
||||
Activity.DisplayName: OrchestratingActivity
|
||||
Activity.Kind: Internal
|
||||
Activity.StartTime: 2023-10-17T01:24:40.4937024Z
|
||||
Activity.Duration: 00:00:00.1043390
|
||||
Activity.Tags:
|
||||
foo: 1
|
||||
Resource associated with Activity:
|
||||
telemetry.sdk.name: opentelemetry
|
||||
telemetry.sdk.language: dotnet
|
||||
telemetry.sdk.version: 0.0.0-alpha.0.2600
|
||||
service.name: unknown_service:links-creation
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Console\OpenTelemetry.Exporter.Console.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue