Skip to content

feat: observability features for MAUI and Android#421

Open
abelonogov-ld wants to merge 69 commits intomainfrom
andrey/recordlog
Open

feat: observability features for MAUI and Android#421
abelonogov-ld wants to merge 69 commits intomainfrom
andrey/recordlog

Conversation

@abelonogov-ld
Copy link
Contributor

@abelonogov-ld abelonogov-ld commented Mar 12, 2026

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 LDObserve can 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 NativePluginConnector with a PluginOrchestrator that starts the native bridge once all plugins are registered, and reworks hook exporting (NativeObservabilityHookExporter and new NativeSessionReplayHookExporter) to forward Identify events into session replay.

On Android, removes the extended-instrumentation contributor mechanism and instead shares the OTel SessionManager via ObservabilityContext; session replay becomes a SessionReplayService initialized on onPluginsReady, adds wake-up/reload events and app-title support in RRWeb generation/export, enables metrics in the MAUI Android bridge, and hardcodes replay client_id to observability-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.

* 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
(cherry picked from commit f883e975ca79da891b4178d8a12e27868f0931eb)
* main:
  chore: release main (#401)
(cherry picked from commit 9901600)
* main:
  chore: release main (#406)
  feat: Make Android SDK35 compilable (#405)
* andrey/hooks:
  comment identify stuff
  fat working
  working
  can launch
@abelonogov-ld abelonogov-ld changed the title WIP Android testing feat: observability features for MAUI and Android Mar 14, 2026
)

val requestJson = json.encodeToString(request)
System.out.println("LD:OBS:GraphQLClient requestJson:${requestJson}")
Copy link

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

There are 4 total unresolved issues (including 1 from previous review).

Fix All in Cursor

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)
Copy link

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

}

otelRUM = rumBuilder.build()
sessionManager = capturedSessionManager!!
Copy link

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

#elif ANDROID
var bridge = new LDObserveAndroid.ObservabilityBridge();
var map = DictionaryTypeConverters.ToJavaDictionary(attributes);
bridge.RecordLog(message, severity, map);
Copy link

Choose a reason for hiding this comment

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

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.

Additional Locations (2)
Fix in Cursor Fix in Web

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.

1 participant