Skip to content

feat: vault-core based logger#395

Merged
torkinos merged 6 commits into
tetherto:mainfrom
hakaari:feat/unified-logger
May 12, 2026
Merged

feat: vault-core based logger#395
torkinos merged 6 commits into
tetherto:mainfrom
hakaari:feat/unified-logger

Conversation

@hakaari

@hakaari hakaari commented May 7, 2026

Copy link
Copy Markdown
Contributor

Requirements

Allows extracting logs from main process + worklet for external support.

Changes

  • Added a unified logger behind Diagnostics → Enable logs toggle.
  • Share logs zips them with metadata into the system share sheet.
  • Ability to persist log level (off / debug) in AsyncStorage; Nightly builds default to debug on first launch, every other distribution stays off.
  • Added Sentry behind isNightly() only.
  • Updated README with new Logging and Error reporting sections.

Testing Notes

Tested on iOS Simulator and Pixel 9

Things reviewers should pay attention to

  • Copy

Screenshots/Recordings

Simulator Screenshot - iPhone 17 - 2026-05-07 at 17 28 56

dependencies

tetherto/pearpass-lib-vault-core#55

@hakaari

hakaari commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

@nickgr2 please review. Ignore any inconsistency in package.json, it's not final, pending vault-core PR merge

@nickgr2 nickgr2 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed at 47a36d3. The Diagnostics screen uses the kit cleanly (PageHeader, ToggleSwitch, Button, Text, useTheme, rawTokens), strings go through Lingui, interactive elements have testIDs, and the README addition is a clear public-facing statement of the Sentry boundary. A few things to address before merge.

Blocker

@sentry/react-native is referenced but missing from package.json / package-lock.json.

  • src/utils/sentry.js: import * as Sentry from '@sentry/react-native'
  • app.config.ts: plugins.push('@sentry/react-native/expo')

Neither declares @sentry/react-native as a dependency, and the package isn't in the lockfile. Nightly builds (PEARPASS_DISTRIBUTION=nightly) will fail at prebuild when Expo tries to load the plugin, and initSentry() will throw at runtime. Please add @sentry/react-native (and update the lockfile) — preferably the version you tested with on the simulator/Pixel 9.

Other findings

loadLogConfiguration() doesn't notify subscribers when storage resolves. registerRootComponent(Main) is intentionally ordered before bootstrap() (per the Android-race comment in index.js), so it's possible for things to read getLogLevelSync() / mount useLogLevel before AsyncStorage returns. The first read sees the default ('off' outside nightly, 'debug' on nightly); the listener registered in useLogLevel's useEffect only fires on setLogLevel, never on the storage-load completion, so the stored level isn't observed until the user toggles. Same applies to the subscribeLogLevel callback wired in src/worklet/index.js after setLogOptions(buildLogOptions(getLogLevelSync())) — if vault-core is created before bootstrap finishes, it gets the default instead of the stored level until the user toggles. Suggest firing all listeners at the end of loadLogConfiguration once cached is updated, so existing consumers reconcile.

getDistributionChannel default changed 'standard''production' in src/constants/distribution.js, but app.config.ts still falls back to 'standard'. The two paths now disagree on the fallback string. Functionally harmless because isFdroid()/isNightly() are the only consumers, but worth aligning to avoid a footgun if anything ever reads the channel string directly.

Minor

  • src/worklet/index.js: the subscribeLogLevel callback is never unsubscribed. One client per app lifetime so currently safe, but worth revisiting if the client can ever be torn down and recreated.
  • createFileLogger allocates a fresh TextEncoder per log line — could be hoisted module-level. Style nit.
  • app.config.ts adds the Sentry plugin whenever isNightly, even if PEARPASS_SENTRY_DSN is unset. The runtime initSentry does check if (!dsn) return, so capturing is safe; just a heads-up that the Expo plugin will still be loaded into the build in that case.

@hakaari

hakaari commented May 11, 2026

Copy link
Copy Markdown
Contributor Author

@nickgr2 please review

@nickgr2 nickgr2 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-reviewed at 993f8c6 (3 commits since 47a36d3).

Blocker — resolved

  • @sentry/react-native@8.9.2 now in package.json and lockfile.
  • EXPO_PUBLIC_SENTRY_DSN env var replaces Constants.expoConfig.extra.sentryDsn in both src/utils/sentry.js and src/worklet/index.js, so the gating is consistent across host and worklet.
  • The new defaultIntegrations: false + explicit list in initSentry looks well-thought-out — the comment explaining the Metro module-table failure is exactly the kind of context I want.

Other findings

loadLogConfiguration() still doesn't notify subscribers when AsyncStorage resolves. Same observation as last round — loadLogConfiguration updates cached but never calls for (const fn of listeners) fn(cached). With registerRootComponent(Main) running before bootstrap() awaits storage, any consumer that registered via useLogLevel / subscribeLogLevel before bootstrap settles will continue seeing the default ('off' outside nightly, 'debug' on nightly) until the user toggles. createPearpassVaultClient reads getLogLevelSync() synchronously when first called and uses it for setLogOptions; if it races bootstrap on a cold start, vault-core gets the wrong sink configuration until a toggle reconciles it. Three-line fix at the end of loadLogConfiguration.

Minor

  • src/utils/errorReporter.js writes [reported] {stack} to the log sink whenever logSinkImpl is set, regardless of whether captureExceptionImpl is registered. On non-nightly distributions nothing is actually reported anywhere, but main.log still gets the [reported] … line. Suggest gating that log emission on captureExceptionImpl being set so the prefix stays truthful.
  • README.md: typo "Loggin is off by default" — should be "Logging".
  • package.json swaps the @tetherto/pearpass-lib-ui-kit spec from git+https://…#design-system-v2 to github:tetherto/…#design-system-v2. Both resolve to the same commit; just an inconsistency vs every other tetherto dep on the next line — easy to align.
  • metro.config.cjs now uses getSentryExpoConfig for all builds, not just nightly. Functionally fine (source-map upload is gated on SENTRY_AUTH_TOKEN), worth a heads-up that the Sentry Metro wrapper is in the build path for standard/F-Droid too.

The split between bundle:* (--defer sentry-bare) and bundle:*:nightly for the bare bundles is a clean way to keep sentry-bare out of public worklet bundles.

boris91
boris91 previously approved these changes May 11, 2026
@torkinos torkinos merged commit 72b2fde into tetherto:main May 12, 2026
2 checks passed
giorgikh93 pushed a commit to giorgikh93/pearpass-app-mobile that referenced this pull request May 27, 2026
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.

4 participants