001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.actuate.autoconfigure.metrics.web.servlet; 018 019import javax.servlet.DispatcherType; 020 021import io.micrometer.core.instrument.MeterRegistry; 022import io.micrometer.core.instrument.config.MeterFilter; 023 024import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; 025import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; 026import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Web.Server; 027import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; 028import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; 029import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; 030import org.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor; 031import org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter; 032import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider; 033import org.springframework.boot.autoconfigure.AutoConfigureAfter; 034import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 035import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 036import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 037import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 038import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 039import org.springframework.boot.context.properties.EnableConfigurationProperties; 040import org.springframework.boot.web.servlet.FilterRegistrationBean; 041import org.springframework.context.annotation.Bean; 042import org.springframework.context.annotation.Configuration; 043import org.springframework.core.Ordered; 044import org.springframework.core.annotation.Order; 045import org.springframework.web.servlet.DispatcherServlet; 046import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 047import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 048 049/** 050 * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring Web 051 * MVC servlet-based request mappings. 052 * 053 * @author Jon Schneider 054 * @author Dmytro Nosan 055 * @since 2.0.0 056 */ 057@Configuration 058@AutoConfigureAfter({ MetricsAutoConfiguration.class, 059 SimpleMetricsExportAutoConfiguration.class }) 060@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) 061@ConditionalOnClass(DispatcherServlet.class) 062@ConditionalOnBean(MeterRegistry.class) 063@EnableConfigurationProperties(MetricsProperties.class) 064public class WebMvcMetricsAutoConfiguration { 065 066 private final MetricsProperties properties; 067 068 public WebMvcMetricsAutoConfiguration(MetricsProperties properties) { 069 this.properties = properties; 070 } 071 072 @Bean 073 @ConditionalOnMissingBean(WebMvcTagsProvider.class) 074 public DefaultWebMvcTagsProvider webMvcTagsProvider() { 075 return new DefaultWebMvcTagsProvider(); 076 } 077 078 @Bean 079 public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter( 080 MeterRegistry registry, WebMvcTagsProvider tagsProvider) { 081 Server serverProperties = this.properties.getWeb().getServer(); 082 WebMvcMetricsFilter filter = new WebMvcMetricsFilter(registry, tagsProvider, 083 serverProperties.getRequestsMetricName(), 084 serverProperties.isAutoTimeRequests()); 085 FilterRegistrationBean<WebMvcMetricsFilter> registration = new FilterRegistrationBean<>( 086 filter); 087 registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); 088 registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC); 089 return registration; 090 } 091 092 @Bean 093 @Order(0) 094 public MeterFilter metricsHttpServerUriTagFilter() { 095 String metricName = this.properties.getWeb().getServer().getRequestsMetricName(); 096 MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(() -> String 097 .format("Reached the maximum number of URI tags for '%s'.", metricName)); 098 return MeterFilter.maximumAllowableTags(metricName, "uri", 099 this.properties.getWeb().getServer().getMaxUriTags(), filter); 100 } 101 102 @Bean 103 public MetricsWebMvcConfigurer metricsWebMvcConfigurer(MeterRegistry meterRegistry, 104 WebMvcTagsProvider tagsProvider) { 105 return new MetricsWebMvcConfigurer(meterRegistry, tagsProvider); 106 } 107 108 /** 109 * {@link WebMvcConfigurer} to add metrics interceptors. 110 */ 111 static class MetricsWebMvcConfigurer implements WebMvcConfigurer { 112 113 private final MeterRegistry meterRegistry; 114 115 private final WebMvcTagsProvider tagsProvider; 116 117 MetricsWebMvcConfigurer(MeterRegistry meterRegistry, 118 WebMvcTagsProvider tagsProvider) { 119 this.meterRegistry = meterRegistry; 120 this.tagsProvider = tagsProvider; 121 } 122 123 @Override 124 public void addInterceptors(InterceptorRegistry registry) { 125 registry.addInterceptor(new LongTaskTimingHandlerInterceptor( 126 this.meterRegistry, this.tagsProvider)); 127 } 128 129 } 130 131}