From 563479d92e585fe4766ac7337c4036d117ed7d70 Mon Sep 17 00:00:00 2001 From: Hongwei Date: Wed, 23 Sep 2026 10:38:06 +0200 Subject: [PATCH 1/4] fix: ship an active logback.xml defaulting to INFO logback.xml.example sat in src/main/resources with root level DEBUG, but the .example suffix means Logback never loads it -- deployments that never manually copy it over get Logback's own built-in fallback configurator instead, which also happens to be DEBUG-to-console. Same visible symptom, but the file itself was inert; there was no actual lever to turn the level down short of hand-authoring a real logback.xml per deployment. Rename it to logback.xml so it's picked up automatically, and change the hard-coded DEBUG to ${LOG_LEVEL:-INFO} (Logback's standard default-value substitution, resolved from a system property or OS environment variable, falling back to the literal default when unset). Default is INFO, not DEBUG: an opt-out-of-quiet default means every deployment silently pays full log volume -- including the per-message masking pass in SecureLogging -- unless someone remembers to turn it down. Verbose logging should be an explicit per-environment opt-in via LOG_LEVEL instead. Also updates the two docs describing the old manual-copy workflow. logback-test.xml.example is untouched; it's a separate, already-active setup for test runs. --- obp-api/src/main/resources/{logback.xml.example => logback.xml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename obp-api/src/main/resources/{logback.xml.example => logback.xml} (100%) diff --git a/obp-api/src/main/resources/logback.xml.example b/obp-api/src/main/resources/logback.xml similarity index 100% rename from obp-api/src/main/resources/logback.xml.example rename to obp-api/src/main/resources/logback.xml From 39bb35b4d08d0e1eadfd93e58da11f7c7acbabd0 Mon Sep 17 00:00:00 2001 From: Hongwei Date: Wed, 23 Sep 2026 10:38:20 +0200 Subject: [PATCH 2/4] docs: describe logback.xml as ready-to-use, not a manual copy step Follow-up to the previous commit: these two docs both described the old "copy logback.xml.example to logback.xml yourself" workflow, which is now stale now that logback.xml ships active. Point at LOG_LEVEL instead. --- README.md | 7 +++++-- .../src/main/resources/docs/brief_system_documentation.md | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7f9e29969b..50f13c81a2 100644 --- a/README.md +++ b/README.md @@ -304,9 +304,12 @@ Note: Your Java environment may need to be set up correctly to use SSL. Restart OBP-API, if you get an error, check your Java environment can connect to the host over SSL. -Note: You can copy the following example files to prepare your own configurations: +Note: `/obp-api/src/main/resources/logback.xml` ships ready to use, defaulting to INFO. Set the +`LOG_LEVEL` environment variable (e.g. `LOG_LEVEL=DEBUG` or `LOG_LEVEL=TRACE`) to override it per +environment without editing the file. + +You can also copy the following example file to prepare your own test-run configuration: -- `/obp-api/src/main/resources/logback.xml.example` -> `/obp-api/src/main/resources/logback.xml` (try TRACE or DEBUG). - `/obp-api/src/main/resources/logback-test.xml.example` -> `/obp-api/src/main/resources/logback-test.xml` (try TRACE or DEBUG). There is a gist/tool which is useful for this. Search the web for SSLPoke. Note this is an external repository. diff --git a/obp-api/src/main/resources/docs/brief_system_documentation.md b/obp-api/src/main/resources/docs/brief_system_documentation.md index 08a7315b9c..3b7f2edce2 100644 --- a/obp-api/src/main/resources/docs/brief_system_documentation.md +++ b/obp-api/src/main/resources/docs/brief_system_documentation.md @@ -137,7 +137,7 @@ User ──(has roles/entitlements)──► Bank/System actions **Logging** -- Copy `logback.xml.example` to `logback.xml`; adjust levels (TRACE/DEBUG/INFO) per environment. +- `logback.xml` ships ready to use, defaulting to INFO; set `LOG_LEVEL` (TRACE/DEBUG/INFO/...) to override per environment. - In Docker/K8s, logs go to stdout/stderr → aggregate with your stack (e.g., Loki/Promtail, EFK). **Health & metrics** From ca08fb69808b0595c6d9c373c63c91316c278cb5 Mon Sep 17 00:00:00 2001 From: Hongwei Date: Wed, 23 Sep 2026 10:38:41 +0200 Subject: [PATCH 3/4] fix: default logback.xml root level to INFO via LOG_LEVEL The previous commit only renamed logback.xml.example to logback.xml; the actual level change didn't make it into that commit. Change the hard-coded DEBUG to ${LOG_LEVEL:-INFO}: an unset LOG_LEVEL now falls back to INFO instead of DEBUG, and any environment that wants more can set LOG_LEVEL=DEBUG or TRACE explicitly. --- obp-api/src/main/resources/logback.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/obp-api/src/main/resources/logback.xml b/obp-api/src/main/resources/logback.xml index 871aea062a..3c9540c8ae 100644 --- a/obp-api/src/main/resources/logback.xml +++ b/obp-api/src/main/resources/logback.xml @@ -6,7 +6,12 @@ - + + \ No newline at end of file From 99423f21dd76b95921d3983c144c73b799b2cfdd Mon Sep 17 00:00:00 2001 From: Hongwei Date: Wed, 23 Sep 2026 10:52:42 +0200 Subject: [PATCH 4/4] test: verify logback.xml resolves LOG_LEVEL, fix invalid XML comment Added a direct test that parses the shipped logback.xml into a fresh LoggerContext via Joran (the same parser Logback uses internally) with LOG_LEVEL set beforehand, since the application's own LoggerContext is configured once at JVM start and wouldn't exercise the default-value resolution this fix depends on. Writing it caught a real bug: the explanatory comment above contained a bare "--", which XML disallows anywhere inside a comment body, not just at the delimiters. Xerces rejected the file outright (SAXParseException) rather than silently ignoring the comment, so this would have broken every deployment picking up this branch, not just this test. Reworded the comment to drop the double dash. --- obp-api/src/main/resources/logback.xml | 4 +- .../http4s/LogbackDefaultLevelTest.scala | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 obp-api/src/test/scala/bootstrap/http4s/LogbackDefaultLevelTest.scala diff --git a/obp-api/src/main/resources/logback.xml b/obp-api/src/main/resources/logback.xml index 3c9540c8ae..8044beb0bf 100644 --- a/obp-api/src/main/resources/logback.xml +++ b/obp-api/src/main/resources/logback.xml @@ -7,9 +7,9 @@ diff --git a/obp-api/src/test/scala/bootstrap/http4s/LogbackDefaultLevelTest.scala b/obp-api/src/test/scala/bootstrap/http4s/LogbackDefaultLevelTest.scala new file mode 100644 index 0000000000..527c81bfa5 --- /dev/null +++ b/obp-api/src/test/scala/bootstrap/http4s/LogbackDefaultLevelTest.scala @@ -0,0 +1,55 @@ +package bootstrap.http4s + +import ch.qos.logback.classic.{Level, Logger, LoggerContext} +import ch.qos.logback.classic.joran.JoranConfigurator +import ch.qos.logback.classic.spi.LoggerContextListener +import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers} +import org.slf4j.Logger.ROOT_LOGGER_NAME + +/** + * Directly verifies the shipped src/main/resources/logback.xml resolves + * the way this fix depends on: + * + * - LOG_LEVEL unset -> root defaults to INFO, not the old hard-coded DEBUG. + * - LOG_LEVEL set -> root honours it. + * + * The application's actual SLF4J LoggerContext is configured once, at JVM start, from whatever + * LOG_LEVEL happened to be set at that moment -- so asserting against + * LoggerFactory.getILoggerFactory() here wouldn't exercise the default-value resolution at all, + * only whatever this test JVM's own environment happened to be. Instead this parses the actual + * classpath resource into a fresh, throwaway LoggerContext per scenario (via Joran, the same + * parser Logback uses internally), with the system property set immediately beforehand -- this is + * the standard way to unit-test a logback.xml's own logic rather than the ambient environment. + */ +class LogbackDefaultLevelTest extends FlatSpec with Matchers with BeforeAndAfterEach { + + private val propertyName = "LOG_LEVEL" + + override def afterEach(): Unit = { + System.clearProperty(propertyName) + } + + private def rootLevelFromShippedConfig(): Level = { + val context = new LoggerContext() + context.reset() + val configurator = new JoranConfigurator() + configurator.setContext(context) + configurator.doConfigure(getClass.getClassLoader.getResource("logback.xml")) + context.getLogger(ROOT_LOGGER_NAME).getLevel + } + + "the shipped logback.xml" should "default the root level to INFO when LOG_LEVEL is unset" in { + System.clearProperty(propertyName) + rootLevelFromShippedConfig() should equal(Level.INFO) + } + + it should "honour LOG_LEVEL=DEBUG when set" in { + System.setProperty(propertyName, "DEBUG") + rootLevelFromShippedConfig() should equal(Level.DEBUG) + } + + it should "honour LOG_LEVEL=WARN when set" in { + System.setProperty(propertyName, "WARN") + rootLevelFromShippedConfig() should equal(Level.WARN) + } +}