Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-04 11:10:18 +04:00
parent 266e49734e
commit 371916a2e9
7 changed files with 115 additions and 119 deletions

View file

@ -1,7 +1,6 @@
package com.tangem.tap
import androidx.hilt.work.HiltWorkerFactory
import com.tangem.TangemSdkLogger
import com.tangem.core.abtests.manager.ABTestsManager
import com.tangem.core.analytics.filter.OneTimeEventFilter
import com.tangem.core.analytics.paramsinterceptor.SendTransactionSignerInfoInterceptor
@ -9,13 +8,12 @@ import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
import com.tangem.tap.common.analytics.handlers.appsflyer.AppsFlyerClient
import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.common.log.TangemLoggingInitializer
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@ -36,11 +34,7 @@ interface ApplicationEntryPoint {
fun getOneTimeEventFilter(): OneTimeEventFilter
fun getTangemSdkLogger(): TangemSdkLogger
fun getTangemAppLogger(): TangemAppLoggerInitializer
fun getAppLogsStore(): AppLogsStore
fun getTangemLoggingInitializer(): TangemLoggingInitializer
fun getBlockchainExceptionHandler(): BlockchainExceptionHandler

View file

@ -8,11 +8,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import coil.ImageLoader
import coil.ImageLoaderFactory
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.tangem.Log
import com.tangem.TangemSdkLogger
import com.tangem.blockchain.common.ExceptionHandler
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.core.abtests.manager.ABTestsManager
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.filter.AppsFlyerEventFilter
@ -21,15 +17,10 @@ import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.datasource.utils.NetworkLogsSaveInterceptor
import com.tangem.datasource.utils.WireMockRedirectInterceptor
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
import com.tangem.domain.common.LogConfig
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.operations.attestation.api.TangemApiServiceSettings
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
@ -39,7 +30,7 @@ import com.tangem.tap.common.analytics.handlers.appsflyer.AppsFlyerClient
import com.tangem.tap.common.analytics.handlers.customerio.CustomerIoAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
import com.tangem.tap.common.images.createCoilImageLoader
import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.common.log.TangemLoggingInitializer
import com.tangem.utils.logging.TangemLogger
import com.tangem.wallet.BuildConfig
import dagger.hilt.EntryPoints
@ -72,14 +63,8 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
private val oneTimeEventFilter: OneTimeEventFilter
get() = entryPoint.getOneTimeEventFilter()
private val tangemSdkLogger: TangemSdkLogger
get() = entryPoint.getTangemSdkLogger()
private val tangemAppLoggerInitializer: TangemAppLoggerInitializer
get() = entryPoint.getTangemAppLogger()
private val appLogsStore: AppLogsStore
get() = entryPoint.getAppLogsStore()
private val tangemLoggingInitializer: TangemLoggingInitializer
get() = entryPoint.getTangemLoggingInitializer()
private val blockchainExceptionHandler: BlockchainExceptionHandler
get() = entryPoint.getBlockchainExceptionHandler()
@ -142,7 +127,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
* Initialize components that need to be initialized before [super.onCreate] is called
*/
fun preInit() {
tangemAppLoggerInitializer.initialize()
tangemLoggingInitializer.initAppLogging()
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
}
@ -157,7 +142,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
TangemLogger.i(excludedBlockchainsManager.toString())
}
initWithConfigDependency(environmentConfig = environmentConfig)
initAnalytics(application = this, environmentConfig = environmentConfig)
abTestsManager.init()
@ -169,26 +154,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
ExceptionHandler.append(blockchainExceptionHandler)
if (LogConfig.network.isBlockchainSdkNetworkLogEnabled) {
BlockchainSdkRetrofitBuilder.interceptors = buildList {
if (BuildConfig.MOCK_DATA_SOURCE) {
add(WireMockRedirectInterceptor())
}
add(createNetworkLoggingInterceptor())
add(ChuckerInterceptor(this@TangemApplication))
}
TangemApiServiceSettings.addInterceptors(
*buildList {
if (BuildConfig.MOCK_DATA_SOURCE) {
add(WireMockRedirectInterceptor())
}
add(createNetworkLoggingInterceptor())
add(ChuckerInterceptor(this@TangemApplication))
add(NetworkLogsSaveInterceptor(appLogsStore))
}.toTypedArray(),
)
}
tangemLoggingInitializer.initSdkLogging(this)
wcInitializeUseCase.init(
projectId = environmentConfig.walletConnectProjectId,
@ -206,11 +172,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
System.loadLibrary("TrustWalletCore")
}
private fun initWithConfigDependency(environmentConfig: EnvironmentConfig) {
initAnalytics(this, environmentConfig)
Log.addLogger(logger = tangemSdkLogger)
}
private fun initAnalytics(application: Application, environmentConfig: EnvironmentConfig) {
val factory = AnalyticsFactory()
factory.addHandlerBuilder(AmplitudeAnalyticsHandler.Builder())

View file

@ -1,28 +0,0 @@
package com.tangem.tap.common.log
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.utils.logging.TangemLogger
import com.tangem.wallet.BuildConfig
/**
* Tangem app logger
*
* @property appLogsStore app logs store
*
[REDACTED_AUTHOR]
*/
class TangemAppLoggerInitializer(
private val appLogsStore: AppLogsStore,
) {
fun initialize() {
TangemLogger.setLogWriters(
buildList {
if (BuildConfig.LOG_ENABLED) {
add(LogcatLogWriter())
}
add(FileLogWriter(appLogsStore))
},
)
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.tap.data
package com.tangem.tap.common.log
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
import com.tangem.datasource.local.logs.AppLogsStore

View file

@ -6,27 +6,40 @@ import com.tangem.TangemSdkLogger
import com.tangem.datasource.local.logs.AppLogsStore
/**
* CardSDK logger implementation
* CardSDK logger implementation.
*
* @property levels logging levels
* @property messageFormatter message formatter
* @property appLogsStore app logs store
* @property appLogsStore app logs store
*
[REDACTED_AUTHOR]
*/
@Suppress("UnusedPrivateMember")
internal class TangemCardSDKLogger(
private val levels: List<Log.Level>,
private val messageFormatter: LogFormat,
private val appLogsStore: AppLogsStore,
) : TangemSdkLogger {
private val messageFormatter: LogFormat = LogFormat.StairsFormatter()
override fun log(message: () -> String, level: Log.Level) {
if (!levels.contains(level)) return
if (!LEVELS.contains(level)) return
appLogsStore.saveLogMessage(
tag = "CardSDK_${level.name}",
message = messageFormatter.format(message = message, level = level),
)
}
private companion object {
val LEVELS = listOf(
Log.Level.ApduCommand,
Log.Level.Apdu,
Log.Level.Tlv,
Log.Level.Nfc,
Log.Level.Command,
Log.Level.Session,
Log.Level.View,
Log.Level.Network,
Log.Level.Error,
Log.Level.Biometric,
Log.Level.Info,
)
}
}

View file

@ -0,0 +1,80 @@
package com.tangem.tap.common.log
import android.app.Application
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.tangem.Log
import com.tangem.TangemSdkLogger
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.datasource.utils.NetworkLogsSaveInterceptor
import com.tangem.datasource.utils.WireMockRedirectInterceptor
import com.tangem.domain.common.LogConfig
import com.tangem.operations.attestation.api.TangemApiServiceSettings
import com.tangem.utils.logging.TangemLogger
import com.tangem.wallet.BuildConfig
/**
* Owns all app-startup wiring of the logging subsystem in a single place:
* - [initAppLogging] registers [TangemLogger] writers (Logcat + file).
* - [initSdkLogging] registers the Card SDK logger with [Log] and installs OkHttp
* interceptors for the Blockchain SDK and the Tangem API.
*
* @property appLogsStore app logs store used by file-based writer and the network logs save
* interceptor
* @property tangemSdkLogger Card SDK logger registered with [Log.addLogger]
*
[REDACTED_AUTHOR]
*/
class TangemLoggingInitializer(
private val appLogsStore: AppLogsStore,
private val tangemSdkLogger: TangemSdkLogger,
) {
fun initAppLogging() {
TangemLogger.setLogWriters(
buildList {
if (BuildConfig.LOG_ENABLED) {
add(LogcatLogWriter())
}
add(FileLogWriter(appLogsStore))
},
)
}
/**
* Configure logging for the underlying SDKs:
* - register [tangemSdkLogger] with the Card SDK static [Log] facade,
* - install OkHttp interceptors for the Blockchain SDK and Tangem API.
*
* Must be called from `TangemApplication.init()` AFTER `entryPoint.getWalletsRepository()`
* has triggered Hilt singletons construction in particular `DefaultCardSdkProvider`,
* whose init block registers `AddHeadersInterceptor` in [TangemApiServiceSettings].
* Calling this method earlier would invert the OkHttp interceptor chain order and
* cause logging interceptors to see requests *without* auth headers.
*/
fun initSdkLogging(application: Application) {
Log.addLogger(logger = tangemSdkLogger)
if (!LogConfig.network.isBlockchainSdkNetworkLogEnabled) return
BlockchainSdkRetrofitBuilder.interceptors = buildList {
if (BuildConfig.MOCK_DATA_SOURCE) {
add(WireMockRedirectInterceptor())
}
add(createNetworkLoggingInterceptor())
add(ChuckerInterceptor(application))
}
TangemApiServiceSettings.addInterceptors(
*buildList {
if (BuildConfig.MOCK_DATA_SOURCE) {
add(WireMockRedirectInterceptor())
}
add(createNetworkLoggingInterceptor())
add(ChuckerInterceptor(application))
add(NetworkLogsSaveInterceptor(appLogsStore))
}.toTypedArray(),
)
}
}

View file

@ -1,13 +1,10 @@
package com.tangem.tap.di.data
import com.tangem.Log
import com.tangem.LogFormat
import com.tangem.TangemSdkLogger
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.common.log.TangemBlockchainSDKLogger
import com.tangem.tap.common.log.TangemCardSDKLogger
import com.tangem.tap.data.TangemBlockchainSDKLogger
import com.tangem.tap.common.log.TangemLoggingInitializer
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -20,31 +17,10 @@ internal object TangemLoggingModule {
@Provides
@Singleton
fun provideAppLoggerInitializer(appLogsStore: AppLogsStore): TangemAppLoggerInitializer {
return TangemAppLoggerInitializer(appLogsStore)
}
@Provides
@Singleton
fun provideCardSDKLogger(appLogsStore: AppLogsStore): TangemSdkLogger {
val logLevels = listOf(
Log.Level.ApduCommand,
Log.Level.Apdu,
Log.Level.Tlv,
Log.Level.Nfc,
Log.Level.Command,
Log.Level.Session,
Log.Level.View,
Log.Level.Network,
Log.Level.Error,
Log.Level.Biometric,
Log.Level.Info,
)
return TangemCardSDKLogger(
levels = logLevels,
messageFormatter = LogFormat.StairsFormatter(),
fun provideLoggingInitializer(appLogsStore: AppLogsStore): TangemLoggingInitializer {
return TangemLoggingInitializer(
appLogsStore = appLogsStore,
tangemSdkLogger = TangemCardSDKLogger(appLogsStore),
)
}