com.jlhood.metrics.MetricNameBuilder Maven / Gradle / Ivy
Show all versions of metrics-cloudwatch Show documentation
/*
* Copyright 2016 James Hood
*
* 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.jlhood.metrics;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.jlhood.metrics.Constants.NAME_DIMENSION_SEPARATOR;
import static com.jlhood.metrics.Constants.NAME_PERMUTE_MARKER;
import static com.jlhood.metrics.Constants.NAME_TOKEN_DELIMITER;
import static com.jlhood.metrics.Constants.NAME_TOKEN_DELIMITER_RGX;
import static com.jlhood.metrics.Constants.VALID_DIMENSION_PART_RGX;
import static com.jlhood.metrics.Constants.VALID_NAME_TOKEN_RGX;
/**
* A builder for the metrics name syntax defined by this module. Useful when programmatically constructing metric names.
*
* Please refer to [README.md](https://github.com/blacklocus/metrics-cloudwatch/blob/master/README.md) for the
* latest usage documentation.
*/
public class MetricNameBuilder {
private final List names = new ArrayList();
private final List dimensions = new ArrayList();
public MetricNameBuilder() {
}
public MetricNameBuilder(String nameSpec) {
add(nameSpec);
}
/**
* @param nameToken must be a single valid name segment which is summarized by the regex
* {@link Constants#VALID_NAME_TOKEN_RGX} (it may end in the permute operator).
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addNameToken(String nameToken) throws MetricsNameSyntaxException {
nameToken = nameToken.trim();
if (!nameToken.matches(VALID_NAME_TOKEN_RGX)) {
throw new MetricsNameSyntaxException("Name must match " + VALID_NAME_TOKEN_RGX);
}
this.names.add(nameToken);
return this;
}
/**
* @param nameToken must be a single valid name segment which is summarized by the regex
* {@link Constants#VALID_NAME_TOKEN_RGX} (it may end in the permute operator).
* @param permute whether or not this token should permute
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addNameToken(String nameToken, boolean permute) throws MetricsNameSyntaxException {
if (permute && !nameToken.endsWith(NAME_PERMUTE_MARKER)) {
nameToken += NAME_PERMUTE_MARKER;
} else if (!permute && nameToken.endsWith(NAME_PERMUTE_MARKER)) {
nameToken = nameToken.substring(0, nameToken.length() - 1);
}
return addNameToken(nameToken);
}
/**
* @param nameSpec a string of encoded name tokens and dimensions, e.g. "MyMetric SomeTag* color=green machine=1.2.3.4*".
* A metric name of this format is already suitable for direct use with metrics reported by the
* {@link CloudWatchReporter} and demuxes into corresponding dimensions and permutations.
* There is no need to use a MetricsNameBuilder if you already have the completed string. Set it
* directly to be the metric name, e.g.
* metricRegistry.counter("MyMetric SomeTag* color=green machine=1.2.3.4*").inc();
*
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder add(String nameSpec) throws MetricsNameSyntaxException {
for (String token : nameSpec.split(NAME_TOKEN_DELIMITER_RGX)) {
if (token.contains(NAME_DIMENSION_SEPARATOR)) {
String[] dimensionTuple = token.split(NAME_DIMENSION_SEPARATOR, 2);
addDimension(dimensionTuple[0], dimensionTuple[1]);
} else {
addNameToken(token);
}
}
return this;
}
/**
* {@link #addDimension(Dimension, boolean)} without permutation (false)
*
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addDimension(Dimension dimension) throws MetricsNameSyntaxException {
return addDimension(dimension, false);
}
/**
* Passes into {@link #addDimension(String, String, boolean)}
*
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addDimension(Dimension dimension, boolean permute) throws MetricsNameSyntaxException {
return addDimension(dimension.getName(), dimension.getValue(), false);
}
/**
* {@link #addDimension(String, String, boolean)} without permutation (false)
*
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addDimension(String name, String value) throws MetricsNameSyntaxException {
return addDimension(name, value, false);
}
/**
* @param name of dimension
* @param value of dimension
* @param permute permutability of dimension
* @return this for chaining
* @throws MetricsNameSyntaxException on validation failure
*/
public MetricNameBuilder addDimension(String name, String value, boolean permute) throws MetricsNameSyntaxException {
if (!name.matches(VALID_DIMENSION_PART_RGX)) {
throw new MetricsNameSyntaxException("Dimension name must match " + VALID_DIMENSION_PART_RGX);
}
if (!value.matches(VALID_DIMENSION_PART_RGX)) {
throw new MetricsNameSyntaxException("Dimension name must match " + VALID_DIMENSION_PART_RGX);
}
this.dimensions.add(name + NAME_DIMENSION_SEPARATOR + value + (permute ? NAME_PERMUTE_MARKER : ""));
return this;
}
/**
* @return properly formatted metric name for use with the {@link MetricRegistry}. The CloudWatchReporter will
* be able to demux this name spec into corresponding permutable name tokens and dimensions.
*/
public String build() {
return toString();
}
/**
* @return properly formatted metric name for use with the {@link MetricRegistry}. The CloudWatchReporter will
* be able to demux this name spec into corresponding permutable name tokens and dimensions.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Iterator iterator = Iterables.concat(names, dimensions).iterator(); iterator.hasNext(); ) {
sb.append(iterator.next());
if (iterator.hasNext()) {
sb.append(NAME_TOKEN_DELIMITER);
}
}
return sb.toString();
}
public static class MetricsNameSyntaxException extends RuntimeException {
public MetricsNameSyntaxException(String message) {
super(message);
}
}
}