From 8b25642d35bac232afa5b70df961675a8350537e Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Mon, 16 Oct 2023 18:44:41 -0700 Subject: [PATCH 01/11] A code sample to show how to create new root activities that link to a previously current activity. --- OpenTelemetry.sln | 9 +- .../Program.cs | 81 ++++++++++++ .../README.md | 118 ++++++++++++++++++ .../links-creation.csproj | 5 + 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 docs/trace/links-creation-with-new-activities/Program.cs create mode 100644 docs/trace/links-creation-with-new-activities/README.md create mode 100644 docs/trace/links-creation-with-new-activities/links-creation.csproj diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 922ba6b2d2..efff1dbed0 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -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 @@ -315,6 +315,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 @@ -589,6 +591,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 @@ -637,6 +643,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} diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs new file mode 100644 index 0000000000..d762db4ff9 --- /dev/null +++ b/docs/trace/links-creation-with-new-activities/Program.cs @@ -0,0 +1,81 @@ +// +// 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. +// + +using System.Diagnostics; +using OpenTelemetry; +using OpenTelemetry.Trace; + +namespace LinksCreationWithNewRootActivitiesDemo; + +internal class Program +{ + private static readonly ActivitySource MyActivitySource = new("LinksCreationWithNewRootActivities"); + + public static void Main(string[] args) + { + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource("LinksCreationWithNewRootActivities") + .AddConsoleExporter() + .Build(); + + using (var activity = MyActivitySource.StartActivity("SayHello")) + { + activity?.SetTag("foo", 1); + DoFanout(); + + using (var nestedActivity = MyActivitySource.StartActivity("WrapUp")) + { + nestedActivity?.SetTag("foo", 1); + } + } + } + + public static void DoFanout() + { + var previous = Activity.Current; + + var activityContext = Activity.Current!.Context; + var links = new List + { + new ActivityLink(activityContext), + }; + + // Fanning out to 10 different 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 < 10; i++) + { + // 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. + Activity.Current = null; + + // 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", + links: links); + + // DO THE FANOUT WORK HERE... + } + + // 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 that activity. + Activity.Current = previous; + } +} diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md new file mode 100644 index 0000000000..2424505026 --- /dev/null +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -0,0 +1,118 @@ +# Creating new root activities that link to an existing activity: An Example + +This example shows how to create new root activities that link 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. + +This example shows to create the new root activities and link each of them to +the original activity. + +## 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 several batched +or fanout operations. Using this approach, you can create a new trace for each +of the fanned out operations and link them to the original activity. + +## References +- https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities +- https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links + +## Sample Output + +You should see output such as the below when you run this example. + +```text +Activity.TraceId: 5ce4d8ad4926ecdd0084681f46fa38d9 +Activity.SpanId: 8f9e9441f0789f6e +Activity.TraceFlags: Recorded +Activity.ActivitySourceName: LinksCreationWithNewRootActivities +Activity.DisplayName: FannedOutActivity +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 +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 +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: SayHello +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 +``` diff --git a/docs/trace/links-creation-with-new-activities/links-creation.csproj b/docs/trace/links-creation-with-new-activities/links-creation.csproj new file mode 100644 index 0000000000..19aa979143 --- /dev/null +++ b/docs/trace/links-creation-with-new-activities/links-creation.csproj @@ -0,0 +1,5 @@ + + + + + From 7cbc1125c9813de52db119ff7f32d02abc23861b Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Mon, 16 Oct 2023 18:50:24 -0700 Subject: [PATCH 02/11] Formatting fixes --- docs/trace/links-creation-with-new-activities/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index 2424505026..1c29764d02 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -5,8 +5,8 @@ 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. -This example shows to create the new root activities and link each of them to -the original activity. +This example shows how to create the new root activities and how to link each +of them to the original activity. ## How does this example work? @@ -27,6 +27,7 @@ or fanout operations. Using this approach, you can create a new trace for each of the fanned out operations and link them to the original activity. ## References + - https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities - https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links From 2c27b98e0d1899063cbfac754047aa02a88a982e Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Mon, 16 Oct 2023 19:05:21 -0700 Subject: [PATCH 03/11] Updating reference URLs --- docs/trace/links-creation-with-new-activities/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index 1c29764d02..ac4fe24801 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -28,8 +28,8 @@ of the fanned out operations and link them to the original activity. ## References -- https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities -- https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links +- [Creating new root activities](https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities). +- [Adding links](https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links). ## Sample Output From 00f1100df94a22735b606d5c53045340f2210434 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Tue, 17 Oct 2023 09:36:14 -0700 Subject: [PATCH 04/11] Incorporated review feedback. --- .../Program.cs | 5 +- .../README.md | 49 ++++++++++++++----- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs index d762db4ff9..3038208b38 100644 --- a/docs/trace/links-creation-with-new-activities/Program.cs +++ b/docs/trace/links-creation-with-new-activities/Program.cs @@ -50,7 +50,7 @@ public static void DoFanout() var activityContext = Activity.Current!.Context; var links = new List { - new ActivityLink(activityContext), + new ActivityLink(activityContext), }; // Fanning out to 10 different operations. @@ -64,6 +64,7 @@ public static void DoFanout() // this step helps us "de-parent" it from the current activity. 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( @@ -75,7 +76,7 @@ public static void DoFanout() } // 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 that activity. + // This will ensure that the rest of the code executes in the context of the original activity. Activity.Current = previous; } } diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index ac4fe24801..d897e4aeb4 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -1,12 +1,32 @@ -# Creating new root activities that link to an existing activity: An Example +# Creating new root activities that link to an existing activity: A Sample -This example shows how to create new root activities that link 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. +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. -This example shows how to create the new root activities and how to link each -of them to the original activity. +To give an example, let's say you have a: +- Service A that receives a request for an operation that impacts 1000s of +resources. +- Let's say Service A fans out calls to Service B for each of these resource +operations. + +If you used the same trace for the entire flow, then you would likely end up +with a single very large trace with several 1000s or tens of 1000s of spans. +This can 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 resources) +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? @@ -22,18 +42,23 @@ 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 several batched -or fanout operations. Using this approach, you can create a new trace for each +This is a good option to consider for operations that involve batched or +fanout operations. Using this approach, you can create a new trace for each of the fanned out operations and link them to the original activity. ## References -- [Creating new root activities](https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities). -- [Adding links](https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links). +- [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) ## Sample Output -You should see output such as the below when you run this example. +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 From 008fba9b0fa156e3d09f83bfcf766283e1b8f5f2 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Tue, 17 Oct 2023 09:39:39 -0700 Subject: [PATCH 05/11] Fix linter issue --- docs/trace/links-creation-with-new-activities/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index d897e4aeb4..b3400d12ea 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -1,6 +1,7 @@ # 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) +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 From c39b87c2672bc8864a40b83cd5f366e066984ef6 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Tue, 17 Oct 2023 10:12:28 -0700 Subject: [PATCH 06/11] Fix linting issue --- .../links-creation-with-new-activities/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index b3400d12ea..c84ac52ce6 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -7,10 +7,11 @@ 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 you have a: -- Service A that receives a request for an operation that impacts 1000s of +To give an example, let's say: + +- Service A receives a request for an operation that impacts 1000s of resources. -- Let's say Service A fans out calls to Service B for each of these resource +- Service A then fans out calls to Service B for each of these resource operations. If you used the same trace for the entire flow, then you would likely end up @@ -18,9 +19,9 @@ with a single very large trace with several 1000s or tens of 1000s of spans. This can 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 resources) -as there would be no single trace that corresponds to each of the individual -resource operations. +*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 From 63f4b8a72073a057d7ca7e872e6ca8fc3e12a760 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Wed, 18 Oct 2023 11:33:37 -0700 Subject: [PATCH 07/11] Updated README --- .../README.md | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index c84ac52ce6..beb7908b51 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -7,16 +7,18 @@ 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: +To give an example, let's say that: - Service A receives a request for an operation that impacts 1000s of resources. -- Service A then fans out calls to Service B for each of these resource -operations. +- 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. -If you used the same trace for the entire flow, then you would likely end up -with a single very large trace with several 1000s or tens of 1000s of spans. -This can make visualizing and understanding the trace difficult. +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 @@ -45,8 +47,16 @@ 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. Using this approach, you can create a new trace for each -of the fanned out operations and link them to the original activity. +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 From d0d8a9da3079951d405673d6d44cd7a03ee3f521 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Thu, 19 Oct 2023 10:21:08 -0700 Subject: [PATCH 08/11] Added an additional fan-in sample reference + added link to a related issue. --- docs/trace/links-creation-with-new-activities/Program.cs | 4 ++++ docs/trace/links-creation-with-new-activities/README.md | 1 + 2 files changed, 5 insertions(+) diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs index 3038208b38..d9cea41f48 100644 --- a/docs/trace/links-creation-with-new-activities/Program.cs +++ b/docs/trace/links-creation-with-new-activities/Program.cs @@ -62,6 +62,10 @@ public static void DoFanout() // 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 diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index beb7908b51..c31861e71b 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -63,6 +63,7 @@ traces. - [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 From 02007275e23260cf274ddc32102494b237d7c1af Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Wed, 1 Nov 2023 11:30:47 -0700 Subject: [PATCH 09/11] Incorporate PR feedback (fixes to make the output more readable). --- docs/trace/links-creation-with-new-activities/Program.cs | 9 +++++---- docs/trace/links-creation-with-new-activities/README.md | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs index d9cea41f48..ee5d86c3dd 100644 --- a/docs/trace/links-creation-with-new-activities/Program.cs +++ b/docs/trace/links-creation-with-new-activities/Program.cs @@ -31,7 +31,7 @@ public static void Main(string[] args) .AddConsoleExporter() .Build(); - using (var activity = MyActivitySource.StartActivity("SayHello")) + using (var activity = MyActivitySource.StartActivity("OrchestratingActivity")) { activity?.SetTag("foo", 1); DoFanout(); @@ -46,6 +46,7 @@ public static void Main(string[] args) public static void DoFanout() { var previous = Activity.Current; + const int NumConcurrentOperations = 10; var activityContext = Activity.Current!.Context; var links = new List @@ -53,11 +54,11 @@ public static void DoFanout() new ActivityLink(activityContext), }; - // Fanning out to 10 different operations. + // 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 < 10; i++) + for (int i = 0; i < NumConcurrentOperations; i++) { // 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, @@ -73,7 +74,7 @@ public static void DoFanout() // 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", + name: $"FannedOutActivity {i + 1}", links: links); // DO THE FANOUT WORK HERE... diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index c31861e71b..c63218eaad 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -78,7 +78,7 @@ Activity.TraceId: 5ce4d8ad4926ecdd0084681f46fa38d9 Activity.SpanId: 8f9e9441f0789f6e Activity.TraceFlags: Recorded Activity.ActivitySourceName: LinksCreationWithNewRootActivities -Activity.DisplayName: FannedOutActivity +Activity.DisplayName: FannedOutActivity 1 Activity.Kind: Internal Activity.StartTime: 2023-10-17T01:24:40.4957326Z Activity.Duration: 00:00:00.0008656 @@ -94,7 +94,7 @@ Activity.TraceId: 16a8ad23d14a085f2a1f260a4b474d05 Activity.SpanId: 0c3e835cfd60c604 Activity.TraceFlags: Recorded Activity.ActivitySourceName: LinksCreationWithNewRootActivities -Activity.DisplayName: FannedOutActivity +Activity.DisplayName: FannedOutActivity 2 Activity.Kind: Internal Activity.StartTime: 2023-10-17T01:24:40.5908290Z Activity.Duration: 00:00:00.0009197 @@ -110,7 +110,7 @@ Activity.TraceId: 46f0b5b68173b4acf4f50e1f5cdb3e55 Activity.SpanId: 42e7f4439fc2b416 Activity.TraceFlags: Recorded Activity.ActivitySourceName: LinksCreationWithNewRootActivities -Activity.DisplayName: FannedOutActivity +Activity.DisplayName: FannedOutActivity 3 Activity.Kind: Internal Activity.StartTime: 2023-10-17T01:24:40.5930378Z Activity.Duration: 00:00:00.0008622 @@ -143,7 +143,7 @@ Activity.TraceId: 2890476acefb53b93af64a0d91939051 Activity.SpanId: 16b83c1517629363 Activity.TraceFlags: Recorded Activity.ActivitySourceName: LinksCreationWithNewRootActivities -Activity.DisplayName: SayHello +Activity.DisplayName: OrchestratingActivity Activity.Kind: Internal Activity.StartTime: 2023-10-17T01:24:40.4937024Z Activity.Duration: 00:00:00.1043390 From 1d6df33efe83b69206d9f7137bf79505597b89b9 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Wed, 1 Nov 2023 11:37:10 -0700 Subject: [PATCH 10/11] Clarify on usage of the term "resource" --- docs/trace/links-creation-with-new-activities/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md index c63218eaad..39552a7cbb 100644 --- a/docs/trace/links-creation-with-new-activities/README.md +++ b/docs/trace/links-creation-with-new-activities/README.md @@ -9,8 +9,9 @@ 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 an operation that impacts 1000s of -resources. +- 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 From e308ef64b2143b5a8d6a0d15157ee28443489139 Mon Sep 17 00:00:00 2001 From: "J. Kalyana Sundaram" Date: Wed, 1 Nov 2023 12:40:28 -0700 Subject: [PATCH 11/11] Incorporated PR feedback from utpilla --- .../Program.cs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs index ee5d86c3dd..633525a4ba 100644 --- a/docs/trace/links-creation-with-new-activities/Program.cs +++ b/docs/trace/links-creation-with-new-activities/Program.cs @@ -24,7 +24,7 @@ internal class Program { private static readonly ActivitySource MyActivitySource = new("LinksCreationWithNewRootActivities"); - public static void Main(string[] args) + public static async Task Main(string[] args) { using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource("LinksCreationWithNewRootActivities") @@ -34,7 +34,7 @@ public static void Main(string[] args) using (var activity = MyActivitySource.StartActivity("OrchestratingActivity")) { activity?.SetTag("foo", 1); - DoFanout(); + await DoFanoutAsync(); using (var nestedActivity = MyActivitySource.StartActivity("WrapUp")) { @@ -43,7 +43,7 @@ public static void Main(string[] args) } } - public static void DoFanout() + public static async Task DoFanoutAsync() { var previous = Activity.Current; const int NumConcurrentOperations = 10; @@ -54,32 +54,44 @@ public static void DoFanout() new ActivityLink(activityContext), }; + var tasks = new List(); + // 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++) { - // 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 {i + 1}", - links: links); - - // DO THE FANOUT WORK HERE... + 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;