/** * Copyright 2013-2016 BlackLocus * * 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 com.blacklocus.metrics; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient; import com.amazonaws.services.cloudwatch.model.MetricDatum; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.ScheduledReporter; import com.codahale.metrics.Timer; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Strings; import java.util.SortedMap; /** * A fluent style builder for a {@link CloudWatchReporter}. {@link #withNamespace(String)} is required. There * are suitable defaults for all other fields. */ public class CloudWatchReporterBuilder { // Defaults are resolved in build() so that 1) it is precisely clear what the caller set, // and 2) so that partial constructions can copy() before setting member variables with // things that should not be part of the copy such as a base builder for similar CloudWatchReporters. private MetricRegistry registry; private String namespace; private AmazonCloudWatchAsync client; private MetricFilter filter; private String dimensions; private Boolean timestampLocal; private String typeDimName; private String typeDimValGauge; private String typeDimValCounterCount; private String typeDimValMeterCount; private String typeDimValHistoSamples; private String typeDimValHistoStats; private String typeDimValTimerSamples; private String typeDimValTimerStats; private Predicate<MetricDatum> reporterFilter; /** * @param registry of metrics for CloudWatchReporter to submit * @return this (for chaining) */ public CloudWatchReporterBuilder withRegistry(MetricRegistry registry) { this.registry = registry; return this; } /** * @param namespace metric namespace to use when submitting metrics to CloudWatch * @return this (for chaining) */ public CloudWatchReporterBuilder withNamespace(String namespace) { this.namespace = namespace; return this; } /** * @param client CloudWatch client * @return this (for chaining) */ public CloudWatchReporterBuilder withClient(AmazonCloudWatchAsync client) { this.client = client; return this; } /** * @param filter which returns true for metrics that should be sent to CloudWatch * @return this (for chaining) */ public CloudWatchReporterBuilder withFilter(MetricFilter filter) { this.filter = filter; return this; } /** * @param dimensions global dimensions in the form name=value that should be appended to all metrics submitted to * CloudWatch * @return this (for chaining) */ public CloudWatchReporterBuilder withDimensions(String dimensions) { this.dimensions = dimensions; return this; } /** * @param timestampLocal whether or not to explicitly timestamp metric data to now (true), or leave it null so that * CloudWatch will timestamp it on receipt (false) * @return this (for chaining) */ public CloudWatchReporterBuilder withTimestampLocal(Boolean timestampLocal) { this.timestampLocal = timestampLocal; return this; } /** * @param typeDimName name of the "metric type" dimension added to CloudWatch submissions. * Defaults to <b>{@value Constants#DEF_DIM_NAME_TYPE}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimName(String typeDimName) { this.typeDimName = typeDimName; return this; } /** * @param typeDimValGauge value of the "metric type" dimension added to CloudWatch submissions of {@link Gauge}s. * Defaults to <b>{@value Constants#DEF_DIM_VAL_GAUGE}</b> * when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValGauge(String typeDimValGauge) { this.typeDimValGauge = typeDimValGauge; return this; } /** * @param typeDimValCounterCount value of the "metric type" dimension added to CloudWatch submissions of * {@link Counter#getCount()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_COUNTER_COUNT}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValCounterCount(String typeDimValCounterCount) { this.typeDimValCounterCount = typeDimValCounterCount; return this; } /** * @param typeDimValMeterCount value of the "metric type" dimension added to CloudWatch submissions of * {@link Meter#getCount()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_METER_COUNT}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValMeterCount(String typeDimValMeterCount) { this.typeDimValMeterCount = typeDimValMeterCount; return this; } /** * @param typeDimValHistoSamples value of the "metric type" dimension added to CloudWatch submissions of * {@link Histogram#getCount()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_HISTO_SAMPLES}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValHistoSamples(String typeDimValHistoSamples) { this.typeDimValHistoSamples = typeDimValHistoSamples; return this; } /** * @param typeDimValHistoStats value of the "metric type" dimension added to CloudWatch submissions of * {@link Histogram#getSnapshot()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_HISTO_STATS}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValHistoStats(String typeDimValHistoStats) { this.typeDimValHistoStats = typeDimValHistoStats; return this; } /** * @param typeDimValTimerSamples value of the "metric type" dimension added to CloudWatch submissions of * {@link Timer#getCount()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_TIMER_SAMPLES}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValTimerSamples(String typeDimValTimerSamples) { this.typeDimValTimerSamples = typeDimValTimerSamples; return this; } /** * @param typeDimValTimerStats value of the "metric type" dimension added to CloudWatch submissions of * {@link Timer#getSnapshot()}. * Defaults to <b>{@value Constants#DEF_DIM_VAL_TIMER_STATS}</b> when using the CloudWatchReporterBuilder * @return this (for chaining) */ public CloudWatchReporterBuilder withTypeDimValTimerStats(String typeDimValTimerStats) { this.typeDimValTimerStats = typeDimValTimerStats; return this; } /** * This filter is applied right before submission to CloudWatch. This filter can access decoded metric name elements * such as {@link MetricDatum#getDimensions()}. true means to keep and submit the metric. false means to exclude it. * <p> * Different from {@link MetricFilter} in that * MetricFilter must operate on the encoded, single-string name (see {@link MetricFilter#matches(String, Metric)}), * and this filter is applied before {@link ScheduledReporter#report(SortedMap, SortedMap, SortedMap, SortedMap, SortedMap)} so that * filtered metrics never reach that method in CloudWatchReporter. * <p> * Defaults to {@link Predicates#alwaysTrue()} - i.e. do not remove any metrics from the submission due to this * particular filter. * * @param reporterFilter to replace 'alwaysTrue()' * @return this (for chaining) */ public CloudWatchReporterBuilder withReporterFilter(Predicate<MetricDatum> reporterFilter) { this.reporterFilter = reporterFilter; return this; } /** * @return a shallow copy of this builder */ public CloudWatchReporterBuilder copy() { return new CloudWatchReporterBuilder() .withRegistry(registry) .withNamespace(namespace) .withClient(client) .withFilter(filter) .withDimensions(dimensions) .withTimestampLocal(timestampLocal) .withTypeDimName(typeDimName) .withTypeDimValGauge(typeDimValGauge) .withTypeDimValCounterCount(typeDimValCounterCount) .withTypeDimValMeterCount(typeDimValMeterCount) .withTypeDimValHistoSamples(typeDimValHistoSamples) .withTypeDimValHistoStats(typeDimValHistoStats) .withTypeDimValTimerSamples(typeDimValTimerSamples) .withTypeDimValTimerStats(typeDimValTimerStats) .withReporterFilter(reporterFilter); } /** * @return a new CloudWatchReporter instance based on the state of this builder */ public CloudWatchReporter build() { Preconditions.checkState(!Strings.isNullOrEmpty(namespace), "Metric namespace is required."); String resolvedNamespace = namespace; // Use specified or fall back to default. Don't secretly modify the fields of this builder // in case the caller wants to re-use it to build other reporters, or something. MetricRegistry resolvedRegistry = null != registry ? registry : new MetricRegistry(); MetricFilter resolvedFilter = null != filter ? filter : MetricFilter.ALL; AmazonCloudWatchAsync resolvedCloudWatchClient = null != client ? client : new AmazonCloudWatchAsyncClient(); String resolvedDimensions = null != dimensions ? dimensions : null; Boolean resolvedTimestampLocal = null != timestampLocal ? timestampLocal : false; String resolvedTypeDimName = null != typeDimName ? typeDimName : Constants.DEF_DIM_NAME_TYPE; String resolvedTypeDimValGauge = null != typeDimValGauge ? typeDimValGauge : Constants.DEF_DIM_VAL_GAUGE; String resolvedTypeDimValCounterCount = null != typeDimValCounterCount ? typeDimValCounterCount : Constants.DEF_DIM_VAL_COUNTER_COUNT; String resolvedTypeDimValMeterCount = null != typeDimValMeterCount ? typeDimValMeterCount : Constants.DEF_DIM_VAL_METER_COUNT; String resolvedTypeDimValHistoSamples = null != typeDimValHistoSamples ? typeDimValHistoSamples : Constants.DEF_DIM_VAL_HISTO_SAMPLES; String resolvedTypeDimValHistoStats = null != typeDimValHistoStats ? typeDimValHistoStats : Constants.DEF_DIM_VAL_HISTO_STATS; String resolvedTypeDimValTimerSamples = null != typeDimValTimerSamples ? typeDimValTimerSamples : Constants.DEF_DIM_VAL_TIMER_SAMPLES; String resolvedTypeDimValTimerStats = null != typeDimValTimerStats ? typeDimValTimerStats : Constants.DEF_DIM_VAL_TIMER_STATS; Predicate<MetricDatum> resolvedReporterFilter = null != reporterFilter ? reporterFilter : Predicates.<MetricDatum>alwaysTrue(); return new CloudWatchReporter( resolvedRegistry, resolvedNamespace, resolvedFilter, resolvedCloudWatchClient) .withDimensions(resolvedDimensions) .withTimestampLocal(resolvedTimestampLocal) .withTypeDimName(resolvedTypeDimName) .withTypeDimValGauge(resolvedTypeDimValGauge) .withTypeDimValCounterCount(resolvedTypeDimValCounterCount) .withTypeDimValMeterCount(resolvedTypeDimValMeterCount) .withTypeDimValHistoSamples(resolvedTypeDimValHistoSamples) .withTypeDimValHistoStats(resolvedTypeDimValHistoStats) .withTypeDimValTimerSamples(resolvedTypeDimValTimerSamples) .withTypeDimValTimerStats(resolvedTypeDimValTimerStats) .withReporterFilter(resolvedReporterFilter); } }