Bug Description
FileLogger.configure() returns a promise that never resolves on Android when SLF4J 2.x ends up on the classpath (e.g. via a transitive dependency like Ktor 3.x). This causes any app that awaits the configure call to hang indefinitely at startup.
Root Cause
In FileLoggerModule.configureLogger(), line 83 casts the SLF4J logger factory to logback's LoggerContext:
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
logback-android:2.0.0 registers with SLF4J using the 1.x binding mechanism (org.slf4j.impl.StaticLoggerBinder). SLF4J 2.x ignores this mechanism — it uses a ServiceLoader-based provider system instead. When no provider is found, getILoggerFactory() returns NOPLoggerFactory, and the cast throws a ClassCastException.
The configure() method has no try/catch, so promise.resolve(null) never executes, leaving the JS promise permanently unresolved.
iOS is unaffected because it uses CocoaLumberjack, not SLF4J/Logback.
Reproduction
Any Android project using react-native-file-logger alongside a dependency that transitively pulls in org.slf4j:slf4j-api:2.x will hit this. Common culprits:
io.ktor:ktor-client-*:3.x → slf4j-api:2.0.17
io.mockk:mockk-jvm:1.13+ → slf4j-api:2.0.5
Gradle resolves to the highest version, so slf4j-api:1.7.33 (declared by this library) gets upgraded to 2.x.
Expected Behavior
configure() should resolve or reject the promise regardless of the SLF4J version on the classpath.
Suggested Fix
- Replace the hard cast with a fallback that creates a standalone
LoggerContext when getILoggerFactory() doesn't return one
- Use the stored context consistently in
renewAppender() and for the logger field used by write()
- Wrap
configure() in try/catch so the promise is always settled
I have a working patch and will open a PR shortly.
Environment
- react-native-file-logger: 0.7.2
- React Native: 0.79.x (New Architecture / TurboModules enabled)
- logback-android: 2.0.0
- SLF4J resolved version: 2.0.17 (from Ktor 3.3.1 transitive dep)
Bug Description
FileLogger.configure()returns a promise that never resolves on Android when SLF4J 2.x ends up on the classpath (e.g. via a transitive dependency like Ktor 3.x). This causes any app thatawaits the configure call to hang indefinitely at startup.Root Cause
In
FileLoggerModule.configureLogger(), line 83 casts the SLF4J logger factory to logback'sLoggerContext:logback-android:2.0.0registers with SLF4J using the 1.x binding mechanism (org.slf4j.impl.StaticLoggerBinder). SLF4J 2.x ignores this mechanism — it uses aServiceLoader-based provider system instead. When no provider is found,getILoggerFactory()returnsNOPLoggerFactory, and the cast throws aClassCastException.The
configure()method has no try/catch, sopromise.resolve(null)never executes, leaving the JS promise permanently unresolved.iOS is unaffected because it uses CocoaLumberjack, not SLF4J/Logback.
Reproduction
Any Android project using
react-native-file-loggeralongside a dependency that transitively pulls inorg.slf4j:slf4j-api:2.xwill hit this. Common culprits:io.ktor:ktor-client-*:3.x→slf4j-api:2.0.17io.mockk:mockk-jvm:1.13+→slf4j-api:2.0.5Gradle resolves to the highest version, so
slf4j-api:1.7.33(declared by this library) gets upgraded to 2.x.Expected Behavior
configure()should resolve or reject the promise regardless of the SLF4J version on the classpath.Suggested Fix
LoggerContextwhengetILoggerFactory()doesn't return onerenewAppender()and for theloggerfield used bywrite()configure()in try/catch so the promise is always settledI have a working patch and will open a PR shortly.
Environment