Skip to content

[FFL-1720] Evaluation Logging: Integration#3147

Open
typotter wants to merge 9 commits intotypo/FFL-1720-pr3-storage-networkfrom
typo/FFL-1720-pr4-integration
Open

[FFL-1720] Evaluation Logging: Integration#3147
typotter wants to merge 9 commits intotypo/FFL-1720-pr3-storage-networkfrom
typo/FFL-1720-pr4-integration

Conversation

@typotter
Copy link
Contributor

@typotter typotter commented Jan 22, 2026

🥞 Evaluation Logging Stacked Pull Requests 🥞

👉 Integration & Configuration (this PR)
☑️ Storage & Network Infrastructure (PR #3146)
☑️ Aggregation Engine & Test Utilities (PR #3145)
☑️ FlagEvaluation Schema (PR #3166)
☑️ Event Schema & Data Models (PR #3144)
☑️ Evaluations Subfeature (PR #3159)
feature/flags-evaluations-logging (feature branch)

Datadog Internal
🎟️ Ticket: FFL-1720 - Implement Evaluation Logging for Android SDK

What does this PR do?

Wires the evaluation logging feature end-to-end by connecting the EvaluationsFeature to the flag evaluation flow. This is the final PR that enables evaluation logging in the Flags SDK.

Motivation

We need to implement Evaluation Logging to provide comprehensive visibility into all feature flag evaluations, including defaults, errors, and successful matches. This goes beyond exposure logging by capturing aggregated metrics about evaluation frequency, error rates, and runtime default usage across all flags.

Additional Notes

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

Copy link
Contributor Author

typotter commented Jan 22, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from 5a11e3d to 1c2b043 Compare January 22, 2026 16:29
@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch 2 times, most recently from 7ceef6b to 7c8d6b7 Compare January 22, 2026 21:27
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from 1c2b043 to cc350e3 Compare January 22, 2026 21:27
@typotter typotter mentioned this pull request Jan 27, 2026
3 tasks
@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch 4 times, most recently from 3618528 to cce61c1 Compare January 28, 2026 23:04
@typotter typotter mentioned this pull request Jan 30, 2026
3 tasks
@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch from 8813c89 to 56da165 Compare January 30, 2026 20:54
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from cc350e3 to 8c8b89d Compare January 30, 2026 20:54
@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch 4 times, most recently from e84dada to fb01eef Compare February 2, 2026 06:20
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from 8c8b89d to 14f24f6 Compare February 2, 2026 06:36
@typotter typotter changed the title [FFL-1720] Evaluation Logging: Integration & Configuration [FFL-1720] Evaluation Logging: Integration Feb 2, 2026
@typotter typotter marked this pull request as ready for review February 2, 2026 06:46
@typotter typotter requested a review from a team as a code owner February 2, 2026 06:46
@codecov-commenter
Copy link

codecov-commenter commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 36.47059% with 54 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.86%. Comparing base (3a685c2) to head (a0fea1d).

Files with missing lines Patch % Lines
...tadog/android/flags/internal/EvaluationsFeature.kt 2.33% 42 Missing ⚠️
...tadog/android/flags/internal/DatadogFlagsClient.kt 66.67% 7 Missing and 3 partials ⚠️
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 0.00% 2 Missing ⚠️
Additional details and impacted files
@@                          Coverage Diff                          @@
##           typo/FFL-1720-pr3-storage-network    #3147      +/-   ##
=====================================================================
- Coverage                              70.92%   70.86%   -0.06%     
=====================================================================
  Files                                    906      906              
  Lines                                  33353    33430      +77     
  Branches                                5623     5643      +20     
=====================================================================
+ Hits                                   23654    23690      +36     
- Misses                                  8127     8166      +39     
- Partials                                1572     1574       +2     
Files with missing lines Coverage Δ
...src/main/kotlin/com/datadog/android/flags/Flags.kt 92.86% <100.00%> (+1.95%) ⬆️
...com/datadog/android/flags/internal/FlagsFeature.kt 85.07% <100.00%> (+0.46%) ⬆️
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 36.21% <0.00%> (-0.31%) ⬇️
...tadog/android/flags/internal/DatadogFlagsClient.kt 88.42% <66.67%> (-2.94%) ⬇️
...tadog/android/flags/internal/EvaluationsFeature.kt 18.18% <2.33%> (-56.82%) ⬇️

... and 38 files with indirect coverage changes

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

@datadog-datadog-prod-us1

This comment has been minimized.

Integrates the evaluation logging feature end-to-end, enabling it in the SDK.

Configuration (FlagsConfiguration):
- Add trackEvaluations(enabled: Boolean) - default true (EVALLOG.12)
- Add useCustomEvaluationEndpoint(endpoint: String) - for testing/proxies
- Add evaluationFlushInterval(intervalMs: Long) - configurable 1-60s, default 10s
- Validation: interval coerced to valid range

Lifecycle (FlagsFeature):
- Initialize evaluation processor on onInitialize() when trackEvaluations enabled
  - Creates scheduled executor for periodic flushing
  - Creates evaluation writer (EvaluationEventRecordWriter)
  - Schedules periodic flush task
- Clean up on onStop():
  - Flush remaining evaluations via processor.stop()
  - Clean up processor and writer references
- Renamed processor → exposureProcessor for clarity
- Renamed dataWriter → exposureWriter for clarity

Integration (DatadogFlagsClient):
- Accept both exposureProcessor and evaluationProcessor (optional)
- Add writeEvaluationEvent() method to log evaluations
- Track ALL evaluations when trackEvaluations enabled:
  - Success evaluations in trackResolution()
  - Error evaluations via new trackErrorResolution() method
- Error evaluations create synthetic PrecomputedFlag with ERROR reason

Factory (FlagsClient):
- Pass both processors to DatadogFlagsClient constructor

Test Updates:
- DatadogFlagsClientTest: Update all instantiations to pass both processors
- FlagsFeatureTest: Update to test dual processor initialization
- Add mock for createScheduledExecutorService()

EVALLOG compliance: Enables evaluation logging (2, 3, 4, 5, 8, 10, 11, 12, 13)
Zero user-facing breaking changes - all new options have defaults.
@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch from fb01eef to 3a685c2 Compare February 2, 2026 18:47
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from cccb7f9 to 03a8d8d Compare February 2, 2026 18:47
internal class FlagsFeature(
private val sdkCore: FeatureSdkCore,
internal val flagsConfiguration: FlagsConfiguration,
internal val evaluationsFeature: EvaluationsFeature? = null
Copy link
Member

Choose a reason for hiding this comment

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

Having it as a property just to be read in the FlagsClient setup without a real usage inside FlagsFeature may look a bit confusing. Maybe simply get it in the FlagsClient.Builder.build as it is done for the FlagsFeature?

doLog = false,
allocationKey = "",
variationKey = "",
extraLogging = org.json.JSONObject(),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
extraLogging = org.json.JSONObject(),
extraLogging = JSONObject(),

We then need to have it as a static object instead of creating the same object all the time. But only if it is not supposed to be mutated during the downstream processing.


// Get initial service from DatadogContext
val internalSdkCore = sdkCore as? InternalSdkCore
val initialService = internalSdkCore?.getDatadogContext()?.service
Copy link
Member

Choose a reason for hiding this comment

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

We should avoid doing this since it is a blocking call and may slow down SDK initialization.

What prevents from reading RUM context and SDK context during the event write stage? I believe it is evaluation aggregation where we write data to the disk only after some time.

Normally, service doesn't change during the SDK core lifetime, because there is no way to set if after SDK is initialized, so it can be read actually during the event write phase, not here.

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.

4 participants