Skip to content

fix(android): refactor KMLog - simplification and added resilience#16152

Open
mcdurdin wants to merge 2 commits into
masterfrom
fix/android/16122-refactor-KMLog
Open

fix(android): refactor KMLog - simplification and added resilience#16152
mcdurdin wants to merge 2 commits into
masterfrom
fix/android/16122-refactor-KMLog

Conversation

@mcdurdin

Copy link
Copy Markdown
Member
  • Clean up KMLog -- simpler code paths, DRY out common validation, remove redundant re-entrancy checks.
  • Use Sentry setTag API and scopes instead of setExtra.
  • Wrap all potential failure points in exception handlers for extra resilience -- do our best to make sure errors are reported in as many cases as possible.

Fixes: #16122
Test-bot: skip

* Clean up `KMLog` -- simpler code paths, DRY out common validation,
  remove redundant re-entrancy checks.
* Use Sentry `setTag` API and scopes instead of `setExtra`.
* Wrap all potential failure points in exception handlers for extra
  resilience -- do our best to make sure errors are reported in as many
  cases as possible.

Fixes: #16122
Test-bot: skip
@keymanapp-test-bot

keymanapp-test-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

User Test Results

Test specification and instructions

User tests are not required

Test Artifacts

  • Android
    • Keyman for Android apk - build : all tests passed (no artifacts on BuildLevel "build")
    • FirstVoices Keyboards for Android apk - build : all tests passed (no artifacts on BuildLevel "build")
    • FirstVoices Keyboards for Android apk (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")
    • Keyman for Android apk (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")

// trigger errors that can also trigger the same logging. We must not get
// caught in an infinite loop / stack-overflow; this field helps us avoid states
// that would otherwise cause error-looping, etc.
private static boolean isLogging = false;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

AFAICT, there is no re-entrancy in this module so this can not arise (the only nested call was from LogExceptionWithData to LogException, and the pattern was actually wrong in this case, as noted in #16122!)

@@ -169,28 +174,7 @@ public static void LogError(String tag, String msg) {
* @param e Throwable exception
*/
public static void LogException(String tag, String msg, Throwable e) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I swapped LogException and LogExceptionWithData implementations -- simpler code path.

}
isLogging = false;

Sentry.withScope(scope -> {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Scopes and tags are the recommended pattern for Sentry 8.x, removes need to call removeExtra() after addExtra().

Note that it's also recommended that we use Logs instead of Breadcrumbs for modern Sentry. Project for another day.

@ermshiperete ermshiperete left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great to see the KMLog improved and the problems fixed!

Comment thread android/KMEA/app/src/main/java/com/keyman/engine/util/KMLog.java
Comment thread android/KMEA/app/src/main/java/com/keyman/engine/util/KMLog.java
String errorMsg = "";
try {
if (msg != null && !msg.isEmpty()) {
errorMsg = msg + "\n" + e.toString();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will throw if e == null.

Suggested change
errorMsg = msg + "\n" + e.toString();
errorMsg = msg + "\n" + e;;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

Comment on lines +217 to +218
if(obj != null && objName != null) {
Sentry.setTag(objName, obj.toString());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From devin.ai:

Sentry tag values have a 200-character limit which may truncate data previously stored as extras

The PR changes Sentry.setExtra(...) to Sentry.setTag(...). Sentry tags are indexed and searchable but have a maximum value length of 200 characters, while extras have no such limit. This matters most for LogExceptionWithData at line 218 where obj.toString() is set as a tag — for example, KeyboardController.java:92-93 passes a JSON list as the obj parameter, which could easily exceed 200 characters and be silently truncated by Sentry. The old code used setExtra which would have preserved the full value.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, I was aware of this. I was trying to remove the need to setExtra and then removeExtra. The use cases for passing large chunks of extra data are pretty narrow. For now, I will restore just this one tag to extra data.

Also add logging if unit test fails
@mcdurdin mcdurdin requested a review from ermshiperete July 1, 2026 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

bug(android): KMLog.LogExceptionWithData doesn't do anything

2 participants