@@ -30,9 +30,9 @@ public class MicrometerMetrics implements Metrics {
3030 private static final String RECONCILIATIONS = "reconciliations." ;
3131 private static final String RECONCILIATIONS_EXECUTIONS = PREFIX + RECONCILIATIONS + "executions." ;
3232 private static final String RECONCILIATIONS_QUEUE_SIZE = PREFIX + RECONCILIATIONS + "queue.size." ;
33+ private final boolean collectPerResourceMetrics ;
3334 private final MeterRegistry registry ;
3435 private final Map <String , AtomicInteger > gauges = new ConcurrentHashMap <>();
35- private final Map <ResourceID , Set <Meter .Id >> metersPerResource = new ConcurrentHashMap <>();
3636 private final Cleaner cleaner ;
3737
3838 /**
@@ -42,43 +42,30 @@ public class MicrometerMetrics implements Metrics {
4242 * @param registry the {@link MeterRegistry} instance to use for metrics recording
4343 */
4444 public MicrometerMetrics (MeterRegistry registry ) {
45- this (registry , 0 );
45+ this (registry , Cleaner . NOOP );
4646 }
4747
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 );
5955 }
6056
6157 /**
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 .
6561 *
6662 * @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
7064 */
71- public MicrometerMetrics (MeterRegistry registry , int cleanUpDelayInSeconds ,
72- int cleaningThreadsNumber ) {
65+ private MicrometerMetrics (MeterRegistry registry , Cleaner cleaner ) {
7366 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 ;
8269 }
8370
8471 @ Override
@@ -153,45 +140,53 @@ private static String getScope(ResourceID resourceID) {
153140
154141 @ Override
155142 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 );
162155 }
163-
164- incrementCounter (event .getRelatedCustomResourceID (), "events.received" ,
165- metadata ,
166- tags );
167156 }
168157
169158 @ Override
170159 public void cleanupDoneFor (ResourceID resourceID , Map <String , Object > metadata ) {
171- incrementCounter (resourceID , "events.delete" , metadata );
160+ if (collectPerResourceMetrics ) {
161+ incrementCounter (resourceID , "events.delete" , metadata );
172162
173- cleaner .removeMetersFor (resourceID );
163+ cleaner .removeMetersFor (resourceID );
164+ }
174165 }
175166
176167 @ Override
177168 public void reconcileCustomResource (HasMetadata resource , RetryInfo retryInfoNullable ,
178169 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+ }
190183 }
191184
192185 @ Override
193186 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+ }
195190 }
196191
197192 @ Override
@@ -215,15 +210,17 @@ public void reconciliationExecutionFinished(HasMetadata resource, Map<String, Ob
215210 @ Override
216211 public void failedReconciliation (HasMetadata resource , Exception exception ,
217212 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 ());
223223 }
224- incrementCounter (ResourceID .fromResource (resource ), RECONCILIATIONS + "failed" , metadata ,
225- "exception" ,
226- cause .getClass ().getSimpleName ());
227224 }
228225
229226 @ Override
@@ -258,48 +255,109 @@ private void incrementCounter(ResourceID id, String counterName, Map<String, Obj
258255 "kind" , gvk .kind ));
259256 }
260257 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 );
262259 counter .increment ();
263260 }
264261
265262 protected Set <Meter .Id > recordedMeterIdsFor (ResourceID resourceID ) {
266- return metersPerResource . get (resourceID );
263+ return cleaner . recordedMeterIdsFor (resourceID );
267264 }
268265
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+ }
271302 }
272303
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 ();
278313 }
279- // then clean-up local recording of associations
280- metersPerResource .remove (resourceID );
281314 }
282315
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+
284324 @ Override
285325 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 );
287343 }
288344 }
289345
290- private class DelayedCleaner implements Cleaner {
346+ private static class DelayedCleaner extends MicrometerMetrics . DefaultCleaner {
291347 private final ScheduledExecutorService metersCleaner ;
292348 private final int cleanUpDelayInSeconds ;
293349
294- private DelayedCleaner (int cleanUpDelayInSeconds , int cleaningThreadsNumber ) {
350+ private DelayedCleaner (MeterRegistry registry , int cleanUpDelayInSeconds ,
351+ int cleaningThreadsNumber ) {
352+ super (registry );
295353 this .cleanUpDelayInSeconds = cleanUpDelayInSeconds ;
296354 this .metersCleaner = Executors .newScheduledThreadPool (cleaningThreadsNumber );
297355 }
298356
299357 @ Override
300358 public void removeMetersFor (ResourceID resourceID ) {
301359 // schedule deletion of meters associated with ResourceID
302- metersCleaner .schedule (() -> MicrometerMetrics . this .removeMetersFor (resourceID ),
360+ metersCleaner .schedule (() -> super .removeMetersFor (resourceID ),
303361 cleanUpDelayInSeconds , TimeUnit .SECONDS );
304362 }
305363 }
0 commit comments