@@ -45,6 +45,7 @@ class InstrumentHelper {
45
45
private final Map<String , Closure > labelFuncs
46
46
private final Closure instrument
47
47
private final GroovyMetricEnvironment metricEnvironment
48
+ private final boolean aggregateAcrossMBeans
48
49
49
50
/**
50
51
* An InstrumentHelper provides the ability to easily create and update {@link io.opentelemetry.api.metrics.Instrument}
@@ -63,8 +64,9 @@ class InstrumentHelper {
63
64
* (e.g. new OtelHelper().&doubleValueRecorder)
64
65
* @param metricenvironment - The {@link GroovyMetricEnvironment} used to register callbacks onto the SDK meter for
65
66
* batch callbacks used to handle {@link CompositeData}
67
+ * @param aggregateAcrossMBeans - Whether to aggregate multiple MBeans together before recording.
66
68
*/
67
- InstrumentHelper (MBeanHelper mBeanHelper , String instrumentName , String description , String unit , Map<String , Closure<?> > labelFuncs , Map<String , Map<String , Closure<?> > > MBeanAttributes , Closure<?> instrument , GroovyMetricEnvironment metricEnvironment ) {
69
+ InstrumentHelper (MBeanHelper mBeanHelper , String instrumentName , String description , String unit , Map<String , Closure<?> > labelFuncs , Map<String , Map<String , Closure<?> > > MBeanAttributes , Closure<?> instrument , GroovyMetricEnvironment metricEnvironment , boolean aggregateAcrossMBeans ) {
68
70
this . mBeanHelper = mBeanHelper
69
71
this . instrumentName = instrumentName
70
72
this . description = description
@@ -73,6 +75,7 @@ class InstrumentHelper {
73
75
this . mBeanAttributes = MBeanAttributes
74
76
this . instrument = instrument
75
77
this . metricEnvironment = metricEnvironment
78
+ this . aggregateAcrossMBeans = aggregateAcrossMBeans
76
79
}
77
80
78
81
void update () {
@@ -181,19 +184,39 @@ class InstrumentHelper {
181
184
return labels
182
185
}
183
186
187
+ private static String getAggregationKey (String instrumentName , Map<String , String > labels ) {
188
+ def labelsKey = labels. sort(). collect { key , value -> " ${ key} :${ value} " }. join(" ;" )
189
+ return " ${ instrumentName} /${ labelsKey} "
190
+ }
191
+
184
192
// Create a closure for simple attributes that will retrieve mbean information on
185
193
// callback to ensure that metrics are collected on request
186
194
private Closure prepareUpdateClosure (List<GroovyMBean > mbeans , attributes ) {
187
195
return { result ->
196
+ def aggregations = [:] as Map<String , Aggregation >
197
+ boolean requireAggregation = aggregateAcrossMBeans && mbeans. size() > 1 && instrumentIsValue(instrument)
188
198
[mbeans, attributes]. combinations(). each { pair ->
189
199
def (mbean, attribute) = pair
190
200
def value = MBeanHelper . getBeanAttribute(mbean, attribute)
191
201
if (value != null ) {
192
202
def labels = getLabels(mbean, labelFuncs, mBeanAttributes[attribute])
193
- logger. fine(" Recording ${ instrumentName} - ${ instrument.method} w/ ${ value} - ${ labels} " )
194
- recordDataPoint(instrument, result, value, GroovyMetricEnvironment . mapToAttributes(labels))
203
+ if (requireAggregation) {
204
+ def key = getAggregationKey(instrumentName, labels)
205
+ if (aggregations[key] == null ) {
206
+ aggregations[key] = new Aggregation (labels)
207
+ }
208
+ logger. fine(" Aggregating ${ mbean.name()} ${ instrumentName} - ${ instrument.method} w/ ${ value} - ${ labels} " )
209
+ aggregations[key]. add(value)
210
+ } else {
211
+ logger. fine(" Recording ${ mbean.name()} ${ instrumentName} - ${ instrument.method} w/ ${ value} - ${ labels} " )
212
+ recordDataPoint(instrument, result, value, GroovyMetricEnvironment . mapToAttributes(labels))
213
+ }
195
214
}
196
215
}
216
+ aggregations. each { entry ->
217
+ logger. fine(" Recording ${ instrumentName} - ${ instrument.method} - w/ ${ entry.value.value} - ${ entry.value.labels} " )
218
+ recordDataPoint(instrument, result, entry. value. value, GroovyMetricEnvironment . mapToAttributes(entry. value. labels))
219
+ }
197
220
}
198
221
}
199
222
@@ -252,6 +275,14 @@ class InstrumentHelper {
252
275
]. contains(inst. method)
253
276
}
254
277
278
+ @PackageScope
279
+ static boolean instrumentIsValue (inst ) {
280
+ return [
281
+ " doubleValueCallback" ,
282
+ " longValueCallback"
283
+ ]. contains(inst. method)
284
+ }
285
+
255
286
@PackageScope
256
287
static boolean instrumentIsCounter (inst ) {
257
288
return [
@@ -261,4 +292,18 @@ class InstrumentHelper {
261
292
" longUpDownCounter"
262
293
]. contains(inst. method)
263
294
}
295
+
296
+ static class Aggregation {
297
+ private final Map<String , String > labels
298
+ private def value
299
+
300
+ Aggregation (Map<String , String > labels ) {
301
+ this . labels = labels
302
+ this . value = 0.0
303
+ }
304
+
305
+ void add (value ) {
306
+ this . value + = value
307
+ }
308
+ }
264
309
}
0 commit comments