Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions pkgs/telemetry/src/TracingHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -41,15 +41,28 @@ public TracingHookBuilder CreateActivities(bool createActivities = true)
return this;
}

/// <summary>
/// The TracingHook will include the flag value in the current activity, if one exists.
/// The value representation is a JSON string. Disabled by default.
/// </summary>
/// <param name="includeValue">true to include value, false otherwise</param>
/// <returns>this builder</returns>
public TracingHookBuilder IncludeValue(bool includeValue = true)
{
_includeValue = includeValue;
return this;
}

/// <summary>
/// The TracingHook will include the flag variant in the current activity, if one exists.
/// The variant representation is a JSON string. Disabled by default.
/// </summary>
/// <param name="includeVariant">true to include variants, false otherwise</param>
/// <returns>this builder</returns>
[System.Obsolete("IncludeVariant is deprecated. Use IncludeValue instead.")]
public TracingHookBuilder IncludeVariant(bool includeVariant = true)
{
_includeVariant = includeVariant;
_includeValue = includeVariant;
return this;
}

Expand Down Expand Up @@ -77,7 +90,7 @@ public TracingHookBuilder EnvironmentId(string environmentId)
/// <returns>the new hook</returns>
public TracingHook Build()
{
return new TracingHook(new TracingHook.Options(_createActivities, _includeVariant, _environmentId));
return new TracingHook(new TracingHook.Options(_createActivities, _includeValue, _environmentId));
}
}

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -179,7 +194,7 @@ public override SeriesData BeforeEvaluation(EvaluationSeriesContext context, Ser

/// <summary>
/// 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.
/// </summary>
/// <param name="context">the evaluation parameters</param>
/// <param name="data">the series data</param>
Expand Down Expand Up @@ -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));
Expand Down
16 changes: 8 additions & 8 deletions pkgs/telemetry/test/TracingHookTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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<Activity> exportedItems = new Collection<Activity>();

Expand All @@ -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");

Expand All @@ -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<string, object>("feature_flag.variant", "true"))));
e.Tags.Contains(new KeyValuePair<string, object>("feature_flag.result.value", "true"))));
Assert.Single(events.Where(e =>
e.Tags.Contains(new KeyValuePair<string, object>("feature_flag.variant", "\"default\""))));
e.Tags.Contains(new KeyValuePair<string, object>("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")));
}
}

Expand Down
Loading