fix(swift): wire setLogLevel and configureLogging into commons logger…
fix(swift): wire setLogLevel and configureLogging into commons logger (#996)
Description
Background & Problem
Calling RunAnywhere.setLogLevel(_:) or RunAnywhere.configureLogging(_:) on the Swift SDK previously only mutated Swift-side state in SDKLogger (Logging.shared.setMinLogLevel / Logging.shared.configure). It never forwarded the configured minimum log level across the C ABI boundary to the C++ commons logger (rac_logger_set_min_level).
This caused two critical issues:
- Native C++ commons statements (
RAC_LOG_*) continued filtering against commons' default level (RAC_LOG_INFO), ignoring whatever level the host application configured. - The Apple MLX runtime log filter added in #989 (
MLX.swift:66) dynamically queries commons' log level viarac_logger_get_min_level(). Because commons never received updates from Swift:setLogLevel(.debug)failed to lower the threshold, keeping MLX debug logs silenced.setLogLevel(.error)failed to raise the threshold, allowing MLX info/warning output to continue writing to stderr.
Changes Made
- Type-Safe Enum Mapping (
SDKLogger.swift):- Added bidirectional mappings between proto
RALogLeveland C ABIrac_log_level_t(RALogLevel.racLogLevelandrac_log_level_t.raLogLevel), avoiding fragile integer clamping or unsafe pointer casts.
- Added bidirectional mappings between proto
- Central Logging Service Synchronization (
SDKLogger.swift):Logging.configure(_:)now forwardsrac_logger_set_min_level(config.minLogLevel.racLogLevel).Logging.setMinLogLevel(_:)now forwardsrac_logger_set_min_level(level.racLogLevel).
- Public API Entrypoints (
RunAnywhere+Logging.swift):- Imported
CRACommons. - Explicitly forwarded both
RunAnywhere.setLogLevel(_:)andRunAnywhere.configureLogging(_:)torac_logger_set_min_level. RunAnywhere.setDebugMode(_:)automatically synchronizes commons since it routes throughsetLogLevel.
- Imported
- Unit Test Coverage (
LoggingParityTests.swift):- Added comprehensive tests verifying full bidirectional mapping between
RALogLevelandrac_log_level_t. - Verified that
RunAnywhere.setLogLevel,setDebugMode, andconfigureLoggingupdaterac_logger_get_min_level(). - Added clean teardown resetting the level to
.infoto prevent test-order side effects.
- Added comprehensive tests verifying full bidirectional mapping between
Cross-SDK Audit (Issue #996 Checklist Item 4)
As requested in #996, audited the sibling SDKs:
- Kotlin:
RunAnywhere.setLogLevelcurrently mutates host-side_configurationonly (SDKLogger.kt:143). JNI does not yet exposerac_logger_set_min_levelinRunAnywhereBridge.kt. - Flutter:
RunAnywhereLogging.setLogLeveldelegates toSDKLoggerConfig(runanywhere_logging.dart:70), mutating Dart-side state only. - React Native & Web: Setters update JS-side
LoggingManager/SDKLoggerwithout forwarding to native / WASM commons. - Recommended follow-up: open companion issues/PRs for Kotlin JNI, Flutter FFI, and RN/Web to expose
rac_logger_set_min_levelin their respective native bridges.
Closes #996.
Type of Change
- Bug fix
- New feature
- Documentation update
- Refactoring
Testing
- Lint passes locally
- Added/updated tests for changes
Platform-Specific Testing (check all that apply)
Swift SDK / iOS Sample:
- Tested on Mac (macOS target) , CI test matrix
- Pre-commit validation gates passed (
check_agents_claude_sync.sh,check_no_hardcoded_defaults.sh,test_release_version_coherence.py,check_engine_prebuilt_pins.sh --offline). - New unit tests added:
LoggingParityTests.swift.
Kotlin SDK / Android Sample:
- Tested on Android Phone (Emulator or Device)
- Tested on Android Tablet
Flutter SDK / Flutter Sample:
- Tested on iOS
- Tested on Android
React Native SDK / React Native Sample:
- Tested on iOS
- Tested on Android
Web SDK / Web Sample:
- Tested in Chrome (Desktop)
- Tested in Firefox
- Tested in Safari
- WASM backends load (LlamaCpp + ONNX)
- OPFS storage persistence verified (survives page refresh)
- Settings persistence verified (localStorage)
Labels
Please add the appropriate label(s):
SDKs:
-
Swift SDK- Changes to Swift SDK (bindings/swift) -
Kotlin SDK- Changes to Kotlin SDK (bindings/kotlin) -
Flutter SDK- Changes to Flutter SDK (bindings/flutter) -
React Native SDK- Changes to React Native SDK (bindings/react-native) -
Web SDK- Changes to Web SDK (bindings/web) -
Commons- Changes to shared native code (core)
Sample Apps:
-
Flutter Sample- Changes to Flutter example app (bindings/flutter/example) -
React Native Sample- Changes to React Native example app (bindings/react-native/example) -
Minimal Examples- Changes to an in-repo SDK harness (bindings/{swift,kotlin,web}/example)
Checklist
- Code follows project style guidelines
- Self-review completed
- Documentation updated (if needed)
Screenshots
N/A (SDK logging configuration and C++ commons synchronization; no UI changes).
Summary by cubic
Makes Swift setLogLevel, setDebugMode, and configureLogging forward the configured minimum log level to the C++ commons logger via rac_logger_set_min_level, so native RAC_LOG_* statements and the MLX runtime filter respect host-configured levels instead of defaulting to info.
- Adds type-safe bidirectional mappings between
RALogLevelandrac_log_level_t. - Synchronizes commons at both the
Loggingservice layer and theRunAnywherepublic entrypoints. - Performs the commons sync inside the existing unfair lock so concurrent readers never observe a stale level.
- Adds
LoggingParityTestscovering the mappings and that all three entrypoints updaterac_logger_get_min_level(), with teardown restoring the prior configuration and commons level to avoid test-order side effects.
Summary by CodeRabbit
- Bug Fixes
- Swift logging settings now stay synchronized with the C++ logger when configuring logging, changing the minimum log level, or enabling debug mode.
- Log levels now map consistently between Swift and C++, with unrecognized values falling back to the informational level.