feat: observability features for MAUI and Android#421
feat: observability features for MAUI and Android#421abelonogov-ld wants to merge 69 commits intomainfrom
Conversation
* main: feat: Optional Jet Compose (#402) feat: Android Incremental Image Diff compression (#390) chore: add CLAUDE.md (#398) chore: release main (#400) fix: correct react native session replay build step (#399) chore: release main (#396) fix: Android span e2e tests (#397) fix: improve network response capture (#379) # Conflicts: # sdk/@launchdarkly/mobile-dotnet/.vscode/tasks.json
* main: chore: release main (#401)
(cherry picked from commit 9901600)
* andrey/hooks: comment identify stuff fat working working can launch
sdk/@launchdarkly/mobile-dotnet/observability/observe/plugin/ObservabilityHook.cs
Show resolved
Hide resolved
This reverts commit 65d1f0d.
sdk/@launchdarkly/mobile-dotnet/observability/Directory.Build.props
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/mobile-dotnet/observability/bridge/DictionaryTypeConverters.cs
Show resolved
Hide resolved
This reverts commit 5145c71.
| ) | ||
|
|
||
| val requestJson = json.encodeToString(request) | ||
| System.out.println("LD:OBS:GraphQLClient requestJson:${requestJson}") |
There was a problem hiding this comment.
Debug print statements accidentally committed in production code
High Severity
Numerous System.out.println debug statements were left in production Android SDK code across multiple files. The most critical is in GraphQLClient.kt which logs the full requestJson including GraphQL query variables, and SessionReplayApiService.kt which logs sessionSecureId, userIdentifier, and userObject — potentially exposing PII. Additional debug prints appear in SessionReplayExporter.kt, ReplayInstrumentation.kt, Observability.kt, SessionReplay.kt, and SessionReplayHookExporter.kt.
Additional Locations (2)
...ib/src/main/kotlin/com/launchdarkly/observability/replay/exporter/SessionReplayApiService.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
There are 4 total unresolved issues (including 1 from previous review).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| .anonymous(true) | ||
| .build() | ||
|
|
||
| //LDClient.get().identify(anonContext) |
There was a problem hiding this comment.
Unused variable and commented-out code committed
Low Severity
The anonContext variable is created but never used because the LDClient.get().identify(anonContext) call on line 96 is commented out. This looks like leftover debugging or experimentation code that was accidentally included in the commit.
| } | ||
|
|
||
| otelRUM = rumBuilder.build() | ||
| sessionManager = capturedSessionManager!! |
There was a problem hiding this comment.
Force-unwrap of captured session manager is fragile
Medium Severity
capturedSessionManager!! will throw a NullPointerException if the ld-session-manager-bridge instrumentation's install callback is never invoked during rumBuilder.build(). This relies on OpenTelemetryRum synchronously installing all instrumentations during build(), which is an internal implementation detail of the OTel Android library that could change.
| #elif ANDROID | ||
| var bridge = new LDObserveAndroid.ObservabilityBridge(); | ||
| var map = DictionaryTypeConverters.ToJavaDictionary(attributes); | ||
| bridge.RecordLog(message, severity, map); |
There was a problem hiding this comment.
New bridge instance allocated per API call
Low Severity
Every Android method (RecordLog, RecordError, RecordMetric, RecordCount, RecordIncr, RecordHistogram, RecordUpDownCounter) creates a new LDObserveAndroid.ObservabilityBridge() on each call. This allocates a new JVM object via JNI for every telemetry event, which adds unnecessary overhead—especially for high-frequency metrics or logs. A single cached instance would suffice.


Summary
How did you test this change?
Are there any deployment considerations?
Note
High Risk
High risk because it refactors Android session replay/observability initialization and export behavior (session management, identify handling, payload emission), and changes the MAUI native bridge/plugin orchestration across iOS/Android, which can affect telemetry correctness and data volume.
Overview
Adds full .NET MAUI Observability documentation and expands the MAUI native bridge so
LDObservecan record logs/errors/metrics on both iOS and Android, including nested attribute conversion and new native hook proxies for observability vs session replay.Refactors MAUI plugin startup by replacing
NativePluginConnectorwith aPluginOrchestratorthat starts the native bridge once all plugins are registered, and reworks hook exporting (NativeObservabilityHookExporterand newNativeSessionReplayHookExporter) to forwardIdentifyevents into session replay.On Android, removes the extended-instrumentation contributor mechanism and instead shares the OTel
SessionManagerviaObservabilityContext; session replay becomes aSessionReplayServiceinitialized ononPluginsReady, adds wake-up/reload events and app-title support in RRWeb generation/export, enables metrics in the MAUI Android bridge, and hardcodes replayclient_idtoobservability-android. Also updates the MAUI sample app with a new Dialogs test page (toolkit popups/bottom sheets/UIWindow) and small e2e demo tweaks (session replay header/toggle, benchmark title, dependency bumps).Written by Cursor Bugbot for commit 271f22f. This will update automatically on new commits. Configure here.