Skip to content

feat(ffe): PHP FFE implementation#3630

Open
leoromanovsky wants to merge 10 commits intomasterfrom
feature/ffe-feature-flagging
Open

feat(ffe): PHP FFE implementation#3630
leoromanovsky wants to merge 10 commits intomasterfrom
feature/ffe-feature-flagging

Conversation

@leoromanovsky
Copy link

@leoromanovsky leoromanovsky commented Feb 7, 2026

Motivation

Add FFE (Feature Flags & Experimentation) support to dd-trace-php. PHP applications can evaluate feature flags delivered via Remote Config using the same datadog-ffe Rust engine used by Ruby and Python. Per the RFC "Flag evaluations tracking for APM tracers", we also emit a feature_flag.evaluations OTel counter metric on each evaluation so flag usage can be tracked in Datadog.

Changes

Core FFE Implementation

  • Rust FFI layer (components-rs/ffe.rs): C-callable bridge to datadog-ffe::rules_based — config store, evaluate, result accessors
  • C extension (ext/ddtrace.c): ffe_evaluate, ffe_has_config, ffe_config_changed, ffe_load_config internal functions that marshal PHP arrays to FfeAttribute structs
  • Remote Config (components-rs/remote_config.rs): Register FfeFlags product + FfeFlagConfigurationRules capability; handle add/remove of FFE configs
  • PHP Provider (src/DDTrace/FeatureFlags/Provider.php): Singleton that checks RC config state, calls native evaluate, parses JSON results, reports exposures; enforces reason=ERROR for any non-zero error code per OpenFeature spec
  • Exposure pipeline: LRU dedup cache (65K entries) + batched writer to /evp_proxy/v2/api/v2/exposures (1000 event buffer cap)
  • OpenFeature adapter (src/DDTrace/OpenFeature/DataDogProvider.php): Implements AbstractProvider for the open-feature/sdk composer package
  • Build: Add datadog-ffe to RUST_FILES in Makefile for PECL packaging
  • Tests: LRU cache unit tests, exposure cache unit tests, 220 evaluation correctness tests from JSON fixtures
  • Config: DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED gating via X-macro in ext/configuration.h

OTel Flag Evaluation Metrics (new)

  • src/DDTrace/FeatureFlags/FlagEvalMetrics.php: OTel counter hook that emits feature_flag.evaluations (count=1) after each evaluation. Tags: feature_flag.key, feature_flag.provider.name=datadog, feature_flag.result.variant, feature_flag.result.reason, feature_flag.result.allocation_key, and on error: error.type (type_mismatch / parse_error / flag_not_found).
  • Error code mapping corrected: errorCodeToTag() now maps Rust constants correctly: 1=ERROR_TYPE_MISMATCH→type_mismatch, 2=ERROR_CONFIG_PARSE→parse_error, 3=ERROR_FLAG_UNRECOGNIZED→flag_not_found (was transposed in initial implementation).
  • Provider.php: Forces reason=ERROR when error_code != 0. The Rust layer returns REASON_DEFAULT for FlagUnrecognizedOrDisabled but the OpenFeature spec requires ERROR to be surfaced to callers.

Decisions

Evaluation in Rust, not PHP. All flag evaluation (UFC parsing, targeting rules, shard hashing, allocation resolution) happens in libdatadog's datadog-ffe crate via FFI. PHP only handles orchestration (config lifecycle, exposure dedup, HTTP transport). This matches Ruby and Python — no language re-implements evaluation logic.

Global config behind Mutex<FfeState>. The Rust FFE config is stored in a lazy_static global with a Mutex. PHP is single-threaded per process, so RwLock would be unnecessary complexity.

Reuses existing RC pipeline. FFE configs flow through the same sidecar → ddog_process_remote_configs() path as APM Tracing and Live Debugger. No new polling mechanism.

Structured attributes, not JSON blobs. The C extension converts PHP arrays into FfeAttribute structs (typed: string/number/bool) before calling Rust, avoiding JSON encode/decode overhead on the hot path.

ExposureWriter caps at 1000 events per request. Matches Ruby and Python. Flush via register_shutdown_function.

FlagEvalMetrics via OTel SDK. Uses open-telemetry/api + OTLP exporter. Recorded after the type-specific evaluation method returns (not inside core evaluate()) so type mismatch errors are captured with reason=error rather than the intermediate targeting_match.

