From 8982fcc6f3f6402d1f63e07a936ae6c9a1829e0c Mon Sep 17 00:00:00 2001 From: Hayanesh Date: Sun, 17 Sep 2023 16:32:10 +0530 Subject: [PATCH] Add Spring Boot service version finder / ResourceProvider --- .../SpringBootServiceNameDetector.java | 5 ++ .../SpringBootServiceVersionDetector.java | 64 +++++++++++++++++++ .../SpringBootServiceVersionDetectorTest.java | 40 ++++++++++++ .../resources/META-INF/build-info.properties | 3 + 4 files changed, 112 insertions(+) create mode 100644 instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java create mode 100644 instrumentation/spring/spring-boot-resources/library/src/test/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetectorTest.java create mode 100644 instrumentation/spring/spring-boot-resources/library/src/test/resources/META-INF/build-info.properties diff --git a/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java b/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java index 59b3517ee7da..ed2908805aa6 100644 --- a/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java +++ b/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java @@ -293,6 +293,11 @@ InputStream openClasspathResource(String filename) { return classLoader.getResourceAsStream(path); } + InputStream openClasspathResource(String filename, String location) { + String path = location + "/" + filename; + return classLoader.getResourceAsStream(path); + } + InputStream openFile(String filename) throws Exception { return Files.newInputStream(Paths.get(filename)); } diff --git a/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java b/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java new file mode 100644 index 000000000000..748e7dc8de42 --- /dev/null +++ b/instrumentation/spring/spring-boot-resources/library/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java @@ -0,0 +1,64 @@ +package io.opentelemetry.instrumentation.spring.resources; + +import static java.util.logging.Level.FINE; + +import com.google.auto.service.AutoService; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ResourceAttributes; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; +import java.util.logging.Logger; +import io.opentelemetry.instrumentation.spring.resources.SpringBootServiceNameDetector.SystemHelper; + +@AutoService(ResourceProvider.class) +public class SpringBootServiceVersionDetector implements ResourceProvider { + + private static final Logger logger = + Logger.getLogger(SpringBootServiceVersionDetector.class.getName()); + + private final SystemHelper system; + + public SpringBootServiceVersionDetector() { + this.system = new SystemHelper(); + } + + // Exists for testing + public SpringBootServiceVersionDetector(SystemHelper system){ + this.system = system; + } + + @Override + public Resource createResource(ConfigProperties config) { + return getServiceVersionFromBuildInfo() + .map(version -> { + logger.log(FINE, "Auto-detected Spring Boot service version: {0}", version); + return Resource.builder().put(ResourceAttributes.SERVICE_VERSION, version).build(); + }) + .orElseGet(Resource::empty); + } + + + private Optional getServiceVersionFromBuildInfo(){ + try(InputStream in = system.openClasspathResource("build-info.properties", "META-INF")){ + return getServiceVersionPropertyFromStream(in); + }catch (Exception e){ + return Optional.empty(); + } + } + + private static Optional getServiceVersionPropertyFromStream(InputStream in){ + Properties properties = new Properties(); + try { + // Note: load() uses ISO 8859-1 encoding, same as spring uses by default for property files + properties.load(in); + return Optional.ofNullable(properties.getProperty("build.version")); + } catch (IOException e) { + return Optional.empty(); + } + } + +} diff --git a/instrumentation/spring/spring-boot-resources/library/src/test/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetectorTest.java b/instrumentation/spring/spring-boot-resources/library/src/test/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetectorTest.java new file mode 100644 index 000000000000..eaf1a33e287f --- /dev/null +++ b/instrumentation/spring/spring-boot-resources/library/src/test/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetectorTest.java @@ -0,0 +1,40 @@ +package io.opentelemetry.instrumentation.spring.resources; + +import static io.opentelemetry.semconv.ResourceAttributes.SERVICE_VERSION; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import java.io.InputStream; + +@ExtendWith(MockitoExtension.class) +class SpringBootServiceVersionDetectorTest { + + static final String BUILD_PROPS = "build-info.properties"; + static final String META_INFO = "META-INF"; + + @Mock + ConfigProperties config; + @Mock + SpringBootServiceNameDetector.SystemHelper system; + + @Test + void givenBuildVersionIsPresentInBuildInfProperties_thenReturnBuildVersion() { + when(system.openClasspathResource(BUILD_PROPS, META_INFO)) + .thenReturn(openClasspathResource(META_INFO + "/" + BUILD_PROPS)); + + SpringBootServiceVersionDetector guesser = new SpringBootServiceVersionDetector(system); + Resource result = guesser.createResource(config); + assertThat(result.getAttribute(SERVICE_VERSION)).isEqualTo("0.0.2"); + } + + private InputStream openClasspathResource(String resource) { + return getClass().getClassLoader().getResourceAsStream(resource); + } + +} diff --git a/instrumentation/spring/spring-boot-resources/library/src/test/resources/META-INF/build-info.properties b/instrumentation/spring/spring-boot-resources/library/src/test/resources/META-INF/build-info.properties new file mode 100644 index 000000000000..2b810fb32475 --- /dev/null +++ b/instrumentation/spring/spring-boot-resources/library/src/test/resources/META-INF/build-info.properties @@ -0,0 +1,3 @@ +build.artifact=something +build.name=some-name +build.version=0.0.2