This commit adds metrics support to the http client (clojure and java, sync
and async). A metric registry can optionally be passed into the client as a
client option on creation. If a metric registry is present, timers will be
added to time each request.
By default, a timer is added for the URL (stripped of username, password,
query string, and path fragments) and the URL plus the method used for the
request. In addition, a request can include a `metric-id` option, which takes
a tuple of metric ids. If this request option is specified, a timer will be
created for each element of the metric id tuple - thus if the tuple is [:foo
:bar :baz] there will be a foo timer, a foo.bar timer, and a foo.bar.baz
timer.
In addition, each timer has a "MetricType" - currently there is only one
metric type, bytes-read, which is stopped when the full response has been
read. In the future, we may add "response-init" timers that get stopped when
the first byte of the response has been read.
This commit also adds a `get-client-metrics`/`.getClientMetrics` function that
takes a client instance and returns the http client-specific metrics from the
metric registry and a `get-client-metrics-data`/`.getClientMetricsData`
function for clojure and java sync and async clients to get out metrics data
from the client. This function takes a client instance and returns a map of
metric name to a map of metric data (for clojure) or a ClientMetricData object
(for java), both of which include the mean, count, and aggregate for the timer
These `get-client-metrics*`/`.getClientMetrics*` functions also have versions
that take a url, url and method, or metric id to allow for filtering of the
timers/metrics data returned by these functions.
The clojure versions of these functions take a metric filter map. There are
also metric filter builder functions to build up the type of metric filter
desired from a url, a url and method, or a metric id. These will prevent users
from having to know the specifics of how to build a metric themselves; instead
they can use a convenience function.
An empty metric id can be passed in to the filter to return all metric-id
timers.
Fix a bug in which a default charset of UTF-8 would be added to the
Content-Type header for certain requests. This change restricts that
behavior to cases in which the body is a string and there is no charset
provided by the caller.
This commit removes the `AsyncClose` class and references to it. These
changes are in preparation for making the close call after the response
has been dereferenced - to be done in a later commit. The `persistent`
flag/option was also removed from request handling as it will no longer
be used for determining whether or not the client should be closed
following a request.
This commit moves each close call made on a `CloseableHttpAsyncClient`
from the thread on which the request callback is made over to a
different thread in order to avoid a deadlock.
Previously, the client close call was made in the context of thread from
which the callback was invoked. The Apache HTTP async client library
makes these calls from one of its i/o reactor threads. In the case of a
"failed" request, e.g., failure to make the client connection, this call
occurs in the context of the primary i/o reactor thread. The client
close call does an indefinite join on the primary i/o reactor thread
and, therefore, this call causes a deadlock. The client never closes
and all resources associated with it - threads, file descriptors, etc. -
remain open until the process is shutdown.
This commit introduces a new class, `AsyncClose`, which manages a small,
fixed size thread pool from which client close calls can be executed.
The `async` Clojure and `JavaClient` APIs were updated to use `AsyncClose`
whenever a client needs to be closed from a callback.
Prior to this commit, the Java client API would throw an NPE if
it got a response from a server where the Content-Type header
did not include a charset.