-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Exemplars to metrics generated in aggregate processor #3165
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -6,6 +6,8 @@ | |||
package org.opensearch.dataprepper.plugins.processor.aggregate.actions; | ||||
|
||||
import org.opensearch.dataprepper.model.metric.JacksonSum; | ||||
import org.opensearch.dataprepper.model.metric.Exemplar; | ||||
import org.opensearch.dataprepper.model.metric.DefaultExemplar; | ||||
import org.opensearch.dataprepper.model.annotations.DataPrepperPlugin; | ||||
import org.opensearch.dataprepper.model.annotations.DataPrepperPluginConstructor; | ||||
import org.opensearch.dataprepper.plugins.otel.codec.OTelProtoCodec; | ||||
|
@@ -19,6 +21,7 @@ | |||
import io.opentelemetry.proto.metrics.v1.AggregationTemporality; | ||||
|
||||
import java.time.Instant; | ||||
import java.util.ArrayList; | ||||
import java.util.List; | ||||
import java.time.ZoneId; | ||||
import java.time.format.DateTimeFormatter; | ||||
|
@@ -42,12 +45,14 @@ public class CountAggregateAction implements AggregateAction { | |||
public final String startTimeKey; | ||||
public final String outputFormat; | ||||
private long startTimeNanos; | ||||
private List<Exemplar> exemplarList; | ||||
|
||||
@DataPrepperPluginConstructor | ||||
public CountAggregateAction(final CountAggregateActionConfig countAggregateActionConfig) { | ||||
this.countKey = countAggregateActionConfig.getCountKey(); | ||||
this.startTimeKey = countAggregateActionConfig.getStartTimeKey(); | ||||
this.outputFormat = countAggregateActionConfig.getOutputFormat(); | ||||
this.exemplarList = new ArrayList<>(); | ||||
} | ||||
|
||||
private long getTimeNanos(Instant time) { | ||||
|
@@ -56,13 +61,25 @@ private long getTimeNanos(Instant time) { | |||
return currentTimeNanos; | ||||
} | ||||
|
||||
public Exemplar createExemplar(final Event event) { | ||||
long curTimeNanos = getTimeNanos(Instant.now()); | ||||
Map<String, Object> attributes = event.toMap(); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this is exactly what the attributes is meant to convey. In the model these are And the current code in Data Prepper for metric exemplars uses only the provided Line 326 in 0c7b7cb
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. I do not know why SAP folks called it Attributes in the DataPrepper implementation |
||||
return new DefaultExemplar( | ||||
OTelProtoCodec.convertUnixNanosToISO8601(curTimeNanos), | ||||
1.0, | ||||
event.get("spanId", String.class), // maybe null | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This value should only be found when this is a e.g.
|
||||
event.get("traceId", String.class), // maybe null | ||||
attributes); | ||||
} | ||||
|
||||
@Override | ||||
public AggregateActionResponse handleEvent(final Event event, final AggregateActionInput aggregateActionInput) { | ||||
final GroupState groupState = aggregateActionInput.getGroupState(); | ||||
if (groupState.get(countKey) == null) { | ||||
groupState.put(startTimeKey, Instant.now()); | ||||
groupState.putAll(aggregateActionInput.getIdentificationKeys()); | ||||
groupState.put(countKey, 1); | ||||
exemplarList.add(createExemplar(event)); | ||||
} else { | ||||
Integer v = (Integer)groupState.get(countKey) + 1; | ||||
groupState.put(countKey, v); | ||||
|
@@ -98,6 +115,7 @@ public AggregateActionOutput concludeGroup(final AggregateActionInput aggregateA | |||
.withUnit(SUM_METRIC_UNIT) | ||||
.withAggregationTemporality(AggregationTemporality.AGGREGATION_TEMPORALITY_DELTA.name()) | ||||
.withValue((double)countValue) | ||||
.withExemplars(exemplarList) | ||||
.withAttributes(attr) | ||||
.build(false); | ||||
event = (Event)sum; | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
|
||
import org.opensearch.dataprepper.model.metric.JacksonHistogram; | ||
import org.opensearch.dataprepper.model.metric.Bucket; | ||
import org.opensearch.dataprepper.model.metric.Exemplar; | ||
import org.opensearch.dataprepper.model.metric.DefaultExemplar; | ||
import org.opensearch.dataprepper.model.annotations.DataPrepperPlugin; | ||
import org.opensearch.dataprepper.model.annotations.DataPrepperPluginConstructor; | ||
import org.opensearch.dataprepper.plugins.otel.codec.OTelProtoCodec; | ||
|
@@ -25,6 +27,7 @@ | |
import java.time.ZoneId; | ||
import java.time.format.DateTimeFormatter; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.List; | ||
import java.util.HashMap; | ||
import java.util.Arrays; | ||
|
@@ -53,6 +56,11 @@ public class HistogramAggregateAction implements AggregateAction { | |
private final String key; | ||
private final String units; | ||
private final boolean recordMinMax; | ||
private List<Exemplar> exemplarList; | ||
private Event minEvent; | ||
private Event maxEvent; | ||
private double minValue; | ||
private double maxValue; | ||
|
||
private long startTimeNanos; | ||
private double[] buckets; | ||
|
@@ -62,6 +70,7 @@ public HistogramAggregateAction(final HistogramAggregateActionConfig histogramAg | |
this.key = histogramAggregateActionConfig.getKey(); | ||
List<Number> bucketList = histogramAggregateActionConfig.getBuckets(); | ||
this.buckets = new double[bucketList.size()+2]; | ||
this.exemplarList = new ArrayList<>(); | ||
int bucketIdx = 0; | ||
this.buckets[bucketIdx++] = -Float.MAX_VALUE; | ||
for (int i = 0; i < bucketList.size(); i++) { | ||
|
@@ -101,6 +110,19 @@ private double convertToDouble(Number value) { | |
return doubleValue; | ||
} | ||
|
||
public Exemplar createExemplar(final String id, final Event event, double value) { | ||
long curTimeNanos = getTimeNanos(Instant.now()); | ||
Map<String, Object> attributes = event.toMap(); | ||
if (Objects.nonNull(id)) { | ||
attributes.put("exemplar_id", id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the right naming convention? Does this work with the OpenSearch schemas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed it to |
||
} | ||
return new DefaultExemplar(OTelProtoCodec.convertUnixNanosToISO8601(curTimeNanos), | ||
value, | ||
event.get("spanId", String.class), // maybe null | ||
event.get("traceId", String.class), // maybe null | ||
attributes); | ||
} | ||
|
||
@Override | ||
public AggregateActionResponse handleEvent(final Event event, final AggregateActionInput aggregateActionInput) { | ||
final GroupState groupState = aggregateActionInput.getGroupState(); | ||
|
@@ -126,6 +148,10 @@ public AggregateActionResponse handleEvent(final Event event, final AggregateAct | |
if (this.recordMinMax) { | ||
groupState.put(minKey, doubleValue); | ||
groupState.put(maxKey, doubleValue); | ||
minEvent = event; | ||
maxEvent = event; | ||
minValue = doubleValue; | ||
maxValue = doubleValue; | ||
} | ||
} else { | ||
Integer v = (Integer)groupState.get(countKey) + 1; | ||
|
@@ -138,10 +164,14 @@ public AggregateActionResponse handleEvent(final Event event, final AggregateAct | |
double min = (double)groupState.get(minKey); | ||
if (doubleValue < min) { | ||
groupState.put(minKey, doubleValue); | ||
minEvent = event; | ||
minValue = doubleValue; | ||
} | ||
double max = (double)groupState.get(maxKey); | ||
if (doubleValue > max) { | ||
groupState.put(maxKey, doubleValue); | ||
maxEvent = event; | ||
maxValue = doubleValue; | ||
} | ||
} | ||
} | ||
|
@@ -159,6 +189,8 @@ public AggregateActionOutput concludeGroup(final AggregateActionInput aggregateA | |
long startTimeNanos = getTimeNanos(startTime); | ||
long endTimeNanos = getTimeNanos(endTime); | ||
String histogramKey = HISTOGRAM_METRIC_NAME + "_key"; | ||
exemplarList.add(createExemplar("min", minEvent, minValue)); | ||
exemplarList.add(createExemplar("max", maxEvent, maxValue)); | ||
if (outputFormat.equals(OutputFormat.RAW.toString())) { | ||
groupState.put(histogramKey, key); | ||
groupState.put(durationKey, endTimeNanos-startTimeNanos); | ||
|
@@ -203,6 +235,7 @@ public AggregateActionOutput concludeGroup(final AggregateActionInput aggregateA | |
.withBuckets(buckets) | ||
.withBucketCountsList(bucketCounts) | ||
.withExplicitBoundsList(explicitBoundsList) | ||
.withExemplars(exemplarList) | ||
.withAttributes(attr) | ||
.build(false); | ||
event = (Event)histogram; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub appears to be reporting some sort of formatting error. Is the Markdown correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. When you view it in "RichText Format", it seems to be fine to me.