mirror of
https://github.com/bitwarden/android.git
synced 2026-11-09 10:34:18 -06:00
chore: Add logger for the SDK (#7403)
This commit is contained in:
@@ -7,8 +7,10 @@ import com.bitwarden.core.util.isBuildVersionAtLeast
|
||||
import com.bitwarden.data.manager.NativeLibraryManager
|
||||
import com.bitwarden.sdk.Client
|
||||
import com.bitwarden.sdk.ManagedSettingsBindingClient
|
||||
import com.bitwarden.sdk.initLogger
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactory
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
@@ -17,11 +19,13 @@ import kotlinx.coroutines.runBlocking
|
||||
/**
|
||||
* Primary implementation of [SdkClientManager].
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
internal class SdkClientManagerImpl(
|
||||
nativeLibraryManager: NativeLibraryManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
sdkRepoFactory: SdkRepositoryFactory,
|
||||
sdkPlatformApiFactory: SdkPlatformApiFactory,
|
||||
sdkLoggerFactory: SdkLoggerFactory,
|
||||
private val featureFlagManager: FeatureFlagManager,
|
||||
private val clientProvider: suspend (
|
||||
userId: String?,
|
||||
@@ -63,6 +67,11 @@ internal class SdkClientManagerImpl(
|
||||
if (!isBuildVersionAtLeast(Build.VERSION_CODES.S)) {
|
||||
nativeLibraryManager.loadLibrary("bitwarden_uniffi")
|
||||
}
|
||||
initLogger(
|
||||
callback = sdkLoggerFactory.getLogCallback(),
|
||||
level = sdkLoggerFactory.logLevel,
|
||||
platformLogger = false,
|
||||
)
|
||||
// Initialize this now, so that we can access it synchronously later on.
|
||||
globalClientDeferred = ioScope.async { clientProvider(null, null) }
|
||||
}
|
||||
|
||||
+13
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.manager.di
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.core.content.getSystemService
|
||||
import com.bitwarden.core.data.manager.BuildInfoManager
|
||||
import com.bitwarden.core.data.manager.dispatcher.DispatcherManager
|
||||
import com.bitwarden.core.data.manager.dispatcher.DispatcherManagerImpl
|
||||
import com.bitwarden.core.data.manager.realtime.RealtimeManager
|
||||
@@ -93,6 +94,8 @@ import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactoryImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactoryImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactoryImpl
|
||||
import com.x8bit.bitwarden.data.platform.processor.AuthenticatorBridgeProcessor
|
||||
import com.x8bit.bitwarden.data.platform.processor.AuthenticatorBridgeProcessorImpl
|
||||
import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepository
|
||||
@@ -241,12 +244,14 @@ object PlatformManagerModule {
|
||||
nativeLibraryManager: NativeLibraryManager,
|
||||
sdkRepositoryFactory: SdkRepositoryFactory,
|
||||
sdkPlatformApiFactory: SdkPlatformApiFactory,
|
||||
sdkLoggerFactory: SdkLoggerFactory,
|
||||
): SdkClientManager = SdkClientManagerImpl(
|
||||
dispatcherManager = dispatcherManager,
|
||||
featureFlagManager = featureFlagManager,
|
||||
nativeLibraryManager = nativeLibraryManager,
|
||||
sdkRepoFactory = sdkRepositoryFactory,
|
||||
sdkPlatformApiFactory = sdkPlatformApiFactory,
|
||||
sdkLoggerFactory = sdkLoggerFactory,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@@ -436,6 +441,14 @@ object PlatformManagerModule {
|
||||
serverCommConfigManager = serverCommConfigManager,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSdkLoggerFactory(
|
||||
buildInfoManager: BuildInfoManager,
|
||||
): SdkLoggerFactory = SdkLoggerFactoryImpl(
|
||||
buildInfoManager = buildInfoManager,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideKeyManager(
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.sdk.log
|
||||
|
||||
import com.bitwarden.sdk.LogCallback
|
||||
import com.bitwarden.sdk.LogLevel
|
||||
|
||||
/**
|
||||
* Creates and manages the logger for the Bitwarden SDK.
|
||||
*/
|
||||
interface SdkLoggerFactory {
|
||||
/**
|
||||
* The log level to be used with the Bitwarden SDK.
|
||||
*/
|
||||
val logLevel: LogLevel
|
||||
|
||||
/**
|
||||
* The [LogCallback] to be used with the Bitwarden SDK.
|
||||
*/
|
||||
fun getLogCallback(): LogCallback
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.sdk.log
|
||||
|
||||
import android.util.Log
|
||||
import com.bitwarden.core.data.manager.BuildInfoManager
|
||||
import com.bitwarden.sdk.LogCallback
|
||||
import com.bitwarden.sdk.LogLevel
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* The default implementation for the [SdkLoggerFactory].
|
||||
*/
|
||||
internal class SdkLoggerFactoryImpl(
|
||||
private val buildInfoManager: BuildInfoManager,
|
||||
) : SdkLoggerFactory {
|
||||
override val logLevel: LogLevel
|
||||
get() = if (buildInfoManager.isDevBuild) LogLevel.DEBUG else LogLevel.INFO
|
||||
|
||||
override fun getLogCallback(): LogCallback = object : LogCallback {
|
||||
override fun onLog(level: LogLevel, target: String, message: String) {
|
||||
Timber
|
||||
.tag(tag = "BitwardenSdkClient")
|
||||
.log(priority = level.logLevel, message = "$target --$message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LogLevel.logLevel: Int
|
||||
get() = when (this) {
|
||||
LogLevel.TRACE -> Log.VERBOSE
|
||||
LogLevel.DEBUG -> Log.DEBUG
|
||||
LogLevel.INFO -> Log.INFO
|
||||
LogLevel.WARN -> Log.WARN
|
||||
LogLevel.ERROR -> Log.ERROR
|
||||
}
|
||||
+3
@@ -8,6 +8,7 @@ import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactory
|
||||
|
||||
/**
|
||||
* The default instance of the [ScopedVaultSdkSource]. This uses its own instance of the
|
||||
@@ -19,6 +20,7 @@ class ScopedVaultSdkSourceImpl(
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
sdkRepositoryFactory: SdkRepositoryFactory,
|
||||
sdkPlatformApiFactory: SdkPlatformApiFactory,
|
||||
sdkLoggerFactory: SdkLoggerFactory,
|
||||
vaultSdkSource: VaultSdkSource = VaultSdkSourceImpl(
|
||||
sdkClientManager = SdkClientManagerImpl(
|
||||
dispatcherManager = dispatcherManager,
|
||||
@@ -30,6 +32,7 @@ class ScopedVaultSdkSourceImpl(
|
||||
sdkRepoFactory = sdkRepositoryFactory,
|
||||
featureFlagManager = featureFlagManager,
|
||||
sdkPlatformApiFactory = sdkPlatformApiFactory,
|
||||
sdkLoggerFactory = sdkLoggerFactory,
|
||||
),
|
||||
dispatcherManager = dispatcherManager,
|
||||
),
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactory
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.ScopedVaultSdkSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.ScopedVaultSdkSourceImpl
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
@@ -43,12 +44,14 @@ object VaultSdkModule {
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
sdkRepositoryFactory: SdkRepositoryFactory,
|
||||
sdkPlatformApiFactory: SdkPlatformApiFactory,
|
||||
sdkLoggerFactory: SdkLoggerFactory,
|
||||
): ScopedVaultSdkSource =
|
||||
ScopedVaultSdkSourceImpl(
|
||||
dispatcherManager = dispatcherManager,
|
||||
featureFlagManager = featureFlagManager,
|
||||
sdkRepositoryFactory = sdkRepositoryFactory,
|
||||
sdkPlatformApiFactory = sdkPlatformApiFactory,
|
||||
sdkLoggerFactory = sdkLoggerFactory,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
||||
+14
-3
@@ -3,11 +3,16 @@ package com.x8bit.bitwarden.data.platform.manager
|
||||
import com.bitwarden.core.data.manager.dispatcher.FakeDispatcherManager
|
||||
import com.bitwarden.core.util.isBuildVersionAtLeast
|
||||
import com.bitwarden.data.manager.NativeLibraryManager
|
||||
import com.bitwarden.sdk.LogLevel
|
||||
import com.bitwarden.sdk.initLogger
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkPlatformApiFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.SdkRepositoryFactory
|
||||
import com.x8bit.bitwarden.data.platform.manager.sdk.log.SdkLoggerFactory
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.runs
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -28,16 +33,21 @@ class SdkClientManagerTest {
|
||||
private val sdkPlatformApiFactory: SdkPlatformApiFactory = mockk {
|
||||
every { getServerCommunicationConfigPlatformApi() } returns mockk()
|
||||
}
|
||||
private val sdkLoggerFactory: SdkLoggerFactory = mockk {
|
||||
every { logLevel } returns LogLevel.INFO
|
||||
every { getLogCallback() } returns mockk()
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockkStatic(::isBuildVersionAtLeast)
|
||||
every { isBuildVersionAtLeast(any()) } returns true
|
||||
mockkStatic(::isBuildVersionAtLeast, ::initLogger)
|
||||
every { isBuildVersionAtLeast(version = any()) } returns true
|
||||
every { initLogger(callback = any(), level = any(), platformLogger = any()) } just runs
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(::isBuildVersionAtLeast)
|
||||
unmockkStatic(::isBuildVersionAtLeast, ::initLogger)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,5 +116,6 @@ class SdkClientManagerTest {
|
||||
featureFlagManager = mockk(),
|
||||
sdkRepoFactory = sdkRepoFactory,
|
||||
sdkPlatformApiFactory = sdkPlatformApiFactory,
|
||||
sdkLoggerFactory = sdkLoggerFactory,
|
||||
)
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager.sdk.log
|
||||
|
||||
import android.util.Log
|
||||
import com.bitwarden.core.data.manager.BuildInfoManager
|
||||
import com.bitwarden.sdk.LogLevel
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import timber.log.Timber
|
||||
|
||||
class SdkLoggerFactoryTest {
|
||||
private val buildInfoManager: BuildInfoManager = mockk {
|
||||
every { isDevBuild } returns false
|
||||
}
|
||||
private val recordingTree = RecordingTree()
|
||||
|
||||
private val sdkLoggerFactory: SdkLoggerFactory = SdkLoggerFactoryImpl(
|
||||
buildInfoManager = buildInfoManager,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
Timber.plant(recordingTree)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
Timber.uproot(recordingTree)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logLevel should be DEBUG when the build is a dev build`() {
|
||||
every { buildInfoManager.isDevBuild } returns true
|
||||
|
||||
assertEquals(LogLevel.DEBUG, sdkLoggerFactory.logLevel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logLevel should be INFO when the build is not a dev build`() {
|
||||
every { buildInfoManager.isDevBuild } returns false
|
||||
|
||||
assertEquals(LogLevel.INFO, sdkLoggerFactory.logLevel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLogCallback should return a callback that logs with the SDK tag`() {
|
||||
sdkLoggerFactory
|
||||
.getLogCallback()
|
||||
.onLog(
|
||||
level = LogLevel.INFO,
|
||||
target = "bitwarden_core::target",
|
||||
message = "mockMessage",
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
LogEntry(
|
||||
priority = Log.INFO,
|
||||
tag = "BitwardenSdkClient",
|
||||
message = "bitwarden_core::target --mockMessage",
|
||||
),
|
||||
),
|
||||
recordingTree.logEntries,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLogCallback should return a callback that maps each SDK level to a log priority`() {
|
||||
val callback = sdkLoggerFactory.getLogCallback()
|
||||
|
||||
LogLevel.entries.forEach {
|
||||
callback.onLog(level = it, target = "mockTarget", message = "mockMessage")
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
listOf(Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR),
|
||||
recordingTree.logEntries.map { it.priority },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Timber.Tree] that records each log for later verification.
|
||||
*/
|
||||
private class RecordingTree : Timber.Tree() {
|
||||
val logEntries: MutableList<LogEntry> = mutableListOf()
|
||||
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
logEntries.add(LogEntry(priority = priority, tag = tag, message = message))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Models a single log received by the [RecordingTree].
|
||||
*/
|
||||
private data class LogEntry(
|
||||
val priority: Int,
|
||||
val tag: String?,
|
||||
val message: String,
|
||||
)
|
||||
Reference in New Issue
Block a user