Skip to content

[FFL-1720] Evaluation Logging: Integration#3147

Merged
typotter merged 14 commits intotypo/FFL-1720-pr3-storage-networkfrom
typo/FFL-1720-pr4-integration
Feb 13, 2026
Merged

[FFL-1720] Evaluation Logging: Integration#3147
typotter merged 14 commits intotypo/FFL-1720-pr3-storage-networkfrom
typo/FFL-1720-pr4-integration

Conversation

@typotter
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown

codecov-commenter commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 33.75000% with 53 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.92%. Comparing base (8ade2db) to head (9b092dc).

Files with missing lines Patch % Lines
...tadog/android/flags/internal/EvaluationsFeature.kt 2.44% 40 Missing ⚠️
...tadog/android/flags/internal/DatadogFlagsClient.kt 67.86% 6 Missing and 3 partials ⚠️
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 33.33% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@                          Coverage Diff                          @@
##           typo/FFL-1720-pr3-storage-network    #3147      +/-   ##
=====================================================================
- Coverage                              71.00%   70.92%   -0.08%     
=====================================================================
  Files                                    906      906              
  Lines                                  33354    33428      +74     
  Branches                                5624     5641      +17     
=====================================================================
+ Hits                                   23681    23706      +25     
- Misses                                  8106     8148      +42     
- Partials                                1567     1574       +7     
Files with missing lines Coverage Δ
...src/main/kotlin/com/datadog/android/flags/Flags.kt 90.91% <100.00%> (ø)
...com/datadog/android/flags/internal/FlagsFeature.kt 85.07% <100.00%> (+0.46%) ⬆️
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 36.67% <33.33%> (+0.14%) ⬆️
...tadog/android/flags/internal/DatadogFlagsClient.kt 88.83% <67.86%> (-3.76%) ⬇️
...tadog/android/flags/internal/EvaluationsFeature.kt 18.87% <2.44%> (-56.13%) ⬇️

... and 36 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.

@typotter typotter force-pushed the typo/FFL-1720-pr3-storage-network branch 2 times, most recently from 46d2cd4 to 5b0da2a Compare February 9, 2026 17:26
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch 2 times, most recently from 4fd1954 to 2d61320 Compare February 9, 2026 18:12
Copy link
Copy Markdown
Contributor Author

@typotter typotter left a comment

Choose a reason for hiding this comment

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

Thanks. PTAL

@typotter typotter requested a review from 0xnm February 9, 2026 18:47
Comment on lines +118 to +119
val service = currentContext?.service
?: (sdkCore as? InternalSdkCore)?.getDatadogContext()?.service
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.

This operation is blocking and may be expensive (and block upstream). Since service doesn't change over SDK lifetime, it is better to read it once during the feature initialization.

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.

🤔 You have suggested removing it from feature initialization before. Do you suggest reverting that or do something differently? wdyt about lazy init?

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.

I was suggesting reading it at the event write stage, this is not implemented. In this case it wouldn't be a blocking call, but an argument received at the withWriteContext callback.

And choosing between making such blocking call multiple times (at the onContextUpdate) vs once (at the feature initialization), the latter is a lighter approach.

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.

Oh, I see, that makes sense. I guess one caveat is rum view name which is dynamic, so on write is too late as it might have changed. We need up-to-date context in processEvaluation() step

Copy link
Copy Markdown
Member

@0xnm 0xnm Feb 10, 2026

Choose a reason for hiding this comment

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

so on write is too late as it might have changed

SDK handles this case. When withWriteContext is called, it is processed on a single thread for the whole SDK, which guarantees sequential processing and also DatadogContext is captured at the moment of the call (it is immutable data class).

This means that if evaluation flow opens withWriteContext as early as possible, and even if there is a time-arranged sequence of client calls (may be done from different threads, so actions may happen in parallel) like startView(A) -> evaluation -> startView(B), evaluation is guaranteed to receive a context at the time once startView(A) finished its processing and it won't be affected by the startView(B) context change.

But I guess since for the evaluation there is an aggregation, and write happens not the moment event is captured, the flow can be different. If write isn't not necessary there is a withContext callback (but there is no callback which would provide only WriteScope though, although it is not a big deal).

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.

Cool. It looks like withContext is what we need here

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.

We are only getting the ddContext once as we are using the currentContext.service and falling through to sdkCore.getDatadogContext() only when the value is null. Also, this first call to onContextUpdate will happen when the Feature is registered so it's not part of a regular queue of onContextUpdate calls (when the context actually is updated). It is, for all intents and purposes, tied into the initialization lifecycle already.

@typotter typotter requested a review from 0xnm February 10, 2026 19:28
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 8ade2db to c095d0d Compare February 13, 2026 15:10
@typotter typotter force-pushed the typo/FFL-1720-pr4-integration branch from 0025368 to 102267f Compare February 13, 2026 15:10
@typotter typotter merged commit 0b4df16 into typo/FFL-1720-pr3-storage-network Feb 13, 2026
6 of 10 checks passed
@typotter typotter deleted the typo/FFL-1720-pr4-integration branch February 13, 2026 18:15
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