diff --git a/pkgs/telemetry/src/TracingHook.cs b/pkgs/telemetry/src/TracingHook.cs index 81323cf0..61d19f8d 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; } @@ -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 /// this builder + [System.Obsolete("IncludeVariant is deprecated. Use IncludeValue instead.")] public TracingHookBuilder IncludeVariant(bool includeVariant = true) { - _includeVariant = includeVariant; + _includeValue = includeVariant; return this; } @@ -77,7 +90,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 +120,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 +194,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 +231,19 @@ public override SeriesData AfterEvaluation(EvaluationSeriesContext context, Seri attributes[SemanticAttributes.FeatureFlagSetId] = context.EnvironmentId; } - if (_options.IncludeVariant) + if (_options.IncludeValue) + { + attributes.Add(SemanticAttributes.FeatureFlagValue, detail.Value.ToJsonString()); + } + + if (detail.Reason.InExperiment) + { + attributes.Add(SemanticAttributes.FeatureFlagInExperiment, detail.Reason.InExperiment); + } + + if (detail.VariationIndex.HasValue) { - attributes.Add(SemanticAttributes.FeatureFlagVariant, detail.Value.ToJsonString()); + 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 70c2402c..d2d48305 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"))); } }