Skip to content

Commit ec7a67d

Browse files
vjkoskelaBrandonArp
authored andcommitted
Unified units and telemetry units. (#60)
1 parent 22a7ad1 commit ec7a67d

36 files changed

+191
-1060
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,13 @@ For example:
105105
"serviceName": "MyApplication",
106106
"sources":
107107
[
108+
{
109+
"type": "com.arpnetworking.metrics.common.sources.ClientHttpSourceV1
110+
"name": "my_application_http_source"
111+
},
108112
{
109113
"type": "com.arpnetworking.metrics.common.sources.FileSource",
110-
"name": "my_application_source",
114+
"name": "my_application_file_source",
111115
"filePath": "/var/log/my-application-query.log",
112116
"parser": {
113117
"type": "com.arpnetworking.metrics.mad.parsers.QueryLogParser"

src/main/java/com/arpnetworking/http/Routes.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ public Flow<HttpRequest, HttpResponse, NotUsed> flow() {
108108
@Override
109109
public CompletionStage<HttpResponse> apply(final HttpRequest request) {
110110
final Stopwatch requestTimer = Stopwatch.createStarted();
111-
_metrics.recordCounter(createMetricName(request, BODY_SIZE_METRIC), request.entity().getContentLengthOption().orElse(0L));
111+
_metrics.recordGauge(
112+
createMetricName(request, BODY_SIZE_METRIC),
113+
request.entity().getContentLengthOption().orElse(0L),
114+
Optional.of(Units.BYTE));
112115
// TODO(vkoskela): Add a request UUID and include in MDC. [MAI-462]
113116
LOGGER.trace()
114117
.setEvent("http.in.start")

src/main/java/com/arpnetworking/metrics/mad/parsers/CollectdJsonToRecordParser.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public List<Record> parse(final HttpRequest request) throws ParsingException {
101101
}
102102
final String metricName = computeMetricName(plugin, pluginInstance, type, typeInstance, sample.getDsName());
103103
final MetricType metricType = mapDsType(sample.getDsType());
104+
// TODO(ville): Support units and normalize
104105
final Metric metric = new DefaultMetric.Builder()
105106
.setType(metricType)
106107
.setValues(Collections.singletonList(

src/main/java/com/arpnetworking/metrics/proxy/models/messages/MetricReport.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
package com.arpnetworking.metrics.proxy.models.messages;
1818

1919
import com.arpnetworking.logback.annotations.Loggable;
20+
import com.arpnetworking.tsdcore.model.Unit;
2021
import com.google.common.base.MoreObjects;
22+
import com.google.common.collect.ImmutableList;
2123
import org.joda.time.DateTime;
2224

25+
import java.util.Optional;
26+
2327
/**
2428
* Message class to hold data about a metric that should be sent to clients.
2529
*
@@ -36,6 +40,7 @@ public final class MetricReport {
3640
* @param statistic name of the statistic
3741
* @param metric name of the metric
3842
* @param value value
43+
* @param unit unit
3944
* @param periodStart start of the period
4045
*/
4146
public MetricReport(
@@ -44,12 +49,14 @@ public MetricReport(
4449
final String statistic,
4550
final String metric,
4651
final double value,
52+
final Optional<Unit> unit,
4753
final DateTime periodStart) {
4854
_service = service;
4955
_host = host;
5056
_statistic = statistic;
5157
_metric = metric;
5258
_value = value;
59+
_numeratorUnits = unit.map(Unit::toString).map(ImmutableList::of).orElse(ImmutableList.of());
5360
_periodStart = periodStart;
5461
}
5562

@@ -73,6 +80,14 @@ public double getValue() {
7380
return _value;
7481
}
7582

83+
public ImmutableList<String> getNumeratorUnits() {
84+
return _numeratorUnits;
85+
}
86+
87+
public ImmutableList<String> getDenominatorUnits() {
88+
return _denominatorUnits;
89+
}
90+
7691
public DateTime getPeriodStart() {
7792
return _periodStart;
7893
}
@@ -87,6 +102,8 @@ public String toString() {
87102
.add("Statistic", _statistic)
88103
.add("Metric", _metric)
89104
.add("Value", _value)
105+
.add("NumeratorUnit", _numeratorUnits)
106+
.add("DenominatorUnit", _denominatorUnits)
90107
.add("PeriodStart", _periodStart)
91108
.toString();
92109
}
@@ -96,5 +113,7 @@ public String toString() {
96113
private final String _statistic;
97114
private final String _metric;
98115
private final double _value;
116+
private final ImmutableList<String> _numeratorUnits;
117+
private final ImmutableList<String> _denominatorUnits = ImmutableList.of();
99118
private final DateTime _periodStart;
100119
}

src/main/java/com/arpnetworking/metrics/proxy/models/protocol/v2/MetricMessagesProcessor.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.fasterxml.jackson.databind.node.ArrayNode;
3333
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
3434
import com.fasterxml.jackson.databind.node.ObjectNode;
35+
import com.google.common.collect.ImmutableList;
3536
import com.google.common.collect.Maps;
3637
import com.google.common.collect.Sets;
3738

@@ -166,10 +167,18 @@ private void processMetricReport(final MetricReport report) {
166167
event.put("timestamp", report.getPeriodStart().getMillis());
167168
event.put("statistic", report.getStatistic());
168169
event.put("data", report.getValue());
170+
event.set("numeratorUnits", createUnitArrayNode(report.getNumeratorUnits()));
171+
event.set("denominatorUnits", createUnitArrayNode(report.getDenominatorUnits()));
169172

170173
_connection.sendCommand(COMMAND_REPORT_METRIC, event);
171174
}
172175

176+
private ArrayNode createUnitArrayNode(final ImmutableList<String> units) {
177+
final ArrayNode unitArrayNode = new ArrayNode(OBJECT_MAPPER.getNodeFactory());
178+
units.forEach(unitArrayNode::add);
179+
return unitArrayNode;
180+
}
181+
173182
private void processMetricsList(final MetricsList metricsList) {
174183
//TODO(barp): Map with a POJO mapper [MAI-184]
175184
final ObjectNode dataNode = JsonNodeFactory.instance.objectNode();

src/main/java/com/arpnetworking/tsdcore/model/Quantity.java

Lines changed: 28 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,13 @@
1717

1818
import com.arpnetworking.commons.builder.OvalBuilder;
1919
import com.arpnetworking.logback.annotations.Loggable;
20-
import com.google.common.base.Function;
2120
import com.google.common.base.MoreObjects;
22-
import com.google.common.collect.Lists;
2321
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2422
import net.sf.oval.constraint.NotNull;
2523

2624
import java.io.Serializable;
27-
import java.util.Collection;
28-
import java.util.List;
2925
import java.util.Objects;
3026
import java.util.Optional;
31-
import javax.annotation.Nullable;
3227

3328
/**
3429
* Represents a sample.
@@ -61,7 +56,7 @@ public Quantity add(final Quantity otherQuantity) {
6156
this,
6257
otherQuantity));
6358
}
64-
if (_unit.equals(otherQuantity._unit)) {
59+
if (Objects.equals(_unit, otherQuantity._unit)) {
6560
return new Quantity(_value + otherQuantity._value, _unit);
6661
}
6762
final Unit smallerUnit = _unit.get().getSmallerUnit(otherQuantity.getUnit().get());
@@ -86,7 +81,7 @@ public Quantity subtract(final Quantity otherQuantity) {
8681
this,
8782
otherQuantity));
8883
}
89-
if (_unit.equals(otherQuantity._unit)) {
84+
if (Objects.equals(_unit, otherQuantity._unit)) {
9085
return new Quantity(_value - otherQuantity._value, _unit);
9186
}
9287
final Unit smallerUnit = _unit.get().getSmallerUnit(otherQuantity.getUnit().get());
@@ -122,73 +117,23 @@ public Quantity multiply(final Quantity otherQuantity) {
122117
public Quantity divide(final Quantity otherQuantity) {
123118
// TODO(vkoskela): Support division by quantity with unit [2F].
124119
if (otherQuantity._unit.isPresent()) {
125-
throw new UnsupportedOperationException("Compount units not supported yet");
120+
throw new UnsupportedOperationException("Compound units not supported yet");
126121
}
127-
if (_unit.equals(otherQuantity._unit)) {
122+
if (Objects.equals(_unit, otherQuantity._unit)) {
128123
return new Quantity(_value / otherQuantity._value, Optional.empty());
129124
}
130125
return new Quantity(
131126
_value / otherQuantity._value,
132127
_unit);
133128
}
134129

135-
/**
136-
* Convert this <code>Quantity</code> to one in the specified unit. This
137-
* <code>Quantity</code> must also have a <code>Unit</code> and it must
138-
* be in the same domain as the provided unit.
139-
*
140-
* @param unit <code>Unit</code> to convert to.
141-
* @return <code>Quantity</code> in specified unit.
142-
*/
143-
public Quantity convertTo(final Unit unit) {
144-
if (!_unit.isPresent()) {
145-
throw new IllegalStateException(String.format(
146-
"Cannot convert a quantity without a unit; this=%s",
147-
this));
148-
}
149-
if (_unit.get().equals(unit)) {
150-
return this;
151-
}
152-
return new Quantity(
153-
unit.convert(_value, _unit.get()),
154-
Optional.of(unit));
155-
}
156-
157-
/**
158-
* Convert this <code>Quantity</code> to one in the specified optional unit.
159-
* Either this <code>Quantity</code> also has a <code>Unit</code> in the
160-
* same domain as the provided unit or both units are absent.
161-
*
162-
* @param unit <code>Optional</code> <code>Unit</code> to convert to.
163-
* @return <code>Quantity</code> in specified unit.
164-
*/
165-
public Quantity convertTo(final Optional<Unit> unit) {
166-
if (_unit.isPresent() != unit.isPresent()) {
167-
throw new IllegalStateException(String.format(
168-
"Units must both be present or absent; quantity=%s unit=%s",
169-
this,
170-
unit));
171-
}
172-
if (_unit.equals(unit)) {
173-
return this;
174-
}
175-
return new Quantity(
176-
unit.get().convert(_value, _unit.get()),
177-
unit);
178-
}
179-
180130
@Override
181131
public int compareTo(final Quantity other) {
182132
if (other._unit.equals(_unit)) {
183133
return Double.compare(_value, other._value);
184-
} else if (other._unit.isPresent() && _unit.isPresent()) {
185-
final Unit smallerUnit = _unit.get().getSmallerUnit(other._unit.get());
186-
final double convertedValue = smallerUnit.convert(_value, _unit.get());
187-
final double otherConvertedValue = smallerUnit.convert(other._value, other._unit.get());
188-
return Double.compare(convertedValue, otherConvertedValue);
189134
}
190135
throw new IllegalArgumentException(String.format(
191-
"Cannot compare a quantity with a unit to a quantity without a unit; this=%s, other=%s",
136+
"Cannot compare mismatched units; this=%s, other=%s",
192137
this,
193138
other));
194139
}
@@ -222,37 +167,6 @@ public String toString() {
222167
.toString();
223168
}
224169

225-
/**
226-
* Ensures all <code>Quantity</code> instances have the same (including no)
227-
* <code>Unit</code>.
228-
*
229-
* @param quantities <code>Quantity</code> instances to convert.
230-
* @return <code>List</code> of <code>Quantity</code> instances with the
231-
* same <code>Unit</code> (or no <code>Unit</code>).
232-
*/
233-
public static List<Quantity> unify(final Collection<Quantity> quantities) {
234-
// This is a 2-pass operation:
235-
// First pass is to grab the smallest unit in the samples
236-
// Second pass is to convert everything to that unit
237-
Optional<Unit> smallestUnit = Optional.empty();
238-
for (final Quantity quantity : quantities) {
239-
if (!smallestUnit.isPresent()) {
240-
smallestUnit = quantity.getUnit();
241-
} else if (quantity.getUnit().isPresent()
242-
&& !smallestUnit.get().getSmallerUnit(quantity.getUnit().get()).equals(smallestUnit.get())) {
243-
smallestUnit = quantity.getUnit();
244-
}
245-
}
246-
247-
final List<Quantity> convertedSamples = Lists.newArrayListWithExpectedSize(quantities.size());
248-
final Function<Quantity, Quantity> converter = SampleConverter.to(smallestUnit);
249-
for (final Quantity quantity : quantities) {
250-
convertedSamples.add(converter.apply(quantity));
251-
}
252-
253-
return convertedSamples;
254-
}
255-
256170
private Quantity(final Builder builder) {
257171
this(builder._value, Optional.ofNullable(builder._unit));
258172
}
@@ -268,37 +182,6 @@ private Quantity(final double value, final Optional<Unit> unit) {
268182

269183
private static final long serialVersionUID = -6339526234042605516L;
270184

271-
private static final class SampleConverter implements Function<Quantity, Quantity> {
272-
273-
public static Function<Quantity, Quantity> to(final Optional<Unit> unit) {
274-
if (unit.isPresent()) {
275-
return new SampleConverter(unit.get());
276-
}
277-
return (q) -> q;
278-
}
279-
280-
@Override
281-
@Nullable
282-
public Quantity apply(@Nullable final Quantity quantity) {
283-
if (quantity == null) {
284-
return null;
285-
}
286-
if (!quantity.getUnit().isPresent()) {
287-
throw new IllegalArgumentException(String.format("Cannot convert a quantity without unit; sample=%s", quantity));
288-
}
289-
return new Quantity.Builder()
290-
.setValue(_unit.convert(quantity.getValue(), quantity.getUnit().get()))
291-
.setUnit(_unit)
292-
.build();
293-
}
294-
295-
private SampleConverter(final Unit convertTo) {
296-
_unit = convertTo;
297-
}
298-
299-
private final Unit _unit;
300-
}
301-
302185
/**
303186
* <code>Builder</code> implementation for <code>Quantity</code>.
304187
*/
@@ -311,6 +194,17 @@ public Builder() {
311194
super((java.util.function.Function<Builder, Quantity>) Quantity::new);
312195
}
313196

197+
/**
198+
* Public constructor.
199+
*
200+
* @param quantity the <code>Quantity</code> to initialize from
201+
*/
202+
public Builder(final Quantity quantity) {
203+
super((java.util.function.Function<Builder, Quantity>) Quantity::new);
204+
_value = quantity._value;
205+
_unit = quantity._unit.orElse(null);
206+
}
207+
314208
/**
315209
* Set the value. Required. Cannot be null.
316210
*
@@ -335,12 +229,21 @@ public Builder setUnit(final Unit value) {
335229

336230
@Override
337231
public Quantity build() {
338-
if (_value == null) {
339-
throw new IllegalStateException("value cannot be null");
340-
}
232+
normalize();
341233
return new Quantity(this);
342234
}
343235

236+
private Builder normalize() {
237+
if (_value != null && _unit != null) {
238+
final Unit defaultUnit = _unit.getType().getDefaultUnit();
239+
if (!Objects.equals(_unit, defaultUnit)) {
240+
_value = defaultUnit.convert(_value, _unit);
241+
_unit = defaultUnit;
242+
}
243+
}
244+
return this;
245+
}
246+
344247
@NotNull
345248
private Double _value;
346249
private Unit _unit;

0 commit comments

Comments
 (0)