-
Notifications
You must be signed in to change notification settings - Fork 784
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A code sample to show how to create new root activities that link to …
…a previously current activity. (#4957)
- Loading branch information
Showing
4 changed files
with
270 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
158 changes: 158 additions & 0 deletions
158
docs/trace/links-creation-with-new-activities/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` |
5 changes: 5 additions & 0 deletions
5
docs/trace/links-creation-with-new-activities/links-creation.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<ItemGroup> | ||
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Console\OpenTelemetry.Exporter.Console.csproj" /> | ||
</ItemGroup> | ||
</Project> |