From 201737c4c21c1f04bfdd98aa66713534283a58e4 Mon Sep 17 00:00:00 2001 From: Robert Pakko Date: Tue, 5 Aug 2025 15:23:14 -0700 Subject: [PATCH 1/2] Updating semantic conventions --- pkgs/telemetry/src/TracingHook.cs | 42 ++++++++++++++++--------- pkgs/telemetry/test/TracingHookTests.cs | 16 +++++----- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/pkgs/telemetry/src/TracingHook.cs b/pkgs/telemetry/src/TracingHook.cs index 81323cf0..299f13bd 100644 --- a/pkgs/telemetry/src/TracingHook.cs +++ b/pkgs/telemetry/src/TracingHook.cs @@ -15,13 +15,13 @@ namespace LaunchDarkly.Sdk.Server.Telemetry public class TracingHookBuilder { private bool _createActivities; - private bool _includeVariant; + private bool _includeValue; private string _environmentId; internal TracingHookBuilder() { _createActivities = false; - _includeVariant = false; + _includeValue = false; _environmentId = null; } @@ -45,11 +45,11 @@ public TracingHookBuilder CreateActivities(bool createActivities = true) /// The TracingHook will include the flag variant in the current activity, if one exists. /// The variant representation is a JSON string. Disabled by default. /// - /// true to include variants, false otherwise + /// true to include variants, false otherwise /// this builder - public TracingHookBuilder IncludeVariant(bool includeVariant = true) + public TracingHookBuilder includeValue(bool includeValue = true) { - _includeVariant = includeVariant; + _includeValue = includeValue; return this; } @@ -77,7 +77,7 @@ public TracingHookBuilder EnvironmentId(string environmentId) /// the new hook public TracingHook Build() { - return new TracingHook(new TracingHook.Options(_createActivities, _includeVariant, _environmentId)); + return new TracingHook(new TracingHook.Options(_createActivities, _includeValue, _environmentId)); } } @@ -107,23 +107,25 @@ private static class SemanticAttributes { public const string EventName = "feature_flag"; public const string FeatureFlagKey = "feature_flag.key"; - public const string FeatureFlagProviderName = "feature_flag.provider_name"; - public const string FeatureFlagVariant = "feature_flag.variant"; - public const string FeatureFlagContextKeyAttributeName = "feature_flag.context.key"; + public const string FeatureFlagProviderName = "feature_flag.provider.name"; + public const string FeatureFlagValue = "feature_flag.result.value"; + public const string FeatureFlagVariationIndex = "feature_flag.result.variationIndex"; + public const string FeatureFlagInExperiment = "feature_flag.result.reason.inExperiment"; + public const string FeatureFlagContextKeyAttributeName = "feature_flag.context.id"; public const string FeatureFlagSetId = "feature_flag.set.id"; } internal struct Options { public bool CreateActivities { get; } - public bool IncludeVariant { get; } + public bool IncludeValue { get; } public string EnvironmentId { get; } - public Options(bool createActivities, bool includeVariant, string environmentId = null) + public Options(bool createActivities, bool includeValue, string environmentId = null) { CreateActivities = createActivities; - IncludeVariant = includeVariant; + IncludeValue = includeValue; EnvironmentId = environmentId; } } @@ -179,7 +181,7 @@ public override SeriesData BeforeEvaluation(EvaluationSeriesContext context, Ser /// /// Ends the activity created in BeforeEvaluation, if it exists. Adds the feature flag key, provider name, and context key - /// to the existing activity. If IncludeVariant is enabled, also adds the variant. + /// to the existing activity. If includeValue is enabled, also adds the variant. /// /// the evaluation parameters /// the series data @@ -216,9 +218,19 @@ public override SeriesData AfterEvaluation(EvaluationSeriesContext context, Seri attributes[SemanticAttributes.FeatureFlagSetId] = context.EnvironmentId; } - if (_options.IncludeVariant) + if (_options.IncludeValue) { - attributes.Add(SemanticAttributes.FeatureFlagVariant, detail.Value.ToJsonString()); + attributes.Add(SemanticAttributes.FeatureFlagValue, detail.Value.ToJsonString()); + } + + if (false) + { // TODO: add this data given appropriate condition + attributes.Add(SemanticAttributes.FeatureFlagVariationIndex, ""); + } + + if (false) + { // TODO: add this data given appropriate condition + attributes.Add(SemanticAttributes.FeatureFlagInExperiment, ""); } Activity.Current?.AddEvent(new ActivityEvent(name: SemanticAttributes.EventName, tags: attributes)); diff --git a/pkgs/telemetry/test/TracingHookTests.cs b/pkgs/telemetry/test/TracingHookTests.cs index 70c2402c..cdfae448 100644 --- a/pkgs/telemetry/test/TracingHookTests.cs +++ b/pkgs/telemetry/test/TracingHookTests.cs @@ -37,10 +37,10 @@ public void CanRetrieveActivitySourceName() [InlineData(false, true)] [InlineData(true, false)] [InlineData(true, true)] - public void ConfigurationOptionsDoNotThrowExceptions(bool includeVariant, bool createSpans) + public void ConfigurationOptionsDoNotThrowExceptions(bool includeValue, bool createSpans) { var hook = TracingHook.Builder() - .IncludeVariant(includeVariant) + .includeValue(includeValue) .CreateActivities(createSpans) .Build(); var context = new EvaluationSeriesContext("foo", Context.New("bar"), LdValue.Null, "testMethod"); @@ -164,7 +164,7 @@ public void TracingHookCreatesChildSpans(bool createSpans) [Theory] [InlineData(true)] [InlineData(false)] - public void TracingHookIncludesVariant(bool includeVariant) + public void TracingHookIncludesVariant(bool includeValue) { ICollection exportedItems = new Collection(); @@ -178,7 +178,7 @@ public void TracingHookIncludesVariant(bool includeVariant) var testSource = new ActivitySource("test-source", "1.0.0"); - var hookUnderTest = TracingHook.Builder().IncludeVariant(includeVariant).Build(); + var hookUnderTest = TracingHook.Builder().includeValue(includeValue).Build(); var featureKey = "feature-key"; var context = Context.New("foo"); @@ -203,21 +203,21 @@ public void TracingHookIncludesVariant(bool includeVariant) Assert.Single(items); Assert.Equal("root-activity", items[0].OperationName); - if (includeVariant) + if (includeValue) { // The idea is to check that the span has two events attached to it, and those events contain the feature // flag variants. It's awkward to check because we don't know the exact order of the events or those // events' tags. var events = items[0].Events; Assert.Single(events.Where(e => - e.Tags.Contains(new KeyValuePair("feature_flag.variant", "true")))); + e.Tags.Contains(new KeyValuePair("feature_flag.result.value", "true")))); Assert.Single(events.Where(e => - e.Tags.Contains(new KeyValuePair("feature_flag.variant", "\"default\"")))); + e.Tags.Contains(new KeyValuePair("feature_flag.result.value", "\"default\"")))); } else { // If not including the variant, then we shouldn't see any variant tag on any events. - Assert.All(items, i => i.Events.All(e => e.Tags.All(kvp => kvp.Key != "feature_flag.variant"))); + Assert.All(items, i => i.Events.All(e => e.Tags.All(kvp => kvp.Key != "feature_flag.result.value"))); } } From 9b2f8296700efe113cc2549868273a6705c708b0 Mon Sep 17 00:00:00 2001 From: Robert Pakko Date: Tue, 5 Aug 2025 16:07:10 -0700 Subject: [PATCH 2/2] Address comments --- pkgs/telemetry/src/TracingHook.cs | 31 ++++++++++++++++++------- pkgs/telemetry/test/TracingHookTests.cs | 4 ++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/pkgs/telemetry/src/TracingHook.cs b/pkgs/telemetry/src/TracingHook.cs index 299f13bd..61d19f8d 100644 --- a/pkgs/telemetry/src/TracingHook.cs +++ b/pkgs/telemetry/src/TracingHook.cs @@ -41,15 +41,28 @@ public TracingHookBuilder CreateActivities(bool createActivities = true) return this; } + /// + /// The TracingHook will include the flag value in the current activity, if one exists. + /// The value representation is a JSON string. Disabled by default. + /// + /// true to include value, false otherwise + /// this builder + public TracingHookBuilder IncludeValue(bool includeValue = true) + { + _includeValue = includeValue; + return this; + } + /// /// The TracingHook will include the flag variant in the current activity, if one exists. /// The variant representation is a JSON string. Disabled by default. /// - /// true to include variants, false otherwise + /// true to include variants, false otherwise /// this builder - public TracingHookBuilder includeValue(bool includeValue = true) + [System.Obsolete("IncludeVariant is deprecated. Use IncludeValue instead.")] + public TracingHookBuilder IncludeVariant(bool includeVariant = true) { - _includeValue = includeValue; + _includeValue = includeVariant; return this; } @@ -223,14 +236,14 @@ public override SeriesData AfterEvaluation(EvaluationSeriesContext context, Seri attributes.Add(SemanticAttributes.FeatureFlagValue, detail.Value.ToJsonString()); } - if (false) - { // TODO: add this data given appropriate condition - attributes.Add(SemanticAttributes.FeatureFlagVariationIndex, ""); + if (detail.Reason.InExperiment) + { + attributes.Add(SemanticAttributes.FeatureFlagInExperiment, detail.Reason.InExperiment); } - if (false) - { // TODO: add this data given appropriate condition - attributes.Add(SemanticAttributes.FeatureFlagInExperiment, ""); + if (detail.VariationIndex.HasValue) + { + attributes.Add(SemanticAttributes.FeatureFlagVariationIndex, detail.VariationIndex.Value); } Activity.Current?.AddEvent(new ActivityEvent(name: SemanticAttributes.EventName, tags: attributes)); diff --git a/pkgs/telemetry/test/TracingHookTests.cs b/pkgs/telemetry/test/TracingHookTests.cs index cdfae448..d2d48305 100644 --- a/pkgs/telemetry/test/TracingHookTests.cs +++ b/pkgs/telemetry/test/TracingHookTests.cs @@ -40,7 +40,7 @@ public void CanRetrieveActivitySourceName() public void ConfigurationOptionsDoNotThrowExceptions(bool includeValue, bool createSpans) { var hook = TracingHook.Builder() - .includeValue(includeValue) + .IncludeValue(includeValue) .CreateActivities(createSpans) .Build(); var context = new EvaluationSeriesContext("foo", Context.New("bar"), LdValue.Null, "testMethod"); @@ -178,7 +178,7 @@ public void TracingHookIncludesVariant(bool includeValue) var testSource = new ActivitySource("test-source", "1.0.0"); - var hookUnderTest = TracingHook.Builder().includeValue(includeValue).Build(); + var hookUnderTest = TracingHook.Builder().IncludeValue(includeValue).Build(); var featureKey = "feature-key"; var context = Context.New("foo");