(TK-316) Improve metrics API

This commit does several things to improve the metrics API:

* Move get-client-metrics(-data) functions off of client:
Previously, the `get-client-metrics(-data)`/`.getClientMetrics(Data)`
functions were on the client. This didn't entirely make sense because if two
clients were using the same metric registry, these functions would actually
return metrics data for *all* clients, rather than just for the client the
function was called on. This commit removes these functions and changes the
tests to use the metrics namepsace/Metrics class versions instead, which take
a metric registry return all http-client related metrics on that metric
registry.

* Add a `with-url-and-method` namespace:
Move the timers that have both the url and the method from the `with-url`
namespace to a new `with-url-and-method` namepsace. This better matches the
data structure are returned in and the filtering mechanisms for getting them
back out (discussed below), and also removes a slight chance of having a
conflict with a url timer.

* Add a ClientTimer class:
Add a ClientTimer class that wraps the Timer class and also holds onto the
url, method, or metric id used to create the timer. Use this to add url,
method, metricId to ClientMetricData.

* Change the `getClientMetrics(Data)` methods to return a map of metric
category to an array of timers or timer data:
Previously, the methods for getting http client metrics/metric data out of a
metric registry returned a map of metric name to timer instance or metric
data. However, the metric name was most likely not useful to users, who
probably just want to iterate through the timers/data. This commit makes the
output of these functions more useful by returning arrays of timers/data
sorted into a map indexed by metric category (url, url and method, or metric
id).

* Add `getClientMetricsBy*` methods:
Add `getClientMetrics(Data)ByUrl`, `getClientMetrics(Data)ByUrlAndMethod`, and
`getClientMetrics(Data)ByMetricId` methods (and clojure versions) that allow
for filtering by a specific metric category and return an array of timers or
timer data that match the url, url and method, or metric id specified.

* Remove the filter-builder functions:
Previously, the `get-client-metrics(-data)` functions did filtering by taking
a filter map, and there were filter-builder functions to build these filter
maps. Now that there are separate filtering methods, these filter maps are no
longer used and the filter-builder functions are removed.
This commit is contained in:
Ruth Linehan 2016-04-06 17:17:53 -07:00
parent df4e36a1aa
commit b744e99749
19 changed files with 961 additions and 705 deletions

View file

@ -15,7 +15,6 @@
(org.apache.http.client.utils URIBuilder)
(org.apache.http.nio.client HttpAsyncClient))
(:require [puppetlabs.http.client.common :as common]
[puppetlabs.http.client.metrics :as metrics]
[schema.core :as schema])
(:refer-clojure :exclude (get)))
@ -243,7 +242,4 @@
(assoc opts :method method :url url)
nil client metric-registry))
(close [_] (.close client))
(get-client-metrics [_] (metrics/get-client-metrics metric-registry))
(get-client-metrics [_ metric-filter] (metrics/get-client-metrics metric-registry metric-filter))
(get-client-metrics-data [_] (metrics/get-client-metrics-data metric-registry))
(get-client-metrics-data [_ metric-filter] (metrics/get-client-metrics-data metric-registry metric-filter)))))
(get-client-metric-registry [_] metric-registry))))

View file

@ -1,10 +1,11 @@
(ns puppetlabs.http.client.common
(:import (java.net URL)
(javax.net.ssl SSLContext)
(com.codahale.metrics MetricRegistry Timer)
(com.codahale.metrics MetricRegistry)
(clojure.lang IBlockingDeref)
(java.io InputStream)
(java.nio.charset Charset))
(java.nio.charset Charset)
(com.puppetlabs.http.client.impl ClientTimer))
(:require [schema.core :as schema])
(:refer-clojure :exclude (get)))
@ -22,8 +23,7 @@
(patch [this url] [this url opts])
(make-request [this url method] [this url method opts])
(close [this])
(get-client-metrics [this] [this metric-filter])
(get-client-metrics-data [this] [this metric-filter]))
(get-client-metric-registry [this]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Schemas
@ -166,26 +166,29 @@
(schema/maybe MetricRegistry))
(def Metrics
{schema/Str Timer})
[ClientTimer])
(def AllMetrics
{:url Metrics
:url-and-method Metrics
:metric-id Metrics})
(def MetricData
{:metric-name schema/Str
:count schema/Int
:mean schema/Num
:aggregate schema/Num})
:aggregate schema/Num
:url (schema/maybe schema/Str)
:method (schema/maybe schema/Str)
:metric-id [schema/Str]})
(def MetricsData
{schema/Str MetricData})
[MetricData])
(def AllMetricsData
{:url MetricsData
:url-and-method MetricsData
:metric-id MetricsData})
(def MetricTypes
(schema/enum :bytes-read))
(def MetricFilter
(schema/conditional
#(contains? % :url)
{:metric-type MetricTypes
:url schema/Str
(ok :method) HTTPMethod}
#(contains? % :metric-id)
{:metric-type MetricTypes
:metric-id MetricId}))

View file

@ -1,32 +1,18 @@
(ns puppetlabs.http.client.metrics
(:require [schema.core :as schema]
[puppetlabs.http.client.common :as common])
(:import (com.codahale.metrics Timer)
(java.util.concurrent TimeUnit)
(com.puppetlabs.http.client.impl Metrics$MetricType Metrics)))
(:import (com.puppetlabs.http.client.impl Metrics$MetricType Metrics
ClientMetricData)))
(schema/defn get-mean :- schema/Num
[timer :- Timer]
(->> timer
.getSnapshot
.getMean
(.toMillis TimeUnit/NANOSECONDS)))
(defn get-metric-data
[timer metric-name]
(let [count (.getCount timer)
mean (get-mean timer)
aggregate (* count mean)]
{:count count
:mean mean
:aggregate aggregate
:metric-name metric-name}))
(defn get-metrics-data
[timers]
(reduce (fn [acc [metric-name timer]]
(assoc acc metric-name (get-metric-data timer metric-name)))
{} timers))
(schema/defn get-metric-data :- common/MetricData
[data :- ClientMetricData]
{:count (.getCount data)
:mean (.getMean data)
:aggregate (.getAggregate data)
:metric-name (.getMetricName data)
:url (.getUrl data)
:method (.getMethod data)
:metric-id (.getMetricId data)})
(defn get-java-metric-type
[metric-type]
@ -40,55 +26,130 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Public
(schema/defn ^:always-validate filter-with-metric-id :- common/MetricFilter
[metric-id :- common/MetricId]
{:metric-id metric-id
:metric-type :bytes-read})
(schema/defn ^:always-validate filter-with-url :- common/MetricFilter
[url :- schema/Str]
{:url url
:metric-type :bytes-read})
(schema/defn ^:always-validate filter-with-url-and-method :- common/MetricFilter
[url :- schema/Str
method :- common/HTTPMethod]
{:url url
:method method
:metric-type :bytes-read})
(schema/defn ^:always-validate get-client-metrics :- (schema/maybe common/Metrics)
(schema/defn ^:always-validate get-client-metrics
:- (schema/maybe common/AllMetrics)
"Returns the http client-specific metrics from the metric registry."
([metric-registry :- common/OptionalMetricRegistry]
(when metric-registry
(into {} (Metrics/getClientMetrics metric-registry))))
([metric-registry :- common/OptionalMetricRegistry
metric-filter :- common/MetricFilter]
(when metric-registry
(cond
(:method metric-filter) (into {} (Metrics/getClientMetricsWithUrlAndMethod
metric-registry
(:url metric-filter)
(uppercase-method (:method metric-filter))
(get-java-metric-type (:metric-type metric-filter))))
(:url metric-filter) (into {} (Metrics/getClientMetricsWithUrl
metric-registry
(:url metric-filter)
(get-java-metric-type (:metric-type metric-filter))))
(:metric-id metric-filter) (into {} (Metrics/getClientMetricsWithMetricId
metric-registry
(into-array String (map name (:metric-id metric-filter)))
(get-java-metric-type (:metric-type metric-filter))))
:else (throw (IllegalArgumentException. "Not an allowed metric filter."))))))
[metric-registry :- common/OptionalMetricRegistry]
(when metric-registry
(let [metrics (Metrics/getClientMetrics metric-registry)]
{:url (get metrics "url")
:url-and-method (get metrics "url-and-method")
:metric-id (get metrics "metric-id")})))
(schema/defn ^:always-validate get-client-metrics-data :- (schema/maybe common/MetricsData)
"Returns a map of metric-id to metric data summary."
([metric-registry :- common/OptionalMetricRegistry]
(when metric-registry
(let [timers (get-client-metrics metric-registry)]
(get-metrics-data timers))))
(schema/defn ^:always-validate get-client-metrics-by-url
:- common/Metrics
"Returns the http client-specific url metrics matching the specified url."
([metric-registry :- common/OptionalMetricRegistry
metric-filter :- common/MetricFilter]
url :- schema/Str]
(get-client-metrics-by-url metric-registry url :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
metric-type :- common/MetricTypes]
(when metric-registry
(let [timers (get-client-metrics metric-registry metric-filter)]
(get-metrics-data timers)))))
(Metrics/getClientMetricsByUrl
metric-registry
url
(get-java-metric-type metric-type)))))
(schema/defn ^:always-validate get-client-metrics-by-url-and-method
:- common/Metrics
"Returns the http client-specific url metrics matching the specified url."
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
method :- common/HTTPMethod]
(get-client-metrics-by-url-and-method metric-registry url method :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
method :- common/HTTPMethod
metric-type :- common/MetricTypes]
(when metric-registry
(Metrics/getClientMetricsByUrlAndMethod
metric-registry
url
method
(get-java-metric-type metric-type)))))
(schema/defn ^:always-validate get-client-metrics-by-metric-id
:- common/Metrics
"Returns the http client-specific url metrics matching the specified url."
([metric-registry :- common/OptionalMetricRegistry
metric-id :- common/MetricId]
(get-client-metrics-by-metric-id metric-registry metric-id :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
metric-id :- common/MetricId
metric-type :- common/MetricTypes]
(when metric-registry
(Metrics/getClientMetricsByMetricId
metric-registry
(into-array String (map name metric-id))
(get-java-metric-type metric-type)))))
(schema/defn ^:always-validate get-client-metrics-data
:- (schema/maybe common/AllMetricsData)
"Returns a summary of the metric data for all http client timers, organized
in a map by category."
([metric-registry :- common/OptionalMetricRegistry]
(get-client-metrics-data metric-registry :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
metric-type :- common/MetricTypes]
(when metric-registry
(let [data (Metrics/getClientMetricsData
metric-registry
(get-java-metric-type metric-type))]
{:url (map get-metric-data (get data "url"))
:url-and-method (map get-metric-data (get data "url-and-method"))
:metric-id (map get-metric-data (get data "metric-id"))}))))
(schema/defn ^:always-validate get-client-metrics-data-by-url
:- common/MetricsData
"Returns a summary of the metric data for all http client timers filtered by
url."
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str]
(get-client-metrics-data-by-url metric-registry url :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
metric-type :- common/MetricTypes]
(when metric-registry
(let [data (Metrics/getClientMetricsDataByUrl
metric-registry
url
(get-java-metric-type metric-type))]
(map get-metric-data data)))))
(schema/defn ^:always-validate get-client-metrics-data-by-url-and-method
:- common/MetricsData
"Returns a summary of the metric data for all http client timers filtered by
url and method."
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
method :- common/HTTPMethod]
(get-client-metrics-data-by-url-and-method metric-registry url method :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
url :- schema/Str
method :- common/HTTPMethod
metric-type :- common/MetricTypes]
(when metric-registry
(let [data (Metrics/getClientMetricsDataByUrlAndMethod
metric-registry
url
(uppercase-method method)
(get-java-metric-type metric-type))]
(map get-metric-data data)))))
(schema/defn ^:always-validate get-client-metrics-data-by-metric-id
:- common/MetricsData
"Returns a summary of the metric data for all http client timers filtered by
metric-id."
([metric-registry :- common/OptionalMetricRegistry
metric-id :- common/MetricId]
(get-client-metrics-data-by-metric-id metric-registry metric-id :bytes-read))
([metric-registry :- common/OptionalMetricRegistry
metric-id :- common/MetricId
metric-type :- common/MetricTypes]
(when metric-registry
(let [data (Metrics/getClientMetricsDataByMetricId
metric-registry
(into-array String (map name metric-id))
(get-java-metric-type metric-type))]
(map get-metric-data data)))))