ERROR reason forced for non-zero error codes. FlagUnrecognizedOrDisabled returns REASON_DEFAULT from Rust (the default value was served) but the OpenFeature spec requires reason=ERROR whenever an error code is set. Provider.php overrides the Rust-reported reason in this case.

Test Results

Unit tests

Unit tests (local, no extension): 243 tests, 75 assertions, 1 skipped
Unit tests (Docker with extension): 243 tests, 735 assertions — all pass

System tests — all FFE tests pass (PHP 8.0-apache)

Scenario: FEATURE_FLAGGING_AND_EXPERIMENTATION
Library: php@8.0-apache

tests/ffe/test_dynamic_evaluation.py ..                                  [ 11%]
tests/ffe/test_exposures.py ...........                                  [ 76%]
tests/ffe/test_flag_eval_metrics.py .....                                [100%]

=============== 17 passed, 1 xfailed in 0:04:12 ================

The 1 xfail is test_cross_request_dedup — expected because PHP's shared-nothing architecture prevents cross-request LRU state.

OTel metrics tests (all 5 pass)

PASSED Test_FFE_Eval_Metric_Basic        — reason=static, variant=on, allocation_key=default-allocation
PASSED Test_FFE_Eval_Metric_Count        — 5 evaluations → metric count ≥ 5
PASSED Test_FFE_Eval_Metric_Different_Flags — two flags → two metric series
PASSED Test_FFE_Eval_Metric_Error        — reason=error, error.type=flag_not_found
PASSED Test_FFE_Eval_Metric_Type_Mismatch — reason=error, error.type=type_mismatch

LOC (excluding Cargo.lock + JSON fixtures)

Category Lines
Rust FFI 323
C extension 126
PHP source (FFE + metrics) 973
PHP tests 559
Build/wiring 8
Total 1,989

Companion PRs

@datadog-datadog-prod-us1
Copy link

datadog-datadog-prod-us1 bot commented Feb 7, 2026

⚠️ Tests

Fix all issues with BitsAI or with Cursor

⚠️ Warnings

🧪 1028 Tests failed

testSearchPhpBinaries from integration.DDTrace\Tests\Integration\PHPInstallerTest (Datadog) (Fix with Cursor)
DDTrace\Tests\Integration\PHPInstallerTest::testSearchPhpBinaries
Test code or tested code printed unexpected output: Searching for available php binaries, this operation might take a while.
testSimplePushAndProcess from laravel-58-test.DDTrace\Tests\Integrations\Laravel\V5_8\QueueTest (Datadog) (Fix with Cursor)
DDTrace\Tests\Integrations\Laravel\V5_8\QueueTest::testSimplePushAndProcess
Test code or tested code printed unexpected output: spanLinksTraceId: 69b30cfc00000000310a4a7712f67dab
tid: 69b30cfc00000000
hexProcessTraceId: 310a4a7712f67dab
hexProcessSpanId: 97a6a2ae4d2b2f23
processTraceId: 3533718732905282987
processSpanId: 10927600415363772195

phpvfscomposer://tests/vendor/phpunit/phpunit/phpunit:106
testSimplePushAndProcess from laravel-8x-test.DDTrace\Tests\Integrations\Laravel\V8_x\QueueTest (Datadog) (Fix with Cursor)
DDTrace\Tests\Integrations\Laravel\V8_x\QueueTest::testSimplePushAndProcess
Test code or tested code printed unexpected output: spanLinksTraceId: 69b31b040000000029004b1fe086a535
tid: 69b31b0400000000
hexProcessTraceId: 29004b1fe086a535
hexProcessSpanId: 5191849678421ce3
processTraceId: 2954443955838035253
processSpanId: 5877624770492767459

phpvfscomposer://tests/vendor/phpunit/phpunit/phpunit:106
View all

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: c77115f | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

@leoromanovsky leoromanovsky force-pushed the feature/ffe-feature-flagging branch from 18f7f00 to 508a8c8 Compare February 7, 2026 03:32
@codecov-commenter
Copy link

codecov-commenter commented Feb 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.39%. Comparing base (237080d) to head (c77115f).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3630      +/-   ##
==========================================
+ Coverage   62.32%   62.39%   +0.07%     
==========================================
  Files         142      142              
  Lines       13586    13586              
  Branches     1775     1775              
