com.jlhood.metrics.DemuxedKey Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metrics-cloudwatch Show documentation
Show all versions of metrics-cloudwatch Show documentation
A Dropwizard metrics reporter to Amazon CloudWatch
/*
* 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.amazonaws.services.cloudwatch.model.MetricDatum;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static com.jlhood.metrics.Constants.*;
class DemuxedKey {
final PermutableChain nameChain;
final PermutableChain dimensionChain;
DemuxedKey(String s) {
String[] segments = s.split(NAME_TOKEN_DELIMITER_RGX);
PermutableChain names = null;
PermutableChain dimensions = null;
// Build NameSegmentChain in reverse. Dimension order is irrelevant.
for (int i = segments.length - 1; i >= 0; i--) {
String segment = segments[i];
boolean permutable = segment.endsWith(NAME_PERMUTE_MARKER);
if (permutable) {
segment = segment.substring(0, segment.length() - 1);
}
if (segment.contains(NAME_DIMENSION_SEPARATOR)) {
String[] dimensionParts = segment.split(NAME_DIMENSION_SEPARATOR, 2);
Dimension dimension = new Dimension().withName(dimensionParts[0]).withValue(dimensionParts[1]);
dimensions = new PermutableChain(dimension, permutable, dimensions);
} else {
assert !segment.contains(NAME_PERMUTE_MARKER);
names = new PermutableChain(segment, permutable, names);
}
}
this.nameChain = names;
this.dimensionChain = dimensions;
}
/**
* @param typeName dimension name to use for the metric type dimension
* @param typeValue dimension value to use for the metric type dimension
* @param datumSpecification writes the metric's data into to the prepared MetricDatum
* @return the generated datums which should be ready for submission to CloudWath
*/
Iterable newDatums(String typeName, String typeValue, Function datumSpecification) {
// All dimension sets include the type dimension.
PermutableChain withDimensionChain = new PermutableChain(
new Dimension().withName(typeName).withValue(typeValue),
false,
dimensionChain
);
List data = new ArrayList();
for (Iterable nameSet : nameChain) {
String name = StringUtils.join(nameSet, " ");
if (StringUtils.isBlank(name)) {
// If all name segments are permutable, there is one combination where all of them are omitted.
// This is expected and supported but of course can not be submitted.
continue;
}
for (Iterable dimensionSet : withDimensionChain) {
data.add(datumSpecification.apply(
new MetricDatum().withMetricName(name).withDimensions(Lists.newArrayList(dimensionSet))
));
}
}
return data;
}
}
class PermutableChain implements Iterable> {
final T token;
final boolean permutable;
final PermutableChain nextSegment;
PermutableChain(T token, boolean permutable, PermutableChain nextSegment) {
this.token = token;
this.permutable = permutable;
this.nextSegment = nextSegment;
}
@Override
public Iterator> iterator() {
return new Iterator>() {
int permutation = permutable ? 2 : 1;
Iterator> nextSegmentIt = nextSegment == null ? null : nextSegment.iterator();
@Override
public boolean hasNext() {
boolean isTail = nextSegmentIt == null;
if (isTail) {
return permutation > 0;
} else {
return permutation > 0 && nextSegmentIt != null && nextSegmentIt.hasNext();
}
}
@Override
public Iterable next() {
assert permutation > 0 && permutation <= 2;
boolean isTail = nextSegmentIt == null;
if (isTail) {
if (permutation == 2) {
permutation = 1;
return Collections.emptyList();
} else {
assert permutation == 1;
permutation = 0;
return ImmutableList.of(token);
}
} else {
if (permutation == 2) {
Iterable next = nextSegmentIt.next();
if (!nextSegmentIt.hasNext()) {
permutation = 1;
nextSegmentIt = nextSegment.iterator();
}
return next;
} else {
assert permutation == 1;
Iterable next = Iterables.concat(ImmutableList.of(token), nextSegmentIt.next());
if (!nextSegmentIt.hasNext()) {
permutation = 0;
nextSegmentIt = null;
}
return next;
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Nope.");
}
};
}
/*
Three option*
hasNext == tail && exhausted || next.hasNext() next: return
Three -> ""
Three -> option
*/
}