Extensible MicrometerMetricsCaptor and polishing
- change `loadCaptor` to return any existing captor - make builders and facades protected to allow subclassing - change `AbstractMeter.getMeter()` to use generics - add test case demonstrating meter name changes - docs * Polishing - PR Comments, and rebase
This commit is contained in:
committed by
Artem Bilan
parent
1d1abf257d
commit
eed5fe7a88
@@ -48,7 +48,7 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
public static final String MICROMETER_CAPTOR_NAME = "integrationMicrometerMetricsCaptor";
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
|
||||
public MicrometerMetricsCaptor(MeterRegistry meterRegistry) {
|
||||
Assert.notNull(meterRegistry, "meterRegistry cannot be null");
|
||||
@@ -81,7 +81,8 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a MicrometerMetricsCaptor to the context if there's a MeterRegistry.
|
||||
* Add a MicrometerMetricsCaptor to the context if there's a MeterRegistry; if
|
||||
* there's already a {@link MetricsCaptor} bean, return that.
|
||||
* @param applicationContext the application context.
|
||||
* @return the instance.
|
||||
*/
|
||||
@@ -93,13 +94,12 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
((GenericApplicationContext) applicationContext).registerBean(MICROMETER_CAPTOR_NAME,
|
||||
MicrometerMetricsCaptor.class,
|
||||
() -> new MicrometerMetricsCaptor(registry));
|
||||
return applicationContext.getBean(MicrometerMetricsCaptor.class);
|
||||
}
|
||||
return applicationContext.getBean(MICROMETER_CAPTOR_NAME, MetricsCaptor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class MicroSample implements SampleFacade {
|
||||
@@ -110,16 +110,17 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
this.sample = sample;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void stop(TimerFacade timer) {
|
||||
this.sample.stop(((MicroTimer) timer).timer);
|
||||
this.sample.stop(((AbstractMeter<Timer>) timer).getMeter());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MicroTimerBuilder implements TimerBuilder {
|
||||
protected static class MicroTimerBuilder implements TimerBuilder {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
|
||||
private final Timer.Builder builder;
|
||||
|
||||
@@ -147,7 +148,7 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
}
|
||||
|
||||
private static abstract class AbstractMeter implements MeterFacade {
|
||||
protected static abstract class AbstractMeter<M extends Meter> implements MeterFacade {
|
||||
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
|
||||
@@ -159,7 +160,7 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
* Get the meter.
|
||||
* @return the meter.
|
||||
*/
|
||||
protected abstract Meter getMeter();
|
||||
protected abstract M getMeter();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@@ -173,17 +174,18 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
}
|
||||
|
||||
}
|
||||
private static class MicroTimer extends AbstractMeter implements TimerFacade {
|
||||
|
||||
protected static class MicroTimer extends AbstractMeter<Timer> implements TimerFacade {
|
||||
|
||||
private final Timer timer;
|
||||
|
||||
MicroTimer(Timer timer, MeterRegistry meterRegistry) {
|
||||
protected MicroTimer(Timer timer, MeterRegistry meterRegistry) {
|
||||
super(meterRegistry);
|
||||
this.timer = timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Meter getMeter() {
|
||||
protected Timer getMeter() {
|
||||
return this.timer;
|
||||
}
|
||||
|
||||
@@ -194,13 +196,13 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
}
|
||||
|
||||
private static class MicroCounterBuilder implements CounterBuilder {
|
||||
protected static class MicroCounterBuilder implements CounterBuilder {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
|
||||
private final Counter.Builder builder;
|
||||
|
||||
MicroCounterBuilder(MeterRegistry meterRegistry, String name) {
|
||||
protected MicroCounterBuilder(MeterRegistry meterRegistry, String name) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
this.builder = Counter.builder(name);
|
||||
}
|
||||
@@ -224,17 +226,17 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
}
|
||||
|
||||
private static class MicroCounter extends AbstractMeter implements CounterFacade {
|
||||
protected static class MicroCounter extends AbstractMeter<Counter> implements CounterFacade {
|
||||
|
||||
private final Counter counter;
|
||||
|
||||
MicroCounter(Counter counter, MeterRegistry meterRegistry) {
|
||||
protected MicroCounter(Counter counter, MeterRegistry meterRegistry) {
|
||||
super(meterRegistry);
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Meter getMeter() {
|
||||
protected Counter getMeter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
@@ -245,13 +247,13 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
}
|
||||
|
||||
private static class MicroGaugeBuilder implements GaugeBuilder {
|
||||
protected static class MicroGaugeBuilder implements GaugeBuilder {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
|
||||
private final Gauge.Builder<Object> builder;
|
||||
|
||||
MicroGaugeBuilder(MeterRegistry meterRegistry, String name, Object obj, ToDoubleFunction<Object> f) {
|
||||
protected MicroGaugeBuilder(MeterRegistry meterRegistry, String name, Object obj, ToDoubleFunction<Object> f) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
this.builder = Gauge.builder(name, obj, f);
|
||||
}
|
||||
@@ -275,17 +277,17 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
}
|
||||
|
||||
private static class MicroGauge extends AbstractMeter implements GaugeFacade {
|
||||
protected static class MicroGauge extends AbstractMeter<Gauge> implements GaugeFacade {
|
||||
|
||||
private final Gauge gauge;
|
||||
|
||||
MicroGauge(Gauge gauge, MeterRegistry meterRegistry) {
|
||||
protected MicroGauge(Gauge gauge, MeterRegistry meterRegistry) {
|
||||
super(meterRegistry);
|
||||
this.gauge = gauge;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Meter getMeter() {
|
||||
protected Gauge getMeter() {
|
||||
return this.gauge;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.support.management.micrometer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.config.EnableIntegrationManagement;
|
||||
import org.springframework.integration.support.management.metrics.MetricsCaptor;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.search.MeterNotFoundException;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 5.1
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class MicrometerCustomMetricsTests {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
@Autowired
|
||||
private QueueChannel queue;
|
||||
|
||||
@Test
|
||||
public void testSend() throws Exception {
|
||||
GenericMessage<String> message = new GenericMessage<>("foo");
|
||||
this.queue.send(message);
|
||||
this.queue.receive();
|
||||
MeterRegistry registry = this.meterRegistry;
|
||||
assertThat(registry.get("spring.integration.channels").gauge().value()).isEqualTo(3);
|
||||
|
||||
assertThat(registry.get("myTimer")
|
||||
.tag("standardTimerName", "spring.integration.send")
|
||||
.tag("name", "queue")
|
||||
.tag("result", "success")
|
||||
.timer().count()).isEqualTo(1);
|
||||
|
||||
assertThat(registry.get("myCounter")
|
||||
.tag("standardCounterName", "spring.integration.receive")
|
||||
.tag("name", "queue")
|
||||
.tag("result", "success")
|
||||
.counter().count()).isEqualTo(1);
|
||||
|
||||
// Test meter removal
|
||||
this.context.close();
|
||||
try {
|
||||
registry.get("myTimer").timers();
|
||||
fail("Expected MeterNotFoundException");
|
||||
}
|
||||
catch (MeterNotFoundException e) {
|
||||
assertThat(e).hasMessageContaining("No meter with name 'myTimer' was found");
|
||||
}
|
||||
try {
|
||||
registry.get("myCounter").counters();
|
||||
fail("Expected MeterNotFoundException");
|
||||
}
|
||||
catch (MeterNotFoundException e) {
|
||||
assertThat(e).hasMessageContaining("No meter with name 'myCounter' was found");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
@EnableIntegrationManagement
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public MeterRegistry meterRegistry() {
|
||||
return new SimpleMeterRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QueueChannel queue() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean(name = MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME)
|
||||
public MetricsCaptor captor() {
|
||||
return new CustomMetricsCaptor(meterRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomMetricsCaptor extends MicrometerMetricsCaptor {
|
||||
|
||||
CustomMetricsCaptor(MeterRegistry meterRegistry) {
|
||||
super(meterRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimerBuilder timerBuilder(String name) {
|
||||
return super.timerBuilder("myTimer")
|
||||
.tag("standardTimerName", name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterBuilder counterBuilder(String name) {
|
||||
return super.counterBuilder("myCounter")
|
||||
.tag("standardCounterName", name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -157,6 +157,9 @@ In addition, there are three `Gauge` Meters:
|
||||
* `spring.integration.handlers`: The number of `MessageHandlers` in the application.
|
||||
* `spring.integration.sources`: The number of `MessageSources` in the application.
|
||||
|
||||
It is possible to customize the names and tags of `Meters` created by integration components by providing a subclass of `MicrometerMetricsCaptor`.
|
||||
The https://github.com/spring-projects/spring-integration/blob/master/spring-integration-core/src/test/java/org/springframework/integration/support/management/micrometer/MicrometerCustomMetricsTests.java[MicrometerCustomMetricsTests] test case shows a simple example of how to do that.
|
||||
You can also further customize the meters by overloading the `build()` methods on builder subclasses.
|
||||
|
||||
[[mgmt-channel-features]]
|
||||
==== `MessageChannel` Metric Features
|
||||
|
||||
@@ -200,3 +200,9 @@ Object name key values are now quoted if they contain any characters other than
|
||||
e.g. `org.springframework.integration:type=MessageChannel,` `name="input:foo.myGroup.errors"`.
|
||||
This has the side effect that previously "allowed" names, with such characters, will now be quoted.
|
||||
e.g. `org.springframework.integration:type=MessageChannel,` `name="input#foo.myGroup.errors"`.
|
||||
|
||||
[[x51.-micrometer]]
|
||||
=== Micrometer Support Changes
|
||||
|
||||
It is now simpler to customize the standard Micrometer meters created by the framework.
|
||||
See <<micrometer-integration>> for more information.
|
||||
|
||||
Reference in New Issue
Block a user