Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@
// new MetricInfo(
// "my.own.jvm.memory.pool.used",
// "Pool memory currently used",
// null,
// "By",
// MetricInfo.Type.UPDOWNCOUNTER);
// MetricInfo poolLimitInfo =
// new MetricInfo(
// "my.own.jvm.memory.pool.limit",
// "Maximum obtainable memory pool size",
// null,
// "By",
// MetricInfo.Type.UPDOWNCOUNTER);
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum Type {
// How to report the metric using OpenTelemetry API
private final String metricName; // used as Instrument name
@Nullable private final String description;
@Nullable private final String sourceUnit;
@Nullable private final String unit;
private final Type type;

Expand All @@ -35,13 +36,19 @@ public enum Type {
*
* @param metricName a String that will be used as a metric name, it should be unique
* @param description a human readable description of the metric
* @param sourceUnit a human readable unit of measurement that is received from metric source
* @param unit a human readable unit of measurement
* @param type the instrument typ to be used for the metric
*/
public MetricInfo(
String metricName, @Nullable String description, String unit, @Nullable Type type) {
String metricName,
@Nullable String description,
@Nullable String sourceUnit,
@Nullable String unit,
@Nullable Type type) {
this.metricName = metricName;
this.description = description;
this.sourceUnit = sourceUnit;
this.unit = unit;
this.type = type == null ? Type.GAUGE : type;
}
Expand All @@ -55,6 +62,11 @@ public String getDescription() {
return description;
}

@Nullable
public String getSourceUnit() {
return sourceUnit;
}

@Nullable
public String getUnit() {
return unit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import io.opentelemetry.instrumentation.jmx.engine.unit.UnitConverter;
import io.opentelemetry.instrumentation.jmx.engine.unit.UnitConverterFactory;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

Expand Down Expand Up @@ -61,6 +64,7 @@ void enrollExtractor(
return;
}

boolean recordDoubleValue = attributeInfo.usesDoubleValues();
MetricInfo metricInfo = extractor.getInfo();
String metricName = metricInfo.getMetricName();
MetricInfo.Type instrumentType = metricInfo.getType();
Expand All @@ -69,6 +73,12 @@ void enrollExtractor(
? metricInfo.getDescription()
: attributeInfo.getDescription();
String unit = metricInfo.getUnit();
String sourceUnit = metricInfo.getSourceUnit();

UnitConverter unitConverter = UnitConverterFactory.getConverter(sourceUnit, unit);
if (unitConverter != null) {
recordDoubleValue = unitConverter.isConvertingToDouble();
}

switch (instrumentType) {
// CHECKSTYLE:OFF
Expand All @@ -79,10 +89,10 @@ void enrollExtractor(
Optional.ofNullable(description).ifPresent(builder::setDescription);
Optional.ofNullable(unit).ifPresent(builder::setUnit);

if (attributeInfo.usesDoubleValues()) {
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor));
if (recordDoubleValue) {
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor, unitConverter));
} else {
builder.buildWithCallback(longTypeCallback(extractor));
builder.buildWithCallback(longTypeCallback(extractor, unitConverter));
}
logger.log(INFO, "Created Counter for {0}", metricName);
}
Expand All @@ -96,10 +106,10 @@ void enrollExtractor(
Optional.ofNullable(description).ifPresent(builder::setDescription);
Optional.ofNullable(unit).ifPresent(builder::setUnit);

if (attributeInfo.usesDoubleValues()) {
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor));
if (recordDoubleValue) {
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor, unitConverter));
} else {
builder.buildWithCallback(longTypeCallback(extractor));
builder.buildWithCallback(longTypeCallback(extractor, unitConverter));
}
logger.log(INFO, "Created UpDownCounter for {0}", metricName);
}
Expand All @@ -113,10 +123,10 @@ void enrollExtractor(
Optional.ofNullable(description).ifPresent(builder::setDescription);
Optional.ofNullable(unit).ifPresent(builder::setUnit);

if (attributeInfo.usesDoubleValues()) {
builder.buildWithCallback(doubleTypeCallback(extractor));
if (recordDoubleValue) {
builder.buildWithCallback(doubleTypeCallback(extractor, unitConverter));
} else {
builder.ofLongs().buildWithCallback(longTypeCallback(extractor));
builder.ofLongs().buildWithCallback(longTypeCallback(extractor, unitConverter));
}
logger.log(INFO, "Created Gauge for {0}", metricName);
}
Expand All @@ -133,8 +143,10 @@ void enrollExtractor(
/*
* A method generating metric collection callback for asynchronous Measurement
* of Double type.
* If unit converter is provided then conversion is applied before metric is recorded.
*/
static Consumer<ObservableDoubleMeasurement> doubleTypeCallback(MetricExtractor extractor) {
static Consumer<ObservableDoubleMeasurement> doubleTypeCallback(
MetricExtractor extractor, @Nullable UnitConverter unitConverter) {
return measurement -> {
DetectionStatus status = extractor.getStatus();
if (status != null) {
Expand All @@ -145,6 +157,10 @@ static Consumer<ObservableDoubleMeasurement> doubleTypeCallback(MetricExtractor
if (metricValue != null) {
// get the metric attributes
Attributes attr = createMetricAttributes(connection, objectName, extractor);

if (unitConverter != null) {
metricValue = unitConverter.convert(metricValue);
}
measurement.record(metricValue.doubleValue(), attr);
}
}
Expand All @@ -155,8 +171,10 @@ static Consumer<ObservableDoubleMeasurement> doubleTypeCallback(MetricExtractor
/*
* A method generating metric collection callback for asynchronous Measurement
* of Long type.
* If unit converter is provided then conversion is applied before metric is recorded.
*/
static Consumer<ObservableLongMeasurement> longTypeCallback(MetricExtractor extractor) {
static Consumer<ObservableLongMeasurement> longTypeCallback(
MetricExtractor extractor, @Nullable UnitConverter unitConverter) {
return measurement -> {
DetectionStatus status = extractor.getStatus();
if (status != null) {
Expand All @@ -167,6 +185,10 @@ static Consumer<ObservableLongMeasurement> longTypeCallback(MetricExtractor extr
if (metricValue != null) {
// get the metric attributes
Attributes attr = createMetricAttributes(connection, objectName, extractor);

if (unitConverter != null) {
metricValue = unitConverter.convert(metricValue);
}
measurement.record(metricValue.longValue(), attr);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.jmx.engine.unit;

import java.util.function.Function;

/** This class is responsible for converting a value using provided algorithm. */
public class UnitConverter {
private final Function<Number, Number> convertingFunction;
private final boolean convertToDouble;

/**
* Create an instance of converter
*
* @param convertingFunction an algorithm applied when converting value
* @param convertToDouble indicates of algorithm will return floating point result. This must be
* in-sync with algorithm implementation.
*/
UnitConverter(Function<Number, Number> convertingFunction, boolean convertToDouble) {
this.convertingFunction = convertingFunction;
this.convertToDouble = convertToDouble;
}

public Number convert(Number value) {
return convertingFunction.apply(value);
}

public boolean isConvertingToDouble() {
return convertToDouble;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.jmx.engine.unit;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import javax.annotation.Nullable;

public class UnitConverterFactory {

private static final Map<String, Map<String, UnitConverter>> conversionMappings = new HashMap<>();

static {
registerConverter("ms", "s", value -> value.doubleValue() / TimeUnit.SECONDS.toMillis(1), true);
registerConverter("ns", "s", value -> value.doubleValue() / TimeUnit.SECONDS.toNanos(1), true);
}

private UnitConverterFactory() {}

public static UnitConverter getConverter(@Nullable String fromUnit, @Nullable String toUnit) {
if (fromUnit == null || toUnit == null) {
return null;
}

Map<String, UnitConverter> converters = conversionMappings.get(fromUnit);
if (converters == null) {
return null;
}

return converters.get(toUnit);
}

public static void registerConverter(
String sourceUnit,
String targetUnit,
Function<Number, Number> convertingFunction,
boolean convertToDouble) {
Map<String, UnitConverter> converters =
conversionMappings.computeIfAbsent(sourceUnit, k -> new HashMap<>());

if (converters.containsKey(targetUnit)) {
throw new IllegalArgumentException(
"Converter from " + sourceUnit + " to " + targetUnit + " already registered");
}
converters.put(targetUnit, new UnitConverter(convertingFunction, convertToDouble));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class JmxRule extends MetricStructure {
@Nullable private String prefix;
private Map<String, Metric> mapping;

@Nullable
public String getBean() {
return bean;
}
Expand Down Expand Up @@ -90,6 +91,7 @@ private String validatePrefix(String prefix) {
return prefix;
}

@Nullable
public String getPrefix() {
return prefix;
}
Expand Down Expand Up @@ -152,6 +154,7 @@ public MetricDef buildMetricDef() throws Exception {
new MetricInfo(
prefix == null ? niceAttributeName : (prefix + niceAttributeName),
null,
getSourceUnit(),
getUnit(),
getMetricType());
} else {
Expand Down Expand Up @@ -226,6 +229,7 @@ protected Number extractNumericalAttribute(
new MetricInfo(
metricInfo.getMetricName(),
metricInfo.getDescription(),
metricInfo.getSourceUnit(),
metricInfo.getUnit(),
MetricInfo.Type.UPDOWNCOUNTER);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Metric extends MetricStructure {
@Nullable private String metric;
@Nullable private String desc;

@Nullable
public String getMetric() {
return metric;
}
Expand All @@ -35,6 +36,7 @@ private String validateMetricName(String name) {
return name;
}

@Nullable
public String getDesc() {
return desc;
}
Expand All @@ -61,11 +63,13 @@ MetricInfo buildMetricInfo(
metricType = defaultType;
}

String sourceUnit = getSourceUnit();

String unit = getUnit();
if (unit == null) {
unit = defaultUnit;
}

return new MetricInfo(metricName, desc, unit, metricType);
return new MetricInfo(metricName, desc, sourceUnit, unit, metricType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ abstract class MetricStructure {
private Map<String, Object> metricAttribute;
private StateMapping stateMapping = StateMapping.empty();
private static final String STATE_MAPPING_DEFAULT = "*";
private String sourcetUnit;
private String unit;

private MetricInfo.Type metricType;
Expand All @@ -58,6 +59,14 @@ void setType(String t) {
this.metricType = MetricInfo.Type.valueOf(t);
}

public String getSourceUnit() {
return sourcetUnit;
}

public void setSourceUnit(String unit) {
this.sourcetUnit = validateUnit(unit.trim());
}

public String getUnit() {
return unit;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ private static void parseMetricStructure(
if (unit != null) {
out.setUnit(unit);
}
String sourceUnit = (String) metricStructureYaml.remove("sourceUnit");
if (sourceUnit != null) {
out.setSourceUnit(sourceUnit);
}
}

private static void failOnExtraKeys(Map<String, Object> yaml) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static void setup() {
+ " ATTRIBUTE2:\n"
+ " metric: METRIC_NAME2\n"
+ " desc: DESCRIPTION2\n"
+ " sourceUnit: SOURCE_UNIT2\n"
+ " unit: UNIT2\n"
+ " ATTRIBUTE3:\n"
+ " ATTRIBUTE4:\n"
Expand Down Expand Up @@ -95,13 +96,15 @@ void testConf2() {
assertThat(m1).isNotNull();
assertThat(m1.getMetric()).isEqualTo("METRIC_NAME1");
assertThat(m1.getMetricType()).isEqualTo(MetricInfo.Type.GAUGE);
assertThat(m1.getSourceUnit()).isNull();
assertThat(m1.getUnit()).isEqualTo("UNIT1");
assertThat(m1.getMetricAttribute()).containsExactly(entry("LABEL_KEY3", "const(CONSTANT)"));

Metric m2 = attr.get("ATTRIBUTE2");
assertThat(m2).isNotNull();
assertThat(m2.getMetric()).isEqualTo("METRIC_NAME2");
assertThat(m2.getDesc()).isEqualTo("DESCRIPTION2");
assertThat(m2.getSourceUnit()).isEqualTo("SOURCE_UNIT2");
assertThat(m2.getUnit()).isEqualTo("UNIT2");

JmxRule def2 = defs.get(1);
Expand Down
Loading
Loading