libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 61ae182a17a32f3ee0e42380ef31849a40395886
parent cfe4bde1d5f83f95599a192334c4535ad1be7421
Author: Antoine A <>
Date:   Mon, 26 May 2025 16:04:03 +0200

common: replace logback with custom logger

Diffstat:
Mbank/build.gradle | 2--
Dbank/src/main/resources/logback.xml | 16----------------
Dbank/src/main/resources/static/README.txt | 2--
Mcommon/build.gradle | 2+-
Mcommon/src/main/kotlin/Cli.kt | 7+++----
Mcommon/src/main/kotlin/Config.kt | 10++++------
Acommon/src/main/kotlin/log.kt | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider | 2++
Mcommon/src/test/kotlin/ConfigTest.kt | 10+++++-----
Mnexus/build.gradle | 4+---
Dnexus/src/main/resources/logback.xml | 16----------------
11 files changed, 122 insertions(+), 55 deletions(-)

diff --git a/bank/build.gradle b/bank/build.gradle @@ -52,7 +52,5 @@ shadowJar { exclude(dependency("com.kohlschutter.junixsocket:junixsocket-core:.*")) // CLI exclude(dependency("com.github.ajalt.mordant:mordant:.*")) - // Logging - exclude(dependency("ch.qos.logback:logback-classic:.*")) } } \ No newline at end of file diff --git a/bank/src/main/resources/logback.xml b/bank/src/main/resources/logback.xml @@ -1,15 +0,0 @@ -<configuration> - <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender"> - <target>System.err</target> - <encoder> - <pattern>%d{dd-MMM-yyyy'T'HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern> - </encoder> - </appender> - - <logger name="ktor" level="WARN" /> - <logger name="com.zaxxer.hikari" level="OFF" /> - - <root level="DEBUG"> - <appender-ref ref="STDERR" /> - </root> -</configuration> -\ No newline at end of file diff --git a/bank/src/main/resources/static/README.txt b/bank/src/main/resources/static/README.txt @@ -1 +0,0 @@ -The spa.html file is generated from merchant-backoffice.git -> /packages/bank/ -\ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle @@ -16,7 +16,6 @@ compileTestKotlin.kotlinOptions.jvmTarget = "17" sourceSets.main.java.srcDirs = ["src/main/kotlin"] dependencies { - implementation("ch.qos.logback:logback-classic:1.5.17") implementation("org.slf4j:slf4j-api:2.0.17") // Crypto implementation("org.bouncycastle:bcprov-jdk18on:1.80") @@ -35,6 +34,7 @@ dependencies { implementation("io.ktor:ktor-server-forwarded-header:$ktor_version") implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") implementation("io.ktor:ktor-server-test-host:$ktor_version") + implementation("io.ktor:ktor-server-call-id:$ktor_version") implementation("com.github.ajalt.clikt:clikt:$clikt_version") diff --git a/common/src/main/kotlin/Cli.kt b/common/src/main/kotlin/Cli.kt @@ -1,6 +1,6 @@ /* * This file is part of LibEuFin. - * Copyright (C) 2023-2024 Taler Systems S.A. + * Copyright (C) 2023-2025 Taler Systems S.A. * LibEuFin is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -39,9 +39,8 @@ import org.slf4j.event.Level private val logger: Logger = LoggerFactory.getLogger("libeufin-config") fun cliCmd(logger: Logger, level: Level, lambda: suspend () -> Unit) { - // Set root log level - val root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger - root.level = ch.qos.logback.classic.Level.convertAnSLF4JLevel(level) + // Set log level + TalerServiceProvider.currentLevel = level // Run cli command catching all errors try { runBlocking { diff --git a/common/src/main/kotlin/Config.kt b/common/src/main/kotlin/Config.kt @@ -1,6 +1,6 @@ /* * This file is part of LibEuFin. - * Copyright (C) 2024 Taler Systems S.A. + * Copyright (C) 2024-2025 Taler Systems S.A. * LibEuFin is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +19,6 @@ package tech.libeufin.common -import ch.qos.logback.core.util.Loader - /** * Putting those values into the 'attributes' container because they * are needed by the util routines that do NOT have Sandbox and Nexus @@ -30,9 +28,9 @@ import ch.qos.logback.core.util.Loader * into circular dependency. */ val VERSION: String by lazy { - Loader.getResource( - "version.txt", ClassLoader.getSystemClassLoader() - ).readText() + ClassLoader.getSystemClassLoader().getResourceAsStream("version.txt") + ?.bufferedReader() + ?.use { it.readText() }!! } sealed interface ServerConfig { diff --git a/common/src/main/kotlin/log.kt b/common/src/main/kotlin/log.kt @@ -0,0 +1,105 @@ +/* + * This file is part of LibEuFin. + * Copyright (C) 2025 Taler Systems S.A. + + * LibEuFin is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3, or + * (at your option) any later version. + + * LibEuFin is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + + * You should have received a copy of the GNU Affero General Public + * License along with LibEuFin; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/> + */ + +package tech.libeufin.common + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.event.Level; +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.helpers.LegacyAbstractLogger; +import org.slf4j.helpers.MessageFormatter; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.helpers.BasicMDCAdapter; +import org.slf4j.spi.MDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.io.PrintStream + + +class TalerLogger(private val loggerName: String): LegacyAbstractLogger() { + private fun isLevelEnabled(level: Level): Boolean = level.toInt() >= TalerServiceProvider.currentLevel.toInt() + override fun isTraceEnabled(): Boolean = isLevelEnabled(Level.TRACE) + override fun isDebugEnabled(): Boolean = isLevelEnabled(Level.DEBUG) + override fun isInfoEnabled(): Boolean = isLevelEnabled(Level.INFO) + override fun isWarnEnabled(): Boolean = isLevelEnabled(Level.WARN) + override fun isErrorEnabled(): Boolean = isLevelEnabled(Level.ERROR) + + override fun getFullyQualifiedCallerName(): String = loggerName + + override fun handleNormalizedLoggingCall(level: Level, marker: Marker?, messagePattern: String?, arguments: Array<Any>?, throwable: Throwable?) { + val name = fullyQualifiedCallerName; + if ( + !isLevelEnabled(level) || + (name.startsWith("io.ktor") && level.toInt() < Level.WARN.toInt()) || + name.startsWith("com.zaxxer.hikari") + ) return + val callId = org.slf4j.MDC.get("call-id") + val logEntry = buildString { + append(LocalDateTime.now().format(dateFormatter)) + if (callId != null) { + append(' ') + append(callId) + } + append(' ') + append(level.name.padEnd(5)) + append(' ') + append(name) + append(" - ") + append(MessageFormatter.basicArrayFormat(messagePattern, arguments)) + + /*throwable.let { t -> + append("\n") + append("${t.javaClass.simpleName}: ${t.message}") + t.stackTrace.take(10).forEach { stackElement -> + append("\n\tat $stackElement") + } + }*/ + } + + System.err.println(logEntry) + } + + companion object { + private val dateFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy'T'HH:mm:ss.SSS") + } +} + +class TalerServiceProvider: SLF4JServiceProvider { + private val markerFactory = BasicMarkerFactory() + private val mdcAdapter = BasicMDCAdapter() + + override fun getLoggerFactory() = TalerServiceProvider + override fun getMarkerFactory() = markerFactory + override fun getMDCAdapter() = mdcAdapter + override fun getRequestedApiVersion() = "2.0.99" + override fun initialize() {} + + companion object: ILoggerFactory { + var currentLevel = Level.TRACE + private val loggerMap: ConcurrentMap<String, TalerLogger> = ConcurrentHashMap() + + override fun getLogger(name: String): Logger + = loggerMap.computeIfAbsent(name, ::TalerLogger) + } +} +\ No newline at end of file diff --git a/common/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/common/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +tech.libeufin.common.TalerServiceProvider +\ No newline at end of file diff --git a/common/src/test/kotlin/ConfigTest.kt b/common/src/test/kotlin/ConfigTest.kt @@ -39,12 +39,12 @@ class ConfigTest { val secondPath = Path("tmp/test-second-conf.conf") fun testErr(msg: String) { - val prevOut = System.out - val tmpOut = ByteArrayOutputStream() - System.setOut(PrintStream(tmpOut)) + val prevErr = System.err + val tmpErr = ByteArrayOutputStream() + System.setErr(PrintStream(tmpErr)) val result = cmd.test("dump -c $configPath") - System.setOut(prevOut) - val lastLog = tmpOut.asUtf8().substringAfterLast(" -- ").trimEnd('\n') + System.setErr(prevErr) + val lastLog = tmpErr.asUtf8().substringAfterLast(" - ").trimEnd('\n') assertEquals(1, result.statusCode, lastLog) assertEquals(msg, lastLog, lastLog) } diff --git a/nexus/build.gradle b/nexus/build.gradle @@ -57,13 +57,11 @@ shadowJar { exclude(dependency("io.ktor:ktor-serialization-kotlinx-json:.*")) // Postgres unix socket driver exclude(dependency("com.kohlschutter.junixsocket:junixsocket-core:.*")) - // Logging - exclude(dependency("ch.qos.logback:logback-classic:.*")) // CIO engine exclude(dependency("io.ktor:ktor-client-cio:.*")) // Crypto exclude(dependency("org.bouncycastle:.*")) - // CLI + // CLI exclude(dependency("com.github.ajalt.mordant:mordant:.*")) } } \ No newline at end of file diff --git a/nexus/src/main/resources/logback.xml b/nexus/src/main/resources/logback.xml @@ -1,15 +0,0 @@ -<configuration> - <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender"> - <target>System.err</target> - <encoder> - <pattern>%d{dd-MMM-yyyy'T'HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern> - </encoder> - </appender> - - <logger name="ktor" level="WARN" /> - <logger name="com.zaxxer.hikari" level="OFF" /> - - <root level="DEBUG"> - <appender-ref ref="STDERR" /> - </root> -</configuration> -\ No newline at end of file