feat: add diagnostics API#219
Open
vazarkevych wants to merge 1 commit into
Open
Conversation
Adds a read-only Diagnostics API to GrowthBookClient exposing SDK health, config, feature, refresh, cache, streaming and remote-eval state: - New diagnostics package with models, enums and provider helpers (health resolver, config/feature/error mappers, secret masker). - getDiagnostics() on GrowthBookClient returning a sanitized snapshot (client keys masked, secrets/URL credentials redacted). - Repository diagnostics accessors and refresh success/failure counters in GBFeaturesRepository, plus SSE connection state tracking. - Shared SDKConstants for default endpoints and SWR TTL.
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
This PR adds a diagnostics API for
GrowthBookClient.The new API exposes a read-only snapshot of the current SDK state:
The goal is to make SDK support and debugging easier by answering common runtime questions:
Motivation
Before this change, users had very limited visibility into the internal SDK state.
If feature evaluations behaved unexpectedly, support and debugging usually required manually checking configuration, logs, cache state, refresh behavior, and streaming behavior separately.
This PR introduces a structured diagnostics snapshot that can be inspected programmatically or copied as JSON into a support ticket.
Public API
A new method is available on
GrowthBookClient:The returned object is immutable and read-only.
Calling
getDiagnostics()does not trigger:A JSON helper is also available:
Diagnostics Response
The diagnostics response is organized into several sections.
sdkSDK metadata.
{ "sdk": { "version": "..." } }healthA high-level derived health summary.
{ "health": { "state": "READY", "issues": [] } }Possible health states:
READYNOT_READYDEGRADEDERRORSHUTDOWNHealth issues include stable machine-readable codes, severity, message, and timestamp.
Example:
{ "code": "FEATURES_STALE", "severity": "WARNING", "message": "Feature data is past its cache expiry.", "timestampMillis": 123456789 }configSanitized SDK configuration metadata.
{ "config": { "apiHost": "https://custom.growthbook.io", "featuresEndpoint": "https://custom.growthbook.io/api/features/cust..._key", "eventsEndpoint": "https://custom.growthbook.io/sub/cust..._key", "clientKeyMasked": "cust..._key", "encryptionConfigured": true, "swrTtlSeconds": 60, "backgroundFetchIntervalMillis": null, "retryMaxAttempts": 5, "enabled": true, "qaMode": false, "stickyBucketingEnabled": false } }Sensitive values are not exposed:
clientKeyis maskedencryptionConfiguredclientClient lifecycle state.
{ "client": { "initialized": true, "shutdown": false, "remoteEvalEnabled": false } }featuresCurrent feature data state.
{ "features": { "state": "LOADED", "source": "LOCAL_REPOSITORY", "available": true, "activeFeatureCount": 12, "totalFeatureCount": 12, "keys": { "available": true, "totalCount": 12, "sampleLimit": 20, "sample": ["checkout-flow", "payment-config"], "truncated": false, "sha256": "..." } } }Feature keys are sampled and hashed to make it easier to compare feature snapshots without dumping the full feature payload.
refreshFeature refresh state, freshness, errors, and counters.
{ "refresh": { "strategy": "STALE_WHILE_REVALIDATE", "lastSuccessfulRefreshAtMillis": 123456789, "lastSuccessfulRefreshAgeMillis": 1000, "nextCacheExpiresAtMillis": 123516789, "millisUntilCacheExpiry": 59000, "stale": false, "successCount": 1, "failureCount": 0, "consecutiveFailures": 0, "lastFailureAtMillis": null, "lastLoadedFromCache": false, "lastError": null } }This makes it possible to distinguish between:
cacheCache status and freshness.
{ "cache": { "state": "AVAILABLE", "mode": "AUTO", "enabled": true, "lastUpdatedMillis": 123456789, "ageMillis": 1000 } }streamingStreaming / SSE state.
{ "streaming": { "state": "CONNECTED", "reconnectAttempts": 0 } }Possible streaming states include:
DISABLEDINITIALIZINGCONNECTEDINTERRUPTEDUNSUPPORTEDSHUTDOWNremoteEvalRemote evaluation configuration and status.
{ "remoteEval": { "enabled": false, "ready": false, "cacheConfigured": false, "cacheSize": 1000, "cacheTtlSeconds": null } }Note:
cacheSizeandcacheTtlSecondscurrently represent configured remote-eval cache values, not live cache occupancy.Security
Diagnostics output is intended to be safe for support workflows.
This PR avoids exposing sensitive values:
clientKeyis maskeddecryptionKey/ legacyencryptionKeyvalues are never returnedtoJson()serializes already-sanitized diagnostics dataExample:
becomes:
Implementation Notes
getDiagnostics()call.FeatureRefreshNotifier, even when no listeners are registered.SDKConstants.esEndpoint() != null) {
lib/src/main/java/growthbook/sdk/java/diagnostics/provider/helper/ConfigDiagnosticsMapper.java:89: return repository.getFeaturesEndpoint();
lib/src/main/java/growthbook/sdk/java/diagnostics/provider/helper/ConfigDiagnosticsMapper.java:100: if (repository != null && repository.getEventsEndpoint() != null) {
lib/src/main/java/growthbook/sdk/java/diagnostics/provider/helper/ConfigDiagnosticsMapper.java:101: return repository.getEventsEndpoint();
Tests
Added dedicated diagnostics coverage for:
toJson()Also moved diagnostics-related
GrowthBookClienttests into a dedicatedGrowthBookClientDiagnosticsTestclass and extracted shared test fixtures.