Skip to content

feat: Add trace when evaluating feature flags#755

Open
kylejuliandev wants to merge 13 commits into
open-feature:mainfrom
kylejuliandev:kylej/improve-tracing
Open

feat: Add trace when evaluating feature flags#755
kylejuliandev wants to merge 13 commits into
open-feature:mainfrom
kylejuliandev:kylej/improve-tracing

Conversation

@kylejuliandev
Copy link
Copy Markdown
Contributor

@kylejuliandev kylejuliandev commented May 7, 2026

This PR

Add trace when evaluating feature flags. This is different from the TraceEnricherHook which enriches the current span or trace with an event, instead this more closely follows the semantic conventions: https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-events/. Also add OpenTelemetry logging to the sample application and ensure traces are always sampled.

Success tracwe

image

Error trace

image

Related Issues

Fixes #595
Fixes #541

Notes

Follow-up Tasks

How to test

Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
@kylejuliandev kylejuliandev requested a review from a team as a code owner May 7, 2026 18:49
@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.61%. Comparing base (5623a0f) to head (06fc54b).

Files with missing lines Patch % Lines
src/OpenFeature/OpenFeatureActivitySource.cs 97.29% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #755      +/-   ##
==========================================
+ Coverage   93.52%   93.61%   +0.08%     
==========================================
  Files          69       70       +1     
  Lines        2981     3037      +56     
  Branches      355      374      +19     
==========================================
+ Hits         2788     2843      +55     
  Misses        135      135              
- Partials       58       59       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements OpenTelemetry tracing for feature flag evaluations in the OpenFeature client, including the addition of an activity source and corresponding unit tests. The review feedback highlights several discrepancies with OpenTelemetry Semantic Conventions, suggesting the use of standard attribute names (e.g., 'feature_flag.provider_name', 'feature_flag.evaluation_reason', 'feature_flag.evaluation_value', 'feature_flag.variant') and recommending that span statuses be explicitly set to 'Error' when failures occur to improve telemetry accuracy.

Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Copy link
Copy Markdown
Member

@askpt askpt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I expect this change to be mentioned in a README since the consumer might need to add extra configuration to remove or add these traces.

cc: @beeme1mr, @open-feature/technical-steering-committee, @WeihanLi, @arttonoyan

Comment thread src/OpenFeature/OpenFeatureActivitySource.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
var provider = providerInfo.Item2;

var activity = OpenFeatureActivitySource.StartActivity("feature_flag.evaluation");
activity?.SetTag("feature_flag.key", flagKey);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the SetTag/SetStatus, think we could add tags in one place and add tags only when IsAllDataRequested

https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.activity.isalldatarequested?view=net-10.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6e943fa - this was a great spot! It helps avoid allocations in high performance scenarios

I wonder if we should add feature_flag.provider.name in all instances or only when IsAllDataRequested is true

@WeihanLi
Copy link
Copy Markdown
Contributor

maybe we want to deprecate the TraceEnricherHook related code also?

Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
var providerMetadata = provider.GetMetadata();
if (providerMetadata != null)
{
activity?.SetTag("feature_flag.provider.name", providerMetadata.Name);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we like to keep these tagName/activityName to be constants in a separated place?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6e943fa - moved the tag names (apart from error.type) to the OpenFeatureActivitySource class

Comment thread samples/AspNetCore/Program.cs Outdated
.ConfigureResource(resource => resource.AddService("openfeature-aspnetcore-sample"))
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.SetSampler(new AlwaysOnSampler())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add AddSource("OpenFeature") to collect OpenFeature activity?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added trace source in 3b8eac5

* Ensure OpenFeature traces are recorded in sample app
* Ensure ActivitySource is disposed of

Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
* Add check on IsAllDataRequested to save on allocations on the activity
  span

Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
@kylejuliandev
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces OpenTelemetry instrumentation to the OpenFeature .NET SDK by adding a new OpenFeatureActivitySource and integrating activity tracking into the OpenFeatureClient evaluation logic. The changes include mapping evaluation results and errors to standard semantic conventions and adding comprehensive tests. Review feedback suggests aligning specific attribute names with OpenTelemetry standards (specifically provider_name and variant), normalizing reason strings to lowercase, and removing a redundant Dispose() call on an activity already managed by a using statement.

Comment thread src/OpenFeature/OpenFeatureActivitySource.cs
Comment thread src/OpenFeature/OpenFeatureActivitySource.cs
Comment thread src/OpenFeature/OpenFeatureActivitySource.cs
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Comment on lines +299 to +305
activity?.SetStatus(ActivityStatusCode.Error);

if (activity?.IsAllDataRequested == true)
{
activity.AddTag("error.type", OpenFeatureActivitySource.GetFlagEvaluationErrorDescription(evaluation.ErrorType));
activity.SetTag(OpenFeatureActivitySource.FeatureFlagErrorMessageName, evaluation.ErrorMessage);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems there's some duplication, maybe we could add one method to avoid duplicates

private static void AttachActivityTags(Activity? activity, FlagEvaluationDetails<T>? evaluation, Exception? exception = null)
{
    if (activity is null) return;
    if (elaluation?.ErrorType != ErrorType.None)
        activity.SetStatus(ActivityStatusCode.Error);
    
    if (activity.IsAllDataRequested != true) return;

    if (elaluation is null)
    {
        // ...
        return;
    }

    activity.SetTag(OpenFeatureActivitySource.FeatureFlagReasonName, OpenFeatureActivitySource.GetFlagEvaluationReasonDescription(evaluation.Reason));
    if (elaluation?.ErrorType == ErrorType.None)
    {
        activity.SetTag(OpenFeatureActivitySource.FeatureFlagValueName, evaluation.Value);
        activity.SetTag(OpenFeatureActivitySource.FeatureFlagVariantName, evaluation.Variant);
    }
    else
    {
        activity.AddTag("error.type", OpenFeatureActivitySource.GetFlagEvaluationErrorDescription(evaluation.ErrorType));
        activity.SetTag(OpenFeatureActivitySource.FeatureFlagErrorMessageName, evaluation.ErrorMessage);
    }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually with all IsAllDataRequested I wonder if makes sense to have an internal extension method to have the AddTag and SetTag. Like AddTagIfRequested or SetTagIfRequested. It would make the code cleaner IMO.

What do you think @WeihanLi and @kylejuliandev?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the extension method approach. It keeps activity enrichment close to the code but simplifies the repeated if IsAllDataRequested checks

Copy link
Copy Markdown
Contributor

@WeihanLi WeihanLi May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think it's more cleaner to introduce extension method for AddTagIfRequested/SetTagIfRequested, but it may cause some duplicated not null and IsAllDataRequested checks, maybe it should be avoid for a hotpath.
While maybe we could evaluate this further if someone complains about this.

@askpt
Copy link
Copy Markdown
Member

askpt commented May 19, 2026

maybe we want to deprecate the TraceEnricherHook related code also?

Not at this point. Until OTEL formally deprecates events in traces, I would keep this Hook enabled since they have different behaviour.

Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Copy link
Copy Markdown
Member

@askpt askpt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two minor comments.

Comment thread src/OpenFeature/OpenFeatureActivitySource.cs Outdated
Comment thread src/OpenFeature/OpenFeatureClient.cs Outdated
Signed-off-by: Kyle Julian <38759683+kylejuliandev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add support for spans instead of span events Update the trace support

4 participants