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來設(shè)置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方法,可以設(shè)置waitForContinue、tags、uriMapper(默認(rèn)是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來上報(bào)名為httpcomponents.httpclient.request,tag為method、uri、status、exportTagsForRoute、extraTags的指標(biāo)
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實(shí)現(xiàn)了MeterBinder接口,它構(gòu)造器接收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
小結(jié)
micrometer為apache httpclient提供了對應(yīng)的binder,用于上報(bào)相關(guān)metrics,其中1.2.0版本提供了MicrometerHttpRequestExecutor(httpcomponents.httpclient.request),1.4.0版本提供了MicrometerHttpClientInterceptor(httpcomponents.httpclient.request),另外對于連接池提供了PoolingHttpClientConnectionManagerMetricsBinder(httpcomponents.httpclient.pool)進(jìn)行監(jiān)控上報(bào)。
以上就是httpclient的監(jiān)控的詳細(xì)內(nèi)容,更多關(guān)于httpclient監(jiān)控的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
聊聊SpringCloud和SpringCloudAlibaba的區(qū)別
這篇文章主要介紹了SpringCloud和SpringCloudAlibaba的區(qū)別,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
MyBatis傳入集合 list 數(shù)組 map參數(shù)的寫法
這篇文章主要介紹了MyBatis傳入集合 list 數(shù)組 map參數(shù)的寫法的相關(guān)資料,非常不錯,具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
使用java.nio.file?庫優(yōu)雅的操作文件詳解
這篇文章主要介紹了使用java.nio.file?庫優(yōu)雅的操作文件詳解,需要的朋友可以參考下2023-05-05
Java基本數(shù)據(jù)類型和運(yùn)算符詳解
這篇文章主要介紹了Java基本數(shù)據(jù)類型和運(yùn)算符,結(jié)合實(shí)例形式詳細(xì)分析了java基本數(shù)據(jù)類型、數(shù)據(jù)類型轉(zhuǎn)換、算術(shù)運(yùn)算符、邏輯運(yùn)算符等相關(guān)原理與操作技巧,需要的朋友可以參考下2020-02-02
Java實(shí)現(xiàn)把文件及文件夾壓縮成zip
這篇文章主要介紹了Java實(shí)現(xiàn)把文件及文件夾壓縮成zip,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
JavaEE Spring MyBatis如何一步一步實(shí)現(xiàn)數(shù)據(jù)庫查詢功能
這篇文章主要介紹了JavaEE Spring MyBatis如何一步一步實(shí)現(xiàn)數(shù)據(jù)庫查詢功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08