View file

@ -4,8 +4,7 @@
(ns puppetlabs.http.client.sync
(:require [puppetlabs.http.client.async :as async]
[schema.core :as schema]
[puppetlabs.http.client.common :as common]
[puppetlabs.http.client.metrics :as metrics])
[puppetlabs.http.client.common :as common])
(:refer-clojure :exclude (get)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -66,10 +65,7 @@
(assoc opts :method method :url url)
client metric-registry))
(close [_] (.close client))
(get-client-metrics [_] (metrics/get-client-metrics metric-registry))
(get-client-metrics [_ metric-filter] (metrics/get-client-metrics metric-registry metric-filter))
(get-client-metrics-data [_] (metrics/get-client-metrics-data metric-registry))
(get-client-metrics-data [_ metric-filter] (metrics/get-client-metrics-data metric-registry metric-filter)))))
(get-client-metric-registry [_] metric-registry))))
(defn get
"Issue a synchronous HTTP GET request. This will raise an exception if an

View file

@ -21,6 +21,7 @@ public class Async {
* @return an AsyncHttpClient that can be used to make requests
*/
public static AsyncHttpClient createClient(ClientOptions clientOptions) {
return new PersistentAsyncHttpClient(JavaClient.createClient(clientOptions), clientOptions.getMetricRegistry());
return new PersistentAsyncHttpClient(JavaClient.createClient(clientOptions),
clientOptions.getMetricRegistry());
}
}

View file

@ -1,14 +1,11 @@
package com.puppetlabs.http.client;
import com.codahale.metrics.Timer;
import com.puppetlabs.http.client.impl.ClientMetricData;
import com.puppetlabs.http.client.impl.Metrics;
import com.codahale.metrics.MetricRegistry;
import com.puppetlabs.http.client.impl.Promise;
import java.io.Closeable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
/**
* This interface represents an asynchronous HTTP client with which
@ -18,58 +15,9 @@ import java.util.Map;
public interface AsyncHttpClient extends Closeable{
/**
* @return a Map of metric name to Timer instance
* @return the MetricRegistry instance associated with this Client
*/
public Map<String, Timer> getClientMetrics();
/**
* @param url a url to filter on
* @param metricType the type of metric to return timers for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String url, Metrics.MetricType metricType);
/**
* @param url a url to filter on
* @param method an HTTP method to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String url, String method, Metrics.MetricType metricType);
/**
* @param metricId a metric id to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String[] metricId, Metrics.MetricType metricType);
/**
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData();
/**
* @param url a url to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String url, Metrics.MetricType metricType);
/**
* @param url a url to filter on
* @param method an HTTP method to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String url, String method, Metrics.MetricType metricType);
/**
* @param metricId a metric id to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String[] metricId, Metrics.MetricType metricType);
public MetricRegistry getMetricRegistry();
/**
* Performs a GET request

View file

@ -2,7 +2,6 @@ package com.puppetlabs.http.client;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Map;
/**

View file

@ -87,7 +87,8 @@ public class Sync {
* @return A persistent synchronous HTTP client
*/
public static SyncHttpClient createClient(ClientOptions clientOptions) {
return new PersistentSyncHttpClient(JavaClient.createClient(clientOptions), clientOptions.getMetricRegistry());
return new PersistentSyncHttpClient(JavaClient.createClient(clientOptions),
clientOptions.getMetricRegistry());
}
/**

View file

@ -1,13 +1,10 @@
package com.puppetlabs.http.client;
import com.codahale.metrics.Timer;
import com.puppetlabs.http.client.impl.ClientMetricData;
import com.puppetlabs.http.client.impl.Metrics;
import com.codahale.metrics.MetricRegistry;
import java.io.Closeable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
/**
* This interface represents a synchronous HTTP client with which
@ -17,58 +14,9 @@ import java.util.Map;
public interface SyncHttpClient extends Closeable {
/**
* @return a Map of metric name to Timer instance
* @return the MetricRegistry instance associated with this Client
*/
public Map<String, Timer> getClientMetrics();
/**
* @param url a url to filter on
* @param metricType the type of metric to return timers for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String url, Metrics.MetricType metricType);
/**
* @param url a url to filter on
* @param method an HTTP method to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String url, String method, Metrics.MetricType metricType);
/**
* @param metricId a metric id to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to Timer instance
*/
public Map<String, Timer> getClientMetrics(String[] metricId, Metrics.MetricType metricType);
/**
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData();
/**
* @param url a url to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String url, Metrics.MetricType metricType);
/**
* @param url a url to filter on
* @param method an HTTP method to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String url, String method, Metrics.MetricType metricType);
/**
* @param metricId a metric id to filter on
* @param metricType the type of metric to return data for
* @return a Map of metric name to metric data
*/
public Map<String, ClientMetricData> getClientMetricsData(String[] metricId, Metrics.MetricType metricType);
public MetricRegistry getMetricRegistry();
/**
* Makes a configurable HTTP request

View file

@ -1,16 +1,25 @@
package com.puppetlabs.http.client.impl;
import java.util.ArrayList;
public class ClientMetricData {
private String metricName;
private Long count;
private Long mean;
private Long aggregate;
private String url;
private String method;
private ArrayList<String> metricId;
ClientMetricData(String metricName, Long count, Long mean, Long aggregate) {
ClientMetricData(String metricName, Long count, Long mean, Long aggregate,
String url, String method, ArrayList<String> metricId) {
this.metricName = metricName;
this.count = count;
this.mean = mean;
this.aggregate = aggregate;
this.url = url;
this.method = method;
this.metricId = metricId;
}
public String getMetricName() {
@ -28,5 +37,17 @@ public class ClientMetricData {
public Long getAggregate() {
return aggregate;
}
public String getUrl() {
return url;
}
public String getMethod() {
return method;
}
public ArrayList<String> getMetricId() {
return metricId;
}
}

View file

@ -3,30 +3,59 @@ package com.puppetlabs.http.client.impl;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.Metric;
import java.util.ArrayList;
public class ClientMetricFilter implements MetricFilter{
private String name;
private String nameEnd;
private String category;
private String url;
private String method;
private ArrayList<String> metricId;
private Metrics.MetricType metricType;
public ClientMetricFilter() {
this.name = null;
public ClientMetricFilter(String category, Metrics.MetricType metricType) {
this.category = category;
this.metricType = metricType;
}
public ClientMetricFilter(String name) {
this.name = name;
public ClientMetricFilter(String url, String method, ArrayList<String> metricId,
Metrics.MetricType metricType) {
this.category = null;
this.url = url;
this.method = method;
this.metricId = metricId;
this.metricType = metricType;
}
public ClientMetricFilter(String name, String nameEnd) {
this.name = name;
this.nameEnd = nameEnd;
private boolean isMatch(ClientTimer metric, String url, String method,
ArrayList<String> metricId, Metrics.MetricType metricType) {
if ( metric.getMetricType().equals(metricType) ) {
if ( category != null ) {
switch (category) {
case Metrics.ID_NAMESPACE:
return metric.getMetricId() != null;
case Metrics.URL_METHOD_NAMESPACE:
return metric.getMethod() != null;
case Metrics.URL_NAMESPACE:
return metric.getUrl() != null && metric.getMethod() == null;
}
} else {
if ( method != null ) {
return url.equals(metric.getUrl()) && method.equals(metric.getMethod()) ;
} else if ( url != null ) {
return url.equals(metric.getUrl()) && metric.getMethod() == null;
} else {
return metricId.equals(metric.getMetricId());
}
}
}
return false;
}
public boolean matches(String s, Metric metric) {
if ( name == null ) {
return s.startsWith(Metrics.METRIC_NAMESPACE);
} else if ( nameEnd == null ){
return s.equals(name);
if ( metric instanceof ClientTimer ){
return isMatch((ClientTimer) metric, url, method, metricId, metricType);
} else {
return s.startsWith(name) && s.endsWith(nameEnd);
return false;
}
}
}

View file

@ -0,0 +1,58 @@
package com.puppetlabs.http.client.impl;
import com.codahale.metrics.Timer;
import java.util.ArrayList;
public class ClientTimer extends Timer {
private String metricName;
private String url;
private String method;
private ArrayList<String> metricId;
private Metrics.MetricType metricType;
public ClientTimer(String metricName, String url, Metrics.MetricType metricType) {
super();
this.metricName = metricName;
this.url = url;
this.metricType = metricType;
}
public ClientTimer(String metricName, String url, String method,
Metrics.MetricType metricType) {
super();
this.metricName = metricName;
this.url = url;
this.method = method;
this.metricType = metricType;
}
public ClientTimer(String metricName, ArrayList<String> metricId,
Metrics.MetricType metricType) {
super();
this.metricName = metricName;
this.metricId = metricId;
this.metricType = metricType;
}
public String getMetricName() {
return metricName;
}
public String getUrl() {
return url;
}
public String getMethod() {
return method;
}
public ArrayList<String> getMetricId() {
return metricId;
}
public Metrics.MetricType getMetricType() {
return metricType;
}
}

View file

@ -1,11 +1,11 @@
package com.puppetlabs.http.client.impl;
import com.codahale.metrics.MetricRegistry;
import com.puppetlabs.http.client.ClientOptions;
import com.puppetlabs.http.client.HttpClientException;
import com.puppetlabs.http.client.HttpMethod;
import com.puppetlabs.http.client.RequestOptions;
import com.puppetlabs.http.client.ResponseBodyType;
import com.codahale.metrics.MetricRegistry;
import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
@ -357,7 +357,8 @@ public class JavaClient {
executeWithConsumer(client, futureCallback, request, registry, metricId);
} else {
TimedFutureCallback<HttpResponse> timedFutureCallback =
new TimedFutureCallback<>(futureCallback, Metrics.startBytesReadTimers(registry, request, metricId));
new TimedFutureCallback<>(futureCallback,
Metrics.startBytesReadTimers(registry, request, metricId));
client.execute(request, timedFutureCallback);
}
}

View file

@ -1,8 +1,8 @@
package com.puppetlabs.http.client.impl;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpRequest;
import org.apache.http.RequestLine;
import org.slf4j.Logger;
@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -18,6 +19,7 @@ import java.util.concurrent.TimeUnit;
public class Metrics {
public static final String METRIC_NAMESPACE = "puppetlabs.http-client.experimental";
public static final String URL_NAMESPACE = "with-url";
public static final String URL_METHOD_NAMESPACE = "with-url-and-method";
public static final String ID_NAMESPACE = "with-metric-id";
public static final String BYTES_READ_STRING = "bytes-read";
public enum MetricType { BYTES_READ; }
@ -30,133 +32,181 @@ public class Metrics {
private static final Logger LOGGER = LoggerFactory.getLogger(Metrics.class);
synchronized private static ClientTimer getOrAddTimer(MetricRegistry metricRegistry,
String name, ClientTimer newTimer) {
Metric timer = metricRegistry.getMetrics().get(name);
if ( timer == null ) {
return metricRegistry.register(name, newTimer);
} else if ( ClientTimer.class.isInstance(timer) ) {
return (ClientTimer) timer;
} else {
throw new IllegalArgumentException(name +
" is already used for a different type of metric");
}
}
private static ArrayList<Timer.Context> startBytesReadMetricIdTimers(MetricRegistry registry,
String[] metricId) {
ArrayList<Timer.Context> timers = new ArrayList<>();
ArrayList<Timer.Context> timerContexts = new ArrayList<>();
for (int i = 0; i < metricId.length; i++) {
ArrayList<String> currentId = new ArrayList<>();
currentId.add(ID_NAMESPACE);
for (int j = 0; j <= i; j++) {
currentId.add(metricId[j]);
}
currentId.add(BYTES_READ_STRING);
ArrayList<String> currentIdWithNamespace = new ArrayList<>();
currentIdWithNamespace.add(ID_NAMESPACE);
currentIdWithNamespace.addAll(currentId);
currentIdWithNamespace.add(BYTES_READ_STRING);
String metric_name = MetricRegistry.name(METRIC_NAMESPACE,
currentId.toArray(new String[currentId.size()]));
timers.add(registry.timer(metric_name).time());
currentIdWithNamespace.toArray(new String[currentIdWithNamespace.size()]));
ClientTimer timer = new ClientTimer(metric_name, currentId, MetricType.BYTES_READ);
timerContexts.add(getOrAddTimer(registry, metric_name, timer).time());
}
return timers;
return timerContexts;
}
private static ArrayList<Timer.Context> startBytesReadUrlTimers(MetricRegistry registry,
HttpRequest request) {
ArrayList<Timer.Context> timers = new ArrayList<>();
ArrayList<Timer.Context> timerContexts = new ArrayList<>();
try {
final RequestLine requestLine = request.getRequestLine();
final URI uri = new URI(requestLine.getUri());
// if the port is not specified, `getPort()` returns -1
// if the port is not specified, `getPort()` returns -1
final String port = uri.getPort() == -1 ? "" : ":" + uri.getPort();
final String strippedUrl = uri.getScheme() + "://" + uri.getHost()
+ port + uri.getRawPath();
final String method = requestLine.getMethod();
final String urlName = MetricRegistry.name(METRIC_NAMESPACE, URL_NAMESPACE,
strippedUrl, BYTES_READ_STRING);
final String urlAndMethodName = MetricRegistry.name(METRIC_NAMESPACE, URL_NAMESPACE,
strippedUrl, requestLine.getMethod(), BYTES_READ_STRING);
final String urlAndMethodName = MetricRegistry.name(METRIC_NAMESPACE, URL_METHOD_NAMESPACE,
strippedUrl, method, BYTES_READ_STRING);
timers.add(registry.timer(urlName).time());
timers.add(registry.timer(urlAndMethodName).time());
ClientTimer urlTimer = new ClientTimer(urlName, strippedUrl, MetricType.BYTES_READ);
timerContexts.add(getOrAddTimer(registry, urlName, urlTimer).time());
ClientTimer urlMethodTimer = new ClientTimer(urlAndMethodName, strippedUrl,
method, MetricType.BYTES_READ);
timerContexts.add(getOrAddTimer(registry, urlAndMethodName, urlMethodTimer).time());
} catch (URISyntaxException e) {
// this shouldn't be possible
LOGGER.warn("Could not build URI out of the request URI. Will not create URI timers. " +
"We recommend you read http://www.stilldrinking.com/programming-sucks. " +
"'now all your snowflakes are urine and you can't even find the cat.'");
}
return timers;
return timerContexts;
}
public static ArrayList<Timer.Context> startBytesReadTimers(MetricRegistry registry,
public static ArrayList<Timer.Context> startBytesReadTimers(MetricRegistry clientRegistry,
HttpRequest request,
String[] metricId) {
if (registry != null) {
ArrayList<Timer.Context> urlTimers = startBytesReadUrlTimers(registry, request);
ArrayList<Timer.Context> allTimers = new ArrayList<>(urlTimers);
if (clientRegistry != null) {
ArrayList<Timer.Context> urlTimerContexts = startBytesReadUrlTimers(clientRegistry,request);
ArrayList<Timer.Context> allTimerContexts = new ArrayList<>(urlTimerContexts);
if (metricId != null) {
ArrayList<Timer.Context> metricIdTimers =
startBytesReadMetricIdTimers(registry, metricId);
allTimers.addAll(metricIdTimers);
startBytesReadMetricIdTimers(clientRegistry, metricId);
allTimerContexts.addAll(metricIdTimers);
}
return allTimers;
return allTimerContexts;
}
else {
return null;
}
}
public static Map<String, Timer> getClientMetrics(MetricRegistry metricRegistry){
public static ArrayList<ClientTimer> getClientTimerArray(Map<String, Timer> timers){
ArrayList<ClientTimer> timerArray = new ArrayList<>();
for (Map.Entry<String, Timer> entry : timers.entrySet()) {
ClientTimer timer = (ClientTimer)entry.getValue();
timerArray.add(timer);
}
return timerArray;
}
public static Map<String, ArrayList<ClientTimer>> getClientMetrics(MetricRegistry metricRegistry){
return getClientMetrics(metricRegistry, MetricType.BYTES_READ);
}
public static Map<String, ArrayList<ClientTimer>> getClientMetrics(MetricRegistry metricRegistry,
MetricType metricType){
if (metricRegistry != null) {
return metricRegistry.getTimers(new ClientMetricFilter());
Map<String, ArrayList<ClientTimer>> timers = new HashMap<>();
timers.put("url", getClientTimerArray(metricRegistry.getTimers(
new ClientMetricFilter(URL_NAMESPACE, metricType))));
timers.put("url-and-method", getClientTimerArray(metricRegistry.getTimers(
new ClientMetricFilter(URL_METHOD_NAMESPACE, metricType))));
timers.put("metric-id", getClientTimerArray(metricRegistry.getTimers(
new ClientMetricFilter(ID_NAMESPACE, metricType))));
return timers;
} else {
return null;
}
}
public static Map<String, Timer> getClientMetricsWithUrl(MetricRegistry metricRegistry,
final String url,
final MetricType metricType){
public static ArrayList<ClientTimer> getClientMetricsByUrl(MetricRegistry metricRegistry,
final String url,
final MetricType metricType){
if (metricRegistry != null) {
String metricName = MetricRegistry.name(METRIC_NAMESPACE, URL_NAMESPACE,
url, metricTypeString(metricType));
return metricRegistry.getTimers(new ClientMetricFilter(metricName));
Map<String, Timer> timers = metricRegistry.getTimers(
new ClientMetricFilter(url, null, null, metricType));
return getClientTimerArray(timers);
} else {
return null;
}
}
public static Map<String, Timer> getClientMetricsWithUrlAndMethod(MetricRegistry metricRegistry,
final String url,
final String method,
public static ArrayList<ClientTimer> getClientMetricsByUrlAndMethod(MetricRegistry metricRegistry,
final String url,
final String method,
final MetricType metricType){
if (metricRegistry != null) {
Map<String, Timer> timers = metricRegistry.getTimers(
new ClientMetricFilter(url, method, null, metricType));
return getClientTimerArray(timers);
} else {
return null;
}
}
public static ArrayList<ClientTimer> getClientMetricsByMetricId(MetricRegistry metricRegistry,
final String[] metricId,
final MetricType metricType){
if (metricRegistry != null) {
String metricName = MetricRegistry.name(METRIC_NAMESPACE, URL_NAMESPACE,
url, method, metricTypeString(metricType));
return metricRegistry.getTimers(new ClientMetricFilter(metricName));
} else {
return null;
}
}
public static Map<String, Timer> getClientMetricsWithMetricId(MetricRegistry metricRegistry,
final String[] metricId,
final MetricType metricType){
if (metricRegistry != null) {
if (metricId.length == 0) {
String metricNameStart = MetricRegistry.name(METRIC_NAMESPACE, ID_NAMESPACE);
String metricNameEnd = metricTypeString(metricType);
return metricRegistry.getTimers(new ClientMetricFilter(metricNameStart, metricNameEnd));
Map<String, Timer> timers = metricRegistry.getTimers(
new ClientMetricFilter(ID_NAMESPACE, metricType));
return getClientTimerArray(timers);
} else {
String metricName = MetricRegistry.name(METRIC_NAMESPACE, ID_NAMESPACE,
StringUtils.join(metricId, "."), metricTypeString(metricType));
return metricRegistry.getTimers(new ClientMetricFilter(metricName));
Map<String, Timer> timers = metricRegistry.getTimers(
new ClientMetricFilter(null, null,
new ArrayList<String>(Arrays.asList(metricId)), metricType));
return getClientTimerArray(timers);
}
} else {
return null;
}
}
public static Map<String, ClientMetricData> computeClientMetricsData(Map<String, Timer> timers){
public static ArrayList<ClientMetricData> computeClientMetricsData(ArrayList<ClientTimer> timers){
if (timers != null) {
Map<String, ClientMetricData> metricsData = new HashMap<>();
for (Map.Entry<String, Timer> entry : timers.entrySet()) {
Timer timer = entry.getValue();
String metricName = entry.getKey();
ArrayList<ClientMetricData> metricsData = new ArrayList<>();
for (ClientTimer timer: timers) {
Double mean = timer.getSnapshot().getMean();
Long meanMillis = TimeUnit.NANOSECONDS.toMillis(mean.longValue());
Long count = timer.getCount();
Long aggregate = count * meanMillis;
String metricName = timer.getMetricName();
String url = timer.getUrl();
String method = timer.getMethod();
ArrayList<String> metricId = timer.getMetricId();
ClientMetricData data = new ClientMetricData(metricName, count, meanMillis, aggregate);
metricsData.put(metricName, data);
ClientMetricData data = new ClientMetricData(metricName, count, meanMillis,
aggregate, url, method, metricId);
metricsData.add(data);
}
return metricsData;
} else {
@ -164,30 +214,44 @@ public class Metrics {
}
}
public static Map<String, ClientMetricData> getClientMetricsData(MetricRegistry metricRegistry){
Map<String, Timer> timers = getClientMetrics(metricRegistry);
public static Map<String, ArrayList<ClientMetricData>> getClientMetricsData(MetricRegistry metricRegistry){
return getClientMetricsData(metricRegistry, MetricType.BYTES_READ);
}
public static Map<String, ArrayList<ClientMetricData>> getClientMetricsData(MetricRegistry metricRegistry,
MetricType metricType){
if ( metricRegistry != null ) {
Map<String, ArrayList<ClientTimer>> timers = getClientMetrics(metricRegistry, metricType);
Map<String, ArrayList<ClientMetricData>> data = new HashMap<>();
data.put("url", computeClientMetricsData(timers.get("url")));
data.put("url-and-method", computeClientMetricsData(timers.get("url-and-method")));
data.put("metric-id", computeClientMetricsData(timers.get("metric-id")));
return data;
} else {
return null;
}
}
public static ArrayList<ClientMetricData> getClientMetricsDataByUrl(MetricRegistry metricRegistry,
String url,
MetricType metricType){
ArrayList<ClientTimer> timers = getClientMetricsByUrl(metricRegistry, url, metricType);
return computeClientMetricsData(timers);
}
public static Map<String, ClientMetricData> getClientMetricsDataWithUrl(MetricRegistry metricRegistry,
String url,
MetricType metricType){
Map<String, Timer> timers = getClientMetricsWithUrl(metricRegistry, url, metricType);
return computeClientMetricsData(timers);
}
public static Map<String, ClientMetricData> getClientMetricsDataWithUrlAndMethod(MetricRegistry metricRegistry,
String url,
String method,
MetricType metricType){
Map<String, Timer> timers = getClientMetricsWithUrlAndMethod(metricRegistry, url, method, metricType);
return computeClientMetricsData(timers);
}
public static Map<String, ClientMetricData> getClientMetricsDataWithMetricId(MetricRegistry metricRegistry,
String[] metricId,
public static ArrayList<ClientMetricData> getClientMetricsDataByUrlAndMethod(MetricRegistry metricRegistry,
String url,
String method,
MetricType metricType){
Map<String, Timer> timers = getClientMetricsWithMetricId(metricRegistry, metricId, metricType);
ArrayList<ClientTimer> timers = getClientMetricsByUrlAndMethod(metricRegistry, url,
method, metricType);
return computeClientMetricsData(timers);
}
public static ArrayList<ClientMetricData> getClientMetricsDataByMetricId(MetricRegistry metricRegistry,
String[] metricId,
MetricType metricType){
ArrayList<ClientTimer> timers = getClientMetricsByMetricId(metricRegistry, metricId, metricType);
return computeClientMetricsData(timers);
}
}

View file

@ -1,7 +1,6 @@
package com.puppetlabs.http.client.impl;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.puppetlabs.http.client.Response;
import com.puppetlabs.http.client.RequestOptions;
import com.puppetlabs.http.client.HttpMethod;
@ -11,13 +10,13 @@ import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
public class PersistentAsyncHttpClient implements AsyncHttpClient {
private CloseableHttpAsyncClient client;
private MetricRegistry metricRegistry;
public PersistentAsyncHttpClient(CloseableHttpAsyncClient client, MetricRegistry metricRegistry) {
public PersistentAsyncHttpClient(CloseableHttpAsyncClient client,
MetricRegistry metricRegistry) {
this.client = client;
this.metricRegistry = metricRegistry;
}
@ -26,42 +25,15 @@ public class PersistentAsyncHttpClient implements AsyncHttpClient {
client.close();
}
public Map<String, Timer> getClientMetrics(){
return Metrics.getClientMetrics(metricRegistry);
}
public Map<String, Timer> getClientMetrics(String url, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithUrl(metricRegistry, url, metricType);
}
public Map<String, Timer> getClientMetrics(String url, String method, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithUrlAndMethod(metricRegistry, url, method, metricType);
}
public Map<String, Timer> getClientMetrics(String[] metricId, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithMetricId(metricRegistry, metricId, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(){
return Metrics.getClientMetricsData(metricRegistry);
}
public Map<String, ClientMetricData> getClientMetricsData(String url, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithUrl(metricRegistry, url, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(String url, String method, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithUrlAndMethod(metricRegistry, url, method, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(String[] metricId, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithMetricId(metricRegistry, metricId, metricType);
public MetricRegistry getMetricRegistry() {
return metricRegistry;
}
private Promise<Response> request(RequestOptions requestOptions, HttpMethod method) {
final Promise<Response> promise = new Promise<>();
final JavaResponseDeliveryDelegate responseDelivery = new JavaResponseDeliveryDelegate(promise);
JavaClient.requestWithClient(requestOptions, method, null, client, responseDelivery, metricRegistry);
JavaClient.requestWithClient(requestOptions, method, null,
client, responseDelivery, metricRegistry);
return promise;
}

View file

@ -1,5 +1,6 @@
package com.puppetlabs.http.client.impl;
import com.codahale.metrics.MetricRegistry;
import com.puppetlabs.http.client.HttpClientException;
import com.puppetlabs.http.client.Response;
import com.puppetlabs.http.client.RequestOptions;
@ -8,20 +9,18 @@ import com.puppetlabs.http.client.SyncHttpClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
public class PersistentSyncHttpClient implements SyncHttpClient {
private CloseableHttpAsyncClient client;
private MetricRegistry metricRegistry;
private static final Logger LOGGER = LoggerFactory.getLogger(PersistentSyncHttpClient.class);
public PersistentSyncHttpClient(CloseableHttpAsyncClient client, MetricRegistry metricRegistry) {
public PersistentSyncHttpClient(CloseableHttpAsyncClient client,
MetricRegistry metricRegistry) {
this.client = client;
this.metricRegistry = metricRegistry;
}
@ -31,42 +30,15 @@ public class PersistentSyncHttpClient implements SyncHttpClient {
throw new HttpClientException(msg, t);
}
public Map<String, Timer> getClientMetrics(){
return Metrics.getClientMetrics(metricRegistry);
}
public Map<String, Timer> getClientMetrics(String url, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithUrl(metricRegistry, url, metricType);
}
public Map<String, Timer> getClientMetrics(String url, String method, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithUrlAndMethod(metricRegistry, url, method, metricType);
}
public Map<String, Timer> getClientMetrics(String[] metricId, Metrics.MetricType metricType) {
return Metrics.getClientMetricsWithMetricId(metricRegistry, metricId, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(){
return Metrics.getClientMetricsData(metricRegistry);
}
public Map<String, ClientMetricData> getClientMetricsData(String url, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithUrl(metricRegistry, url, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(String url, String method, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithUrlAndMethod(metricRegistry, url, method, metricType);
}
public Map<String, ClientMetricData> getClientMetricsData(String[] metricId, Metrics.MetricType metricType) {
return Metrics.getClientMetricsDataWithMetricId(metricRegistry, metricId, metricType);
public MetricRegistry getMetricRegistry() {
return metricRegistry;
}
public Response request(RequestOptions requestOptions, HttpMethod method) {
final Promise<Response> promise = new Promise<>();
final JavaResponseDeliveryDelegate responseDelivery = new JavaResponseDeliveryDelegate(promise);
JavaClient.requestWithClient(requestOptions, method, null, client, responseDelivery, metricRegistry);
JavaClient.requestWithClient(requestOptions, method, null, client,
responseDelivery, metricRegistry);
Response response = null;
try {
response = promise.deref();

View file

@ -11,7 +11,8 @@ public final class TimedFutureCallback<T> implements FutureCallback<T> {
private final ArrayList<Timer.Context> timerContexts;
public TimedFutureCallback(FutureCallback<T> delegate, ArrayList<Timer.Context> timerContexts) {
public TimedFutureCallback(FutureCallback<T> delegate,
ArrayList<Timer.Context> timerContexts) {
this.delegate = delegate;
this.timerContexts = timerContexts;
}

View file

@ -13,7 +13,7 @@
(deftest start-bytes-read-timers-test
(testing "startBytesReadTimers creates the right timers"
(let [url-id (add-metric-ns "with-url.http://localhost/foo.bytes-read")
url-method-id (add-metric-ns "with-url.http://localhost/foo.GET.bytes-read")]
url-method-id (add-metric-ns "with-url-and-method.http://localhost/foo.GET.bytes-read")]
(testing "metric id timers are not created for a request without a metric id"
(let [metric-registry (MetricRegistry.)]
(Metrics/startBytesReadTimers metric-registry
@ -38,20 +38,29 @@
(set (keys (.getTimers metric-registry)))))))
(testing "url timers should strip off username, password, query string, and fragment"
(let [metric-registry (MetricRegistry.)]
(Metrics/startBytesReadTimers metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?te%2cst=one")
nil)
(Metrics/startBytesReadTimers metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz#x%2cyz")
nil)
(Metrics/startBytesReadTimers metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?te%2cst=one#x%2cyz")
nil)
(Metrics/startBytesReadTimers metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?#x%2cyz")
nil)
(is (= (set (list (add-metric-ns "with-url.http://localhost:1234/foo%2cbar/baz.bytes-read")
(add-metric-ns "with-url.http://localhost:1234/foo%2cbar/baz.GET.bytes-read")))
(Metrics/startBytesReadTimers
metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?te%2cst=one")
nil)
(Metrics/startBytesReadTimers
metric-registry
(BasicHttpRequest. "GET" "http://user:pwd@localhost:1234/foo%2cbar/baz#x%2cyz")
nil)
(Metrics/startBytesReadTimers
metric-registry
(BasicHttpRequest.
"GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?te%2cst=one#x%2cyz")
nil)
(Metrics/startBytesReadTimers
metric-registry
(BasicHttpRequest.
"GET" "http://user:pwd@localhost:1234/foo%2cbar/baz?#x%2cyz")
nil)
(is (= (set (list
(add-metric-ns
"with-url.http://localhost:1234/foo%2cbar/baz.bytes-read")
(add-metric-ns
"with-url-and-method.http://localhost:1234/foo%2cbar/baz.GET.bytes-read")))
(set (keys (.getTimers metric-registry))))))))))
(defn start-and-stop-timers! [registry req id]
@ -69,106 +78,165 @@
(start-and-stop-timers! registry (BasicHttpRequest. "POST" url) nil)
(start-and-stop-timers! registry (BasicHttpRequest. "POST" url) (into-array ["foo" "bar"]))
(start-and-stop-timers! registry (BasicHttpRequest. "GET" url2) (into-array ["foo" "abc"]))
(testing "getClientMetrics without args returns all timers"
(is (= (set
["puppetlabs.http-client.experimental.with-url.http://test.com/one.bytes-read"
"puppetlabs.http-client.experimental.with-url.http://test.com/one.GET.bytes-read"
"puppetlabs.http-client.experimental.with-url.http://test.com/one.POST.bytes-read"
"puppetlabs.http-client.experimental.with-metric-id.foo.bytes-read"
"puppetlabs.http-client.experimental.with-metric-id.foo.bar.bytes-read"
"puppetlabs.http-client.experimental.with-url.http://test.com/one/two.bytes-read"
"puppetlabs.http-client.experimental.with-url.http://test.com/one/two.GET.bytes-read"
"puppetlabs.http-client.experimental.with-metric-id.foo.abc.bytes-read"])
(testing "getClientMetrics without args returns all timers organized by category"
(is (= (set ["url" "url-and-method" "metric-id"])
(set (keys (Metrics/getClientMetrics registry)))
(set (keys (Metrics/getClientMetricsData registry))))))
(set (keys (Metrics/getClientMetricsData registry)))))
(is (= (set [:url :url-and-method :metric-id])
(set (keys (metrics/get-client-metrics registry)))
(set (keys (metrics/get-client-metrics-data registry)))))
(is (= (set
[(add-metric-ns "with-url.http://test.com/one.bytes-read")
(add-metric-ns "with-url.http://test.com/one/two.bytes-read")])
(set (map #(.getMetricName %) (get (Metrics/getClientMetrics registry) "url")))
(set (map #(.getMetricName %) (:url (metrics/get-client-metrics registry))))
(set (map #(.getMetricName %) (get (Metrics/getClientMetricsData registry) "url")))
(set (map :metric-name (:url (metrics/get-client-metrics-data registry))))))
(is (= (set
[(add-metric-ns "with-url-and-method.http://test.com/one.GET.bytes-read")
(add-metric-ns "with-url-and-method.http://test.com/one.POST.bytes-read")
(add-metric-ns "with-url-and-method.http://test.com/one/two.GET.bytes-read")])
(set (map #(.getMetricName %)
(get (Metrics/getClientMetrics registry) "url-and-method")))
(set (map #(.getMetricName %)
(:url-and-method (metrics/get-client-metrics registry))))
(set (map #(.getMetricName %)
(get (Metrics/getClientMetricsData registry) "url-and-method")))
(set (map :metric-name
(:url-and-method (metrics/get-client-metrics-data registry))))))
(is (= (set ["puppetlabs.http-client.experimental.with-metric-id.foo.bytes-read"
"puppetlabs.http-client.experimental.with-metric-id.foo.bar.bytes-read"
"puppetlabs.http-client.experimental.with-metric-id.foo.abc.bytes-read"])
(set (map #(.getMetricName %)
(get (Metrics/getClientMetrics registry) "metric-id")))
(set (map #(.getMetricName %)
(:metric-id (metrics/get-client-metrics registry))))
(set (map #(.getMetricName %)
(get (Metrics/getClientMetricsData registry) "metric-id")))
(set (map :metric-name
(:metric-id (metrics/get-client-metrics-data registry)))))))
(testing "getClientMetricsData with url returns the right thing"
(let [java-data (Metrics/getClientMetricsDataWithUrl registry url bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:url url :metric-type :bytes-read})]
(let [java-data (Metrics/getClientMetricsDataByUrl registry url bytes-read)
clj-data (metrics/get-client-metrics-data-by-url registry url)]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-url.http://test.com/one.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 3 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataWithUrl registry url2 bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:url url2 :metric-type :bytes-read})]
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 3 (.getCount (first java-data))
(:count (first clj-data)))))
(let [java-data (Metrics/getClientMetricsDataByUrl registry url2 bytes-read)
clj-data (metrics/get-client-metrics-data-by-url registry url2)]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-url.http://test.com/one/two.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 1 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 1 (.getCount (first java-data))
(:count (first clj-data)))))
(testing "getClientMetricsData with url returns nothing if url is not a full match"
(is (= {} (Metrics/getClientMetricsDataWithUrl registry "http://test.com" bytes-read)
(metrics/get-client-metrics-data
registry {:url "http://test.com" :metric-type :bytes-read})))))
(is (= [] (Metrics/getClientMetricsDataByUrl registry "http://test.com" bytes-read)
(metrics/get-client-metrics-data-by-url registry "http://test.com")))))
(testing "getClientMetricsData with url and method returns the right thing"
(let [java-data (Metrics/getClientMetricsDataWithUrlAndMethod registry url "GET" bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:url url :method :get :metric-type :bytes-read})]
(is (= (add-metric-ns "with-url.http://test.com/one.GET.bytes-read")
(first (keys clj-data))
(first (keys java-data))))
(is (= 1 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataWithUrlAndMethod registry url "POST" bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:url url :method :post :metric-type :bytes-read})]
(is (= (add-metric-ns "with-url.http://test.com/one.POST.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 2 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataWithUrlAndMethod registry url2 "GET" bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:url url2 :method :get :metric-type :bytes-read})]
(is (= (add-metric-ns "with-url.http://test.com/one/two.GET.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 1 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataByUrlAndMethod registry url "GET" bytes-read)
clj-data (metrics/get-client-metrics-data-by-url-and-method registry url :get)]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-url-and-method.http://test.com/one.GET.bytes-read")
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 1 (.getCount (first java-data))
(:count (first clj-data)))))
(let [java-data (Metrics/getClientMetricsDataByUrlAndMethod
registry url "POST" bytes-read)
clj-data (metrics/get-client-metrics-data-by-url-and-method
registry url :post)]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-url-and-method.http://test.com/one.POST.bytes-read")
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 2 (.getCount (first java-data))
(:count (first clj-data)))))
(let [java-data (Metrics/getClientMetricsDataByUrlAndMethod
registry url2 "GET" bytes-read)
clj-data (metrics/get-client-metrics-data-by-url-and-method registry url2 :get)]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-url-and-method.http://test.com/one/two.GET.bytes-read")
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 1 (.getCount (first java-data))
(:count (first clj-data)))))
(testing "getClientMetricsData with url and method returns nothing if method is not a match"
(is (= {} (Metrics/getClientMetricsDataWithUrlAndMethod
(is (= [] (Metrics/getClientMetricsDataByUrlAndMethod
registry "http://test.com" "PUT" bytes-read)
(metrics/get-client-metrics-data
registry {:url "http://test.com" :method :put :metric-type :bytes-read})))))
(metrics/get-client-metrics-data-by-url-and-method registry "http://test.com" :put)))))
(testing "getClientMetricsData with metric id returns the right thing"
(let [java-data (Metrics/getClientMetricsDataWithMetricId
(let [java-data (Metrics/getClientMetricsDataByMetricId
registry (into-array ["foo"]) bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:metric-id ["foo"] :metric-type :bytes-read})]
clj-data (metrics/get-client-metrics-data-by-metric-id registry ["foo"])]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-metric-id.foo.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 2 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataWithMetricId
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 2 (.getCount (first java-data))
(:count (first clj-data)))))
(let [java-data (Metrics/getClientMetricsDataByMetricId
registry (into-array ["foo" "bar"]) bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:metric-id ["foo" "bar"] :metric-type :bytes-read})]
clj-data (metrics/get-client-metrics-data-by-metric-id
registry ["foo" "bar"])]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-metric-id.foo.bar.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 1 (.getCount (first (vals java-data)))
(:count (first (vals clj-data))))))
(let [java-data (Metrics/getClientMetricsDataWithMetricId
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 1 (.getCount (first java-data))
(:count (first clj-data)))))
(let [java-data (Metrics/getClientMetricsDataByMetricId
registry (into-array ["foo" "abc"]) bytes-read)
clj-data (metrics/get-client-metrics-data
registry {:metric-id ["foo" "abc"] :metric-type :bytes-read})]
clj-data (metrics/get-client-metrics-data-by-metric-id
registry ["foo" "abc"])]
(is (= 1 (count java-data) (count clj-data)))
(is (= (add-metric-ns "with-metric-id.foo.abc.bytes-read")
(first (keys java-data))
(first (keys clj-data))))
(is (= 1 (.getCount (first (vals java-data)))
(:count (first (vals clj-data)))))
(.getMetricName (first java-data))
(:metric-name (first clj-data))))
(is (= 1 (.getCount (first java-data))
(:count (first clj-data))))
(testing "metric id can be specified as keyword or string"
(is (= clj-data
(metrics/get-client-metrics-data
registry {:metric-id ["foo" :abc] :metric-type :bytes-read})))))
(metrics/get-client-metrics-data-by-metric-id registry ["foo" :abc])))))
(testing "getClientMetricsData with metric id returns nothing if id is not a match"
(is (= {} (Metrics/getClientMetricsDataWithMetricId
(is (= [] (Metrics/getClientMetricsDataByMetricId
registry (into-array ["foo" "cat"]) bytes-read)
(metrics/get-client-metrics-data
registry {:metric-id ["foo" "cat"] :metric-type :bytes-read})))))))
(metrics/get-client-metrics-data-by-metric-id registry ["foo" "cat"]))))
(testing "getClientMetrics|Data returns nil if no metric registry passed in"
(is (= nil (Metrics/getClientMetrics nil) (Metrics/getClientMetricsData nil)))
(is (= nil (metrics/get-client-metrics nil) (metrics/get-client-metrics-data nil))))
(testing (str "getClientMetrics|Data returns map with empty arrays as values"
" if no requests have been made yet")
(is (= {"url" [] "url-and-method" [] "metric-id" []}
(into {} (Metrics/getClientMetrics (MetricRegistry.)))
(into {} (Metrics/getClientMetricsData (MetricRegistry.)))))
(is (= {:url [] :url-and-method [] :metric-id []}
(metrics/get-client-metrics (MetricRegistry.))
(metrics/get-client-metrics-data (MetricRegistry.)))))
(testing "getClientMetrics returns correctly without metric-id on request"
(let [registry (MetricRegistry.)
url "http://test.com/one"]
(start-and-stop-timers! registry (BasicHttpRequest. "GET" url) nil)
(let [client-metrics (Metrics/getClientMetrics registry)
client-metrics-data (Metrics/getClientMetricsData registry)]
(is (= (set ["url" "url-and-method" "metric-id"])
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (= (set [(add-metric-ns
"with-url.http://test.com/one.bytes-read")])
(set (map #(.getMetricName %) (get client-metrics "url")))
(set (map #(.getMetricName %) (get client-metrics-data "url")))))
(is (= (set [(add-metric-ns
"with-url-and-method.http://test.com/one.GET.bytes-read")])
(set (map #(.getMetricName %)
(get client-metrics "url-and-method")))
(set (map #(.getMetricName %)
(get client-metrics-data "url-and-method")))))
(is (= []
(get client-metrics "metric-id")
(get client-metrics-data "metric-id")))))))))
(deftest empty-metric-id-filter-test
(testing "a metric id filter with an empty array returns all metric id timers"
@ -177,22 +245,12 @@
foo-id (add-metric-ns "with-metric-id.foo.bytes-read")
foo-bar-id (add-metric-ns "with-metric-id.foo.bar.bytes-read")
foo-bar-baz-id (add-metric-ns "with-metric-id.foo.bar.baz.bytes-read")]
(start-and-stop-timers! registry (BasicHttpRequest. "GET" url) (into-array ["foo" "bar" "baz"]))
(start-and-stop-timers! registry (BasicHttpRequest. "GET" url)
(into-array ["foo" "bar" "baz"]))
(testing "empty metric filter returns all metric id timers"
(is (= (set (list foo-id foo-bar-id foo-bar-baz-id))
(set (keys (Metrics/getClientMetricsDataWithMetricId registry (into-array String []) bytes-read)))
(set (keys (metrics/get-client-metrics-data registry (metrics/filter-with-metric-id []))))))))))
(deftest metrics-filter-builder-test
(let [metric-registry (MetricRegistry.)
url "http://test.com/foo/bar"]
(start-and-stop-timers! metric-registry (BasicHttpRequest. "GET" url) (into-array ["foo" "bar"]))
(testing "url-filter works"
(is (= (metrics/get-client-metrics-data metric-registry {:url url :metric-type :bytes-read})
(metrics/get-client-metrics-data metric-registry (metrics/filter-with-url url)))))
(testing "url-method-filter works"
(is (= (metrics/get-client-metrics-data metric-registry {:url url :method :get :metric-type :bytes-read})
(metrics/get-client-metrics-data metric-registry (metrics/filter-with-url-and-method url :get)))))
(testing "metric-id-filter works"
(is (= (metrics/get-client-metrics-data metric-registry {:metric-id [:foo :bar] :metric-type :bytes-read})
(metrics/get-client-metrics-data metric-registry (metrics/filter-with-metric-id [:foo :bar])))))))
(set (map #(.getMetricName %)
(Metrics/getClientMetricsDataByMetricId
registry (into-array String []) bytes-read)))
(set (map :metric-name
(metrics/get-client-metrics-data-by-metric-id registry [])))))))))

View file

@ -8,125 +8,156 @@
[puppetlabs.http.client.async :as async]
[puppetlabs.http.client.sync :as sync]
[puppetlabs.http.client.common :as common]
[puppetlabs.trapperkeeper.core :as tk])
(:import (com.puppetlabs.http.client.impl ClientMetricData)
(com.puppetlabs.http.client Async RequestOptions ClientOptions ResponseBodyType Sync)
(com.codahale.metrics Timer MetricRegistry)
[puppetlabs.trapperkeeper.core :as tk]
[puppetlabs.http.client.metrics :as metrics])
(:import (com.puppetlabs.http.client.impl ClientMetricData Metrics ClientTimer)
(com.puppetlabs.http.client Async RequestOptions
ClientOptions ResponseBodyType Sync)
(com.codahale.metrics MetricRegistry)
(java.net SocketTimeoutException)
(java.util.concurrent TimeoutException)))
(def metric-namespace "puppetlabs.http-client.experimental")
(tk/defservice test-metric-web-service
[[:WebserverService add-ring-handler]]
(init [this context]
(add-ring-handler (fn [_] {:status 200 :body "Hello, World!"}) "/hello")
(add-ring-handler (fn [_]
(do
(Thread/sleep 5)
{:status 200 :body "short"}))
"/short")
(add-ring-handler (fn [_]
(do
(Thread/sleep 100)
{:status 200 :body "long"}))
"/long")
context))
(init [this context]
(add-ring-handler
(fn [_] {:status 200 :body "Hello, World!"}) "/hello")
(add-ring-handler (fn [_]
(do
(Thread/sleep 5)
{:status 200 :body "short"}))
"/short")
(add-ring-handler (fn [_]
(do
(Thread/sleep 100)
{:status 200 :body "long"}))
"/long")
context))
(def hello-url "http://localhost:10000/hello")
(def short-url "http://localhost:10000/short")
(def long-url "http://localhost:10000/long")
(def short-name-base "puppetlabs.http-client.experimental.with-url.http://localhost:10000/short")
(def short-name (str short-name-base ".bytes-read"))
(def short-name-with-get (str short-name-base ".GET" ".bytes-read"))
(def short-name-with-post (str short-name-base ".POST" ".bytes-read"))
(def short-name (format "%s.with-url.%s.bytes-read" metric-namespace short-url))
(def short-name-with-get (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace short-url))
(def short-name-with-post (format "%s.with-url-and-method.%s.POST.bytes-read"
metric-namespace short-url))
(def long-name-base "puppetlabs.http-client.experimental.with-url.http://localhost:10000/long")
(def long-name (str long-name-base ".bytes-read"))
(def long-name-with-method (str long-name-base ".GET" ".bytes-read"))
(def long-foo-name "puppetlabs.http-client.experimental.with-metric-id.foo.bytes-read")
(def long-foo-bar-name "puppetlabs.http-client.experimental.with-metric-id.foo.bar.bytes-read")
(def long-foo-bar-baz-name "puppetlabs.http-client.experimental.with-metric-id.foo.bar.baz.bytes-read")
(def long-name (format "%s.with-url.%s.bytes-read" metric-namespace long-url))
(def long-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace long-url))
(def hello-name-base "puppetlabs.http-client.experimental.with-url.http://localhost:10000/hello")
(def hello-name (str hello-name-base ".bytes-read"))
(def hello-name-with-method (str hello-name-base ".GET" ".bytes-read"))
(def long-foo-name
"puppetlabs.http-client.experimental.with-metric-id.foo.bytes-read")
(def long-foo-bar-name
"puppetlabs.http-client.experimental.with-metric-id.foo.bar.bytes-read")
(def long-foo-bar-baz-name
"puppetlabs.http-client.experimental.with-metric-id.foo.bar.baz.bytes-read")
(def hello-name (format "%s.with-url.%s.bytes-read" metric-namespace hello-url))
(def hello-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace hello-url))
(deftest metrics-test-java-async
(testing "metrics work with java async client"
(testlogging/with-test-logging
(testutils/with-app-with-config
app
[jetty9/jetty9-service test-metric-web-service]
{:webserver {:port 10000}}
(let [metric-registry (MetricRegistry.)
hello-request-opts (RequestOptions. hello-url)
short-request-opts (RequestOptions. short-url)
long-request-opts (doto (RequestOptions. long-url)
(.setMetricId (into-array ["foo" "bar" "baz"])))]
(with-open [client (Async/createClient (doto (ClientOptions.)
(.setMetricRegistry metric-registry)))]
(-> client (.get hello-request-opts) (.deref)) ; warm it up
(let [short-response (-> client (.get short-request-opts) (.deref))
long-response (-> client (.get long-request-opts) (.deref))]
(-> client (.post short-request-opts) (.deref))
(is (= 200 (.getStatus short-response)))
(is (= "short" (slurp (.getBody short-response))))
(is (= 200 (.getStatus long-response)))
(is (= "long" (slurp (.getBody long-response))))
(.timer metric-registry "fake")
(let [client-metrics (.getClientMetrics client)
client-metrics-data (.getClientMetricsData client)
all-metrics (.getMetrics metric-registry)]
(testing ".getClientMetrics returns only http client metrics"
(is (= 11 (count all-metrics)))
(is (= 10 (count client-metrics)))
(is (= 10 (count client-metrics-data))))
(testing "get-client-metrics returns a map of metric name to timer instance"
(is (= (set (list hello-name hello-name-with-method short-name short-name-with-get
short-name-with-post long-name long-name-with-method
long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics))))
(testing "get-client-metrics-data returns a map of metric name to metric data"
(let [short-data (get client-metrics-data short-name)
short-data-get (get client-metrics-data short-name-with-get)
short-data-post (get client-metrics-data short-name-with-post)
long-data (get client-metrics-data long-name)]
(is (every? #(instance? ClientMetricData %) (vals client-metrics-data)))
(testlogging/with-test-logging
(testutils/with-app-with-config
app
[jetty9/jetty9-service test-metric-web-service]
{:webserver {:port 10000}}
(let [metric-registry (MetricRegistry.)
hello-request-opts (RequestOptions. hello-url)
short-request-opts (RequestOptions. short-url)
long-request-opts (doto (RequestOptions. long-url)
(.setMetricId (into-array ["foo" "bar" "baz"])))]
(with-open [client (Async/createClient (doto (ClientOptions.)
(.setMetricRegistry metric-registry)))]
(-> client (.get hello-request-opts) (.deref)) ; warm it up
(let [short-response (-> client (.get short-request-opts) (.deref))
long-response (-> client (.get long-request-opts) (.deref))]
(-> client (.post short-request-opts) (.deref))
(is (= 200 (.getStatus short-response)))
(is (= "short" (slurp (.getBody short-response))))
(is (= 200 (.getStatus long-response)))
(is (= "long" (slurp (.getBody long-response))))
(.timer metric-registry "fake")
(let [client-metric-registry (.getMetricRegistry client)
client-metrics (Metrics/getClientMetrics client-metric-registry)
client-metrics-data (Metrics/getClientMetricsData client-metric-registry)
url-metrics (get client-metrics "url")
url-and-method-metrics (get client-metrics "url-and-method")
metric-id-metrics (get client-metrics "metric-id")
url-metrics-data (get client-metrics-data "url")
url-and-method-metrics-data (get client-metrics-data "url-and-method")
metric-id-metrics-data (get client-metrics-data "metric-id")
all-metrics (.getMetrics metric-registry)]
(testing ".getMetricRegistry returns the associated MetricRegistry"
(is (instance? MetricRegistry client-metric-registry)))
(testing "Metrics/getClientMetrics returns only http client metrics"
(is (= 11 (count all-metrics)))
(is (= 10 (+ (count url-metrics)
(count url-and-method-metrics)
(count metric-id-metrics))))
(is (= 10 (+ (count url-metrics-data)
(count url-and-method-metrics-data)
(count metric-id-metrics-data)))))
(testing ".getClientMetrics returns a map of category to array of timers"
(is (= (set (list hello-name short-name long-name))
(set (map #(.getMetricName %) url-metrics))
(set (map #(.getMetricName %) url-metrics-data))))
(is (= (set (list hello-name-with-method short-name-with-get
short-name-with-post long-name-with-method))
(set (map #(.getMetricName %) url-and-method-metrics))
(set (map #(.getMetricName %) url-and-method-metrics-data))))
(is (= (set (list long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (map #(.getMetricName %) metric-id-metrics))
(set (map #(.getMetricName %) metric-id-metrics-data))))
(is (every? #(instance? ClientTimer %) url-metrics))
(is (every? #(instance? ClientTimer %) url-and-method-metrics))
(is (every? #(instance? ClientTimer %) metric-id-metrics)))
(testing ".getClientMetricsData returns a map of metric category to arrays of metric data"
(let [short-data (first (filter #(= short-name (.getMetricName %)) url-metrics-data))
short-data-get (first (filter #(= short-name-with-get (.getMetricName %))
url-and-method-metrics-data))
short-data-post (first (filter #(= short-name-with-post (.getMetricName %))
url-and-method-metrics-data))
long-data (first (filter #(= long-name (.getMetricName %)) url-metrics-data))]
(is (every? #(instance? ClientMetricData %)
(concat url-metrics-data
url-and-method-metrics-data
metric-id-metrics-data)))
(is (= short-name (.getMetricName short-data)))
(is (= 2 (.getCount short-data)))
(is (<= 5 (.getMean short-data)))
(is (<= 10 (.getAggregate short-data)))
(is (= short-name (.getMetricName short-data)))
(is (= 2 (.getCount short-data)))
(is (<= 5 (.getMean short-data)))
(is (<= 10 (.getAggregate short-data)))
(is (= short-name-with-get (.getMetricName short-data-get)))
(is (= 1 (.getCount short-data-get)))
(is (<= 5 (.getMean short-data-get)))
(is (<= 5 (.getAggregate short-data-get)))
(is (= short-name-with-get (.getMetricName short-data-get)))
(is (= 1 (.getCount short-data-get)))
(is (<= 5 (.getMean short-data-get)))
(is (<= 5 (.getAggregate short-data-get)))
(is (= short-name-with-post (.getMetricName short-data-post)))
(is (= 1 (.getCount short-data-post)))
(is (<= 5 (.getMean short-data-post)))
(is (<= 5 (.getAggregate short-data-post)))
(is (= short-name-with-post (.getMetricName short-data-post)))
(is (= 1 (.getCount short-data-post)))
(is (<= 5 (.getMean short-data-post)))
(is (<= 5 (.getAggregate short-data-post)))
(is (>= 1 (Math/abs (- (.getAggregate short-data)
(+ (.getAggregate short-data-get)
(.getAggregate short-data-post))))))
(is (>= 1 (Math/abs (- (.getAggregate short-data)
(+ (.getAggregate short-data-get)
(.getAggregate short-data-post))))))
(is (= long-name (.getMetricName long-data)))
(is (= 1 (.getCount long-data)))
(is (<= 100 (.getMean long-data)))
(is (<= 100 (.getAggregate long-data)))
(is (= long-name (.getMetricName long-data)))
(is (= 1 (.getCount long-data)))
(is (<= 100 (.getMean long-data)))
(is (<= 100 (.getAggregate long-data)))
(is (> (.getAggregate long-data) (.getAggregate short-data))))))))
(with-open [client (Async/createClient (ClientOptions.))]
(testing ".getClientMetrics returns nil if no metrics registry passed in"
(let [response (-> client (.get hello-request-opts) (.deref))]
(is (= 200 (.getStatus response)))
(is (= "Hello, World!" (slurp (.getBody response))))
(is (= nil (.getClientMetrics client)))
(is (= nil (.getClientMetricsData client)))))))))))
(is (> (.getAggregate long-data) (.getAggregate short-data))))))))
(with-open [client (Async/createClient (ClientOptions.))]
(testing ".getMetricRegistry returns nil if no metric registry passed in"
(is (= nil (.getMetricRegistry client))))))))))
(deftest metrics-test-clojure-async
(testing "metrics work with clojure async client"
@ -136,7 +167,8 @@
[jetty9/jetty9-service test-metric-web-service]
{:webserver {:port 10000}}
(let [metric-registry (MetricRegistry.)]
(with-open [client (async/create-client {:metric-registry metric-registry})]
(with-open [client (async/create-client
{:metric-registry metric-registry})]
@(common/get client hello-url) ; warm it up
(let [short-response @(common/get client short-url {:as :text :metric-id ["foo" "bar" "baz"]})
long-response @(common/get client long-url)]
@ -145,25 +177,47 @@
(is (= 200 (:status long-response)))
(is (= "long" (slurp (:body long-response))))
(.timer metric-registry "fake")
(let [client-metrics (common/get-client-metrics client)
client-metrics-data (common/get-client-metrics-data client)
(let [client-metric-registry (common/get-client-metric-registry client)
client-metrics (metrics/get-client-metrics client-metric-registry)
client-metrics-data (metrics/get-client-metrics-data client-metric-registry)
url-metrics (:url client-metrics)
url-and-method-metrics (:url-and-method client-metrics)
metric-id-metrics (:metric-id client-metrics)
url-metrics-data (:url client-metrics-data)
url-and-method-metrics-data (:url-and-method client-metrics-data)
metric-id-metrics-data (:metric-id client-metrics-data)
all-metrics (.getMetrics metric-registry)]
(testing "get-client-metric-registry returns the associated MetricRegistry"
(is (instance? MetricRegistry client-metric-registry)))
(testing "get-client-metrics and get-client-metrics data return only http client metrics"
(is (= 11 (count all-metrics)))
(is (= 10 (count client-metrics)))
(is (= 10 (count client-metrics-data))))
(testing "get-client-metrics returns a map of metric name to timer instance"
(is (= (set (list hello-name hello-name-with-method short-name short-name-with-get
short-name-with-post long-name long-name-with-method
long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics))))
(testing "get-client-metrics-data returns a map of metric name to metrics data"
(let [short-data (get client-metrics-data short-name)
short-data-get (get client-metrics-data short-name-with-get)
short-data-post (get client-metrics-data short-name-with-post)
long-data (get client-metrics-data long-name)]
(is (= 10 (+ (count url-metrics)
(count url-and-method-metrics)
(count metric-id-metrics))))
(is (= 10 (+ (count url-metrics-data)
(count url-and-method-metrics-data)
(count metric-id-metrics-data)))))
(testing "get-client-metrics returns a map of category to array of timers"
(is (= (set (list hello-name short-name long-name))
(set (map #(.getMetricName %) url-metrics))
(set (map :metric-name url-metrics-data))))
(is (= (set (list hello-name-with-method short-name-with-get
short-name-with-post long-name-with-method))
(set (map #(.getMetricName %) url-and-method-metrics))
(set (map :metric-name url-and-method-metrics-data))))
(is (= (set (list long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (map #(.getMetricName %) metric-id-metrics))
(set (map :metric-name metric-id-metrics-data))))
(is (every? #(instance? ClientTimer %) url-metrics))
(is (every? #(instance? ClientTimer %) url-and-method-metrics))
(is (every? #(instance? ClientTimer %) metric-id-metrics)))
(testing "get-client-metrics-data returns a map of metric category to metric data"
(let [short-data (first (filter #(= short-name (:metric-name %)) url-metrics-data))
short-data-get (first (filter #(= short-name-with-get (:metric-name %))
url-and-method-metrics-data))
short-data-post (first (filter #(= short-name-with-post (:metric-name %))
url-and-method-metrics-data))
long-data (first (filter #(= long-name (:metric-name %)) url-metrics-data))]
(is (= short-name (:metric-name short-data)))
(is (= 2 (:count short-data)))
(is (<= 5 (:mean short-data)))
@ -190,12 +244,8 @@
(is (> (:mean long-data) (:mean short-data)))))))))
(with-open [client (async/create-client {})]
(testing "get-client-metrics returns nil if no metrics registry passed in"
(let [response (common/get client hello-url)]
(is (= 200 (:status @response)))
(is (= "Hello, World!" (slurp (:body @response))))
(is (= nil (common/get-client-metrics client)))
(is (= nil (common/get-client-metrics-data client))))))))))
(testing "get-client-metric-registry returns nil if no metric registry passed in"
(is (= nil (common/get-client-metric-registry client)))))))))
(deftest metrics-test-java-sync
(testing "metrics work with java sync client"
@ -220,26 +270,52 @@
(is (= 200 (.getStatus long-response)))
(is (= "long" (slurp (.getBody long-response))))
(.timer metric-registry "fake")
(let [client-metrics (.getClientMetrics client)
client-metrics-data (.getClientMetricsData client)
(let [client-metric-registry (.getMetricRegistry client)
client-metrics (Metrics/getClientMetrics client-metric-registry)
client-metrics-data (Metrics/getClientMetricsData client-metric-registry)
url-metrics (get client-metrics "url")
url-and-method-metrics (get client-metrics "url-and-method")
metric-id-metrics (get client-metrics "metric-id")
url-metrics-data (get client-metrics-data "url")
url-and-method-metrics-data (get client-metrics-data "url-and-method")
metric-id-metrics-data (get client-metrics-data "metric-id")
all-metrics (.getMetrics metric-registry)]
(testing ".getClientMetrics returns only http client metrics"
(testing ".getMetricRegistry returns the associated MetricRegistry"
(is (instance? MetricRegistry client-metric-registry)))
(testing "Metrics/getClientMetrics returns only http client metrics"
(is (= 11 (count all-metrics)))
(is (= 10 (count client-metrics)))
(is (= 10 (count client-metrics-data))))
(testing ".getClientMetrics returns a map of metric name to timer instance"
(is (= (set (list hello-name hello-name-with-method short-name short-name-with-get
short-name-with-post long-name long-name-with-method
long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics))))
(testing ".getClientMetricsData returns a map of metric name to metric data"
(let [short-data (get client-metrics-data short-name)
short-data-get (get client-metrics-data short-name-with-get)
short-data-post (get client-metrics-data short-name-with-post)
long-data (get client-metrics-data long-name)]
(is (every? #(instance? ClientMetricData %) (vals client-metrics-data)))
(is (= 10 (+ (count url-metrics)
(count url-and-method-metrics)
(count metric-id-metrics))))
(is (= 10 (+ (count url-metrics-data)
(count url-and-method-metrics-data)
(count metric-id-metrics-data)))))
(testing ".getClientMetrics returns a map of category to array of timers"
(is (= (set (list hello-name short-name long-name))
(set (map #(.getMetricName %) url-metrics))
(set (map #(.getMetricName %) url-metrics-data))))
(is (= (set (list hello-name-with-method short-name-with-get
short-name-with-post long-name-with-method))
(set (map #(.getMetricName %) url-and-method-metrics))
(set (map #(.getMetricName %) url-and-method-metrics-data))))
(is (= (set (list long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (map #(.getMetricName %) metric-id-metrics))
(set (map #(.getMetricName %) metric-id-metrics-data))))
(is (every? #(instance? ClientTimer %) url-metrics))
(is (every? #(instance? ClientTimer %) url-and-method-metrics))
(is (every? #(instance? ClientTimer %) metric-id-metrics)))
(testing ".getClientMetricsData returns a map of metric category to arrays of metric data"
(let [short-data (first (filter #(= short-name (.getMetricName %)) url-metrics-data))
short-data-get (first (filter #(= short-name-with-get (.getMetricName %))
url-and-method-metrics-data))
short-data-post (first (filter #(= short-name-with-post (.getMetricName %))
url-and-method-metrics-data))
long-data (first (filter #(= long-name (.getMetricName %)) url-metrics-data))]
(is (every? #(instance? ClientMetricData %)
(concat url-metrics-data
url-and-method-metrics-data
metric-id-metrics-data)))
(is (= short-name (.getMetricName short-data)))
(is (= 2 (.getCount short-data)))
@ -267,12 +343,8 @@
(is (> (.getMean long-data) (.getMean short-data))))))))
(with-open [client (Sync/createClient (ClientOptions.))]
(testing ".getClientMetrics returns nil if no metrics registry passed in"
(let [response (.get client hello-request-opts)]
(is (= 200 (.getStatus response)))
(is (= "Hello, World!" (slurp (.getBody response))))
(is (= nil (.getClientMetrics client)))
(is (= nil (.getClientMetricsData client)))))))))))
(testing ".getMetricRegistry returns nil if no metric registry passed in"
(is (= nil (.getMetricRegistry client))))))))))
(deftest metrics-test-clojure-sync
(testing "metrics work with clojure sync client"
@ -290,25 +362,47 @@
(is (= {:status 200 :body "short"} (select-keys short-response [:status :body])))
(is (= {:status 200 :body "long"} (select-keys long-response [:status :body])))
(.timer metric-registry "fake")
(let [client-metrics (common/get-client-metrics client)
client-metrics-data (common/get-client-metrics-data client)
(let [client-metric-registry (common/get-client-metric-registry client)
client-metrics (metrics/get-client-metrics client-metric-registry)
client-metrics-data (metrics/get-client-metrics-data client-metric-registry)
url-metrics (:url client-metrics)
url-and-method-metrics (:url-and-method client-metrics)
metric-id-metrics (:metric-id client-metrics)
url-metrics-data (:url client-metrics-data)
url-and-method-metrics-data (:url-and-method client-metrics-data)
metric-id-metrics-data (:metric-id client-metrics-data)
all-metrics (.getMetrics metric-registry)]
(testing "get-client-metric-registry returns the associated MetricRegistry"
(is (instance? MetricRegistry client-metric-registry)))
(testing "get-client-metrics and get-client-metrics data return only http client metrics"
(is (= 11 (count all-metrics)))
(is (= 10 (count client-metrics)))
(is (= 10 (count client-metrics-data))))
(testing "get-client-metrics returns a map of metric name to timer instance"
(is (= (set (list hello-name hello-name-with-method short-name short-name-with-get
short-name-with-post long-name long-name-with-method
long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics))))
(testing "get-client-metrics-data returns a map of metric name to metrics data"
(let [short-data (get client-metrics-data short-name)
short-data-get (get client-metrics-data short-name-with-get)
short-data-post (get client-metrics-data short-name-with-post)
long-data (get client-metrics-data long-name)]
(is (= 10 (+ (count url-metrics)
(count url-and-method-metrics)
(count metric-id-metrics))))
(is (= 10 (+ (count url-metrics-data)
(count url-and-method-metrics-data)
(count metric-id-metrics-data)))))
(testing "get-client-metrics returns a map of category to array of timers"
(is (= (set (list hello-name short-name long-name))
(set (map #(.getMetricName %) url-metrics))
(set (map :metric-name url-metrics-data))))
(is (= (set (list hello-name-with-method short-name-with-get
short-name-with-post long-name-with-method))
(set (map #(.getMetricName %) url-and-method-metrics))
(set (map :metric-name url-and-method-metrics-data))))
(is (= (set (list long-foo-name long-foo-bar-name long-foo-bar-baz-name))
(set (map #(.getMetricName %) metric-id-metrics))
(set (map :metric-name metric-id-metrics-data))))
(is (every? #(instance? ClientTimer %) url-metrics))
(is (every? #(instance? ClientTimer %) url-and-method-metrics))
(is (every? #(instance? ClientTimer %) metric-id-metrics)))
(testing "get-client-metrics-data returns a map of metric category to metric data"
(let [short-data (first (filter #(= short-name (:metric-name %)) url-metrics-data))
short-data-get (first (filter #(= short-name-with-get (:metric-name %))
url-and-method-metrics-data))
short-data-post (first (filter #(= short-name-with-post (:metric-name %))
url-and-method-metrics-data))
long-data (first (filter #(= long-name (:metric-name %)) url-metrics-data))]
(is (= short-name (:metric-name short-data)))
(is (= 2 (:count short-data)))
(is (<= 5 (:mean short-data)))
@ -335,12 +429,8 @@
(is (> (:mean long-data) (:mean short-data))))))))
(with-open [client (sync/create-client {})]
(testing "get-client-metrics returns nil if no metrics registry passed in"
(let [response (common/get client hello-url)]
(is (= 200 (:status response)))
(is (= "Hello, World!" (slurp (:body response))))
(is (= nil (common/get-client-metrics client)))
(is (= nil (common/get-client-metrics-data client)))))))))))
(testing "get-client-metric-registry returns nil if no metric registry passed in"
(is (= nil (common/get-client-metric-registry client))))))))))
(deftest java-metrics-for-unbuffered-streaming-test
(testlogging/with-test-logging
@ -354,7 +444,8 @@
(.setConnectTimeoutMilliseconds 100)
(.setMetricRegistry metric-registry)
(Async/createClient))]
(let [request-options (doto (RequestOptions. (str "http://localhost:" port "/hello"))
(let [url (str "http://localhost:" port "/hello")
request-options (doto (RequestOptions. url)
(.setAs ResponseBodyType/UNBUFFERED_STREAM))
response (-> client (.get request-options) .deref)
status (.getStatus response)
@ -366,17 +457,26 @@
(is (= "xxxx" (String. buf "UTF-8"))) ;; Make sure we can read a few chars off of the stream
(Thread/sleep 1000) ;; check that the bytes-read metric takes this into account
(is (= (str data "yyyy") (str "xxxx" (slurp instream))))) ;; Read the rest and validate
(let [client-metrics (.getClientMetrics client)
client-metrics-data (.getClientMetricsData client)
base-metric-name (str "puppetlabs.http-client.experimental.with-url.http://localhost:" port "/hello")
bytes-read-name (str base-metric-name ".bytes-read")
bytes-read-name-with-method (str base-metric-name ".GET" ".bytes-read")]
(is (= (set (list bytes-read-name bytes-read-name-with-method))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics)))
(let [bytes-read-data (get client-metrics-data bytes-read-name)]
(is (every? #(instance? ClientMetricData %) (vals client-metrics-data)))
(let [client-metric-registry (.getMetricRegistry client)
client-metrics (Metrics/getClientMetrics client-metric-registry)
client-metrics-data (Metrics/getClientMetricsData client-metric-registry)
bytes-read-name (format "%s.with-url.%s.bytes-read" metric-namespace url)
bytes-read-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace url)]
(is (= [bytes-read-name]
(map #(.getMetricName %) (get client-metrics "url"))
(map #(.getMetricName %) (get client-metrics-data "url"))))
(is (= [bytes-read-name-with-method]
(map #(.getMetricName %) (get client-metrics "url-and-method"))
(map #(.getMetricName %) (get client-metrics-data "url-and-method"))))
(is (= [] (get client-metrics "metric-id") (get client-metrics-data "metric-id")))
(is (every? #(instance? ClientTimer %)
(concat (get client-metrics "url")
(get client-metrics "url-and-method"))))
(let [bytes-read-data (first (get client-metrics-data "url"))]
(is (every? #(instance? ClientMetricData %)
(concat (get client-metrics-data "url")
(get client-metrics-data "url-and-method"))))
(is (= 1 (.getCount bytes-read-data)))
(is (= bytes-read-name (.getMetricName bytes-read-data)))
@ -392,24 +492,35 @@
(.setConnectTimeoutMilliseconds 100)
(.setMetricRegistry metric-registry)
(Async/createClient))]
(let [request-options (doto (RequestOptions. (str "http://localhost:" port "/hello"))
(let [url (str "http://localhost:" port "/hello")
request-options (doto (RequestOptions. url)
(.setAs ResponseBodyType/UNBUFFERED_STREAM))
response (-> client (.get request-options) .deref)
error (.getError response)
body (.getBody response)]
(is (nil? error))
(is (thrown? SocketTimeoutException (slurp body)))
(let [client-metrics (.getClientMetrics client)
client-metrics-data (.getClientMetricsData client)
base-metric-name (str "puppetlabs.http-client.experimental.with-url.http://localhost:" port "/hello")
bytes-read-name (str base-metric-name ".bytes-read")
bytes-read-name-with-method (str base-metric-name ".GET" ".bytes-read")]
(is (= (set (list bytes-read-name bytes-read-name-with-method))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics)))
(let [bytes-read-data (get client-metrics-data bytes-read-name)]
(is (every? #(instance? ClientMetricData %) (vals client-metrics-data)))
(let [client-metric-registry (.getMetricRegistry client)
client-metrics (Metrics/getClientMetrics client-metric-registry)
client-metrics-data (Metrics/getClientMetricsData client-metric-registry)
bytes-read-name (format "%s.with-url.%s.bytes-read" metric-namespace url)
bytes-read-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace url)]
(is (= [bytes-read-name]
(map #(.getMetricName %) (get client-metrics "url"))
(map #(.getMetricName %) (get client-metrics-data "url"))))
(is (= [bytes-read-name-with-method]
(map #(.getMetricName %) (get client-metrics "url-and-method"))
(map #(.getMetricName %) (get client-metrics-data "url-and-method"))))
(is (= [] (get client-metrics "metric-id")
(get client-metrics-data "metric-id")))
(is (every? #(instance? ClientTimer %)
(concat (get client-metrics "url")
(get client-metrics "url-and-method"))))
(let [bytes-read-data (first (get client-metrics-data "url"))]
(is (every? #(instance? ClientMetricData %)
(concat (get client-metrics-data "url")
(get client-metrics-data "url-and-method"))))
(is (= 1 (.getCount bytes-read-data)))
(is (= bytes-read-name (.getMetricName bytes-read-data)))
@ -430,7 +541,8 @@
(with-open [client (async/create-client {:connect-timeout-milliseconds 100
:socket-timeout-milliseconds 20000
:metric-registry metric-registry})]
(let [response @(common/get client (str "http://localhost:" port "/hello") opts)
(let [url (str "http://localhost:" port "/hello")
response @(common/get client url opts)
{:keys [status body]} response]
(is (= 200 status))
(let [instream body
@ -439,16 +551,23 @@
(is (= "xxxx" (String. buf "UTF-8"))) ;; Make sure we can read a few chars off of the stream
(Thread/sleep 1000) ;; check that the bytes-read metric takes this into account
(is (= (str data "yyyy") (str "xxxx" (slurp instream))))) ;; Read the rest and validate
(let [client-metrics (common/get-client-metrics client)
client-metrics-data (common/get-client-metrics-data client)
base-metric-name (str "puppetlabs.http-client.experimental.with-url.http://localhost:" port "/hello")
bytes-read-name (str base-metric-name ".bytes-read")
bytes-read-name-with-method (str base-metric-name ".GET" ".bytes-read")]
(is (= (set (list bytes-read-name bytes-read-name-with-method))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics)))
(let [bytes-read-data (get client-metrics-data bytes-read-name)]
(let [client-metric-registry (common/get-client-metric-registry client)
client-metrics (metrics/get-client-metrics client-metric-registry)
client-metrics-data (metrics/get-client-metrics-data client-metric-registry)
bytes-read-name (format "%s.with-url.%s.bytes-read" metric-namespace url)
bytes-read-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace url)]
(is (= [bytes-read-name]
(map #(.getMetricName %) (:url client-metrics))
(map :metric-name (:url client-metrics-data))))
(is (= [bytes-read-name-with-method]
(map #(.getMetricName %) (:url-and-method client-metrics))
(map :metric-name (:url-and-method client-metrics-data))))
(is (= [] (:metric-id client-metrics) (:metric-id client-metrics-data)))
(is (every? #(instance? ClientTimer %)
(concat (:url client-metrics)
(:url-and-method client-metrics))))
(let [bytes-read-data (first (:url client-metrics-data))]
(is (= {:count 1 :metric-name bytes-read-name}
(select-keys bytes-read-data [:metric-name :count])))
(is (<= 1000 (:mean bytes-read-data)))
@ -457,25 +576,33 @@
(try
(testwebserver/with-test-webserver-and-config
(unbuffered-test/blocking-handler data) port {:shutdown-timeout-seconds 1}
(let [metric-registry (MetricRegistry.)]
(let [metric-registry (MetricRegistry.)
url (str "http://localhost:" port "/hello")]
(with-open [client (async/create-client {:connect-timeout-milliseconds 100
:socket-timeout-milliseconds 200
:metric-registry metric-registry})]
(let [response @(common/get client (str "http://localhost:" port "/hello") opts)
(let [response @(common/get client url opts)
{:keys [body error]} response]
(is (nil? error))
;; Consume the body to get the exception
(is (thrown? SocketTimeoutException (slurp body))))
(let [client-metrics (common/get-client-metrics client)
client-metrics-data (common/get-client-metrics-data client)
base-metric-name (str "puppetlabs.http-client.experimental.with-url.http://localhost:" port "/hello")
bytes-read-name (str base-metric-name ".bytes-read")
bytes-read-name-with-method (str base-metric-name ".GET" ".bytes-read")]
(is (= (set (list bytes-read-name bytes-read-name-with-method))
(set (keys client-metrics))
(set (keys client-metrics-data))))
(is (every? #(instance? Timer %) (vals client-metrics)))
(let [bytes-read-data (get client-metrics-data bytes-read-name)]
(let [client-metric-registry (common/get-client-metric-registry client)
client-metrics (metrics/get-client-metrics client-metric-registry)
client-metrics-data (metrics/get-client-metrics-data client-metric-registry)
bytes-read-name (format "%s.with-url.%s.bytes-read" metric-namespace url)
bytes-read-name-with-method (format "%s.with-url-and-method.%s.GET.bytes-read"
metric-namespace url)]
(is (= [bytes-read-name]
(map #(.getMetricName %) (:url client-metrics))
(map :metric-name (:url client-metrics-data))))
(is (= [bytes-read-name-with-method]
(map #(.getMetricName %) (:url-and-method client-metrics))
(map :metric-name (:url-and-method client-metrics-data))))
(is (= [] (:metric-id client-metrics) (:metric-id client-metrics-data)))
(is (every? #(instance? ClientTimer %)
(concat (:url client-metrics)
(:url-and-method client-metrics))))
(let [bytes-read-data (first (:url client-metrics-data))]
(is (= {:count 1 :metric-name bytes-read-name}
(select-keys bytes-read-data [:metric-name :count])))
(is (<= 200 (:mean bytes-read-data)))