@@ -30,9 +30,9 @@ public class MicrometerMetrics implements Metrics {
30
30
private static final String RECONCILIATIONS = "reconciliations." ;
31
31
private static final String RECONCILIATIONS_EXECUTIONS = PREFIX + RECONCILIATIONS + "executions." ;
32
32
private static final String RECONCILIATIONS_QUEUE_SIZE = PREFIX + RECONCILIATIONS + "queue.size." ;
33
+ private final boolean collectPerResourceMetrics ;
33
34
private final MeterRegistry registry ;
34
35
private final Map <String , AtomicInteger > gauges = new ConcurrentHashMap <>();
35
- private final Map <ResourceID , Set <Meter .Id >> metersPerResource = new ConcurrentHashMap <>();
36
36
private final Cleaner cleaner ;
37
37
38
38
/**
@@ -42,43 +42,30 @@ public class MicrometerMetrics implements Metrics {
42
42
* @param registry the {@link MeterRegistry} instance to use for metrics recording
43
43
*/
44
44
public MicrometerMetrics (MeterRegistry registry ) {
45
- this (registry , 0 );
45
+ this (registry , Cleaner . NOOP );
46
46
}
47
47
48
- /**
49
- * Creates a micrometer-based Metrics implementation that delays cleaning up {@link Meter}s
50
- * associated with deleted resources by the specified amount of seconds, using a single thread for
51
- * that process.
52
- *
53
- * @param registry the {@link MeterRegistry} instance to use for metrics recording
54
- * @param cleanUpDelayInSeconds the number of seconds to wait before meters are removed for
55
- * deleted resources
56
- */
57
- public MicrometerMetrics (MeterRegistry registry , int cleanUpDelayInSeconds ) {
58
- this (registry , cleanUpDelayInSeconds , 1 );
48
+ @ SuppressWarnings ("unused" )
49
+ public static MicrometerMetrics withoutPerResourceMetrics (MeterRegistry registry ) {
50
+ return new MicrometerMetrics (registry );
51
+ }
52
+
53
+ public static MicrometerMetricsBuilder newMicrometerMetrics (MeterRegistry registry ) {
54
+ return new MicrometerMetricsBuilder (registry );
59
55
}
60
56
61
57
/**
62
- * Creates a micrometer-based Metrics implementation that delays cleaning up {@link Meter}s
63
- * associated with deleted resources by the specified amount of seconds, using the specified
64
- * (maximally) number of threads for that process .
58
+ * Creates a micrometer-based Metrics implementation that cleans up {@link Meter}s associated with
59
+ * deleted resources as specified by the (possibly {@code null}) provided {@link Cleaner}
60
+ * instance .
65
61
*
66
62
* @param registry the {@link MeterRegistry} instance to use for metrics recording
67
- * @param cleanUpDelayInSeconds the number of seconds to wait before meters are removed for
68
- * deleted resources
69
- * @param cleaningThreadsNumber the number of threads to use for the cleaning process
63
+ * @param cleaner the {@link Cleaner} to use
70
64
*/
71
- public MicrometerMetrics (MeterRegistry registry , int cleanUpDelayInSeconds ,
72
- int cleaningThreadsNumber ) {
65
+ private MicrometerMetrics (MeterRegistry registry , Cleaner cleaner ) {
73
66
this .registry = registry ;
74
- if (cleanUpDelayInSeconds < 0 ) {
75
- cleaner = new NoDelayCleaner ();
76
- } else {
77
- cleaningThreadsNumber =
78
- cleaningThreadsNumber <= 0 ? Runtime .getRuntime ().availableProcessors ()
79
- : cleaningThreadsNumber ;
80
- cleaner = new DelayedCleaner (cleanUpDelayInSeconds , cleaningThreadsNumber );
81
- }
67
+ this .cleaner = cleaner ;
68
+ this .collectPerResourceMetrics = Cleaner .NOOP != cleaner ;
82
69
}
83
70
84
71
@ Override
@@ -153,45 +140,53 @@ private static String getScope(ResourceID resourceID) {
153
140
154
141
@ Override
155
142
public void receivedEvent (Event event , Map <String , Object > metadata ) {
156
- final String [] tags ;
157
- if (event instanceof ResourceEvent ) {
158
- tags = new String [] {"event" , event .getClass ().getSimpleName (), "action" ,
159
- ((ResourceEvent ) event ).getAction ().toString ()};
160
- } else {
161
- tags = new String [] {"event" , event .getClass ().getSimpleName ()};
143
+ if (collectPerResourceMetrics ) {
144
+ final String [] tags ;
145
+ if (event instanceof ResourceEvent ) {
146
+ tags = new String [] {"event" , event .getClass ().getSimpleName (), "action" ,
147
+ ((ResourceEvent ) event ).getAction ().toString ()};
148
+ } else {
149
+ tags = new String [] {"event" , event .getClass ().getSimpleName ()};
150
+ }
151
+
152
+ incrementCounter (event .getRelatedCustomResourceID (), "events.received" ,
153
+ metadata ,
154
+ tags );
162
155
}
163
-
164
- incrementCounter (event .getRelatedCustomResourceID (), "events.received" ,
165
- metadata ,
166
- tags );
167
156
}
168
157
169
158
@ Override
170
159
public void cleanupDoneFor (ResourceID resourceID , Map <String , Object > metadata ) {
171
- incrementCounter (resourceID , "events.delete" , metadata );
160
+ if (collectPerResourceMetrics ) {
161
+ incrementCounter (resourceID , "events.delete" , metadata );
172
162
173
- cleaner .removeMetersFor (resourceID );
163
+ cleaner .removeMetersFor (resourceID );
164
+ }
174
165
}
175
166
176
167
@ Override
177
168
public void reconcileCustomResource (HasMetadata resource , RetryInfo retryInfoNullable ,
178
169
Map <String , Object > metadata ) {
179
- Optional <RetryInfo > retryInfo = Optional .ofNullable (retryInfoNullable );
180
- incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "started" ,
181
- metadata ,
182
- RECONCILIATIONS + "retries.number" ,
183
- String .valueOf (retryInfo .map (RetryInfo ::getAttemptCount ).orElse (0 )),
184
- RECONCILIATIONS + "retries.last" ,
185
- String .valueOf (retryInfo .map (RetryInfo ::isLastAttempt ).orElse (true )));
186
-
187
- var controllerQueueSize =
188
- gauges .get (RECONCILIATIONS_QUEUE_SIZE + metadata .get (CONTROLLER_NAME ));
189
- controllerQueueSize .incrementAndGet ();
170
+ if (collectPerResourceMetrics ) {
171
+ Optional <RetryInfo > retryInfo = Optional .ofNullable (retryInfoNullable );
172
+ incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "started" ,
173
+ metadata ,
174
+ RECONCILIATIONS + "retries.number" ,
175
+ String .valueOf (retryInfo .map (RetryInfo ::getAttemptCount ).orElse (0 )),
176
+ RECONCILIATIONS + "retries.last" ,
177
+ String .valueOf (retryInfo .map (RetryInfo ::isLastAttempt ).orElse (true )));
178
+
179
+ var controllerQueueSize =
180
+ gauges .get (RECONCILIATIONS_QUEUE_SIZE + metadata .get (CONTROLLER_NAME ));
181
+ controllerQueueSize .incrementAndGet ();
182
+ }
190
183
}
191
184
192
185
@ Override
193
186
public void finishedReconciliation (HasMetadata resource , Map <String , Object > metadata ) {
194
- incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "success" , metadata );
187
+ if (collectPerResourceMetrics ) {
188
+ incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "success" , metadata );
189
+ }
195
190
}
196
191
197
192
@ Override
@@ -215,15 +210,17 @@ public void reconciliationExecutionFinished(HasMetadata resource, Map<String, Ob
215
210
@ Override
216
211
public void failedReconciliation (HasMetadata resource , Exception exception ,
217
212
Map <String , Object > metadata ) {
218
- var cause = exception .getCause ();
219
- if (cause == null ) {
220
- cause = exception ;
221
- } else if (cause instanceof RuntimeException ) {
222
- cause = cause .getCause () != null ? cause .getCause () : cause ;
213
+ if (collectPerResourceMetrics ) {
214
+ var cause = exception .getCause ();
215
+ if (cause == null ) {
216
+ cause = exception ;
217
+ } else if (cause instanceof RuntimeException ) {
218
+ cause = cause .getCause () != null ? cause .getCause () : cause ;
219
+ }
220
+ incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "failed" , metadata ,
221
+ "exception" ,
222
+ cause .getClass ().getSimpleName ());
223
223
}
224
- incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "failed" , metadata ,
225
- "exception" ,
226
- cause .getClass ().getSimpleName ());
227
224
}
228
225
229
226
@ Override
@@ -258,48 +255,109 @@ private void incrementCounter(ResourceID id, String counterName, Map<String, Obj
258
255
"kind" , gvk .kind ));
259
256
}
260
257
final var counter = registry .counter (PREFIX + counterName , tags .toArray (new String [0 ]));
261
- metersPerResource . computeIfAbsent (id , resourceID -> new HashSet <>()). add ( counter . getId () );
258
+ cleaner . recordAssociation (id , counter );
262
259
counter .increment ();
263
260
}
264
261
265
262
protected Set <Meter .Id > recordedMeterIdsFor (ResourceID resourceID ) {
266
- return metersPerResource . get (resourceID );
263
+ return cleaner . recordedMeterIdsFor (resourceID );
267
264
}
268
265
269
- private interface Cleaner {
270
- void removeMetersFor (ResourceID resourceID );
266
+ public static class MicrometerMetricsBuilder {
267
+ private final MeterRegistry registry ;
268
+ private int cleaningThreadsNumber ;
269
+ private int cleanUpDelayInSeconds ;
270
+
271
+ private MicrometerMetricsBuilder (MeterRegistry registry ) {
272
+ this .registry = registry ;
273
+ }
274
+
275
+ public MicrometerMetricsBuilder withCleaningThreadNumber (int cleaningThreadsNumber ) {
276
+ this .cleaningThreadsNumber = cleaningThreadsNumber ;
277
+ return this ;
278
+ }
279
+
280
+ /**
281
+ * @param cleanUpDelayInSeconds the number of seconds to wait before meters are removed for
282
+ * deleted resources
283
+ */
284
+ public MicrometerMetricsBuilder withCleanUpDelayInSeconds (int cleanUpDelayInSeconds ) {
285
+ this .cleanUpDelayInSeconds = cleanUpDelayInSeconds ;
286
+ return this ;
287
+ }
288
+
289
+ public MicrometerMetrics build () {
290
+ MicrometerMetrics .Cleaner cleaner ;
291
+ if (cleanUpDelayInSeconds < 0 ) {
292
+ cleaner = new MicrometerMetrics .DefaultCleaner (registry );
293
+ } else {
294
+ cleaningThreadsNumber =
295
+ cleaningThreadsNumber <= 0 ? Runtime .getRuntime ().availableProcessors ()
296
+ : cleaningThreadsNumber ;
297
+ cleaner = new DelayedCleaner (registry , cleanUpDelayInSeconds , cleaningThreadsNumber );
298
+ }
299
+
300
+ return new MicrometerMetrics (registry , cleaner );
301
+ }
271
302
}
272
303
273
- private void removeMetersFor (ResourceID resourceID ) {
274
- // remove each meter
275
- final var toClean = metersPerResource .get (resourceID );
276
- if (toClean != null ) {
277
- toClean .forEach (registry ::remove );
304
+ private interface Cleaner {
305
+ Cleaner NOOP = new Cleaner () {};
306
+
307
+ default void removeMetersFor (ResourceID resourceID ) {}
308
+
309
+ default void recordAssociation (ResourceID resourceID , Meter meter ) {}
310
+
311
+ default Set <Meter .Id > recordedMeterIdsFor (ResourceID resourceID ) {
312
+ return Collections .emptySet ();
278
313
}
279
- // then clean-up local recording of associations
280
- metersPerResource .remove (resourceID );
281
314
}
282
315
283
- private class NoDelayCleaner implements Cleaner {
316
+ private static class DefaultCleaner implements Cleaner {
317
+ private final Map <ResourceID , Set <Meter .Id >> metersPerResource = new ConcurrentHashMap <>();
318
+ private final MeterRegistry registry ;
319
+
320
+ private DefaultCleaner (MeterRegistry registry ) {
321
+ this .registry = registry ;
322
+ }
323
+
284
324
@ Override
285
325
public void removeMetersFor (ResourceID resourceID ) {
286
- MicrometerMetrics .this .removeMetersFor (resourceID );
326
+ // remove each meter
327
+ final var toClean = metersPerResource .get (resourceID );
328
+ if (toClean != null ) {
329
+ toClean .forEach (registry ::remove );
330
+ }
331
+ // then clean-up local recording of associations
332
+ metersPerResource .remove (resourceID );
333
+ }
334
+
335
+ @ Override
336
+ public void recordAssociation (ResourceID resourceID , Meter meter ) {
337
+ metersPerResource .computeIfAbsent (resourceID , id -> new HashSet <>()).add (meter .getId ());
338
+ }
339
+
340
+ @ Override
341
+ public Set <Meter .Id > recordedMeterIdsFor (ResourceID resourceID ) {
342
+ return metersPerResource .get (resourceID );
287
343
}
288
344
}
289
345
290
- private class DelayedCleaner implements Cleaner {
346
+ private static class DelayedCleaner extends MicrometerMetrics . DefaultCleaner {
291
347
private final ScheduledExecutorService metersCleaner ;
292
348
private final int cleanUpDelayInSeconds ;
293
349
294
- private DelayedCleaner (int cleanUpDelayInSeconds , int cleaningThreadsNumber ) {
350
+ private DelayedCleaner (MeterRegistry registry , int cleanUpDelayInSeconds ,
351
+ int cleaningThreadsNumber ) {
352
+ super (registry );
295
353
this .cleanUpDelayInSeconds = cleanUpDelayInSeconds ;
296
354
this .metersCleaner = Executors .newScheduledThreadPool (cleaningThreadsNumber );
297
355
}
298
356
299
357
@ Override
300
358
public void removeMetersFor (ResourceID resourceID ) {
301
359
// schedule deletion of meters associated with ResourceID
302
- metersCleaner .schedule (() -> MicrometerMetrics . this .removeMetersFor (resourceID ),
360
+ metersCleaner .schedule (() -> super .removeMetersFor (resourceID ),
303
361
cleanUpDelayInSeconds , TimeUnit .SECONDS );
304
362
}
305
363
}
0 commit comments