From cf54967255b83696ff824276e318187c9ef87032 Mon Sep 17 00:00:00 2001 From: vkanellopoulos Date: Tue, 23 Jul 2024 16:07:28 +0300 Subject: [PATCH] expose Logger interface through EudiWalletConfig so implementor can pass custom Logger implementations; changed the Logger interface; If no custom logger implementation is set, then library will use the default --- README.md | 11 +++- .../eu/europa/ec/eudi/wallet/EudiWallet.kt | 5 +- .../europa/ec/eudi/wallet/EudiWalletConfig.kt | 15 +++++ .../issue/openid4vci/IssuerAuthorization.kt | 2 + .../openid4vci/ProcessDeferredOutcome.kt | 1 + .../issue/openid4vci/ProcessResponse.kt | 1 + .../ec/eudi/wallet/issue/openid4vci/Utils.kt | 2 + .../europa/ec/eudi/wallet/logging/Logger.kt | 66 +++++++++++++------ .../OpenId4VpCBORResponseGeneratorImpl.kt | 4 +- .../transfer/openid4vp/OpenId4vpManager.kt | 3 + .../util/KtorHttpClientFactoryExtensions.kt | 1 + .../ec/eudi/wallet/EudiWalletConfigTest.kt | 30 +++++++++ 12 files changed, 116 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index c1d8c7b3..95d7bb1b 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,10 @@ the following options: default value is null. - `openId4VciConfig` method allows you to specify the configuration for OpenID4VCI. The default value is null. +- `logger` method allows you to specify the logger. If the logger is not provided, the default + logger will be used. +- `logLevel` method allows you to specify the log level for the default logger. The default value + is `Logger.LEVEL_ERROR`. The following example shows how to initialize the library: @@ -153,11 +157,16 @@ import eu.europa.ec.eudi.wallet.EudiWallet import eu.europa.ec.eudi.wallet.EudiWalletConfig import eu.europa.ec.eudi.wallet.Logger import java.security.cert.X509Certificate - +val logger = Logger { record: Logger.Record -> + // log the record +} val storageDir = applicationContext.noBackupFilesDir val verifierApiUri = "https://verifier-api-uri" val config = EudiWalletConfig.Builder(applicationContext) + // set the log level for the default logger .logLevel(Logger.LEVEL_DEBUG) + // or set a custom logger + .logger(logger) .ktorHttpClientFactory { // Provide your own Ktor HttpClient. // This will be used for OpenId4VCI and OpenId4VP communication. diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWallet.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWallet.kt index 2febc0c9..2619eb4d 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWallet.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWallet.kt @@ -35,7 +35,6 @@ import eu.europa.ec.eudi.wallet.document.sample.SampleDocumentManager import eu.europa.ec.eudi.wallet.internal.getCertificate import eu.europa.ec.eudi.wallet.internal.mainExecutor import eu.europa.ec.eudi.wallet.issue.openid4vci.* -import eu.europa.ec.eudi.wallet.logging.Logger import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4VpCBORResponse import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4VpCBORResponseGeneratorImpl import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4vpManager @@ -77,9 +76,7 @@ object EudiWallet { private var transferMode: TransferMode? = null private val logger by lazy { - requireInit { - Logger(_config) - } + requireInit { _config.logger } } /** diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWalletConfig.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWalletConfig.kt index 82a99b44..9f8c9e96 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWalletConfig.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWalletConfig.kt @@ -163,6 +163,11 @@ class EudiWalletConfig private constructor(builder: Builder) { */ val logLevel: Int = builder.logLevel + /** + * The logger. If no [Logger] instance is provided and [logLevel] is not [Logger.OFF], then the default will be used + */ + val logger: Logger? = builder.logger ?: Logger(this).takeUnless { builder.logLevel == Logger.OFF } + /** * Ktor http client factory */ @@ -202,6 +207,7 @@ class EudiWalletConfig private constructor(builder: Builder) { var verifyMsoPublicKey: Boolean = true var openId4VpConfig: OpenId4VpConfig? = null var openId4VciConfig: OpenId4VciConfig? = null + var logger: Logger? = null var logLevel: Int = Logger.LEVEL_ERROR var ktorHttpClientFactory: (() -> HttpClient)? = null @@ -366,6 +372,15 @@ class EudiWalletConfig private constructor(builder: Builder) { this.openId4VciConfig = OpenId4VciConfig.Builder().apply(block).build() } + /** + * Set a logger + * @param logger The logger + * @return [EudiWalletConfig.Builder] + */ + fun logger(logger: Logger) = apply { + this.logger = logger + } + /** * Set the debug logging level. * The default value is [LogLevel.OFF]. diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/IssuerAuthorization.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/IssuerAuthorization.kt index 34c8d5cc..9aef4225 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/IssuerAuthorization.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/IssuerAuthorization.kt @@ -26,6 +26,8 @@ import eu.europa.ec.eudi.openid4vci.AuthorizedRequest import eu.europa.ec.eudi.openid4vci.Issuer import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d +import eu.europa.ec.eudi.wallet.logging.e import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.cancellation.CancellationException diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessDeferredOutcome.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessDeferredOutcome.kt index b60ac6f2..d22cb575 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessDeferredOutcome.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessDeferredOutcome.kt @@ -23,6 +23,7 @@ import eu.europa.ec.eudi.wallet.document.DocumentManager import eu.europa.ec.eudi.wallet.document.StoreDocumentResult import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d import org.bouncycastle.util.encoders.Hex import java.util.* diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessResponse.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessResponse.kt index c7a0d5b9..02d438a5 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessResponse.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/ProcessResponse.kt @@ -25,6 +25,7 @@ import eu.europa.ec.eudi.wallet.document.UnsignedDocument import eu.europa.ec.eudi.wallet.issue.openid4vci.IssueEvent.Companion.documentFailed import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/Utils.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/Utils.kt index 37808781..83a3f504 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/Utils.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/issue/openid4vci/Utils.kt @@ -24,6 +24,8 @@ import eu.europa.ec.eudi.wallet.document.DocumentManager import eu.europa.ec.eudi.wallet.document.UnsignedDocument import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d +import eu.europa.ec.eudi.wallet.logging.e import org.bouncycastle.util.io.pem.PemObject import org.bouncycastle.util.io.pem.PemWriter import java.io.StringWriter diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/logging/Logger.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/logging/Logger.kt index 44e7ce6f..c1faf5b5 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/logging/Logger.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/logging/Logger.kt @@ -22,17 +22,21 @@ import eu.europa.ec.eudi.wallet.EudiWalletConfig import eu.europa.ec.eudi.wallet.logging.Logger.Companion.LEVEL_DEBUG import eu.europa.ec.eudi.wallet.logging.Logger.Companion.LEVEL_ERROR import eu.europa.ec.eudi.wallet.logging.Logger.Companion.LEVEL_INFO +import java.time.Instant -interface Logger { +fun interface Logger { - @Level - val level: Int - fun log(level: Int, tag: String, message: String, throwable: Throwable? = null) + data class Record( + @Level val level: Int, + val instant: Instant = Instant.now(), + val message: String, + val thrown: Throwable? = null, + val sourceClassName: String? = null, + val sourceMethod: String? = null, + ) - fun d(tag: String, message: String) = log(LEVEL_DEBUG, tag, message) - fun i(tag: String, message: String) = log(LEVEL_INFO, tag, message) - fun e(tag: String, message: String, throwable: Throwable? = null) = log(LEVEL_ERROR, tag, message, throwable) + fun log(record: Record) companion object { const val OFF = 0 @@ -51,19 +55,16 @@ interface Logger { } class LoggerImpl(val config: EudiWalletConfig, private val maxLogSize: Int = 1000) : Logger { - override val level: Int = config.logLevel - override fun log(level: Int, tag: String, message: String, throwable: Throwable?) { - splitMessage(message).forEachIndexed { i, m -> + override fun log(record: Logger.Record) { + val tag = record.sourceClassName ?: "" + splitMessage(record.message).forEachIndexed { i, m -> when { - level == LEVEL_ERROR && config.logLevel >= LEVEL_ERROR && i == 0 && throwable != null -> Log.e( - tag, - m, - throwable - ) + record.level == LEVEL_ERROR && config.logLevel >= LEVEL_ERROR && i == 0 && record.thrown != null -> + Log.e(tag, m, record.thrown) - level == LEVEL_ERROR && config.logLevel >= LEVEL_ERROR -> Log.e(tag, m) - level == LEVEL_INFO && config.logLevel >= LEVEL_INFO -> Log.i(tag, m) - level == LEVEL_DEBUG && config.logLevel >= LEVEL_DEBUG -> Log.d(tag, m) + record.level == LEVEL_ERROR && config.logLevel >= LEVEL_ERROR -> Log.e(tag, m) + record.level == LEVEL_INFO && config.logLevel >= LEVEL_INFO -> Log.i(tag, m) + record.level == LEVEL_DEBUG && config.logLevel >= LEVEL_DEBUG -> Log.d(tag, m) } } } @@ -76,7 +77,34 @@ class LoggerImpl(val config: EudiWalletConfig, private val maxLogSize: Int = 100 } return messages } +} +@JvmSynthetic +internal fun Logger.d(tag: String, message: String) = log( + Logger.Record( + level = LEVEL_DEBUG, + sourceClassName = tag, + message = message + ) +) -} +@JvmSynthetic +internal fun Logger.i(tag: String, message: String) = log( + Logger.Record( + level = LEVEL_INFO, + sourceClassName = tag, + message = message + ) +) + +@JvmSynthetic +internal fun Logger.e(tag: String, message: String, throwable: Throwable? = null) = + log( + Logger.Record( + level = LEVEL_ERROR, + sourceClassName = tag, + message = message, + thrown = throwable + ) + ) diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4VpCBORResponseGeneratorImpl.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4VpCBORResponseGeneratorImpl.kt index 809e96fd..dff9f3c7 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4VpCBORResponseGeneratorImpl.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4VpCBORResponseGeneratorImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 European Commission + * Copyright (c) 2023-2024 European Commission * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,8 @@ import eu.europa.ec.eudi.iso18013.transfer.response.SessionTranscriptBytes import eu.europa.ec.eudi.openid4vp.legalName import eu.europa.ec.eudi.wallet.internal.Openid4VpX509CertificateTrust import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.e +import eu.europa.ec.eudi.wallet.logging.i private const val TAG = "OpenId4VpCBORResponseGe" diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4vpManager.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4vpManager.kt index 5acfd8f5..8a291ec6 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4vpManager.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transfer/openid4vp/OpenId4vpManager.kt @@ -31,6 +31,9 @@ import eu.europa.ec.eudi.prex.PresentationSubmission import eu.europa.ec.eudi.wallet.internal.Openid4VpUtils import eu.europa.ec.eudi.wallet.internal.mainExecutor import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d +import eu.europa.ec.eudi.wallet.logging.e +import eu.europa.ec.eudi.wallet.logging.i import eu.europa.ec.eudi.wallet.util.CBOR import eu.europa.ec.eudi.wallet.util.wrappedWithContentNegotiation import eu.europa.ec.eudi.wallet.util.wrappedWithLogging diff --git a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/util/KtorHttpClientFactoryExtensions.kt b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/util/KtorHttpClientFactoryExtensions.kt index b7714c62..899bfa0f 100644 --- a/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/util/KtorHttpClientFactoryExtensions.kt +++ b/wallet-core/src/main/java/eu/europa/ec/eudi/wallet/util/KtorHttpClientFactoryExtensions.kt @@ -18,6 +18,7 @@ package eu.europa.ec.eudi.wallet.util import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.d import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* diff --git a/wallet-core/src/test/java/eu/europa/ec/eudi/wallet/EudiWalletConfigTest.kt b/wallet-core/src/test/java/eu/europa/ec/eudi/wallet/EudiWalletConfigTest.kt index e2debdd0..55ef370d 100644 --- a/wallet-core/src/test/java/eu/europa/ec/eudi/wallet/EudiWalletConfigTest.kt +++ b/wallet-core/src/test/java/eu/europa/ec/eudi/wallet/EudiWalletConfigTest.kt @@ -17,6 +17,8 @@ package eu.europa.ec.eudi.wallet import android.content.Context +import eu.europa.ec.eudi.wallet.logging.Logger +import eu.europa.ec.eudi.wallet.logging.LoggerImpl import eu.europa.ec.eudi.wallet.transfer.openid4vp.ClientIdScheme import eu.europa.ec.eudi.wallet.transfer.openid4vp.EncryptionAlgorithm import eu.europa.ec.eudi.wallet.transfer.openid4vp.EncryptionMethod @@ -124,4 +126,32 @@ class EudiWalletConfigTest { assertNull(config.openId4VPConfig) assertNull(config.openId4VciConfig) } + + @Test + fun testLoggerIsNullWhenLogLevelIsOff() { + val config = EudiWalletConfig(context) { + logLevel = Logger.OFF + } + + assertNull(config.logger) + } + + @Test + fun testLoggerIsDefaultImplementationWhenLogLevelIsNotOff() { + val config = EudiWalletConfig(context) { + logLevel = Logger.LEVEL_ERROR + } + + assertTrue(config.logger is LoggerImpl) + } + + @Test + fun testCustomLogger() { + val logger = Logger { record -> println(record) } + val config = EudiWalletConfig(context) { + this.logger = logger + } + + assertTrue(config.logger == logger) + } } \ No newline at end of file