diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index c8ef34f78c..c202ae0e1a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -248,6 +248,11 @@ elasticsearch true + + org.eclipse.jetty + jetty-server + true + org.flywaydb flyway-core @@ -470,6 +475,11 @@ aspectjrt test + + org.eclipse.jetty + jetty-webapp + test + org.hsqldb hsqldb diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfiguration.java new file mode 100644 index 0000000000..ca96c9b180 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.web.jetty; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics; +import org.eclipse.jetty.server.Server; + +import org.springframework.boot.actuate.metrics.web.jetty.JettyServerThreadPoolMetricsBinder; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Jetty metrics. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Configuration +@ConditionalOnWebApplication +@ConditionalOnClass({ JettyServerThreadPoolMetrics.class, Server.class }) +public class JettyMetricsAutoConfiguration { + + @Bean + @ConditionalOnBean(MeterRegistry.class) + @ConditionalOnMissingBean({ JettyServerThreadPoolMetrics.class, + JettyServerThreadPoolMetricsBinder.class }) + public JettyServerThreadPoolMetricsBinder jettyServerThreadPoolMetricsBinder( + MeterRegistry meterRegistry) { + return new JettyServerThreadPoolMetricsBinder(meterRegistry); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/package-info.java new file mode 100644 index 0000000000..9132210467 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Auto-configuration for Jetty actuator metrics. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.web.jetty; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 29af9cef1b..da69ef3055 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -64,6 +64,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetric org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.web.jetty.JettyMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat.TomcatMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfigurationTests.java new file mode 100644 index 0000000000..75189b8437 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/jetty/JettyMetricsAutoConfigurationTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.web.jetty; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.Test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.metrics.web.jetty.JettyServerThreadPoolMetricsBinder; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; +import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.server.reactive.HttpHandler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link JettyMetricsAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class JettyMetricsAutoConfigurationTests { + + @Test + public void autoConfiguresThreadPoolMetricsWithEmbeddedServletJetty() { + new WebApplicationContextRunner( + AnnotationConfigServletWebServerApplicationContext::new) + .withConfiguration( + AutoConfigurations.of(JettyMetricsAutoConfiguration.class, + ServletWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration(ServletWebServerConfiguration.class, + MeterRegistryConfiguration.class) + .run((context) -> { + context.publishEvent( + new ApplicationStartedEvent(new SpringApplication(), + null, context.getSourceApplicationContext())); + assertThat(context).hasSingleBean( + JettyServerThreadPoolMetricsBinder.class); + SimpleMeterRegistry registry = context + .getBean(SimpleMeterRegistry.class); + assertThat(registry.find("jetty.threads.config.min").meter()) + .isNotNull(); + }); + } + + @Test + public void autoConfiguresThreadPoolMetricsWithEmbeddedReactiveJetty() { + new ReactiveWebApplicationContextRunner( + AnnotationConfigReactiveWebServerApplicationContext::new) + .withConfiguration( + AutoConfigurations.of(JettyMetricsAutoConfiguration.class, + ReactiveWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration(ReactiveWebServerConfiguration.class, + MeterRegistryConfiguration.class) + .run((context) -> { + context.publishEvent( + new ApplicationStartedEvent(new SpringApplication(), + null, context.getSourceApplicationContext())); + SimpleMeterRegistry registry = context + .getBean(SimpleMeterRegistry.class); + assertThat(registry.find("jetty.threads.config.min").meter()) + .isNotNull(); + }); + } + + @Test + public void allowsCustomJettyServerThreadPoolMetricsBinderToBeUsed() { + new WebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(JettyMetricsAutoConfiguration.class)) + .withUserConfiguration(CustomJettyServerThreadPoolMetricsBinder.class, + MeterRegistryConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(JettyServerThreadPoolMetricsBinder.class) + .hasBean("customJettyServerThreadPoolMetricsBinder")); + } + + @Configuration + static class MeterRegistryConfiguration { + + @Bean + public SimpleMeterRegistry meterRegistry() { + return new SimpleMeterRegistry(); + } + + } + + @Configuration + static class ServletWebServerConfiguration { + + @Bean + public JettyServletWebServerFactory jettyFactory() { + return new JettyServletWebServerFactory(0); + } + + } + + @Configuration + static class ReactiveWebServerConfiguration { + + @Bean + public JettyReactiveWebServerFactory jettyFactory() { + return new JettyReactiveWebServerFactory(0); + } + + @Bean + public HttpHandler httpHandler() { + return mock(HttpHandler.class); + } + + } + + @Configuration + static class CustomJettyServerThreadPoolMetricsBinder { + + @Bean + public JettyServerThreadPoolMetricsBinder customJettyServerThreadPoolMetricsBinder( + MeterRegistry meterRegistry) { + return new JettyServerThreadPoolMetricsBinder(meterRegistry); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/pom.xml b/spring-boot-project/spring-boot-actuator/pom.xml index a02ba2d1e7..de7fa8560c 100644 --- a/spring-boot-project/spring-boot-actuator/pom.xml +++ b/spring-boot-project/spring-boot-actuator/pom.xml @@ -113,6 +113,11 @@ aspectjweaver true + + org.eclipse.jetty + jetty-server + true + org.elasticsearch elasticsearch diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/JettyServerThreadPoolMetricsBinder.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/JettyServerThreadPoolMetricsBinder.java new file mode 100644 index 0000000000..86b3c0976b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/JettyServerThreadPoolMetricsBinder.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.metrics.web.jetty; + +import java.util.Collections; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics; +import org.eclipse.jetty.util.thread.ThreadPool; + +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.boot.web.embedded.jetty.JettyWebServer; +import org.springframework.boot.web.server.WebServer; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; + +/** + * Binds {@link JettyServerThreadPoolMetrics} in response to the + * {@link ApplicationStartedEvent}. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +public class JettyServerThreadPoolMetricsBinder + implements ApplicationListener { + + private final MeterRegistry meterRegistry; + + private final Iterable tags; + + public JettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry) { + this(meterRegistry, Collections.emptyList()); + } + + public JettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry, + Iterable tags) { + this.meterRegistry = meterRegistry; + this.tags = tags; + } + + @Override + public void onApplicationEvent(ApplicationStartedEvent event) { + ApplicationContext applicationContext = event.getApplicationContext(); + ThreadPool threadPool = findThreadPool(applicationContext); + if (threadPool != null) { + new JettyServerThreadPoolMetrics(threadPool, this.tags) + .bindTo(this.meterRegistry); + } + } + + private ThreadPool findThreadPool(ApplicationContext applicationContext) { + if (applicationContext instanceof WebServerApplicationContext) { + WebServer webServer = ((WebServerApplicationContext) applicationContext) + .getWebServer(); + if (webServer instanceof JettyWebServer) { + return ((JettyWebServer) webServer).getServer().getThreadPool(); + } + } + return null; + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/package-info.java new file mode 100644 index 0000000000..c977a9ab42 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/jetty/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Actuator support for Jetty metrics. + */ +package org.springframework.boot.actuate.metrics.web.jetty;