From 62e92d23adaa2fa2c5a207ebf1fec661fea0791b Mon Sep 17 00:00:00 2001 From: Eric Wittmann Date: Fri, 11 Mar 2016 13:40:12 -0500 Subject: [PATCH] added a first version of hawkular metrics support - only basic metrics are created, further improvements need to be made! --- common/net/.gitignore | 1 + common/net/pom.xml | 52 +++ .../net/hawkular/HawkularMetricsClient.java | 356 ++++++++++++++++++ .../hawkular/beans/BucketDataPointBean.java | 156 ++++++++ .../net/hawkular/beans/BucketSizeType.java | 42 +++ .../net/hawkular/beans/DataPointLongBean.java | 73 ++++ .../common/net/hawkular/beans/MetricBean.java | 92 +++++ .../net/hawkular/beans/MetricLongBean.java | 90 +++++ .../common/net/hawkular/beans/MetricType.java | 26 ++ .../common/net/hawkular/beans/TenantBean.java | 54 +++ .../errors/HawkularMetricsException.java | 40 ++ .../errors/InvalidTypeParameterException.java | 32 ++ .../errors/UnexpectedMetricsException.java | 39 ++ common/pom.xml | 1 + .../engine/es/PollCachingESRegistry.java | 3 +- gateway/engine/hawkular/.gitignore | 1 + gateway/engine/hawkular/pom.xml | 31 ++ .../engine/hawkular/HawkularMetrics.java | 170 +++++++++ .../engine/jdbc/PollCachingJdbcRegistry.java | 3 +- gateway/engine/pom.xml | 1 + gateway/platforms/war/micro/pom.xml | 4 + gateway/platforms/war/pom.xml | 4 + gateway/test/pom.xml | 4 + .../core/metrics/AbstractMetricsAccessor.java | 182 +++++++++ .../manager/api/es/ESMetricsAccessor.java | 121 +----- manager/api/hawkular/.gitignore | 1 + manager/api/hawkular/pom.xml | 69 ++++ .../api/hawkular/HawkularMetricsAccessor.java | 229 +++++++++++ .../src/main/resources/META-INF/beans.xml | 0 manager/api/micro/pom.xml | 4 + manager/api/pom.xml | 1 + manager/api/war/pom.xml | 4 + manager/test/api/pom.xml | 4 + .../test/es/ESMetricsAccessorTest.java | 13 +- pom.xml | 15 + 35 files changed, 1789 insertions(+), 129 deletions(-) create mode 100644 common/net/.gitignore create mode 100644 common/net/pom.xml create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/HawkularMetricsClient.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketDataPointBean.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketSizeType.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/DataPointLongBean.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricBean.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricLongBean.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricType.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/beans/TenantBean.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/errors/HawkularMetricsException.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/errors/InvalidTypeParameterException.java create mode 100644 common/net/src/main/java/io/apiman/common/net/hawkular/errors/UnexpectedMetricsException.java create mode 100644 gateway/engine/hawkular/.gitignore create mode 100644 gateway/engine/hawkular/pom.xml create mode 100644 gateway/engine/hawkular/src/main/java/io/apiman/gateway/engine/hawkular/HawkularMetrics.java create mode 100644 manager/api/core/src/main/java/io/apiman/manager/api/core/metrics/AbstractMetricsAccessor.java create mode 100644 manager/api/hawkular/.gitignore create mode 100644 manager/api/hawkular/pom.xml create mode 100644 manager/api/hawkular/src/main/java/io/apiman/manager/api/hawkular/HawkularMetricsAccessor.java create mode 100644 manager/api/hawkular/src/main/resources/META-INF/beans.xml diff --git a/common/net/.gitignore b/common/net/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/common/net/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/common/net/pom.xml b/common/net/pom.xml new file mode 100644 index 0000000000..69ac2cc2c8 --- /dev/null +++ b/common/net/pom.xml @@ -0,0 +1,52 @@ + + 4.0.0 + + io.apiman + apiman-common + 1.2.3-SNAPSHOT + + apiman-common-net + bundle + apiman-common-net + + + + + ${project.groupId} + apiman-common-config + + + + + commons-codec + commons-codec + + + commons-lang + commons-lang + + + commons-io + commons-io + + + com.squareup.okhttp + okhttp + + + com.fasterxml.jackson.core + jackson-databind + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/HawkularMetricsClient.java b/common/net/src/main/java/io/apiman/common/net/hawkular/HawkularMetricsClient.java new file mode 100644 index 0000000000..80aeff01c8 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/HawkularMetricsClient.java @@ -0,0 +1,356 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular; + +import io.apiman.common.config.options.HttpConnectorOptions; +import io.apiman.common.net.hawkular.beans.BucketDataPointBean; +import io.apiman.common.net.hawkular.beans.BucketSizeType; +import io.apiman.common.net.hawkular.beans.DataPointLongBean; +import io.apiman.common.net.hawkular.beans.MetricBean; +import io.apiman.common.net.hawkular.beans.MetricLongBean; +import io.apiman.common.net.hawkular.beans.TenantBean; +import io.apiman.common.net.hawkular.errors.HawkularMetricsException; +import io.apiman.common.net.hawkular.errors.UnexpectedMetricsException; + +import java.io.IOException; +import java.net.CookieHandler; +import java.net.MalformedURLException; +import java.net.ProxySelector; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.net.SocketFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.squareup.okhttp.CertificatePinner; +import com.squareup.okhttp.ConnectionPool; +import com.squareup.okhttp.ConnectionSpec; +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Protocol; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.internal.Internal; +import com.squareup.okhttp.internal.Network; +import com.squareup.okhttp.internal.Util; +import com.squareup.okhttp.internal.http.AuthenticatorAdapter; + +/** + * A REST client to the Hawkular Metrics server. For more information about the + * Hawkular Metrics REST API, see: http://www.hawkular.org/docs/rest/rest-metrics.html + * @author eric.wittmann@gmail.com + */ +public class HawkularMetricsClient { + + private static final ObjectMapper mapper = new ObjectMapper(); + private static URL toURL(String url) { + try { + if (!url.endsWith("/")) { //$NON-NLS-1$ + url += "/"; //$NON-NLS-1$ + } + return new URL(url); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + private static RequestBody toBody(Object bean) { + try { + RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(bean)); + return body; + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); //$NON-NLS-1$ + + private static final int DEFAULT_READ_TIMEOUT = 10; + private static final int DEFAULT_WRITE_TIMEOUT = 10; + private static final int DEFAULT_CONNECT_TIMEOUT = 10; + private static final List DEFAULT_CONNECTION_SPECS = Util.immutableList( + ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT); + + private OkHttpClient httpClient; + private URL serverUrl; + + /** + * Constructor. + * @param metricsServer + */ + public HawkularMetricsClient(String metricsServer) { + this(toURL(metricsServer)); + } + + /** + * Constructor. + * @param metricsServer + * @param options + */ + public HawkularMetricsClient(String metricsServer, HttpConnectorOptions options) { + this(toURL(metricsServer), options); + } + + /** + * Constructor. + * @param metricsServer + */ + public HawkularMetricsClient(URL metricsServer) { + this.serverUrl = metricsServer; + httpClient = new OkHttpClient(); + httpClient.setReadTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS); + httpClient.setWriteTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS); + httpClient.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS); + httpClient.setFollowRedirects(true); + httpClient.setFollowSslRedirects(true); + httpClient.setProxySelector(ProxySelector.getDefault()); + httpClient.setCookieHandler(CookieHandler.getDefault()); + httpClient.setCertificatePinner(CertificatePinner.DEFAULT); + httpClient.setAuthenticator(AuthenticatorAdapter.INSTANCE); + httpClient.setConnectionPool(ConnectionPool.getDefault()); + httpClient.setProtocols(Util.immutableList(Protocol.HTTP_1_1)); + httpClient.setConnectionSpecs(DEFAULT_CONNECTION_SPECS); + httpClient.setSocketFactory(SocketFactory.getDefault()); + Internal.instance.setNetwork(httpClient, Network.DEFAULT); + } + + /** + * Constructor. + * @param metricsServer + * @param options + */ + public HawkularMetricsClient(URL metricsServer, HttpConnectorOptions options) { + this(metricsServer); + httpClient.setReadTimeout(options.getReadTimeout(), TimeUnit.SECONDS); + httpClient.setWriteTimeout(options.getWriteTimeout(), TimeUnit.SECONDS); + httpClient.setConnectTimeout(options.getConnectTimeout(), TimeUnit.SECONDS); + httpClient.setFollowRedirects(options.isFollowRedirects()); + httpClient.setFollowSslRedirects(options.isFollowRedirects()); + } + + /** + * Creates a new tenant. + * @param tenantId + */ + public void createTenant(String tenantId) { + TenantBean tenant = new TenantBean(tenantId); + try { + URL endpoint = serverUrl.toURI().resolve("tenants").toURL(); //$NON-NLS-1$ + Request request = new Request.Builder() + .url(endpoint) + .post(toBody(tenant)) + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Get a list of all counter metrics for a given tenant. + * @param tenantId + */ + public List listCounterMetrics(String tenantId) { + try { + URL endpoint = serverUrl.toURI().resolve("counters").toURL(); //$NON-NLS-1$ + Request request = new Request.Builder() + .url(endpoint) + .header("Accept", "application/json") //$NON-NLS-1$ //$NON-NLS-2$ + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + String responseBody = response.body().string(); + return mapper.reader(new TypeReference>() {}).readValue(responseBody); + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Adds a single data point to the given counter. + * @param tenantId + * @param counterId + * @param timestamp + * @param value + */ + public void addCounterDataPoint(String tenantId, String counterId, Date timestamp, long value) { + List dataPoints = new ArrayList<>(); + dataPoints.add(new DataPointLongBean(timestamp, value)); + addCounterDataPoints(tenantId, counterId, dataPoints); + } + + /** + * Adds multiple data points to a counter. + * @param tenantId + * @param counterId + * @param dataPoints + */ + public void addCounterDataPoints(String tenantId, String counterId, List dataPoints) { + try { + URL endpoint = serverUrl.toURI().resolve("counters/" + counterId + "/data").toURL(); //$NON-NLS-1$ //$NON-NLS-2$ + Request request = new Request.Builder() + .url(endpoint) + .post(toBody(dataPoints)) + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Adds one or more data points for multiple counters all at once! + * @param tenantId + * @param data + */ + public void addMultipleCounterDataPoints(String tenantId, List data) { + try { + URL endpoint = serverUrl.toURI().resolve("counters/data").toURL(); //$NON-NLS-1$ + Request request = new Request.Builder() + .url(endpoint) + .post(toBody(data)) + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets a list of buckets containing aggregate information about data in the + * indicated counter. The number of buckets is determined by the bucket size + * and date/time range specified. + * @param tenantId + * @param counterId + * @param from + * @param to + * @param bucketSize + */ + @SuppressWarnings("nls") + public List getCounterData(String tenantId, String counterId, Date from, Date to, BucketSizeType bucketSize) { + try { + StringBuilder params = new StringBuilder(); + params.append("?") + .append("start=") + .append(from.getTime()) + .append("&end=") + .append(to.getTime()) + .append("&bucketDuration=") + .append(bucketSize.getValue()); + URL endpoint = serverUrl.toURI().resolve("counters/" + counterId + "/data" + params.toString()).toURL(); //$NON-NLS-1$ + Request request = new Request.Builder() + .url(endpoint) + .header("Accept", "application/json") //$NON-NLS-1$ //$NON-NLS-2$ + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + String responseBody = response.body().string(); + return mapper.reader(new TypeReference>() {}).readValue(responseBody); + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("nls") + public List getCounterData(String tenantId, String counterId, Date from, Date to, int numBuckets) { + try { + StringBuilder params = new StringBuilder(); + params.append("?") + .append("start=") + .append(from.getTime()) + .append("&end=") + .append(to.getTime()) + .append("&buckets=") + .append(numBuckets); + URL endpoint = serverUrl.toURI().resolve("counters/" + counterId + "/data" + params.toString()).toURL(); //$NON-NLS-1$ + Request request = new Request.Builder() + .url(endpoint) + .header("Accept", "application/json") //$NON-NLS-1$ //$NON-NLS-2$ + .header("Hawkular-Tenant", tenantId) //$NON-NLS-1$ + .build(); + Response response = httpClient.newCall(request).execute(); + if (response.code() >= 400) { + throw hawkularMetricsError(response); + } + String responseBody = response.body().string(); + return mapper.reader(new TypeReference>() {}).readValue(responseBody); + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * @param response + */ + private static HawkularMetricsException hawkularMetricsError(Response response) { + // TODO better error handling goes here. + return new UnexpectedMetricsException(response.message()); + } + + + + @SuppressWarnings("nls") + public static void main(String[] args) throws Exception { + HawkularMetricsClient client = new HawkularMetricsClient("http://bluejay:8080/hawkular/metrics"); //$NON-NLS-1$ + List metrics = client.listCounterMetrics("XYZ"); //$NON-NLS-1$ + for (MetricBean metric : metrics) { + System.out.println("-------------"); //$NON-NLS-1$ + System.out.println(mapper.writer().writeValueAsString(metric)); + } + + client.addCounterDataPoint("FOO", "counter-1", new Date(), 1); + client.addCounterDataPoint("FOO", "counter-1", new Date(), 1); + client.addCounterDataPoint("FOO", "counter-2", new Date(), 1); + client.addCounterDataPoint("FOO", "counter-2", new Date(), 1); + client.addCounterDataPoint("FOO", "counter-2", new Date(), 1); + client.addCounterDataPoint("FOO", "counter-2", new Date(), 1); + + long fiveMinsAgo = System.currentTimeMillis() - 3 * 60 * 1000; + long now = System.currentTimeMillis(); + Date from = new Date(fiveMinsAgo); + Date to = new Date(now); + List counterData = client.getCounterData("FOO", "counter-2", from, to, BucketSizeType.Minute); + System.out.println("+++++++++++++"); //$NON-NLS-1$ + System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(counterData)); + System.out.println("+++++++++++++"); //$NON-NLS-1$ + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketDataPointBean.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketDataPointBean.java new file mode 100644 index 0000000000..064f2bc9aa --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketDataPointBean.java @@ -0,0 +1,156 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author eric.wittmann@gmail.com + */ +@JsonIgnoreProperties(ignoreUnknown=true) +public class BucketDataPointBean { + + private Date start; + private Date end; + private long samples; + private double min; + private double avg; + private double median; + private double max; + private boolean empty; + + /** + * Constructor. + */ + public BucketDataPointBean() { + } + + /** + * @return the start + */ + public Date getStart() { + return start; + } + + /** + * @param start the start to set + */ + public void setStart(Date start) { + this.start = start; + } + + /** + * @return the end + */ + public Date getEnd() { + return end; + } + + /** + * @param end the end to set + */ + public void setEnd(Date end) { + this.end = end; + } + + /** + * @return the samples + */ + public long getSamples() { + return samples; + } + + /** + * @param samples the samples to set + */ + public void setSamples(long samples) { + this.samples = samples; + } + + /** + * @return the min + */ + public double getMin() { + return min; + } + + /** + * @param min the min to set + */ + public void setMin(double min) { + this.min = min; + } + + /** + * @return the avg + */ + public double getAvg() { + return avg; + } + + /** + * @param avg the avg to set + */ + public void setAvg(double avg) { + this.avg = avg; + } + + /** + * @return the median + */ + public double getMedian() { + return median; + } + + /** + * @param median the median to set + */ + public void setMedian(double median) { + this.median = median; + } + + /** + * @return the max + */ + public double getMax() { + return max; + } + + /** + * @param max the max to set + */ + public void setMax(double max) { + this.max = max; + } + + /** + * @return the empty + */ + public boolean isEmpty() { + return empty; + } + + /** + * @param empty the empty to set + */ + public void setEmpty(boolean empty) { + this.empty = empty; + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketSizeType.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketSizeType.java new file mode 100644 index 0000000000..4680f6d632 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/BucketSizeType.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +/** + * @author eric.wittmann@gmail.com + */ +@SuppressWarnings("nls") +public enum BucketSizeType { + + Second("1s"), Minute("1mn"), Hour("1h"), Day("1d"), Week("7d"), Month("30d"); + private final String value; + + /** + * Constructor. + */ + private BucketSizeType(String value) { + this.value = value; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/DataPointLongBean.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/DataPointLongBean.java new file mode 100644 index 0000000000..42e553eea7 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/DataPointLongBean.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +import java.util.Date; + +/** + * @author eric.wittmann@gmail.com + */ +public class DataPointLongBean { + + private Date timestamp; + private long value; + + /** + * Constructor. + */ + public DataPointLongBean() { + } + + /** + * Constructor. + * @param timestamp + * @param value + */ + public DataPointLongBean(Date timestamp, long value) { + setTimestamp(timestamp); + setValue(value); + } + + /** + * @return the timestamp + */ + public Date getTimestamp() { + return timestamp; + } + + /** + * @param timestamp the timestamp to set + */ + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } + + /** + * @return the value + */ + public long getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(long value) { + this.value = value; + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricBean.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricBean.java new file mode 100644 index 0000000000..ca011055e9 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricBean.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +/** + * @author eric.wittmann@gmail.com + */ +public class MetricBean { + + private String id; + private int dataRetention; + private MetricType type; + private String tenantId; + + /** + * Constructor. + */ + public MetricBean() { + + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the dataRetention + */ + public int getDataRetention() { + return dataRetention; + } + + /** + * @param dataRetention the dataRetention to set + */ + public void setDataRetention(int dataRetention) { + this.dataRetention = dataRetention; + } + + /** + * @return the type + */ + public MetricType getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(MetricType type) { + this.type = type; + } + + /** + * @return the tenantId + */ + public String getTenantId() { + return tenantId; + } + + /** + * @param tenantId the tenantId to set + */ + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricLongBean.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricLongBean.java new file mode 100644 index 0000000000..2189d41675 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricLongBean.java @@ -0,0 +1,90 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author eric.wittmann@gmail.com + */ +public class MetricLongBean { + + private String id; + private List dataPoints = new ArrayList<>(); + private MetricType type = MetricType.counter; + + /** + * Constructor. + */ + public MetricLongBean() { + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the dataPoints + */ + public List getDataPoints() { + return dataPoints; + } + + /** + * @param dataPoints the dataPoints to set + */ + public void setDataPoints(List dataPoints) { + this.dataPoints = dataPoints; + } + + /** + * @return the type + */ + public MetricType getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(MetricType type) { + this.type = type; + } + + /** + * Adds a single data point to the metric. + * @param timestamp + * @param value + */ + public void addDataPoint(Date timestamp, long value) { + DataPointLongBean point = new DataPointLongBean(timestamp, value); + dataPoints.add(point); + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricType.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricType.java new file mode 100644 index 0000000000..2170faa5ed --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/MetricType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +/** + * @author eric.wittmann@gmail.com + */ +public enum MetricType { + + gauge, counter, availability; + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/beans/TenantBean.java b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/TenantBean.java new file mode 100644 index 0000000000..fe203d9391 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/beans/TenantBean.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.beans; + +/** + * @author eric.wittmann@gmail.com + */ +public class TenantBean { + + private String id; + + /** + * Constructor. + */ + public TenantBean() { + } + + /** + * Constructor. + * @param id + */ + public TenantBean(String id) { + setId(id); + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/errors/HawkularMetricsException.java b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/HawkularMetricsException.java new file mode 100644 index 0000000000..1878966aa1 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/HawkularMetricsException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.errors; + +/** + * @author eric.wittmann@gmail.com + */ +public class HawkularMetricsException extends RuntimeException { + + private static final long serialVersionUID = 2698656081524383049L; + + /** + * Constructor. + */ + public HawkularMetricsException() { + } + + /** + * Constructor. + * @param message + */ + public HawkularMetricsException(String message) { + super(message); + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/errors/InvalidTypeParameterException.java b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/InvalidTypeParameterException.java new file mode 100644 index 0000000000..85c43586c2 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/InvalidTypeParameterException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.errors; + +/** + * @author eric.wittmann@gmail.com + */ +public class InvalidTypeParameterException extends HawkularMetricsException { + + private static final long serialVersionUID = 9102966234315825287L; + + /** + * Constructor. + */ + public InvalidTypeParameterException() { + } + +} diff --git a/common/net/src/main/java/io/apiman/common/net/hawkular/errors/UnexpectedMetricsException.java b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/UnexpectedMetricsException.java new file mode 100644 index 0000000000..ec0a1a0c33 --- /dev/null +++ b/common/net/src/main/java/io/apiman/common/net/hawkular/errors/UnexpectedMetricsException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.common.net.hawkular.errors; + +/** + * @author eric.wittmann@gmail.com + */ +public class UnexpectedMetricsException extends HawkularMetricsException { + + private static final long serialVersionUID = 5426394351607391460L; + + /** + * Constructor. + */ + public UnexpectedMetricsException() { + } + + /** + * Constructor. + * @param message + */ + public UnexpectedMetricsException(String message) { + super(message); + } +} diff --git a/common/pom.xml b/common/pom.xml index b6659ae0f0..2bf82e685a 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -14,6 +14,7 @@ auth config + net plugin servlet util diff --git a/gateway/engine/es/src/main/java/io/apiman/gateway/engine/es/PollCachingESRegistry.java b/gateway/engine/es/src/main/java/io/apiman/gateway/engine/es/PollCachingESRegistry.java index 5101c1a575..88d624b8a6 100644 --- a/gateway/engine/es/src/main/java/io/apiman/gateway/engine/es/PollCachingESRegistry.java +++ b/gateway/engine/es/src/main/java/io/apiman/gateway/engine/es/PollCachingESRegistry.java @@ -180,9 +180,8 @@ public void run() { checkCacheVersion(); } } - }); + }, "ESRegistryCacheInvalidator"); //$NON-NLS-1$ thread.setDaemon(true); - thread.setName(getClass().getSimpleName()); thread.start(); } diff --git a/gateway/engine/hawkular/.gitignore b/gateway/engine/hawkular/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/gateway/engine/hawkular/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/gateway/engine/hawkular/pom.xml b/gateway/engine/hawkular/pom.xml new file mode 100644 index 0000000000..105182cd29 --- /dev/null +++ b/gateway/engine/hawkular/pom.xml @@ -0,0 +1,31 @@ + + 4.0.0 + + io.apiman + apiman-gateway-engine + 1.2.3-SNAPSHOT + + apiman-gateway-engine-hawkular + apiman-gateway-engine-hawkular + + + + + ${project.groupId} + apiman-common-util + + + ${project.groupId} + apiman-common-net + + + ${project.groupId} + apiman-gateway-engine-beans + + + ${project.groupId} + apiman-gateway-engine-core + + + diff --git a/gateway/engine/hawkular/src/main/java/io/apiman/gateway/engine/hawkular/HawkularMetrics.java b/gateway/engine/hawkular/src/main/java/io/apiman/gateway/engine/hawkular/HawkularMetrics.java new file mode 100644 index 0000000000..d211c2fd1b --- /dev/null +++ b/gateway/engine/hawkular/src/main/java/io/apiman/gateway/engine/hawkular/HawkularMetrics.java @@ -0,0 +1,170 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.gateway.engine.hawkular; + +import io.apiman.common.config.options.HttpConnectorOptions; +import io.apiman.common.net.hawkular.HawkularMetricsClient; +import io.apiman.common.net.hawkular.beans.MetricLongBean; +import io.apiman.common.net.hawkular.beans.MetricType; +import io.apiman.gateway.engine.IComponentRegistry; +import io.apiman.gateway.engine.IMetrics; +import io.apiman.gateway.engine.metrics.RequestMetric; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; + +/** + * An implementation of the apiman {@link IMetrics} interface that pushes metrics + * data to a Hawkular Metrics server. For more information about Hawkular Metrics, + * see: http://www.hawkular.org/docs/components/metrics/index.html + * + * @author eric.wittmann@gmail.com + */ +public class HawkularMetrics implements IMetrics { + + private static final int DEFAULT_QUEUE_SIZE = 10000; + + private final HawkularMetricsClient client; + private final BlockingQueue queue; + + /** + * Constructor. + * @param config + */ + @SuppressWarnings("nls") + public HawkularMetrics(Map config) { + String endpoint = config.get("hawkular.endpoint"); + if (endpoint == null) { + throw new RuntimeException("Missing configuration property: apiman-gateway.metrics.hawkular.endpoint"); + } + Map httpOptions = new HashMap<>(); + httpOptions.put("http.timeouts.read", config.get("http.timeouts.read")); + httpOptions.put("http.timeouts.write", config.get("http.timeouts.write")); + httpOptions.put("http.timeouts.connect", config.get("http.timeouts.connect")); + httpOptions.put("http.followRedirects", config.get("http.followRedirects")); + client = new HawkularMetricsClient(endpoint, new HttpConnectorOptions(httpOptions)); + + int queueSize = DEFAULT_QUEUE_SIZE; + String queueSizeConfig = config.get("hawkular.queueSize"); + if (queueSizeConfig != null) { + queueSize = new Integer(queueSizeConfig); + } + queue = new LinkedBlockingDeque<>(queueSize); + startConsumerThread(); + } + + /** + * Starts a thread which will serially pull information off the blocking + * queue and submit that information to hawkular metrics. + */ + private void startConsumerThread() { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + while (Boolean.TRUE) { + processQueue(); + } + } + }, "HawkularMetricsConsumer"); //$NON-NLS-1$ + thread.setDaemon(true); + thread.start(); + } + + /** + * Process the next item in the queue. + */ + protected void processQueue() { + try { + QueueItem item = queue.take(); + client.addMultipleCounterDataPoints(item.tenantId, item.data); + } catch (InterruptedException e) { + // TODO better logging of this unlikely error + e.printStackTrace(); + return; + } + } + + /** + * @see io.apiman.gateway.engine.IMetrics#record(io.apiman.gateway.engine.metrics.RequestMetric) + */ + @Override + public void record(RequestMetric metric) { + // Record data points (potentially) for the following metrics: + // 1) # of total requests (always) + // 2) # of failures (only when a failure) + // 3) # of errors (only when an error) + String tenantId = metric.getApiOrgId(); + List data = new ArrayList<>(); + + // # of total requests + MetricLongBean totalRequests = new MetricLongBean(); + totalRequests.addDataPoint(metric.getRequestStart(), 1); + totalRequests.setId("apis." + metric.getApiId() + "." + metric.getApiVersion()); //$NON-NLS-1$ //$NON-NLS-2$ + totalRequests.setType(MetricType.counter); + data.add(totalRequests); + + // # of failures + if (metric.isFailure()) { + MetricLongBean failedRequests = new MetricLongBean(); + failedRequests.addDataPoint(metric.getRequestStart(), 1); + failedRequests.setId("apis." + metric.getApiId() + "." + metric.getApiVersion() + ".Failed"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + failedRequests.setType(MetricType.counter); + data.add(failedRequests); + } + + // # of errors + if (metric.isError()) { + MetricLongBean erroredRequests = new MetricLongBean(); + erroredRequests.addDataPoint(metric.getRequestStart(), 1); + erroredRequests.setId("apis." + metric.getApiId() + "." + metric.getApiVersion() + ".Errored"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + erroredRequests.setType(MetricType.counter); + data.add(erroredRequests); + } + + try { + queue.put(new QueueItem(tenantId, data)); + } catch (InterruptedException e) { + // TODO better logging of this unlikely error + e.printStackTrace(); + } + } + + /** + * @see io.apiman.gateway.engine.IMetrics#setComponentRegistry(io.apiman.gateway.engine.IComponentRegistry) + */ + @Override + public void setComponentRegistry(IComponentRegistry registry) { + } + + + private static class QueueItem { + public String tenantId; + public List data; + + /** + * Constructor. + */ + public QueueItem(String tenantId, List data) { + this.tenantId = tenantId; + this.data = data; + } + } +} diff --git a/gateway/engine/jdbc/src/main/java/io/apiman/gateway/engine/jdbc/PollCachingJdbcRegistry.java b/gateway/engine/jdbc/src/main/java/io/apiman/gateway/engine/jdbc/PollCachingJdbcRegistry.java index c1bcd5c320..419decc16f 100644 --- a/gateway/engine/jdbc/src/main/java/io/apiman/gateway/engine/jdbc/PollCachingJdbcRegistry.java +++ b/gateway/engine/jdbc/src/main/java/io/apiman/gateway/engine/jdbc/PollCachingJdbcRegistry.java @@ -182,9 +182,8 @@ public void run() { checkCacheVersion(); } } - }); + }, "JdbcRegistryCacheInvalidator"); //$NON-NLS-1$ thread.setDaemon(true); - thread.setName(getClass().getSimpleName()); thread.start(); } diff --git a/gateway/engine/pom.xml b/gateway/engine/pom.xml index 696ab5395d..b328133467 100644 --- a/gateway/engine/pom.xml +++ b/gateway/engine/pom.xml @@ -14,6 +14,7 @@ beans core es + hawkular influxdb ispn jdbc diff --git a/gateway/platforms/war/micro/pom.xml b/gateway/platforms/war/micro/pom.xml index 885c61df0f..0f121573e6 100644 --- a/gateway/platforms/war/micro/pom.xml +++ b/gateway/platforms/war/micro/pom.xml @@ -48,6 +48,10 @@ ${project.groupId} apiman-gateway-engine-es + + ${project.groupId} + apiman-gateway-engine-hawkular + ${project.groupId} apiman-gateway-engine-jdbc diff --git a/gateway/platforms/war/pom.xml b/gateway/platforms/war/pom.xml index 1029e881f9..1b83dad189 100644 --- a/gateway/platforms/war/pom.xml +++ b/gateway/platforms/war/pom.xml @@ -31,6 +31,10 @@ ${project.groupId} apiman-gateway-engine-es + + ${project.groupId} + apiman-gateway-engine-hawkular + ${project.groupId} apiman-gateway-engine-jdbc diff --git a/gateway/test/pom.xml b/gateway/test/pom.xml index 058359ee12..901bf86ec8 100644 --- a/gateway/test/pom.xml +++ b/gateway/test/pom.xml @@ -35,6 +35,10 @@ ${project.groupId} apiman-gateway-engine-es + + ${project.groupId} + apiman-gateway-engine-hawkular + ${project.groupId} apiman-gateway-engine-jdbc diff --git a/manager/api/core/src/main/java/io/apiman/manager/api/core/metrics/AbstractMetricsAccessor.java b/manager/api/core/src/main/java/io/apiman/manager/api/core/metrics/AbstractMetricsAccessor.java new file mode 100644 index 0000000000..af8f8a4775 --- /dev/null +++ b/manager/api/core/src/main/java/io/apiman/manager/api/core/metrics/AbstractMetricsAccessor.java @@ -0,0 +1,182 @@ +/* + * Copyright 2016 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.apiman.manager.api.core.metrics; + +import io.apiman.manager.api.beans.metrics.HistogramBean; +import io.apiman.manager.api.beans.metrics.HistogramDataPoint; +import io.apiman.manager.api.beans.metrics.HistogramIntervalType; +import io.apiman.manager.api.core.IMetricsAccessor; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.time.DateFormatUtils; +import org.joda.time.DateTime; +import org.joda.time.DateTimeConstants; +import org.joda.time.format.ISODateTimeFormat; + +/** + * Optional base class for metrics implementations. + * @author eric.wittmann@gmail.com + */ +public abstract class AbstractMetricsAccessor implements IMetricsAccessor { + + /** + * Based on the given interval, create a "floor" value relative to the + * given date. This basically means zero'ing out certain fields (different + * fields based on the interval type) and returning the modified date. + * @param date + * @param interval + */ + protected static DateTime floor(DateTime date, HistogramIntervalType interval) { + DateTime rval = date.withMillisOfSecond(0); + + switch (interval) { + case day: + rval = rval.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0); + break; + case hour: + rval = rval.withMinuteOfHour(0).withSecondOfMinute(0); + break; + case minute: + rval = rval.withSecondOfMinute(0); + break; + case month: + rval = rval.withDayOfMonth(1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0); + break; + case week: + rval = rval.withDayOfWeek(DateTimeConstants.MONDAY).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0); + break; + } + + return rval; + } + + /** + * @param date + */ + protected static String formatDate(DateTime date) { + return ISODateTimeFormat.dateTimeNoMillis().print(date); + } + + /** + * @param date + */ + protected static String formatDateWithMillis(DateTime date) { + return ISODateTimeFormat.dateTime().print(date); + } + + /** + * @param date + */ + protected static String formatDate(Calendar date) { + return DateFormatUtils.formatUTC(date.getTimeInMillis(), "yyyy-MM-dd'T'HH:mm:ss'Z'"); //$NON-NLS-1$ + } + + /** + * @param date + */ + protected static String formatDateWithMillis(Calendar date) { + return DateFormatUtils.formatUTC(date.getTimeInMillis(), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); //$NON-NLS-1$ + } + + /** + * Generate the histogram buckets based on the time frame requested and the interval. This will + * add an entry for each 'slot' or 'bucket' in the histogram, setting the count to 0. + * @param rval + * @param from + * @param to + * @param interval + */ + public static Map generateHistogramSkeleton(HistogramBean rval, DateTime from, DateTime to, + HistogramIntervalType interval, Class dataType) { + Map index = new HashMap<>(); + + Calendar fromCal = from.toGregorianCalendar(); + Calendar toCal = to.toGregorianCalendar(); + + switch(interval) { + case day: + fromCal.set(Calendar.HOUR_OF_DAY, 0); + fromCal.set(Calendar.MINUTE, 0); + fromCal.set(Calendar.SECOND, 0); + fromCal.set(Calendar.MILLISECOND, 0); + break; + case hour: + fromCal.set(Calendar.MINUTE, 0); + fromCal.set(Calendar.SECOND, 0); + fromCal.set(Calendar.MILLISECOND, 0); + break; + case minute: + fromCal.set(Calendar.SECOND, 0); + fromCal.set(Calendar.MILLISECOND, 0); + break; + case month: + fromCal.set(Calendar.DAY_OF_MONTH, 1); + fromCal.set(Calendar.HOUR_OF_DAY, 0); + fromCal.set(Calendar.MINUTE, 0); + fromCal.set(Calendar.SECOND, 0); + fromCal.set(Calendar.MILLISECOND, 0); + break; + case week: + fromCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); + fromCal.set(Calendar.HOUR_OF_DAY, 0); + fromCal.set(Calendar.MINUTE, 0); + fromCal.set(Calendar.SECOND, 0); + fromCal.set(Calendar.MILLISECOND, 0); + break; + default: + break; + } + + while (fromCal.before(toCal)) { + String label = formatDateWithMillis(fromCal); + T point; + try { + point = dataType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + point.setLabel(label); + rval.addDataPoint(point); + index.put(label, point); + switch (interval) { + case day: + fromCal.add(Calendar.DAY_OF_YEAR, 1); + break; + case hour: + fromCal.add(Calendar.HOUR_OF_DAY, 1); + break; + case minute: + fromCal.add(Calendar.MINUTE, 1); + break; + case month: + fromCal.add(Calendar.MONTH, 1); + break; + case week: + fromCal.add(Calendar.WEEK_OF_YEAR, 1); + break; + default: + break; + } + } + + return index; + + } +} diff --git a/manager/api/es/src/main/java/io/apiman/manager/api/es/ESMetricsAccessor.java b/manager/api/es/src/main/java/io/apiman/manager/api/es/ESMetricsAccessor.java index 86936af47b..4306df72ab 100644 --- a/manager/api/es/src/main/java/io/apiman/manager/api/es/ESMetricsAccessor.java +++ b/manager/api/es/src/main/java/io/apiman/manager/api/es/ESMetricsAccessor.java @@ -16,8 +16,6 @@ package io.apiman.manager.api.es; import io.apiman.manager.api.beans.metrics.ClientUsagePerApiBean; -import io.apiman.manager.api.beans.metrics.HistogramBean; -import io.apiman.manager.api.beans.metrics.HistogramDataPoint; import io.apiman.manager.api.beans.metrics.HistogramIntervalType; import io.apiman.manager.api.beans.metrics.ResponseStatsDataPoint; import io.apiman.manager.api.beans.metrics.ResponseStatsHistogramBean; @@ -31,6 +29,7 @@ import io.apiman.manager.api.core.IMetricsAccessor; import io.apiman.manager.api.core.logging.ApimanLogger; import io.apiman.manager.api.core.logging.IApimanLogger; +import io.apiman.manager.api.core.metrics.AbstractMetricsAccessor; import io.searchbox.client.JestClient; import io.searchbox.core.Search; import io.searchbox.core.SearchResult; @@ -40,7 +39,6 @@ import io.searchbox.core.search.aggregation.MetricAggregation; import java.io.IOException; -import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,9 +49,7 @@ import javax.inject.Named; import org.apache.commons.lang.text.StrSubstitutor; -import org.apache.commons.lang.time.DateFormatUtils; import org.joda.time.DateTime; -import org.joda.time.format.ISODateTimeFormat; /** * An elasticsearch implementation of the {@link IMetricsAccessor} interface. This @@ -63,7 +59,7 @@ * @author eric.wittmann@redhat.com */ @ApplicationScoped @Alternative -public class ESMetricsAccessor implements IMetricsAccessor { +public class ESMetricsAccessor extends AbstractMetricsAccessor implements IMetricsAccessor { private static final String INDEX_NAME = "apiman_metrics"; //$NON-NLS-1$ @@ -151,91 +147,6 @@ public UsageHistogramBean getUsage(String organizationId, String apiId, String v return rval; } - /** - * Generate the histogram buckets based on the time frame requested and the interval. This will - * add an entry for each 'slot' or 'bucket' in the histogram, setting the count to 0. - * @param rval - * @param from - * @param to - * @param interval - */ - public static Map generateHistogramSkeleton(HistogramBean rval, DateTime from, DateTime to, - HistogramIntervalType interval, Class dataType) { - Map index = new HashMap<>(); - - Calendar fromCal = from.toGregorianCalendar(); - Calendar toCal = to.toGregorianCalendar(); - - switch(interval) { - case day: - fromCal.set(Calendar.HOUR_OF_DAY, 0); - fromCal.set(Calendar.MINUTE, 0); - fromCal.set(Calendar.SECOND, 0); - fromCal.set(Calendar.MILLISECOND, 0); - break; - case hour: - fromCal.set(Calendar.MINUTE, 0); - fromCal.set(Calendar.SECOND, 0); - fromCal.set(Calendar.MILLISECOND, 0); - break; - case minute: - fromCal.set(Calendar.SECOND, 0); - fromCal.set(Calendar.MILLISECOND, 0); - break; - case month: - fromCal.set(Calendar.DAY_OF_MONTH, 1); - fromCal.set(Calendar.HOUR_OF_DAY, 0); - fromCal.set(Calendar.MINUTE, 0); - fromCal.set(Calendar.SECOND, 0); - fromCal.set(Calendar.MILLISECOND, 0); - break; - case week: - fromCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); - fromCal.set(Calendar.HOUR_OF_DAY, 0); - fromCal.set(Calendar.MINUTE, 0); - fromCal.set(Calendar.SECOND, 0); - fromCal.set(Calendar.MILLISECOND, 0); - break; - default: - break; - } - - while (fromCal.before(toCal)) { - String label = formatDateWithMillis(fromCal); - T point; - try { - point = dataType.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); - } - point.setLabel(label); - rval.addDataPoint(point); - index.put(label, point); - switch (interval) { - case day: - fromCal.add(Calendar.DAY_OF_YEAR, 1); - break; - case hour: - fromCal.add(Calendar.HOUR_OF_DAY, 1); - break; - case minute: - fromCal.add(Calendar.MINUTE, 1); - break; - case month: - fromCal.add(Calendar.MONTH, 1); - break; - case week: - fromCal.add(Calendar.WEEK_OF_YEAR, 1); - break; - default: - break; - } - } - - return index; - - } - /** * @see io.apiman.manager.api.core.IMetricsAccessor#getUsagePerClient(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) */ @@ -754,34 +665,6 @@ public ClientUsagePerApiBean getClientUsagePerApi(String organizationId, String } - /** - * @param date - */ - protected static String formatDate(DateTime date) { - return ISODateTimeFormat.dateTimeNoMillis().print(date); - } - - /** - * @param date - */ - protected static String formatDateWithMillis(DateTime date) { - return ISODateTimeFormat.dateTime().print(date); - } - - /** - * @param date - */ - protected static String formatDate(Calendar date) { - return DateFormatUtils.formatUTC(date.getTimeInMillis(), "yyyy-MM-dd'T'HH:mm:ss'Z'"); //$NON-NLS-1$ - } - - /** - * @param date - */ - protected static String formatDateWithMillis(Calendar date) { - return DateFormatUtils.formatUTC(date.getTimeInMillis(), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); //$NON-NLS-1$ - } - /** * @return the esClient */ diff --git a/manager/api/hawkular/.gitignore b/manager/api/hawkular/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/manager/api/hawkular/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/manager/api/hawkular/pom.xml b/manager/api/hawkular/pom.xml new file mode 100644 index 0000000000..fdf9e73e9e --- /dev/null +++ b/manager/api/hawkular/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + io.apiman + apiman-manager-api + 1.2.3-SNAPSHOT + + apiman-manager-api-hawkular + bundle + apiman-manager-api-hawkular + + + + + ${project.groupId} + apiman-common-util + + + ${project.groupId} + apiman-common-net + + + ${project.groupId} + apiman-manager-api-beans + + + ${project.groupId} + apiman-manager-api-core + + + + + commons-codec + commons-codec + + + commons-io + commons-io + + + commons-lang + commons-lang + + + org.apache.commons + commons-lang3 + + + joda-time + joda-time + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + !javax.enterprise.context,!javax.enterprise.inject,!javax.inject,* + + + + + + diff --git a/manager/api/hawkular/src/main/java/io/apiman/manager/api/hawkular/HawkularMetricsAccessor.java b/manager/api/hawkular/src/main/java/io/apiman/manager/api/hawkular/HawkularMetricsAccessor.java new file mode 100644 index 0000000000..be00dbfd98 --- /dev/null +++ b/manager/api/hawkular/src/main/java/io/apiman/manager/api/hawkular/HawkularMetricsAccessor.java @@ -0,0 +1,229 @@ +/* + * Copyright 2015 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.apiman.manager.api.hawkular; + +import io.apiman.common.config.options.HttpConnectorOptions; +import io.apiman.common.net.hawkular.HawkularMetricsClient; +import io.apiman.common.net.hawkular.beans.BucketDataPointBean; +import io.apiman.common.net.hawkular.beans.BucketSizeType; +import io.apiman.manager.api.beans.metrics.ClientUsagePerApiBean; +import io.apiman.manager.api.beans.metrics.HistogramIntervalType; +import io.apiman.manager.api.beans.metrics.ResponseStatsDataPoint; +import io.apiman.manager.api.beans.metrics.ResponseStatsHistogramBean; +import io.apiman.manager.api.beans.metrics.ResponseStatsPerClientBean; +import io.apiman.manager.api.beans.metrics.ResponseStatsPerPlanBean; +import io.apiman.manager.api.beans.metrics.ResponseStatsSummaryBean; +import io.apiman.manager.api.beans.metrics.UsageDataPoint; +import io.apiman.manager.api.beans.metrics.UsageHistogramBean; +import io.apiman.manager.api.beans.metrics.UsagePerClientBean; +import io.apiman.manager.api.beans.metrics.UsagePerPlanBean; +import io.apiman.manager.api.core.IMetricsAccessor; +import io.apiman.manager.api.core.metrics.AbstractMetricsAccessor; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.joda.time.DateTime; + +/** + * An elasticsearch implementation of the {@link IMetricsAccessor} interface. This + * implementation knows how to get metrics/analytics information out of an + * elasticsearch store. + * + * @author eric.wittmann@redhat.com + */ +public class HawkularMetricsAccessor extends AbstractMetricsAccessor implements IMetricsAccessor { + + private HawkularMetricsClient client; + + /** + * Constructor. + */ + @SuppressWarnings("nls") + public HawkularMetricsAccessor(Map config) { + String endpoint = config.get("hawkular.endpoint"); + Map httpOptions = new HashMap<>(); + httpOptions.put("http.timeouts.read", config.get("http.timeouts.read")); + httpOptions.put("http.timeouts.write", config.get("http.timeouts.write")); + httpOptions.put("http.timeouts.connect", config.get("http.timeouts.connect")); + httpOptions.put("http.followRedirects", config.get("http.followRedirects")); + client = new HawkularMetricsClient(endpoint, new HttpConnectorOptions(httpOptions)); + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getUsage(java.lang.String, java.lang.String, java.lang.String, io.apiman.manager.api.beans.metrics.HistogramIntervalType, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public UsageHistogramBean getUsage(String organizationId, String apiId, String version, + HistogramIntervalType interval, DateTime from, DateTime to) { + String tenantId = organizationId; + String totalCounterId = "apis." + apiId + "." + version; //$NON-NLS-1$ //$NON-NLS-2$ + + BucketSizeType bucketSize = bucketSizeFromInterval(interval); + List data = client.getCounterData(tenantId, totalCounterId, floor(from, interval).toDate(), to.toDate(), bucketSize); + UsageHistogramBean rval = new UsageHistogramBean(); + for (BucketDataPointBean bucket : data) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(bucket.getStart()); + String label = formatDateWithMillis(calendar); + UsageDataPoint dataPoint = new UsageDataPoint(label, bucket.getSamples()); + rval.getData().add(dataPoint); + } + return rval; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getUsagePerClient(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public UsagePerClientBean getUsagePerClient(String organizationId, String apiId, String version, + DateTime from, DateTime to) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getUsagePerPlan(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public UsagePerPlanBean getUsagePerPlan(String organizationId, String apiId, String version, + DateTime from, DateTime to) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getResponseStats(java.lang.String, java.lang.String, java.lang.String, io.apiman.manager.api.beans.metrics.HistogramIntervalType, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public ResponseStatsHistogramBean getResponseStats(String organizationId, String apiId, String version, + HistogramIntervalType interval, DateTime from, DateTime to) { + String tenantId = organizationId; + String totalCounterId = "apis." + apiId + "." + version; //$NON-NLS-1$ //$NON-NLS-2$ + String failureCounterId = totalCounterId + ".Failed"; //$NON-NLS-1$ + String errorCounterId = totalCounterId + ".Errored"; //$NON-NLS-1$ + + BucketSizeType bucketSize = bucketSizeFromInterval(interval); + DateTime fromFloor = floor(from, interval); + List data = client.getCounterData(tenantId, totalCounterId, fromFloor.toDate(), to.toDate(), bucketSize); + List failureData = client.getCounterData(tenantId, failureCounterId, fromFloor.toDate(), to.toDate(), bucketSize); + List errorData = client.getCounterData(tenantId, errorCounterId, fromFloor.toDate(), to.toDate(), bucketSize); + + ResponseStatsHistogramBean rval = new ResponseStatsHistogramBean(); + for (int idx = 0; idx < data.size(); idx++) { + BucketDataPointBean totalDataPoint = data.get(idx); + BucketDataPointBean failureDataPoint = failureData.get(idx); + BucketDataPointBean errorDataPoint = errorData.get(idx); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(totalDataPoint.getStart()); + String label = formatDateWithMillis(calendar); + ResponseStatsDataPoint dataPoint = new ResponseStatsDataPoint(label, totalDataPoint.getSamples(), + failureDataPoint.getSamples(), errorDataPoint.getSamples()); + rval.getData().add(dataPoint); + } + return rval; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getResponseStatsSummary(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public ResponseStatsSummaryBean getResponseStatsSummary(String organizationId, String apiId, + String version, DateTime from, DateTime to) { + String tenantId = organizationId; + String totalCounterId = "apis." + apiId + "." + version; //$NON-NLS-1$ //$NON-NLS-2$ + String failureCounterId = totalCounterId + ".Failed"; //$NON-NLS-1$ + String errorCounterId = totalCounterId + ".Errored"; //$NON-NLS-1$ + + List data = client.getCounterData(tenantId, totalCounterId, from.toDate(), to.toDate(), 1); + List failureData = client.getCounterData(tenantId, failureCounterId, from.toDate(), to.toDate(), 1); + List errorData = client.getCounterData(tenantId, errorCounterId, from.toDate(), to.toDate(), 1); + + ResponseStatsSummaryBean rval = new ResponseStatsSummaryBean(); + if (data.size() > 0) { + BucketDataPointBean totalDataPoint = data.get(0); + BucketDataPointBean failureDataPoint = failureData.get(0); + BucketDataPointBean errorDataPoint = errorData.get(0); + rval.setTotal(totalDataPoint.getSamples()); + rval.setErrors(errorDataPoint.getSamples()); + rval.setFailures(failureDataPoint.getSamples()); + } + return rval; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getResponseStatsPerClient(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public ResponseStatsPerClientBean getResponseStatsPerClient(String organizationId, String apiId, + String version, DateTime from, DateTime to) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getResponseStatsPerPlan(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public ResponseStatsPerPlanBean getResponseStatsPerPlan(String organizationId, String apiId, + String version, DateTime from, DateTime to) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see io.apiman.manager.api.core.IMetricsAccessor#getClientUsagePerApi(java.lang.String, java.lang.String, java.lang.String, org.joda.time.DateTime, org.joda.time.DateTime) + */ + @Override + public ClientUsagePerApiBean getClientUsagePerApi(String organizationId, String clientId, String version, + DateTime from, DateTime to) { + // TODO Auto-generated method stub + return null; + } + + + /** + * Converts an interval into a bucket size. + * @param interval + */ + private static BucketSizeType bucketSizeFromInterval(HistogramIntervalType interval) { + BucketSizeType bucketSize; + switch (interval) { + case minute: + bucketSize = BucketSizeType.Minute; + break; + case hour: + bucketSize = BucketSizeType.Hour; + break; + case day: + bucketSize = BucketSizeType.Day; + break; + case week: + bucketSize = BucketSizeType.Week; + break; + case month: + bucketSize = BucketSizeType.Month; + break; + default: + bucketSize = BucketSizeType.Day; + break; + } + return bucketSize; + } + +} diff --git a/manager/api/hawkular/src/main/resources/META-INF/beans.xml b/manager/api/hawkular/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/manager/api/micro/pom.xml b/manager/api/micro/pom.xml index 2755e3b53f..28fd8308f9 100644 --- a/manager/api/micro/pom.xml +++ b/manager/api/micro/pom.xml @@ -67,6 +67,10 @@ ${project.groupId} apiman-manager-api-es + + ${project.groupId} + apiman-manager-api-hawkular + ${project.groupId} apiman-manager-api-gateway diff --git a/manager/api/pom.xml b/manager/api/pom.xml index 4f7411f3bf..eba5c2490f 100644 --- a/manager/api/pom.xml +++ b/manager/api/pom.xml @@ -16,6 +16,7 @@ es export-import gateway + hawkular ispn jpa micro diff --git a/manager/api/war/pom.xml b/manager/api/war/pom.xml index 0c343edb42..4eb1435750 100644 --- a/manager/api/war/pom.xml +++ b/manager/api/war/pom.xml @@ -74,6 +74,10 @@ ${project.groupId} apiman-manager-api-es + + ${project.groupId} + apiman-manager-api-hawkular + ${project.groupId} apiman-manager-api-gateway diff --git a/manager/test/api/pom.xml b/manager/test/api/pom.xml index f677f6a89b..22281c6614 100644 --- a/manager/test/api/pom.xml +++ b/manager/test/api/pom.xml @@ -63,6 +63,10 @@ ${project.groupId} apiman-manager-api-es + + ${project.groupId} + apiman-manager-api-hawkular + ${project.groupId} apiman-manager-api-gateway diff --git a/manager/test/api/src/test/java/io/apiman/manager/test/es/ESMetricsAccessorTest.java b/manager/test/api/src/test/java/io/apiman/manager/test/es/ESMetricsAccessorTest.java index 902d57dc4e..96ec8bea88 100644 --- a/manager/test/api/src/test/java/io/apiman/manager/test/es/ESMetricsAccessorTest.java +++ b/manager/test/api/src/test/java/io/apiman/manager/test/es/ESMetricsAccessorTest.java @@ -28,6 +28,7 @@ import io.apiman.manager.api.beans.metrics.UsageHistogramBean; import io.apiman.manager.api.beans.metrics.UsagePerClientBean; import io.apiman.manager.api.beans.metrics.UsagePerPlanBean; +import io.apiman.manager.api.core.metrics.AbstractMetricsAccessor; import io.apiman.manager.api.es.ESMetricsAccessor; import io.searchbox.client.JestClient; import io.searchbox.indices.Refresh; @@ -269,7 +270,7 @@ public void testGenerateHistogramSkeleton() throws Exception { DateTime from = parseDate("2015-01-01T00:00:00Z"); DateTime to = parseDate("2015-01-10T00:00:00Z"); UsageHistogramBean histogram = new UsageHistogramBean(); - Map index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, + Map index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.day, UsageDataPoint.class); Assert.assertEquals(9, index.size()); Assert.assertEquals(9, histogram.getData().size()); @@ -281,7 +282,7 @@ public void testGenerateHistogramSkeleton() throws Exception { from = parseDate("2015-01-01T00:00:00Z"); to = parseDate("2015-01-03T00:00:00Z"); histogram = new UsageHistogramBean(); - index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.hour, + index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.hour, UsageDataPoint.class); Assert.assertEquals(48, index.size()); Assert.assertEquals(48, histogram.getData().size()); @@ -294,7 +295,7 @@ public void testGenerateHistogramSkeleton() throws Exception { from = parseDate("2015-01-01"); to = parseDate("2015-01-03"); histogram = new UsageHistogramBean(); - index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.hour, + index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.hour, UsageDataPoint.class); Assert.assertEquals(48, index.size()); Assert.assertEquals(48, histogram.getData().size()); @@ -307,7 +308,7 @@ public void testGenerateHistogramSkeleton() throws Exception { from = parseDate("2015-01-01T00:00:00Z"); to = parseDate("2015-01-02T00:00:00Z"); histogram = new UsageHistogramBean(); - index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, + index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.minute, UsageDataPoint.class); Assert.assertEquals(1440, index.size()); Assert.assertEquals(1440, histogram.getData().size()); @@ -319,7 +320,7 @@ public void testGenerateHistogramSkeleton() throws Exception { from = parseDate("2015-01-01"); to = parseDate("2015-12-31"); histogram = new UsageHistogramBean(); - index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.month, + index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.month, UsageDataPoint.class); Assert.assertEquals(12, index.size()); Assert.assertEquals(12, histogram.getData().size()); @@ -331,7 +332,7 @@ public void testGenerateHistogramSkeleton() throws Exception { from = parseDate("2015-01-01"); to = parseDate("2015-12-30"); histogram = new UsageHistogramBean(); - index = ESMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.week, + index = AbstractMetricsAccessor.generateHistogramSkeleton(histogram, from, to, HistogramIntervalType.week, UsageDataPoint.class); Assert.assertEquals(53, index.size()); diff --git a/pom.xml b/pom.xml index d8274e6769..35573debcb 100644 --- a/pom.xml +++ b/pom.xml @@ -190,6 +190,11 @@ apiman-common-util ${project.version} + + ${project.groupId} + apiman-common-net + ${project.version} + ${project.groupId} apiman-common-config @@ -230,6 +235,11 @@ apiman-manager-api-es ${project.version} + + ${project.groupId} + apiman-manager-api-hawkular + ${project.version} + ${project.groupId} apiman-manager-api-core @@ -391,6 +401,11 @@ apiman-gateway-engine-es ${project.version} + + ${project.groupId} + apiman-gateway-engine-hawkular + ${project.version} + ${project.groupId} apiman-gateway-engine-jdbc