Skip to content
Draft
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
4 changes: 2 additions & 2 deletions tracer/build/PackageVersionsGeneratorDefinitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,10 @@
"IntegrationName": "OpenFeature",
"SampleProjectName": "Samples.OpenFeature",
"NugetPackageSearchName": "OpenFeature",
"MinVersion": "2.0.0",
"MinVersion": "2.3.0",
"MaxVersionExclusive": "3.0.0",
"SpecificVersions": [
"2.0.0",
"2.3.0",
"2.10.0"
]
}
Expand Down
673 changes: 15 additions & 658 deletions tracer/build/PackageVersionsLatestMajors.g.props

Large diffs are not rendered by default.

4,481 changes: 7 additions & 4,474 deletions tracer/build/PackageVersionsLatestMinors.g.props

Large diffs are not rendered by default.

1,023 changes: 32 additions & 991 deletions tracer/build/PackageVersionsLatestSpecific.g.props

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion tracer/build/nuget_version_cache.json
Original file line number Diff line number Diff line change
Expand Up @@ -14257,7 +14257,8 @@
"2.11.3",
"2.11.8",
"2.12.1",
"2.12.4"
"2.12.4",
"2.12.8"
]
},
{
Expand Down
30 changes: 15 additions & 15 deletions tracer/build/supported_versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
"name": "AWSSDK.DynamoDBv2",
"minVersionAvailableInclusive": "3.1.0",
"minVersionSupportedInclusive": "3.1.0",
"minVersionTestedInclusive": "3.1.5.3",
"minVersionTestedInclusive": "3.3.106.47",
"maxVersionSupportedInclusive": "4.0.17.1",
"maxVersionAvailableInclusive": "4.0.17.1",
"maxVersionTestedInclusive": "4.0.17.1"
Expand Down Expand Up @@ -292,7 +292,7 @@
"name": "AWSSDK.Kinesis",
"minVersionAvailableInclusive": "3.1.0",
"minVersionSupportedInclusive": "3.1.0",
"minVersionTestedInclusive": "3.1.3.5",
"minVersionTestedInclusive": "3.3.101.1",
"maxVersionSupportedInclusive": "4.0.8.4",
"maxVersionAvailableInclusive": "4.0.8.4",
"maxVersionTestedInclusive": "4.0.8.4"
Expand Down Expand Up @@ -343,7 +343,7 @@
"name": "AWSSDK.Core",
"minVersionAvailableInclusive": "3.1.0",
"minVersionSupportedInclusive": "3.1.0",
"minVersionTestedInclusive": "3.1.11",
"minVersionTestedInclusive": "3.3.107.40",
"maxVersionSupportedInclusive": "4.0.3.21",
"maxVersionAvailableInclusive": "4.0.3.21",
"maxVersionTestedInclusive": "4.0.3.21"
Expand All @@ -360,7 +360,7 @@
"name": "AWSSDK.SimpleNotificationService",
"minVersionAvailableInclusive": "3.1.0",
"minVersionSupportedInclusive": "3.1.0",
"minVersionTestedInclusive": "3.1.2.1",
"minVersionTestedInclusive": "3.3.102.17",
"maxVersionSupportedInclusive": "4.0.2.20",
"maxVersionAvailableInclusive": "4.0.2.20",
"maxVersionTestedInclusive": "4.0.2.20"
Expand All @@ -377,7 +377,7 @@
"name": "AWSSDK.SQS",
"minVersionAvailableInclusive": "3.1.0",
"minVersionSupportedInclusive": "3.1.0",
"minVersionTestedInclusive": "3.1.0.13",
"minVersionTestedInclusive": "3.3.103.26",
"maxVersionSupportedInclusive": "4.0.2.18",
"maxVersionAvailableInclusive": "4.0.2.18",
"maxVersionTestedInclusive": "4.0.2.18"
Expand Down Expand Up @@ -886,7 +886,7 @@
"name": "log4net",
"minVersionAvailableInclusive": "1.2.10",
"minVersionSupportedInclusive": "1.2.10",
"minVersionTestedInclusive": "1.2.11",
"minVersionTestedInclusive": "2.0.17",
"maxVersionSupportedInclusive": "3.3.0",
"maxVersionAvailableInclusive": "3.3.0",
"maxVersionTestedInclusive": "3.3.0"
Expand All @@ -903,7 +903,7 @@
"name": "MongoDB.Driver",
"minVersionAvailableInclusive": "1.0.3744.30075",
"minVersionSupportedInclusive": "2.1.0",
"minVersionTestedInclusive": "2.0.2",
"minVersionTestedInclusive": "2.30.0",
"maxVersionSupportedInclusive": "3.7.1",
"maxVersionAvailableInclusive": "3.7.1",
"maxVersionTestedInclusive": "3.7.1"
Expand All @@ -920,7 +920,7 @@
"name": "MongoDB.Driver",
"minVersionAvailableInclusive": "1.0.3744.30075",
"minVersionSupportedInclusive": "2.1.0",
"minVersionTestedInclusive": "2.0.2",
"minVersionTestedInclusive": "2.30.0",
"maxVersionSupportedInclusive": "3.5.2",
"maxVersionAvailableInclusive": "3.7.1",
"maxVersionTestedInclusive": "3.7.1"
Expand Down Expand Up @@ -1059,7 +1059,7 @@
"name": "NLog",
"minVersionAvailableInclusive": "1.0.0.505",
"minVersionSupportedInclusive": "1.0.0.505",
"minVersionTestedInclusive": "1.0.0.505",
"minVersionTestedInclusive": "4.7.15",
"maxVersionSupportedInclusive": "6.1.1",
"maxVersionAvailableInclusive": "6.1.1",
"maxVersionTestedInclusive": "6.1.1"
Expand Down Expand Up @@ -1230,7 +1230,7 @@
"name": "Serilog",
"minVersionAvailableInclusive": "0.1.6",
"minVersionSupportedInclusive": "1.0.1",
"minVersionTestedInclusive": "1.4.214",
"minVersionTestedInclusive": "2.12.0",
"maxVersionSupportedInclusive": "4.3.1",
"maxVersionAvailableInclusive": "4.3.1",
"maxVersionTestedInclusive": "4.3.1"
Expand All @@ -1247,7 +1247,7 @@
"name": "ServiceStack.Redis",
"minVersionAvailableInclusive": "2.9.0",
"minVersionSupportedInclusive": "4.0.2",
"minVersionTestedInclusive": "4.5.14",
"minVersionTestedInclusive": "6.1.0",
"maxVersionSupportedInclusive": "10.0.6",
"maxVersionAvailableInclusive": "10.0.6",
"maxVersionTestedInclusive": "10.0.6"
Expand Down Expand Up @@ -1339,10 +1339,10 @@
"name": "StackExchange.Redis",
"minVersionAvailableInclusive": "1.0.187",
"minVersionSupportedInclusive": "1.0.187",
"minVersionTestedInclusive": "1.0.488",
"maxVersionSupportedInclusive": "2.12.4",
"maxVersionAvailableInclusive": "2.12.4",
"maxVersionTestedInclusive": "2.12.4"
"minVersionTestedInclusive": "1.2.6",
"maxVersionSupportedInclusive": "2.12.8",
"maxVersionAvailableInclusive": "2.12.8",
"maxVersionTestedInclusive": "2.12.8"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
<ItemGroup>
<!-- Integration: StackExchange.Redis -->
<!-- Assembly: StackExchange.Redis -->
<!-- Latest package https://www.nuget.org/packages/StackExchange.Redis/2.12.4 -->
<PackageReference Include="StackExchange.Redis" Version="2.12.4" />
<!-- Latest package https://www.nuget.org/packages/StackExchange.Redis/2.12.8 -->
<PackageReference Include="StackExchange.Redis" Version="2.12.8" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

<ItemGroup>
<!-- If you update this version, be sure to update the TargetFrameworks element above-->
<PackageReference Include="OpenFeature" Version="2.0.0" />
<PackageReference Include="OpenFeature" Version="2.3.0" />
</ItemGroup>

<PropertyGroup>
Expand Down
30 changes: 28 additions & 2 deletions tracer/src/Datadog.FeatureFlags.OpenFeature/DatadogProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Channels;
Expand All @@ -20,15 +21,21 @@ namespace Datadog.FeatureFlags.OpenFeature;
/// <summary>
/// OpenFeature V2.0.0+ Provider for Datadog
/// </summary>
public sealed class DatadogProvider : global::OpenFeature.FeatureProvider
public sealed class DatadogProvider : global::OpenFeature.FeatureProvider, IDisposable
{
private static Action? _onNewConfig = null;
private Metadata _metadata = new Metadata("datadog-openfeature-provider");
private readonly Metadata _metadata = new Metadata("datadog-openfeature-provider");
#if NET6_0_OR_GREATER
private readonly FlagEvalMetricsHook _metricsHook;
#endif

/// <summary> Initializes a new instance of the <see cref="DatadogProvider"/> class. </summary>
public DatadogProvider()
{
FeatureFlagsSdk.RegisterOnNewConfigEventHandler(() => SignalGeneralUpdate());
#if NET6_0_OR_GREATER
_metricsHook = new FlagEvalMetricsHook();
#endif
}

/// <summary> Gets a value indicating whether the Datadog's provider is instrumented and available </summary>
Expand Down Expand Up @@ -126,4 +133,23 @@ public override Task<ResolutionDetails<Value>> ResolveStructureValueAsync(string
var res = FeatureFlagsSdk.Resolve<Value>(flagKey, Trace.FeatureFlags.ValueType.Json, defaultValue, context);
return Task.FromResult(res);
}

/// <summary> Gets provider hooks for flag evaluation metrics tracking. </summary>
/// <returns> Returns the list of provider hooks. </returns>
public override IImmutableList<Hook> GetProviderHooks()
{
#if NET6_0_OR_GREATER
return ImmutableList.Create<Hook>(_metricsHook);
#else
return ImmutableList<Hook>.Empty;
#endif
}

/// <inheritdoc/>
public void Dispose()
{
#if NET6_0_OR_GREATER
_metricsHook.Dispose();
#endif
}
}
90 changes: 90 additions & 0 deletions tracer/src/Datadog.FeatureFlags.OpenFeature/FlagEvalMetrics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// <copyright file="FlagEvalMetrics.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

#if NET6_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;

namespace Datadog.FeatureFlags.OpenFeature;

/// <summary>
/// Manages OTel metric instruments for flag evaluation tracking.
/// Uses System.Diagnostics.Metrics which is the standard .NET metrics API.
/// </summary>
internal sealed class FlagEvalMetrics : IDisposable
{
internal const string MeterName = "Datadog.FeatureFlags.OpenFeature";
internal const string MetricName = "feature_flag.evaluations";
internal const string MetricUnit = "{evaluation}";
internal const string MetricDescription = "Number of feature flag evaluations";

internal const string TagFlagKey = "feature_flag.key";
internal const string TagVariant = "feature_flag.result.variant";
internal const string TagReason = "feature_flag.result.reason";
internal const string TagErrorType = "error.type";
internal const string TagAllocationKey = "feature_flag.result.allocation_key";

internal const string MetadataAllocationKey = "dd_allocationKey";

private readonly Meter _meter;
private readonly Counter<long> _counter;

/// <summary>
/// Initializes a new instance of the <see cref="FlagEvalMetrics"/> class.
/// </summary>
public FlagEvalMetrics()
{
_meter = new Meter(MeterName);
_counter = _meter.CreateCounter<long>(
MetricName,
unit: MetricUnit,
description: MetricDescription);
}

/// <summary>
/// Records a single flag evaluation metric with the specified attributes.
/// </summary>
/// <param name="flagKey">The flag key that was evaluated.</param>
/// <param name="variant">The resolved variant, or empty string if none.</param>
/// <param name="reason">The evaluation reason (e.g., "targeting_match", "error").</param>
/// <param name="errorType">The error type if reason is error, or null.</param>
/// <param name="allocationKey">The allocation key if available, or null.</param>
public void Record(
string flagKey,
string? variant,
string reason,
string? errorType,
string? allocationKey)
{
var tags = new List<KeyValuePair<string, object?>>
{
new(TagFlagKey, flagKey),
new(TagVariant, variant ?? string.Empty),
new(TagReason, reason)
};

if (!string.IsNullOrEmpty(errorType))
{
tags.Add(new(TagErrorType, errorType));
}

if (!string.IsNullOrEmpty(allocationKey))
{
tags.Add(new(TagAllocationKey, allocationKey));
}

_counter.Add(1, tags.ToArray());
}

/// <inheritdoc/>
public void Dispose()
{
_meter.Dispose();
}
}
#endif
Loading
Loading