diff --git a/core/src/main/java/com/linecorp/armeria/server/Server.java b/core/src/main/java/com/linecorp/armeria/server/Server.java index abc50c791b8..95df0cb1118 100644 --- a/core/src/main/java/com/linecorp/armeria/server/Server.java +++ b/core/src/main/java/com/linecorp/armeria/server/Server.java @@ -49,6 +49,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import com.google.common.collect.Iterables; @@ -58,13 +59,16 @@ import com.linecorp.armeria.common.metric.MeterIdPrefix; import com.linecorp.armeria.common.util.EventLoopGroups; import com.linecorp.armeria.common.util.StartStopSupport; +import com.linecorp.armeria.common.util.Version; import com.linecorp.armeria.internal.ChannelUtil; import com.linecorp.armeria.internal.ConnectionLimitingHandler; import com.linecorp.armeria.internal.PathAndQuery; import com.linecorp.armeria.internal.TransportType; import com.linecorp.armeria.server.logging.AccessLogWriter; +import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -118,6 +122,8 @@ public static ServerBuilder builder() { final MeterIdPrefix idPrefix = new MeterIdPrefix("armeria.server.parsedPathCache"); PathAndQuery.registerMetrics(config.meterRegistry(), idPrefix); + setupVersionMetrics(); + // Invoke the serviceAdded() method in Service so that it can keep the reference to this Server or // add a listener to it. config.serviceConfigs().forEach(cfg -> ServiceCallbackInvoker.invokeServiceAdded(cfg, cfg.service())); @@ -305,6 +311,27 @@ public int numConnections() { return connectionLimitingHandler.numConnections(); } + /** + * Sets up the version metrics. + */ + @VisibleForTesting + void setupVersionMetrics() { + final MeterRegistry meterRegistry = config().meterRegistry(); + final Map map = Version.identify(getClass().getClassLoader()); + final Version versionInfo = map.get("armeria"); + final String version = versionInfo.artifactVersion(); + final String commit = versionInfo.longCommitHash(); + final String repositoryStatus = versionInfo.repositoryStatus(); + final List tags = ImmutableList.of(Tag.of("version", version), + Tag.of("commit", commit), + Tag.of("repoStatus", repositoryStatus)); + Gauge.builder("armeria.build.info", () -> 1) + .tags(tags) + .description("A metric with a constant '1' value labeled by version and commit hash" + + " from which Armeria was built.") + .register(meterRegistry); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/core/src/test/java/com/linecorp/armeria/server/ServerTest.java b/core/src/test/java/com/linecorp/armeria/server/ServerTest.java index 37133a01b64..5986c7f01f2 100644 --- a/core/src/test/java/com/linecorp/armeria/server/ServerTest.java +++ b/core/src/test/java/com/linecorp/armeria/server/ServerTest.java @@ -67,6 +67,7 @@ import com.linecorp.armeria.testing.internal.AnticipatedException; import com.linecorp.armeria.testing.junit4.server.ServerRule; +import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import io.netty.channel.ChannelOption; import io.netty.handler.codec.http.HttpStatusClass; @@ -436,6 +437,19 @@ public void notGracefulShutdownBlockingTaskExecutor() { assertThat(MoreExecutors.shutdownAndAwaitTermination(executor, 10, TimeUnit.SECONDS)).isTrue(); } + @Test + public void versionMetrics() { + final Server server = ServerTest.server.server(); + server.setupVersionMetrics(); + + final MeterRegistry meterRegistry = server.config().meterRegistry(); + final Gauge gauge = meterRegistry.find("armeria.build.info") + .tagKeys("version", "commit", "repoStatus") + .gauge(); + assertThat(gauge).isNotNull(); + assertThat(gauge.value()).isOne(); + } + private static void testSimple( String reqLine, String expectedStatusLine, String... expectedHeaders) throws Exception {