feat: add apply dedup and flush delivery telemetry - #575
Open
vahidlazio wants to merge 14 commits into
Open
Conversation
Add telemetry for the apply deduplication feature and WriteFlagLogs batch delivery outcomes across all providers. Apply dedup telemetry (ApplyDedupTelemetry, field 10 on TelemetryData): - applies_total, applies_deduped, applies_not_cached, sweeps (delta counters) - map_size, map_capacity (gauges) - Tracked via inline u64 counters on ApplyDedup — zero overhead - Wired into WASM guest (bounded_flush_logs + prometheus_snapshot) - Wired into Cloudflare resolver (per-request delta) Flush delivery telemetry (fields 11-12 on TelemetryData): - flush_succeeded, flush_failed (delta counters) - Host SDKs track delivery outcomes locally and merge into TelemetryData before the next send — zero WASM calls, no resolve-path contention - JS: addFlushDeliveryTelemetry() decode/set/encode - Java: drainFlushCounters() on WasmFlagLogger, merged in ProviderTelemetryResolver - Go: atomic counters, swap-and-inject in Write() - Python: counters merged in _write_logs() - Cloudflare: tracked in queue consumer via update_prometheus_kv() Proto fields are additive — old consumers ignore them. Follow-up PRs needed in epx-flags-admin and epx-flags-resolver (VictoriaMetricsClient converters) and epx-insights (dashboard GraphType entries) to display the metrics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add events_published, event_batches_succeeded, event_batches_failed (proto fields 13-15 on TelemetryData) to track event pipeline delivery outcomes. Piggybacked on the flag logs TelemetryData channel since the events pipeline has no telemetry path of its own. Host SDKs track event delivery locally and merge counters into TelemetryData during the next flag logs flush — same zero-overhead pattern as flush_succeeded/flush_failed. - JS: counters in addFlushDeliveryTelemetry alongside flush counters - Java: drainEventCounters() on provider, merged in ProviderTelemetryResolver - Go: RecordEventBatch() on FlagLogger interface, drained in Write() - Python: _event_telemetry_* counters, drained in _write_logs() - Cloudflare: update_events_kv() in queue consumer after delivery Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on failure - Remove duplicate map_size Prometheus block in write_apply_dedup (would cause Prometheus/OpenMetrics parser rejection) - Cloudflare: only increment events_published on successful delivery - Java: use separate telemetryFlushSucceeded/telemetryFlushFailed counters instead of reusing failures (which races with the periodic log window) - Add OpenMetrics parser test with all new telemetry types - Add accumulate_delta test for event counters Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bugs fixed: - Remove duplicate map_size Prometheus block (would break scrapers) - Cloudflare: only count events_published on successful delivery - Java: separate telemetryFlushSucceeded/Failed counters to avoid racing with the existing periodic log window - Go: add RecordEventBatch to test mocks (CapturingFlagLogger, trackingFlagLogger, MockFlagLogger) — adding the method to the FlagLogger interface broke all existing tests Tests added: - OpenMetrics parser test with all new telemetry types - Event counter accumulate_delta test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the ApplyDedupTelemetry message to the shared provider proto so host SDKs can read dedup counters (applies_total, applies_deduped, applies_not_cached, sweeps, map_size, map_capacity) from TelemetryData. Verified under concurrent load test (2000 resolves, 2000 events): - applies_total correctly counts only matching resolves entering dedup - applies_deduped shows 97.4% dedup ratio for repeated same-user resolves - map_size/map_capacity gauges report correct values - Zero applies_not_cached (map well within capacity) - No panics or data races under concurrent load Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Go provider's embedded WASM must be built in Docker for deterministic output. The locally-built binary doesn't match the CI Docker build, failing the WASM sync check. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previously committed Python proto was missing apply_dedup (field 10), events_published (field 13), event_batches_succeeded (field 14), and event_batches_failed (field 15). The provider code references these fields and would crash at runtime with AttributeError. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Docker-built WASM reflecting apply_dedup telemetry changes in confidence-resolver. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vahidlazio
marked this pull request as ready for review
September 2, 2026 13:25
…itTelemetry TypeScript strict mode requires all non-optional fields. The existing TelemetryData literal in addProviderInitTelemetry was missing the new flush and event counter fields. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ts-proto drops unknown fields during decode→encode. The provider proto was missing resolveLatency, resolveRate, stateAge, memoryBytes — fields set by the WASM guest that must survive when hosts re-encode TelemetryData (in addFlushDeliveryTelemetry, addProviderInitTelemetry). Without these fields, JS resolve-logging tests fail because resolve rate and latency telemetry are stripped during re-encoding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align with epx-flags-resolver PR #1734: restructure flush and events
telemetry from flat fields (11-15) to nested messages (11-12).
TelemetryData.flush = FlushTelemetry { succeeded, failed }
TelemetryData.events = EventsTelemetry { published, batches_succeeded, batches_failed }
Updated across all providers: JS, Java, Go, Python, Cloudflare, and
core Rust telemetry. WASM rebuilt in Docker for Go sync check.
Also adds WASM-produced fields (resolve_latency, resolve_rate,
state_age, memory_bytes) to provider proto so decode→encode
round-trips in ts-proto preserve them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ApplyDedupTelemetry(proto field 10) tracking dedup counters: applies_total, applies_deduped, applies_not_cached, sweeps, map_size, map_capacityflush_succeeded/flush_failed(proto fields 11-12) tracking WriteFlagLogs batch delivery outcomes across all providersApply Dedup Metrics
applies_totalapplies_dedupedapplies_not_cachedsweepsmap_sizemap_capacityFlush Delivery Metrics
flush_succeededflush_failedCompatibility
Proto fields are additive — old consumers ignore them. Follow-up PRs needed:
convertApplyDedup+convertFlushin VictoriaMetricsClientTest plan
🤖 Generated with Claude Code