From f53c702436388b188bdf326ca82af495d53f005f Mon Sep 17 00:00:00 2001 From: Thomas Beekman Date: Thu, 26 Feb 2026 14:38:20 +0100 Subject: [PATCH 1/2] Add support for logging in JSON format --- pom.xml | 6 ++++++ src/main/resources/application.yml | 6 ++++++ src/main/resources/logback-spring.xml | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 src/main/resources/logback-spring.xml diff --git a/pom.xml b/pom.xml index 720be8f..5cc0925 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ UTF-8 21 + 1.7.0 @@ -150,6 +151,11 @@ 5.12.2 test + + co.elastic.logging + logback-ecs-encoder + ${ecs-logging-java.version} + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b5591fe..cce8d04 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -77,3 +77,9 @@ info: build: artifact: "@project.artifactId@" version: "@project.version@" + +# Logging settings to enable logging in JSON format (e.g. for usage in Graylog or Elastic Stack) +# logging: +# config: classpath:logback-spring.xml +# file: +# path: logs/ diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..6ec4343 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 6b1109c0c7cef4c2fff6b98e1479d9e7ab242067 Mon Sep 17 00:00:00 2001 From: Thomas Beekman Date: Thu, 26 Feb 2026 14:49:59 +0100 Subject: [PATCH 2/2] Added additional monitoring information to the info actuator --- pom.xml | 14 ++++- .../actuator/ReleaseDaysInfoContributor.java | 39 +++++++++++++ .../java/aa/config/BuildPropertiesConfig.java | 54 ++++++++++++++++++ .../ReleaseDaysInfoContributorTest.java | 55 +++++++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/main/java/aa/actuator/ReleaseDaysInfoContributor.java create mode 100644 src/main/java/aa/config/BuildPropertiesConfig.java create mode 100644 src/test/java/aa/actuator/ReleaseDaysInfoContributorTest.java diff --git a/pom.xml b/pom.xml index 5cc0925..999ee85 100644 --- a/pom.xml +++ b/pom.xml @@ -162,7 +162,19 @@ org.springframework.boot spring-boot-maven-plugin - 3.5.3 + + + + build-info + + + + ${java.version} + ${project.parent.version} + + + + io.github.git-commit-id diff --git a/src/main/java/aa/actuator/ReleaseDaysInfoContributor.java b/src/main/java/aa/actuator/ReleaseDaysInfoContributor.java new file mode 100644 index 0000000..eeb798d --- /dev/null +++ b/src/main/java/aa/actuator/ReleaseDaysInfoContributor.java @@ -0,0 +1,39 @@ +package aa.actuator; + +import aa.config.BuildPropertiesConfig; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; + +@Component +@Import(BuildPropertiesConfig.class) +public class ReleaseDaysInfoContributor implements InfoContributor { + + private static final String RELEASE_DAYS_KEY = "days_since_release"; + + private final BuildProperties buildProperties; + + public ReleaseDaysInfoContributor(BuildProperties buildProperties) { + this.buildProperties = buildProperties; + } + + @Override + public void contribute(Info.Builder builder) { + long currentDays = 0L; + + if (null != buildProperties.getTime()) { + LocalDate releaseDate = LocalDate.ofInstant(buildProperties.getTime(), ZoneId.systemDefault()); + LocalDate currentDate = LocalDate.ofInstant(Instant.now(), ZoneId.systemDefault()); + currentDays = ChronoUnit.DAYS.between(releaseDate, currentDate); + } + builder.withDetail(RELEASE_DAYS_KEY, currentDays); + } + +} diff --git a/src/main/java/aa/config/BuildPropertiesConfig.java b/src/main/java/aa/config/BuildPropertiesConfig.java new file mode 100644 index 0000000..be90237 --- /dev/null +++ b/src/main/java/aa/config/BuildPropertiesConfig.java @@ -0,0 +1,54 @@ +package aa.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; + +import java.io.IOException; +import java.time.Instant; +import java.util.Properties; + +@Configuration +public class BuildPropertiesConfig { + + private static final Logger LOGGER = LoggerFactory.getLogger(BuildPropertiesConfig.class); + + @Bean + public BuildProperties buildProperties() { + try { + Resource resource = new ClassPathResource("META-INF/build-info.properties"); + if (!resource.exists()) { + LOGGER.warn("META-INF/build-info.properties not found, using default build properties"); + return new BuildProperties(buildDefaultProperties("test")); + } + + Properties properties = PropertiesLoaderUtils.loadProperties(resource); + Properties flattenedProperties = new Properties(); + properties.forEach((key, value) -> { + String newKey = key.toString().replaceFirst("^build\\.", ""); + flattenedProperties.put(newKey, value); + }); + + return new BuildProperties(flattenedProperties); + } catch (IOException e) { + LOGGER.error("Error loading build-info.properties", e); + return new BuildProperties(buildDefaultProperties("error")); + } + } + + private Properties buildDefaultProperties(String tag) { + Properties defaultProperties = new Properties(); + defaultProperties.put("time", Instant.now().toString()); + defaultProperties.put("version", String.format("0.0.0-%s", tag.toUpperCase())); + defaultProperties.put("name", String.format("%s-build", tag)); + defaultProperties.put("group", String.format("%s-group", tag)); + defaultProperties.put("artifact", String.format("%s-artifact", tag)); + return defaultProperties; + } + +} diff --git a/src/test/java/aa/actuator/ReleaseDaysInfoContributorTest.java b/src/test/java/aa/actuator/ReleaseDaysInfoContributorTest.java new file mode 100644 index 0000000..af30584 --- /dev/null +++ b/src/test/java/aa/actuator/ReleaseDaysInfoContributorTest.java @@ -0,0 +1,55 @@ +package aa.actuator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.info.BuildProperties; + +import java.time.Duration; +import java.time.Instant; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ReleaseDaysInfoContributorTest { + + @Mock + private BuildProperties buildProperties; + + @InjectMocks + private ReleaseDaysInfoContributor infoIndicator; + + @Test + void testSeveralDays() { + when(buildProperties.getTime()).thenReturn(Instant.now().minus(Duration.ofDays(3))); + Info.Builder builder = new Info.Builder(); + infoIndicator.contribute(builder); + Info info = builder.build(); + + assertEquals(3L, info.get("days_since_release")); + } + + @Test + void testZeroDays() { + when(buildProperties.getTime()).thenReturn(Instant.now()); + Info.Builder builder = new Info.Builder(); + infoIndicator.contribute(builder); + Info info = builder.build(); + + assertEquals(0L, info.get("days_since_release")); + } + + @Test + void testNoBuildInfo() { + Info.Builder builder = new Info.Builder(); + infoIndicator.contribute(builder); + Info info = builder.build(); + + assertEquals(0L, info.get("days_since_release")); + } + +}