diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml
index 386a330..0c77785 100644
--- a/.github/workflows/deploy-release.yml
+++ b/.github/workflows/deploy-release.yml
@@ -29,7 +29,7 @@ jobs:
MAVEN_GPG_KEY: ${{ secrets.MAVEN_GPG_KEY }}
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
- run: mvn clean deploy --no-transfer-progress
+ run: mvn clean deploy -Pci-publish --no-transfer-progress
- name: Get current version
id: version
run: echo "::set-output name=prop::$(mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)"
diff --git a/docs/console.png b/docs/console.png
index 4816b27..fdc46e9 100644
Binary files a/docs/console.png and b/docs/console.png differ
diff --git a/docs/console_banner.png b/docs/console_banner.png
new file mode 100644
index 0000000..67e68ce
Binary files /dev/null and b/docs/console_banner.png differ
diff --git a/docs/illustration.svg b/docs/illustration.svg
new file mode 100644
index 0000000..f4123c0
--- /dev/null
+++ b/docs/illustration.svg
@@ -0,0 +1,176 @@
+
+
+
+
diff --git a/docs/illustrationColoree.png b/docs/illustrationColoree.png
new file mode 100644
index 0000000..75e18ff
Binary files /dev/null and b/docs/illustrationColoree.png differ
diff --git a/pom.xml b/pom.xml
index e8f3f66..a521c1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
io.github.fbibonneboot-properties-logger-starter
- 2.1.0
+ 2.2.0jar
@@ -107,6 +107,59 @@
+
+
+ ci-publish
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ ${maven-gpg-plugin.version}
+
+ bc
+
+
+
+ sign-artifacts
+ install
+
+ sign
+
+
+
+
+
+ dev.sigstore
+ sigstore-maven-plugin
+ ${sigstore-maven-plugin.version}
+
+
+ sign
+ install
+
+ sign
+
+
+
+
+
+ org.sonatype.central
+ central-publishing-maven-plugin
+ ${central-publishing-maven-plugin.version}
+ true
+
+ central
+ Properties-Logger
+ true
+
+
+
+
+
+
+
+
@@ -152,47 +205,6 @@
-
- org.apache.maven.plugins
- maven-gpg-plugin
- ${maven-gpg-plugin.version}
-
- bc
-
-
-
- sign-artifacts
- install
-
- sign
-
-
-
-
-
- dev.sigstore
- sigstore-maven-plugin
- ${sigstore-maven-plugin.version}
-
-
- sign
- install
-
- sign
-
-
-
-
-
- org.sonatype.central
- central-publishing-maven-plugin
- ${central-publishing-maven-plugin.version}
- true
-
- central
- Properties-Logger
-
-
diff --git a/src/main/java/io/github/fbibonne/springaddons/boot/propertieslogger/PropertiesLogger.java b/src/main/java/io/github/fbibonne/springaddons/boot/propertieslogger/PropertiesLogger.java
index c44f754..34b5386 100644
--- a/src/main/java/io/github/fbibonne/springaddons/boot/propertieslogger/PropertiesLogger.java
+++ b/src/main/java/io/github/fbibonne/springaddons/boot/propertieslogger/PropertiesLogger.java
@@ -11,15 +11,20 @@
/**
* Class doing the real stuff for logging properties. The collect of properties to log, their value and the logging is done
- * inside the {@link this#doLogProperties()} method.
+ * inside the doLogProperties method.
* The state of the class stores {@link PropertySource} found, and a reference to an operator providing the origin of a property
* which is found while scanning propertySources
*/
-class PropertiesLogger {
+public class PropertiesLogger {
public static final String SEPARATION_LINE = "================================================================================";
public static final String MASK = "******";
private static final LocalLogger log = new LocalLogger(PropertiesLogger.class);
+ public static final String ANSI_CYAN_BOLD_SEQUENCE = "\u001B[1;36m";
+ public static final String ANSI_NORMAL_SEQUENCE = "\u001B[0m";
+ public static final String ANSI_BROWN_UNDERLINE_SEQUENCE = "\u001B[4;33m";
+ public static final String AINSI_PURPLE_ITALIC_SEQUENCE = "\u001B[1;3;35m";
+ public static final String AINSI_GREEN_BOLD_SEQUENCE = "\u001B[1;32m";
final PropertiesWithHiddenValues propertiesWithHiddenValues;
final AllowedPrefixForProperties allowedPrefixForProperties;
@@ -46,7 +51,7 @@ class PropertiesLogger {
*
debug message is logged if the propertySource is ignored
*
warn message is logged if the propertySource is a {@link org.springframework.boot.ansi.AnsiPropertySource} (whose processing is not implmented).
* in such case, it will be ignored
-
+ *
*
If propertySource has an unknown type, a warning is logged
*
*
@@ -58,14 +63,14 @@ class PropertiesLogger {
*
*
*/
- public void doLogProperties() {
+ void doLogProperties() {
debugStarting();
final StringBuilder stringWithPropertiesToDisplay = new StringBuilder();
Map propertyNamesBySource = propertyNamesBySourceFromEnvironment();
final Set propertySourceNames = propertyNamesBySource.keySet();
- stringWithPropertiesToDisplay.append( headerBlock(propertySourceNames))
+ stringWithPropertiesToDisplay.append(headerBlock(propertySourceNames))
.append(toKeyValuesBlock(propertyNamesBySource))
.append(System.lineSeparator())
.append(SEPARATION_LINE);
@@ -77,10 +82,10 @@ private String headerBlock(Set propertySourceNames) {
return """
%1$s
- Values of properties from sources :
- %2$s
+ %2$sValues of properties from sources :%3$s
+ %4$s
====
- """.formatted(SEPARATION_LINE, insertPropretySourceNamesOnePerLine(propertySourceNames));
+ """.formatted(SEPARATION_LINE, AINSI_GREEN_BOLD_SEQUENCE, ANSI_NORMAL_SEQUENCE, propretySourceNamesOnePerLine(propertySourceNames));
}
private String toKeyValuesBlock(Map propertyNamesBySource) {
@@ -113,7 +118,7 @@ private void debugStarting() {
+ ignoredPropertySources + ". Values masked for properties whose keys contain " + propertiesWithHiddenValues);
}
- private String insertPropretySourceNamesOnePerLine(Set propertySourceNames) {
+ private String propretySourceNamesOnePerLine(Set propertySourceNames) {
return propertySourceNames.stream().sorted().map(name -> "- " + name).collect(Collectors.joining(System.lineSeparator()));
}
@@ -141,12 +146,13 @@ private static void traceIgnored(PropertySource> propertySource) {
}
private String toDisplayedLine(String key) {
- return key + " = " + resolveValueThenMaskItIfSecret(key, this.abstractEnvironment)
+ return ANSI_CYAN_BOLD_SEQUENCE + key + ANSI_NORMAL_SEQUENCE + " = "
+ + ANSI_BROWN_UNDERLINE_SEQUENCE + resolveValueThenMaskItIfSecret(key, this.abstractEnvironment) + ANSI_NORMAL_SEQUENCE
+ this.originFinder.findOriginFor(key).map(PropertiesLogger::originAsLine).orElse("");
}
private static String originAsLine(String origin) {
- return " ### " + origin + " ###";
+ return " ### " + AINSI_PURPLE_ITALIC_SEQUENCE + origin + ANSI_NORMAL_SEQUENCE + " ###";
}
private @Nullable String resolveValueThenMaskItIfSecret(String key, EnvironmentPreparedEventForPropertiesLogging.CustomAbstractEnvironment environment) {
@@ -163,6 +169,7 @@ private boolean mustBeMasked(String key) {
/**
* Implementation of a String#containsIgnoreCase based the algorithm of String#contains
* but using String#equalsIgnoreCase to test equality
+ *
* @param container the string which is supposed to contain the argument passed to the predicate.
* Must be not null
* @return a predicate such as container::containsIgnoreCase
@@ -170,12 +177,12 @@ private boolean mustBeMasked(String key) {
*/
Predicate super String> isValueContainedIgnoringCaseIn(String container) {
return value -> {
- if (value.isEmpty()){
+ if (value.isEmpty()) {
return true;
}
int valueLength = value.length();
- for(int i = 0; i <= container.length()- valueLength; i++) {
- if (container.substring(i, i+valueLength).equalsIgnoreCase(value)){
+ for (int i = 0; i <= container.length() - valueLength; i++) {
+ if (container.substring(i, i + valueLength).equalsIgnoreCase(value)) {
return true;
}
}
diff --git a/src/test/java/io/github/fbibonne/test/ExcludedPropertySourcesTest.java b/src/test/java/io/github/fbibonne/test/ExcludedPropertySourcesTest.java
index c34adfb..feea2dd 100644
--- a/src/test/java/io/github/fbibonne/test/ExcludedPropertySourcesTest.java
+++ b/src/test/java/io/github/fbibonne/test/ExcludedPropertySourcesTest.java
@@ -17,6 +17,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.*;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = ExcludedPropertySourcesTest.class, properties = {
@@ -63,11 +64,11 @@ void contextLoad_shouldNotPrintExcludedPropertySources(@Autowired Environment en
assertThat(environment.getProperty("properties.logger.sources-ignored")).hasToString("systemProperties, systemEnvironment,[application.properties],[otherProps/application.properties],commandLineArgs,Inlined Test Properties,["+ externalPropertiesPath.toAbsolutePath()+"]");
assertThat(environment.getProperty("io.github.fbibonne.shared")).hasToString("dynamicPropertySource");
assertThat(environment.getProperty("io.github.fbibonne.specific.nonExcludedFile")).hasToString("nonExcludedFile");
- assertThat(logOutput).contains("io.github.fbibonne.shared = inlineTestProperties")
+ assertThat(logOutput).contains("io.github.fbibonne.shared"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"inlineTestProperties")
.doesNotContain("io.github.fbibonne.specific.dynamicPropertySource")
- .contains("io.github.fbibonne.specific.nonExcludedFile = nonExcludedFile")
+ .contains("io.github.fbibonne.specific.nonExcludedFile"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"nonExcludedFile")
.doesNotContain("io.github.fbibonne.sharedWithExternal = nonExcludedFile")
- .contains("io.github.fbibonne.sharedWithExternal = inFileSystem")
+ .contains("io.github.fbibonne.sharedWithExternal"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"inFileSystem")
.doesNotContain("io.github.fbibonne.specific.inFileSystem = inFileSystem")
.doesNotContain("io.github.fbibonne.specific.applicationproperties")
.doesNotContain("io.github.fbibonne.specific.additionalPropsInClasspath")
diff --git a/src/test/java/io/github/fbibonne/test/ExternalPropertiesFilesIntegrationTest.java b/src/test/java/io/github/fbibonne/test/ExternalPropertiesFilesIntegrationTest.java
index 1560de8..81e6c3e 100644
--- a/src/test/java/io/github/fbibonne/test/ExternalPropertiesFilesIntegrationTest.java
+++ b/src/test/java/io/github/fbibonne/test/ExternalPropertiesFilesIntegrationTest.java
@@ -13,6 +13,8 @@
import java.io.IOException;
import java.nio.file.Path;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.ANSI_BROWN_UNDERLINE_SEQUENCE;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.ANSI_NORMAL_SEQUENCE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -40,14 +42,14 @@ void startingSpringBootApplicationWithExternalOptionalPropertiesFilesAndUnexisti
"--spring.main.web-application-type=none")).doesNotThrowAnyException();
Environment environment = contextRef.context.getEnvironment();
assertThatCode(()->environment.getProperty("spring.config.location")).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Could not resolve placeholder 'unexisting'");
- assertThat(capturedOutput.toString()).contains("spring.config.location = optional:file:/${unexisting}/application.properties");
+ assertThat(capturedOutput.toString()).contains("spring.config.location"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"optional:file:/${unexisting}/application.properties");
//otherProps/application.properties
/*
* io.github.fbibonne.shared = additionalPropsInClasspath
* io.github.fbibonne.specific.additionalPropsInClasspath = additionalPropsInClasspath
*/
assertThat(environment.getProperty("io.github.fbibonne.specific.additionalPropsInClasspath")).hasToString("additionalPropsInClasspath");
- assertThat(capturedOutput.toString()).contains("io.github.fbibonne.specific.additionalPropsInClasspath = additionalPropsInClasspath");
+ assertThat(capturedOutput.toString()).contains("io.github.fbibonne.specific.additionalPropsInClasspath"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"additionalPropsInClasspath");
// /${existing}/application.properties => nonExcluded/application.properties
/*
* io.github.fbibonne.shared = nonExcludedFile
@@ -55,7 +57,7 @@ void startingSpringBootApplicationWithExternalOptionalPropertiesFilesAndUnexisti
* io.github.fbibonne.sharedWithExternal = nonExcludedFile
*/
assertThat(environment.getProperty("io.github.fbibonne.specific.nonExcludedFile")).hasToString("nonExcludedFile");
- assertThat(capturedOutput.toString()).contains("io.github.fbibonne.specific.nonExcludedFile = nonExcludedFile");
+ assertThat(capturedOutput.toString()).contains("io.github.fbibonne.specific.nonExcludedFile"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"nonExcludedFile");
// /${existing:"+ ignoredPath +"}/application.properties => not /ignored/application.properties
assertThat(environment.getProperty("io.github.fbibonne.specific.ignoredFile")).isNull();
assertThat(capturedOutput.toString()).doesNotContain("io.github.fbibonne.specific.ignoredFile");
diff --git a/src/test/java/io/github/fbibonne/test/MaskedValuesTest.java b/src/test/java/io/github/fbibonne/test/MaskedValuesTest.java
index eeb8b3f..144b2a7 100644
--- a/src/test/java/io/github/fbibonne/test/MaskedValuesTest.java
+++ b/src/test/java/io/github/fbibonne/test/MaskedValuesTest.java
@@ -8,6 +8,7 @@
import org.springframework.context.annotation.Configuration;
import static io.github.fbibonne.springaddons.boot.propertieslogger.ConstantsForTests.MASK;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.*;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = ExcludedPropertySourcesTest.class, properties = {
@@ -21,7 +22,7 @@ class MaskedValuesTest {
@Test
void checkMaskValuesIgnoreCase(CapturedOutput output) {
assertThat(output.toString()).doesNotContain("verysecretpassword")
- .contains("com.mycompany.serviceContactPassword = "+MASK);
+ .contains(ANSI_CYAN_BOLD_SEQUENCE+"com.mycompany.serviceContactPassword"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+MASK);
}
}
diff --git a/src/test/java/io/github/fbibonne/test/WebAppIntegrationTest.java b/src/test/java/io/github/fbibonne/test/WebAppIntegrationTest.java
index 3387bb9..557c075 100644
--- a/src/test/java/io/github/fbibonne/test/WebAppIntegrationTest.java
+++ b/src/test/java/io/github/fbibonne/test/WebAppIntegrationTest.java
@@ -9,6 +9,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.*;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = WebAppIntegrationTest.class, properties = {
@@ -28,11 +29,10 @@ class WebAppIntegrationTest {
@Test
@DisplayName("Properties should be correctly displayed and sorted when starting in Web context")
void contextLoads(CapturedOutput output) {
- //### FROM "spring.application.pid" from property source "applicationInfo" ###
assertThat(output.toString()).contains(("""
main] i.g.f.s.b.p.PropertiesLogger : %n\
================================================================================
- Values of properties from sources :
+ %1$sValues of properties from sources :%2$s
- Config resource 'class path resource [additional-file.properties]' via location 'classpath:additional-file.properties'%n\
- Config resource 'class path resource [application.properties]' via location 'optional:classpath:/'%n\
- Config resource 'file [src/test/resources/otherProps/application.properties]' via location 'file:src/test/resources/otherProps/application.properties'%n\
@@ -41,22 +41,22 @@ void contextLoads(CapturedOutput output) {
- commandLineArgs%n\
- systemProperties%n\
====%n\
- from.system.properties = true ### FROM "from.system.properties" from property source "systemProperties" ###
- io.github.fbibonne.secret = ****** ### FROM class path resource [application.properties] - 2:29 ###
- io.github.fbibonne.shared = additionalPropsInClasspath ### FROM URL [file:src/test/resources/otherProps/application.properties] - 1:29 ###
- io.github.fbibonne.specific.additional-file = additional-file.properties ### FROM class path resource [additional-file.properties] - 2:47 ###
- io.github.fbibonne.specific.additionalPropsInClasspath = additionalPropsInClasspath ### WARNING ! Configuration property name 'io.github.fbibonne.specific.additionalPropsInClasspath' is not valid : see org.springframework.boot.context.properties.source.ConfigurationPropertyName ###
- io.github.fbibonne.specific.applicationproperties = application.properties ### FROM class path resource [application.properties] - 4:53 ###
- io.github.fbibonne.test = ok ### FROM class path resource [application.properties] - 1:27 ###
- logging.level.io.github.fbibonne.springaddons.boot = trace ### FROM "logging.level.io.github.fbibonne.springaddons.boot" from property source "Inlined Test Properties" ###
- properties.logger.prefix-for-properties = info, logging, spring, server, management, properties, springdoc, io, from ### FROM "properties.logger.prefix-for-properties" from property source "Inlined Test Properties" ###
- properties.logger.sources-ignored = systemEnvironment ### FROM "properties.logger.sources-ignored" from property source "Inlined Test Properties" ###
- spring.application.pid =\s""").formatted())
+ %3$sfrom.system.properties%2$s = %4$strue%2$s ### %5$sFROM "from.system.properties" from property source "systemProperties"%2$s ###
+ %3$sio.github.fbibonne.secret%2$s = %4$s******%2$s ### %5$sFROM class path resource [application.properties] - 2:29%2$s ###
+ %3$sio.github.fbibonne.shared%2$s = %4$sadditionalPropsInClasspath%2$s ### %5$sFROM URL [file:src/test/resources/otherProps/application.properties] - 1:29%2$s ###
+ %3$sio.github.fbibonne.specific.additional-file%2$s = %4$sadditional-file.properties%2$s ### %5$sFROM class path resource [additional-file.properties] - 2:47%2$s ###
+ %3$sio.github.fbibonne.specific.additionalPropsInClasspath%2$s = %4$sadditionalPropsInClasspath%2$s ### %5$sWARNING ! Configuration property name 'io.github.fbibonne.specific.additionalPropsInClasspath' is not valid : see org.springframework.boot.context.properties.source.ConfigurationPropertyName%2$s ###
+ %3$sio.github.fbibonne.specific.applicationproperties%2$s = %4$sapplication.properties%2$s ### %5$sFROM class path resource [application.properties] - 4:53%2$s ###
+ %3$sio.github.fbibonne.test%2$s = %4$sok%2$s ### %5$sFROM class path resource [application.properties] - 1:27%2$s ###
+ %3$slogging.level.io.github.fbibonne.springaddons.boot%2$s = %4$strace%2$s ### %5$sFROM "logging.level.io.github.fbibonne.springaddons.boot" from property source "Inlined Test Properties"%2$s ###
+ %3$sproperties.logger.prefix-for-properties%2$s = %4$sinfo, logging, spring, server, management, properties, springdoc, io, from%2$s ### %5$sFROM "properties.logger.prefix-for-properties" from property source "Inlined Test Properties"%2$s ###
+ %3$sproperties.logger.sources-ignored%2$s = %4$ssystemEnvironment%2$s ### %5$sFROM "properties.logger.sources-ignored" from property source "Inlined Test Properties"%2$s ###
+ %3$sspring.application.pid%2$s =\s""").formatted(AINSI_GREEN_BOLD_SEQUENCE, ANSI_NORMAL_SEQUENCE, ANSI_CYAN_BOLD_SEQUENCE, ANSI_BROWN_UNDERLINE_SEQUENCE, AINSI_PURPLE_ITALIC_SEQUENCE))
.contains(("""
- spring.config.additional-location = classpath:additional-file.properties,file:src/test/resources/otherProps/application.properties ### FROM "spring.config.additional-location" from property source "commandLineArgs" ###
- spring.datasource.username = user_prod ### FROM System Environment Property "SPRING_DATASOURCE_USERNAME" ###
- spring.jmx.enabled = false ### FROM "spring.jmx.enabled" from property source "Inlined Test Properties" ###
- ================================================================================%n""").formatted()
+ %3$sspring.config.additional-location%2$s = %4$sclasspath:additional-file.properties,file:src/test/resources/otherProps/application.properties%2$s ### %5$sFROM "spring.config.additional-location" from property source "commandLineArgs"%2$s ###
+ %3$sspring.datasource.username%2$s = %4$suser_prod%2$s ### %5$sFROM System Environment Property "SPRING_DATASOURCE_USERNAME"%2$s ###
+ %3$sspring.jmx.enabled%2$s = %4$sfalse%2$s ### %5$sFROM "spring.jmx.enabled" from property source "Inlined Test Properties"%2$s ###
+ ================================================================================%n""").formatted(AINSI_GREEN_BOLD_SEQUENCE, ANSI_NORMAL_SEQUENCE, ANSI_CYAN_BOLD_SEQUENCE, ANSI_BROWN_UNDERLINE_SEQUENCE, AINSI_PURPLE_ITALIC_SEQUENCE)
);
}
diff --git a/src/test/java/io/github/fbibonne/test/examples/WithEnvironmentVariableTest.java b/src/test/java/io/github/fbibonne/test/examples/WithEnvironmentVariableTest.java
index 17ca0fa..f76e449 100644
--- a/src/test/java/io/github/fbibonne/test/examples/WithEnvironmentVariableTest.java
+++ b/src/test/java/io/github/fbibonne/test/examples/WithEnvironmentVariableTest.java
@@ -1,6 +1,5 @@
package io.github.fbibonne.test.examples;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
@@ -8,6 +7,7 @@
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.annotation.Configuration;
+import static io.github.fbibonne.springaddons.boot.propertieslogger.PropertiesLogger.*;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = WithEnvironmentVariableTest.class)
@@ -19,7 +19,7 @@ class WithEnvironmentVariableTest {
void shouldPickKeyFromApplicationPropertiesAndValueFromEnvironmentVariable(CapturedOutput output) {
String logOutput = output.toString();
- assertThat(logOutput).contains("spring.datasource.username = user_prod ### FROM System Environment Property \"SPRING_DATASOURCE_USERNAME\" ###");
+ assertThat(logOutput).contains("spring.datasource.username"+ANSI_NORMAL_SEQUENCE+" = "+ANSI_BROWN_UNDERLINE_SEQUENCE+"user_prod"+ANSI_NORMAL_SEQUENCE+" ### "+AINSI_PURPLE_ITALIC_SEQUENCE+"FROM System Environment Property \"SPRING_DATASOURCE_USERNAME\""+ANSI_NORMAL_SEQUENCE+" ###");
}
}