Skip to content

feat: Add trace when evaluating feature flags#755

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

feat: Add trace when evaluating feature flags#755
kylejuliandev wants to merge 10 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

@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.55072% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.63%. Comparing base (ec94acf) to head (6d64f4f).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
src/OpenFeature/OpenFeatureActivitySource.cs 96.87% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #755      +/-   ##
==========================================
+ Coverage   93.47%   93.63%   +0.16%     
==========================================
  Files          68       70       +2     
  Lines        2956     3050      +94     
  Branches      351      368      +17     
==========================================
+ Hits         2763     2856      +93     
  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
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 on lines +44 to +47
static string GetLibraryVersion()
=> typeof(OpenFeatureActivitySource).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion ?? "UNKNOWN";
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.

Could you please remove the +<sha> in the version. You can see it in the screenshots you posted.

Also I wonder if we should "cache" the version string somewhere to prevent doing GetCustomAttribute all the time.

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.

The ActivitySource is static, so it's initialized once during the first flag evaluation and then subsequent evaluations don't fetch a new version

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've opted to use AssemblyVersion instead of the InformationalVersion in 3b8eac5

In Common.prod.props we set the Assembly version

<VersionPrefix>$(VersionNumber)</VersionPrefix>
<AssemblyVersion>$(VersionNumber)</AssemblyVersion>
<FileVersion>$(VersionNumber)</FileVersion>

I do a ToString on the Version, so we get major.minor.patch in the trace:

Screenshot 2026-05-14 200334

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

var activity = OpenFeatureActivitySource.StartActivity("feature_flag.evaluation");
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.

Copy link
Copy Markdown
Contributor

@WeihanLi WeihanLi May 13, 2026

Choose a reason for hiding this comment

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

Wonder if we should set it as Client

personally think it's fine to keep it using default Internal

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 if the Provider (InMemory, Flagd, etc..) traces, they may opt to use Client in this example. I figured here at this point we don't necessarily know if the flag evaluation is remote. But we are confident we are delegating the actual evaluation to another component that is running in the same process

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

var activity = OpenFeatureActivitySource.StartActivity("feature_flag.evaluation");
Copy link
Copy Markdown
Contributor

@WeihanLi WeihanLi May 13, 2026

Choose a reason for hiding this comment

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

Suggested change
var activity = OpenFeatureActivitySource.StartActivity("feature_flag.evaluation");
using var activity = OpenFeatureActivitySource.StartActivity("feature_flag.evaluation");

maybe we could add using for this

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.

Great spot, this was probably leaving activity sources undisposed of (potentially leaving resources hanging). Fixed in 3b8eac5

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 <[email protected]>
* Add check on IsAllDataRequested to save on allocations on the activity
  span

Signed-off-by: Kyle Julian <[email protected]>
@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
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

3 participants