httpclient的監(jiān)控流程源碼解讀
序
本文主要研究一下如何監(jiān)控httpclient
MicrometerHttpRequestExecutor
micrometer-core-1.3.0-sources.jar!/io/micrometer/core/instrument/binder/httpcomponents/MicrometerHttpRequestExecutor.java
@Incubating(since = "1.2.0") public class MicrometerHttpRequestExecutor extends HttpRequestExecutor { /** * Default header name for URI pattern. */ public static final String DEFAULT_URI_PATTERN_HEADER = "URI_PATTERN"; private static final String METER_NAME = "httpcomponents.httpclient.request"; private static final String UNKNOWN = "UNKNOWN"; private static final Tag STATUS_UNKNOWN = Tag.of("status", UNKNOWN); private static final Tag STATUS_CLIENT_ERROR = Tag.of("status", "CLIENT_ERROR"); private static final Tag STATUS_IO_ERROR = Tag.of("status", "IO_ERROR"); private final MeterRegistry registry; private final Function<HttpRequest, String> uriMapper; private final Iterable<Tag> extraTags; private final boolean exportTagsForRoute; /** * Use {@link #builder(MeterRegistry)} to create an instance of this class. */ private MicrometerHttpRequestExecutor(int waitForContinue, MeterRegistry registry, Function<HttpRequest, String> uriMapper, Iterable<Tag> extraTags, boolean exportTagsForRoute) { super(waitForContinue); this.registry = Optional.ofNullable(registry).orElseThrow(() -> new IllegalArgumentException("registry is required but has been initialized with null")); this.uriMapper = Optional.ofNullable(uriMapper).orElseThrow(() -> new IllegalArgumentException("uriMapper is required but has been initialized with null")); this.extraTags = Optional.ofNullable(extraTags).orElse(Collections.emptyList()); this.exportTagsForRoute = exportTagsForRoute; } //...... }
MicrometerHttpRequestExecutor繼承了HttpRequestExecutor,它覆蓋了execute方法,使用timer來監(jiān)控,定義了method、uri、status、routeTags(target.scheme、target.host、target.port)、extraTags這幾個tag,metric名為httpcomponents.httpclient.request。
HttpClientBuilder.create() .setRequestExecutor(MicrometerHttpRequestExecutor .builder(meterRegistry) .build()) .build();
具體使用可以通過setRequestExecutor來設置MicrometerHttpRequestExecutor
Builder
public static Builder builder(MeterRegistry registry) { return new Builder(registry); } public static class Builder { private final MeterRegistry registry; private int waitForContinue = HttpRequestExecutor.DEFAULT_WAIT_FOR_CONTINUE; private Iterable<Tag> tags = Collections.emptyList(); private Function<HttpRequest, String> uriMapper = new DefaultUriMapper(); private boolean exportTagsForRoute = false; Builder(MeterRegistry registry) { this.registry = registry; } /** * @param waitForContinue Overrides the wait for continue time for this * request executor. See {@link HttpRequestExecutor} * for details. * @return This builder instance. */ public Builder waitForContinue(int waitForContinue) { this.waitForContinue = waitForContinue; return this; } /** * @param tags Additional tags which should be exposed with every value. * @return This builder instance. */ public Builder tags(Iterable<Tag> tags) { this.tags = tags; return this; } /** * Allows to register a mapping function for exposing request URIs. Be * careful, exposing request URIs could result in a huge number of tag * values, which could cause problems in your meter registry. * * By default, this feature is almost disabled. It only exposes values * of the {@link #DEFAULT_URI_PATTERN_HEADER} HTTP header. * * @param uriMapper A mapper that allows mapping and exposing request * paths. * @return This builder instance. * @see DefaultUriMapper */ public Builder uriMapper(Function<HttpRequest, String> uriMapper) { this.uriMapper = uriMapper; return this; } /** * Allows to expose the target scheme, host and port with every metric. * Be careful with enabling this feature: If your client accesses a huge * number of remote servers, this would result in a huge number of tag * values, which could cause cardinality problems. * * By default, this feature is disabled. * * @param exportTagsForRoute Set this to true, if the metrics should be * tagged with the target route. * @return This builder instance. */ public Builder exportTagsForRoute(boolean exportTagsForRoute) { this.exportTagsForRoute = exportTagsForRoute; return this; } /** * @return Creates an instance of {@link MicrometerHttpRequestExecutor} * with all the configured properties. */ public MicrometerHttpRequestExecutor build() { return new MicrometerHttpRequestExecutor(waitForContinue, registry, uriMapper, tags, exportTagsForRoute); } }
MicrometerHttpRequestExecutor提供了builder方法,可以設置waitForContinue、tags、uriMapper(默認是DefaultUriMapper)、exportTagsForRoute
DefaultUriMapper
/** * Extracts the pattern from the request header of the request if available. */ private static class DefaultUriMapper implements Function<HttpRequest, String> { @Override public String apply(HttpRequest httpRequest) { Header uriPattern = httpRequest.getLastHeader(DEFAULT_URI_PATTERN_HEADER); if (uriPattern != null && uriPattern.getValue() != null) { return uriPattern.getValue(); } return UNKNOWN; } }
DefaultUriMapper用于獲取uriPattern
MicrometerHttpClientInterceptor
micrometer-core-1.5.9.jar!/io/micrometer/core/instrument/binder/httpcomponents/MicrometerHttpClientInterceptor.java
@Incubating( since = "1.4.0" ) public class MicrometerHttpClientInterceptor { private static final String METER_NAME = "httpcomponents.httpclient.request"; private final Map<HttpContext, Timer.Sample> timerByHttpContext; private final HttpRequestInterceptor requestInterceptor; private final HttpResponseInterceptor responseInterceptor; public MicrometerHttpClientInterceptor(MeterRegistry meterRegistry, Function<HttpRequest, String> uriMapper, Iterable<Tag> extraTags, boolean exportTagsForRoute) { this.timerByHttpContext = new ConcurrentHashMap(); this.requestInterceptor = (request, context) -> { this.timerByHttpContext.put(context, Timer.start(meterRegistry).tags(new String[]{"method", request.getRequestLine().getMethod(), "uri", (String)uriMapper.apply(request)})); }; this.responseInterceptor = (response, context) -> { Timer.Sample sample = (Timer.Sample)this.timerByHttpContext.remove(context); sample.stop(meterRegistry, Timer.builder("httpcomponents.httpclient.request").tag("status", Integer.toString(response.getStatusLine().getStatusCode())).tags(exportTagsForRoute ? HttpContextUtils.generateTagsForRoute(context) : Tags.empty()).tags(extraTags)); }; } public MicrometerHttpClientInterceptor(MeterRegistry meterRegistry, Iterable<Tag> extraTags, boolean exportTagsForRoute) { this(meterRegistry, new DefaultUriMapper(), extraTags, exportTagsForRoute); } public HttpRequestInterceptor getRequestInterceptor() { return this.requestInterceptor; } public HttpResponseInterceptor getResponseInterceptor() { return this.responseInterceptor; } }
micrometer1.4.0版本開始提供了MicrometerHttpClientInterceptor,它定義了requestInterceptor、responseInterceptor,通過timer來上報名為httpcomponents.httpclient.request,tag為method、uri、status、exportTagsForRoute、extraTags的指標
PoolingHttpClientConnectionManagerMetricsBinder
io/micrometer/core/instrument/binder/httpcomponents/PoolingHttpClientConnectionManagerMetricsBinder.java
public class PoolingHttpClientConnectionManagerMetricsBinder implements MeterBinder { private final PoolingHttpClientConnectionManager connectionManager; private final Iterable<Tag> tags; /** * Creates a metrics binder for the given pooling connection manager. * * @param connectionManager The connection manager to monitor. * @param name Name of the connection manager. Will be added as tag with the * key "httpclient". * @param tags Tags to apply to all recorded metrics. Must be an even number * of arguments representing key/value pairs of tags. */ @SuppressWarnings("WeakerAccess") public PoolingHttpClientConnectionManagerMetricsBinder(PoolingHttpClientConnectionManager connectionManager, String name, String... tags) { this(connectionManager, name, Tags.of(tags)); } /** * Creates a metrics binder for the given pooling connection manager. * * @param connectionManager The connection manager to monitor. * @param name Name of the connection manager. Will be added as tag with the * key "httpclient". * @param tags Tags to apply to all recorded metrics. */ @SuppressWarnings("WeakerAccess") public PoolingHttpClientConnectionManagerMetricsBinder(PoolingHttpClientConnectionManager connectionManager, String name, Iterable<Tag> tags) { this.connectionManager = connectionManager; this.tags = Tags.concat(tags, "httpclient", name); } @Override public void bindTo(@NonNull MeterRegistry registry) { registerTotalMetrics(registry); } private void registerTotalMetrics(MeterRegistry registry) { Gauge.builder("httpcomponents.httpclient.pool.total.max", connectionManager, (connectionManager) -> connectionManager.getTotalStats().getMax()) .description("The configured maximum number of allowed persistent connections for all routes.") .tags(tags) .register(registry); Gauge.builder("httpcomponents.httpclient.pool.total.connections", connectionManager, (connectionManager) -> connectionManager.getTotalStats().getAvailable()) .description("The number of persistent and leased connections for all routes.") .tags(tags).tag("state", "available") .register(registry); Gauge.builder("httpcomponents.httpclient.pool.total.connections", connectionManager, (connectionManager) -> connectionManager.getTotalStats().getLeased()) .description("The number of persistent and leased connections for all routes.") .tags(tags).tag("state", "leased") .register(registry); Gauge.builder("httpcomponents.httpclient.pool.total.pending", connectionManager, (connectionManager) -> connectionManager.getTotalStats().getPending()) .description("The number of connection requests being blocked awaiting a free connection for all routes.") .tags(tags) .register(registry); Gauge.builder("httpcomponents.httpclient.pool.route.max.default", connectionManager, PoolingHttpClientConnectionManager::getDefaultMaxPerRoute) .description("The configured default maximum number of allowed persistent connections per route.") .tags(tags) .register(registry); } }
PoolingHttpClientConnectionManagerMetricsBinder實現(xiàn)了MeterBinder接口,它構造器接收PoolingHttpClientConnectionManager、name、tags,其bindTo方法定義了如下幾個metrics
- httpcomponents.httpclient.pool.total.max
- httpcomponents.httpclient.pool.total.connections, tag:state=available
- httpcomponents.httpclient.pool.total.connections, tag:state=leased
- httpcomponents.httpclient.pool.total.pending
- httpcomponents.httpclient.pool.route.max.default
小結
micrometer為apache httpclient提供了對應的binder,用于上報相關metrics,其中1.2.0版本提供了MicrometerHttpRequestExecutor(httpcomponents.httpclient.request
),1.4.0版本提供了MicrometerHttpClientInterceptor(httpcomponents.httpclient.request
),另外對于連接池提供了PoolingHttpClientConnectionManagerMetricsBinder(httpcomponents.httpclient.pool
)進行監(jiān)控上報。
以上就是httpclient的監(jiān)控的詳細內容,更多關于httpclient監(jiān)控的資料請關注腳本之家其它相關文章!
相關文章
聊聊SpringCloud和SpringCloudAlibaba的區(qū)別
這篇文章主要介紹了SpringCloud和SpringCloudAlibaba的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11MyBatis傳入集合 list 數(shù)組 map參數(shù)的寫法
這篇文章主要介紹了MyBatis傳入集合 list 數(shù)組 map參數(shù)的寫法的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-06-06使用java.nio.file?庫優(yōu)雅的操作文件詳解
這篇文章主要介紹了使用java.nio.file?庫優(yōu)雅的操作文件詳解,需要的朋友可以參考下2023-05-05JavaEE Spring MyBatis如何一步一步實現(xiàn)數(shù)據(jù)庫查詢功能
這篇文章主要介紹了JavaEE Spring MyBatis如何一步一步實現(xiàn)數(shù)據(jù)庫查詢功能,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08