Skip to content

Commit

Permalink
Issue ReactiveX#72: Created a CircuitBreakerMetrics class which can b…
Browse files Browse the repository at this point in the history
…e used to export CircuitBreaker.Metrics as Dropwizard Metrics Gauges.
  • Loading branch information
RobWin authored Apr 3, 2017
1 parent ad68445 commit f276112
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 4 deletions.
2 changes: 2 additions & 0 deletions resilience4j-metrics/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dependencies {
compile (libraries.metrics)
compileOnly project(':resilience4j-circuitbreaker')
testCompile project(':resilience4j-test')
testCompile project(':resilience4j-circuitbreaker')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
*
* Copyright 2017: Robert Winkler
*
* 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 io.github.resilience4j.metrics;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.MetricSet;

import java.util.Map;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import javaslang.collection.Array;
import javaslang.collection.Seq;

import static com.codahale.metrics.MetricRegistry.name;

/**
* An adapter which exports {@link CircuitBreaker.Metrics} as Dropwizard Metrics Gauges.
*/
public class CircuitBreakerMetrics implements MetricSet{

private final MetricRegistry metricRegistry = new MetricRegistry();

private CircuitBreakerMetrics(Seq<CircuitBreaker> circuitBreakers){
circuitBreakers.forEach(circuitBreaker -> {
String name = circuitBreaker.getName();
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();

metricRegistry.register(name("resilience4j.circuitbreaker", name, "successful"),
(Gauge<Integer>) metrics::getNumberOfSuccessfulCalls);
metricRegistry.register(name("resilience4j.circuitbreaker", name, "failed"),
(Gauge<Integer>) metrics::getNumberOfFailedCalls);
metricRegistry.register(name("resilience4j.circuitbreaker", name, "not_permitted"),
(Gauge<Long>) metrics::getNumberOfNotPermittedCalls);
metricRegistry.register(name("resilience4j.circuitbreaker", name, "buffered"),
(Gauge<Integer>) metrics::getNumberOfBufferedCalls);
metricRegistry.register(name("resilience4j.circuitbreaker", name, "buffered_max"),
(Gauge<Integer>) metrics::getMaxNumberOfBufferedCalls);
}
);
}

public static CircuitBreakerMetrics of(CircuitBreakerRegistry circuitBreakerRegistry) {
return new CircuitBreakerMetrics(circuitBreakerRegistry.getAllCircuitBreakers());
}

public static CircuitBreakerMetrics of(Seq<CircuitBreaker> circuitBreakers) {
return new CircuitBreakerMetrics(circuitBreakers);
}

public static CircuitBreakerMetrics of(CircuitBreaker circuitBreaker) {
return new CircuitBreakerMetrics(Array.of(circuitBreaker));
}

@Override
public Map<String, Metric> getMetrics() {
return metricRegistry.getMetrics();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
*
* Copyright 2017: Robert Winkler
*
* 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 io.github.resilience4j.metrics;

import com.codahale.metrics.MetricRegistry;

import org.junit.Before;
import org.junit.Test;
import org.mockito.BDDMockito;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.test.HelloWorldService;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;

public class CircuitBreakerMetricsTest {

private MetricRegistry metricRegistry;
private HelloWorldService helloWorldService;

@Before
public void setUp(){
metricRegistry = new MetricRegistry();
helloWorldService = mock(HelloWorldService.class);
}

@Test
public void shouldRegisterMetrics() throws Throwable {
//Given
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults();
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName");
metricRegistry.registerAll(CircuitBreakerMetrics.of(circuitBreakerRegistry));

// Given the HelloWorldService returns Hello world
BDDMockito.given(helloWorldService.returnHelloWorld()).willReturn("Hello world");

//When
String value = circuitBreaker.executeSupplier(helloWorldService::returnHelloWorld);

//Then
assertThat(value).isEqualTo("Hello world");
// Then the helloWorldService should be invoked 1 time
BDDMockito.then(helloWorldService).should(times(1)).returnHelloWorld();
assertThat(metricRegistry.getMetrics()).hasSize(5);
assertThat(metricRegistry.getGauges().get("resilience4j.circuitbreaker.testName.buffered").getValue()).isEqualTo(1);
assertThat(metricRegistry.getGauges().get("resilience4j.circuitbreaker.testName.successful").getValue()).isEqualTo(1);
assertThat(metricRegistry.getGauges().get("resilience4j.circuitbreaker.testName.failed").getValue()).isEqualTo(0);
assertThat(metricRegistry.getGauges().get("resilience4j.circuitbreaker.testName.not_permitted").getValue()).isEqualTo(0L);
assertThat(metricRegistry.getGauges().get("resilience4j.circuitbreaker.testName.buffered_max").getValue()).isEqualTo(100);

}
}
6 changes: 4 additions & 2 deletions resilience4j-prometheus/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
dependencies {
compile (libraries.prometheus_simpleclient)
compile project(':resilience4j-circuitbreaker')
compile project(':resilience4j-ratelimiter')
compileOnly project(':resilience4j-circuitbreaker')
compileOnly project(':resilience4j-ratelimiter')
testCompile project(':resilience4j-circuitbreaker')
testCompile project(':resilience4j-ratelimiter')
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@
public class CircuitBreakerAutoConfiguration {

@Bean
public CircuitBreakerRegistry circuitBreakerRegistry(){
return new InMemoryCircuitBreakerRegistry();
public CircuitBreakerRegistry circuitBreakerRegistry(CircuitBreakerProperties circuitBreakerProperties){
CircuitBreakerRegistry circuitBreakerRegistry = new InMemoryCircuitBreakerRegistry();
circuitBreakerProperties.getBackends().forEach(
(name, properties) -> circuitBreakerRegistry.circuitBreaker(name, circuitBreakerProperties
.createCircuitBreakerConfig(name))
);
return circuitBreakerRegistry;
}

@Bean
Expand Down

0 comments on commit f276112

Please sign in to comment.