==========================================
+ Hits         8467     8477      +10     
+ Misses       4311     4304       -7     
+ Partials      808      805       -3     

see 3 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 237080d...c77115f. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pr-commenter
Copy link

pr-commenter bot commented Feb 7, 2026

Benchmarks [ tracer ]

Benchmark execution time: 2026-03-12 20:09:41

Comparing candidate commit c77115f in PR branch feature/ffe-feature-flagging with baseline commit 237080d in branch master.

Found 2 performance improvements and 38 performance regressions! Performance is the same for 153 metrics, 1 unstable metrics.

scenario:ComposerTelemetryBench/benchTelemetryParsing

  • 🟥 mem_peak [+101.232KB; +101.232KB] or [+2.481%; +2.481%]

scenario:ContextPropagationBench/benchExtractHeaders128Bit

  • 🟥 mem_peak [+89.520KB; +89.520KB] or [+2.188%; +2.188%]

scenario:ContextPropagationBench/benchExtractHeaders128Bit-opcache

  • 🟩 execution_time [-818.821ns; -762.512ns] or [-49.746%; -46.325%]

scenario:ContextPropagationBench/benchExtractHeaders64Bit

  • 🟥 mem_peak [+89.520KB; +89.520KB] or [+2.188%; +2.188%]

scenario:ContextPropagationBench/benchExtractTraceContext128Bit

  • 🟥 mem_peak [+89.520KB; +89.520KB] or [+2.188%; +2.188%]

scenario:ContextPropagationBench/benchExtractTraceContext128Bit-opcache

  • 🟩 execution_time [-861.715ns; -766.285ns] or [-32.286%; -28.711%]

scenario:ContextPropagationBench/benchExtractTraceContext64Bit

  • 🟥 mem_peak [+89.520KB; +89.520KB] or [+2.188%; +2.188%]

scenario:ContextPropagationBench/benchInject128Bit

  • 🟥 mem_peak [+89.512KB; +89.512KB] or [+2.187%; +2.187%]

scenario:ContextPropagationBench/benchInject64Bit

  • 🟥 mem_peak [+89.512KB; +89.512KB] or [+2.187%; +2.187%]

scenario:EmptyFileBench/benchEmptyFileDdprof

  • 🟥 mem_peak [+117.028KB; +119.974KB] or [+2.230%; +2.286%]

scenario:HookBench/benchHookOverheadInstallHookOnFunction

  • 🟥 mem_peak [+89.648KB; +89.648KB] or [+2.191%; +2.191%]

scenario:HookBench/benchHookOverheadInstallHookOnMethod

  • 🟥 mem_peak [+89.648KB; +89.648KB] or [+2.191%; +2.191%]

scenario:HookBench/benchHookOverheadTraceFunction-opcache

  • 🟥 execution_time [+3.561µs; +7.879µs] or [+2.154%; +4.765%]

scenario:HookBench/benchWithoutHook

  • 🟥 mem_peak [+89.632KB; +89.632KB] or [+2.191%; +2.191%]

scenario:LaravelBench/benchLaravelDdprof

  • 🟥 mem_peak [+119.624KB; +122.357KB] or [+2.278%; +2.331%]

