diff --git a/pom.xml b/pom.xml
index 720be8f..999ee85 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
UTF-8
21
+ 1.7.0
@@ -150,13 +151,30 @@
5.12.2
test
+
+ co.elastic.logging
+ logback-ecs-encoder
+ ${ecs-logging-java.version}
+
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/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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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"));
+ }
+
+}