scenario:LogsInjectionBench/benchLogsInfoBaseline-opcache

  • 🟥 execution_time [+112.785ns; +143.615ns] or [+6.794%; +8.651%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization

  • 🟥 execution_time [+2.555µs; +3.745µs] or [+2.375%; +3.481%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization-opcache

  • 🟥 execution_time [+9.489µs; +11.151µs] or [+9.051%; +10.636%]

scenario:PHPRedisBench/benchRedisBaseline

  • 🟥 mem_peak [+90.392KB; +90.392KB] or [+2.209%; +2.209%]

scenario:PHPRedisBench/benchRedisOverhead-opcache

  • 🟥 mem_peak [+52.184KB; +52.184KB] or [+2.123%; +2.123%]

scenario:SamplingRuleMatchingBench/benchGlobMatching1

  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchGlobMatching2

  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchGlobMatching3

  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchGlobMatching4

  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchRegexMatching1

  • 🟥 execution_time [+79.314ns; +150.286ns] or [+6.781%; +12.849%]
  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchRegexMatching1-opcache

  • 🟥 execution_time [+54.077ns; +87.723ns] or [+4.259%; +6.910%]

scenario:SamplingRuleMatchingBench/benchRegexMatching2

  • 🟥 execution_time [+90.420ns; +136.580ns] or [+7.769%; +11.736%]
  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchRegexMatching2-opcache

  • 🟥 execution_time [+37.310ns; +93.490ns] or [+2.894%; +7.253%]

scenario:SamplingRuleMatchingBench/benchRegexMatching3

  • 🟥 execution_time [+83.403ns; +145.797ns] or [+7.136%; +12.475%]
  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchRegexMatching3-opcache

  • 🟥 execution_time [+29.089ns; +93.511ns] or [+2.248%; +7.228%]

scenario:SamplingRuleMatchingBench/benchRegexMatching4

  • 🟥 execution_time [+113.684ns; +152.916ns] or [+9.932%; +13.360%]
  • 🟥 mem_peak [+86.392KB; +86.392KB] or [+2.110%; +2.110%]

scenario:SamplingRuleMatchingBench/benchRegexMatching4-opcache

  • 🟥 execution_time [+43.111ns; +96.089ns] or [+3.359%; +7.487%]

scenario:SpanBench/benchDatadogAPI

  • 🟥 mem_peak [+88.160KB; +88.160KB] or [+2.154%; +2.154%]

scenario:WordPressBench/benchWordPressBaseline

  • 🟥 mem_peak [+162.720KB; +162.720KB] or [+2.011%; +2.011%]

scenario:WordPressBench/benchWordPressDdprof

  • 🟥 mem_peak [+162.720KB; +162.720KB] or [+2.011%; +2.011%]

scenario:WordPressBench/benchWordPressOverhead

  • 🟥 mem_peak [+162.720KB; +162.720KB] or [+2.011%; +2.011%]

gh-worker-dd-mergequeue-cf854d bot pushed a commit to DataDog/libdatadog that referenced this pull request Feb 9, 2026
## Motivation

Add Feature Flagging and Experimentation (FFE) support to the remote config infrastructure, enabling tracers to subscribe to FFE_FLAGS configurations via the sidecar.

WIP: php tracer changes (DataDog/dd-trace-php#3630)

## Changes

- Add `FfeFlags` variant to `RemoteConfigProduct` enum
- Add `"FFE_FLAGS"` string mapping in Display and FromStr
- Add `FfeFlagConfigurationRules = 46` to `RemoteConfigCapabilities`
- Add `FfeFlags(Vec<u8>)` variant to `RemoteConfigData` to preserve raw config bytes

## Decisions

- Raw bytes are preserved (not parsed) in `FfeFlags(Vec<u8>)` since each tracer handles evaluation with the `datadog-ffe` crate directly
- Capability bit 46 matches the server-side FFE capability definition

Co-authored-by: leo.romanovsky <leo.romanovsky@datadoghq.com>
@leoromanovsky leoromanovsky force-pushed the feature/ffe-feature-flagging branch from 1990188 to 867337e Compare February 9, 2026 19:24
@leoromanovsky leoromanovsky changed the title Feature/ffe feature flagging port ffe feature flagging sdk to php Feb 9, 2026
@leoromanovsky leoromanovsky force-pushed the feature/ffe-feature-flagging branch from a24b1ae to 24e4304 Compare February 11, 2026 13:41
@leoromanovsky leoromanovsky force-pushed the feature/ffe-feature-flagging branch from 2a5d688 to 1ec323b Compare February 12, 2026 00:52
@leoromanovsky leoromanovsky changed the title port ffe feature flagging sdk to php feat(ffe): PHP FFE implementation with OTel flag evaluation metrics Mar 11, 2026
Add FFE support to dd-trace-php. Flag evaluation is delegated to
libdatadog's datadog-ffe Rust crate via FFI. PHP handles orchestration:
config lifecycle, exposure dedup, and HTTP transport.

Rust FFI layer (components-rs/ffe.rs):
- C-callable bridge to datadog-ffe::rules_based
- Global config store behind Mutex<FfeState>
- Structured attribute passing (no JSON on hot path)

C extension (ext/ddtrace.c):
- ffe_evaluate, ffe_has_config, ffe_config_changed, ffe_load_config
- Marshals PHP arrays to FfeAttribute structs

Remote Config (components-rs/remote_config.rs):
- Register FfeFlags product + FfeFlagConfigurationRules capability
- Handle add/remove of FFE configs via sidecar

PHP Provider (src/DDTrace/FeatureFlags/Provider.php):
- Singleton checking RC config state
- Calls native evaluate, parses JSON results
- Reports exposures via LRU-deduplicated writer

Exposure pipeline:
- LRU cache (65K entries) with length-prefixed composite keys
- Batched writer to /evp_proxy/v2/api/v2/exposures (1000 cap)
- Auto-flush via register_shutdown_function

OpenFeature adapter (src/DDTrace/OpenFeature/DataDogProvider.php):
- Implements AbstractProvider for open-feature/sdk

Build:
- Add datadog-ffe to RUST_FILES in Makefile for PECL packaging
- Cargo.lock: minimal additions only (73 new crates, no gratuitous bumps)
- Bump libdatadog to ed316b638 (FFE RC support, libdatadog#1532)

Tests:
- LRU cache unit tests (11 tests)
- Exposure cache unit tests (12 tests)
- 220 evaluation correctness tests from JSON fixtures

Config: DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED (default: false)
…OpenFeature layers

- Add null check for flag_key in ddog_ffe_evaluate Rust FFI
- Set variant in OpenFeature ResolutionDetails (was always null)
- Replace magic numbers with named constants for reason/error codes
- Fix json_decode null ambiguity in JSON type parsing with json_last_error()
- Add dropped event tracking and curl failure logging (DD_TRACE_DEBUG)
- Guard against missing curl extension in ExposureWriter flush
- Fix buildEvent docblock parameter order
Add FlagEvalMetrics OpenFeature hook that records an OTel counter
(feature_flag.evaluations) after every flag evaluation.

Attributes: feature_flag.key, feature_flag.result.variant,
feature_flag.result.reason (lowercase), error.type (on error).

Enabled only when DD_METRICS_OTEL_ENABLED=true and open-telemetry/sdk
is installed. Is a complete noop otherwise.

Register hook in DataDogProvider constructor via setHooks().
Add FlagEvalMetrics.php to _files_tracer.php autoloader.
…-zero error codes

- Fix errorCodeToTag() to match actual Rust constants:
  1=ERROR_TYPE_MISMATCH→type_mismatch, 2=ERROR_CONFIG_PARSE→parse_error,
  3=ERROR_FLAG_UNRECOGNIZED→flag_not_found (was transposed)
- Per OpenFeature spec, force reason=ERROR for any non-zero error_code.
  FlagUnrecognizedOrDisabled returns REASON_DEFAULT from the Rust layer
  but must be reported as ERROR to callers.
- FlagEvalMetrics.php: class constant visibility (private const) requires
  PHP 7.1+; drop to bare const for PHP 7.0 compatibility. The class is
  already internal so visibility adds nothing.
- metadata/supported-configurations.json: regenerate after adding
  DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED to configuration.h.
  Fixes the "Configuration Consistency" CI check.
…tements

Windows MSVC compiles PHP extensions in C89 mode (no /std:c11),
which requires all variable declarations to precede executable
statements within a block scope.

The ffe_evaluate handler had three violations:
- c_attrs and attrs_count declared after the targeting_key if-statement
- idx/key/val declared after the c_attrs = ecalloc() call
- val/var/ak declared after array_init(return_value)

Moves all declarations to the top of their respective blocks.
@leoromanovsky leoromanovsky changed the title feat(ffe): PHP FFE implementation with OTel flag evaluation metrics feat(ffe): PHP FFE implementation Mar 11, 2026
- Add feature_flag.provider.name=datadog to OTel metric attributes
- Propagate error codes to OpenFeature ResolutionDetails via withError()
- Prefer dd_trace_env_config over getenv in isFeatureFlagEnabled()
- Log non-2xx HTTP status codes in ExposureWriter debug mode
- Clarify continue-in-switch comment in ddtrace.c
@leoromanovsky leoromanovsky requested review from a team, dd-oleksii and greghuels and removed request for a team March 12, 2026 01:32
Adds EvaluationTest.php with a data-provider that scans all JSON fixture
files under tests/FeatureFlags/fixtures/evaluation-cases/ and drives
ffe_evaluate() for each case, asserting value and reason.

Fixture files cover boolean, integer, numeric, string, JSON, kill-switch,
disabled, regex, date, comparator, null-operator, and special-character
flag types. JSON variation fixtures use float values (1.0/2.0) matching
the raw JSON returned by the FFE engine (php json_decode preserves the
decimal point from the UFC config).

Also fixes a minor LRUCache put() return-value doc inconsistency.
@leoromanovsky leoromanovsky marked this pull request as ready for review March 12, 2026 18:56
@leoromanovsky leoromanovsky requested review from a team as code owners March 12, 2026 18:56
Copy link
Member

@dd-oleksii dd-oleksii left a comment

Choose a reason for hiding this comment

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

Looks good overall. I think the only major piece is that we shouldn't default targeting key to empty string. oh, and a suspicious const-cast that probably needs some comments/justification

Not sure if that would speed up reviews or not but this PR seems pretty splittable:

  • general setup returning default values, OF integration, public API
  • evaluation, rust pieces
  • exposures, lru cache, etc.
  • evaluation metrics

/// contention is not a practical concern. Keeping a Mutex for simplicity.
struct FfeState {
config: Option<Configuration>,
changed: bool,
Copy link
Member

Choose a reason for hiding this comment

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

minor: not sure how changed is used by the other side but having a global changed flag seems error-prone. What do you think about replacing it with version: u64?

Comment on lines +75 to +77
let was_changed = state.changed;
state.changed = false;
was_changed
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: not necessarily better but there's a function for this:

Suggested change
let was_changed = state.changed;
state.changed = false;
was_changed
std::mem::relpace(&mut state.changed, false)

Comment on lines +115 to +120
pub value_json: CString,
pub variant: Option<CString>,
pub allocation_key: Option<CString>,
pub reason: i32,
pub error_code: i32,
pub do_log: bool,
Copy link
Member

Choose a reason for hiding this comment

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

minor: shall fields be non-public if it's supposed to be opaque?

Suggested change
pub value_json: CString,
pub variant: Option<CString>,
pub allocation_key: Option<CString>,
pub reason: i32,
pub error_code: i32,
pub do_log: bool,
value_json: CString,
variant: Option<CString>,
allocation_key: Option<CString>,
reason: i32,
error_code: i32,
do_log: bool,

attributes_count: usize,
) -> *mut FfeResult {
if flag_key.is_null() {
return std::ptr::null_mut();
Copy link
Member

Choose a reason for hiding this comment

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

minor: consider returning an error result on errors?

};

// Build targeting key
let tk = if targeting_key.is_null() {
Copy link
Member

Choose a reason for hiding this comment

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

nitpick:

Suggested change
let tk = if targeting_key.is_null() {
let targeting_key = if targeting_key.is_null() {

return rtrim($agentUrl, '/');
}

$host = $this->getConfigValue('DD_AGENT_HOST', 'localhost');
Copy link
Member

Choose a reason for hiding this comment

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

just checking — is this name correct? The other two start with DD_TRACE_AGENT and this one is DD_AGENT

Comment on lines +14 to +29
private static $REASON_MAP = [
0 => 'STATIC',
1 => 'DEFAULT',
2 => 'TARGETING_MATCH',
3 => 'SPLIT',
4 => 'DISABLED',
5 => 'ERROR',
];

private static $TYPE_MAP = [
'STRING' => 0,
'INTEGER' => 1,
'NUMERIC' => 2,
'BOOLEAN' => 3,
'JSON' => 4,
];
Copy link
Member

Choose a reason for hiding this comment

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

minor: does it make sense to keep these translations in C, so we can use enums vs. having to sync maps manually?

{
$this->writer = new ExposureWriter();
$this->exposureCache = new ExposureCache(65536);
$this->enabled = $this->isFeatureFlagEnabled();
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: misleading name for the function

* Flag configurations are received via Remote Config through the sidecar.
* Reports exposure events to the EVP proxy for analytics.
*/
class Provider
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't look like it actually implements openfeature provider, so the name is misleading

Comment on lines +100 to +104
$targetingKey = '';
$attributes = [];

if ($context !== null) {
$targetingKey = $context->getTargetingKey() ?? '';
Copy link
Member

Choose a reason for hiding this comment

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

major: don't default targeting key to empty string. Default value should be null

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.

3 participants