Skip to content

Commit

Permalink
Add bulkhead metrics support for Prometheus (ReactiveX#308)
Browse files Browse the repository at this point in the history
  • Loading branch information
vwallden authored and RobWin committed Jan 22, 2019
1 parent 807fee0 commit 0a979f3
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 14 deletions.
2 changes: 2 additions & 0 deletions resilience4j-prometheus/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ dependencies {
compile (libraries.prometheus_simpleclient)
compileOnly project(':resilience4j-circuitbreaker')
compileOnly project(':resilience4j-ratelimiter')
compileOnly project(':resilience4j-bulkhead')
testCompile project(':resilience4j-circuitbreaker')
testCompile project(':resilience4j-ratelimiter')
testCompile project(':resilience4j-bulkhead')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
*
* Copyright 2018 Valtteri Walldén
*
* 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.prometheus;

import java.util.List;
import java.util.function.Supplier;

import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadRegistry;
import io.prometheus.client.Collector;
import io.prometheus.client.GaugeMetricFamily;
import io.vavr.collection.Array;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;

/**
* An adapter from builtin {@link Bulkhead.Metrics} to prometheus
* {@link io.prometheus.client.CollectorRegistry}.
*/
public class BulkheadExports extends Collector {
private static final String DEFAULT_NAME = "resilience4j_bulkhead";

private final String name;
private final Supplier<Iterable<Bulkhead>> bulkheadsSupplier;

/**
* Creates a new instance of {@link BulkheadExports} with specified metrics names prefix and
* {@link Supplier} of bulkheads
*
* @param prefix the prefix of metrics names
* @param bulkheadSupplier the supplier of bulkheads
*/
public static BulkheadExports ofSupplier(String prefix, Supplier<Iterable<Bulkhead>> bulkheadSupplier) {
return new BulkheadExports(prefix, bulkheadSupplier);
}

/**
* Creates a new instance of {@link BulkheadExports} with default metrics names prefix and
* {@link Supplier} of bulkheads
*
* @param bulkheadSupplier the supplier of bulkheads
*/
public static BulkheadExports ofSupplier(Supplier<Iterable<Bulkhead>> bulkheadSupplier) {
return new BulkheadExports(DEFAULT_NAME, bulkheadSupplier);
}

/**
* Creates a new instance of {@link BulkheadExports} with default metrics names prefix and
* {@link BulkheadRegistry} as a source of bulkheads.
* @param bulkheadRegistry the registry of bulkheads
*/
public static BulkheadExports ofBulkheadRegistry(BulkheadRegistry bulkheadRegistry) {
return new BulkheadExports(bulkheadRegistry.getAllBulkheads());
}

/**
* Creates a new instance of {@link BulkheadExports} with default metrics names prefix and
* a bulkhead as a source.
*
* @param bulkhead the bulkhead
*/
public static BulkheadExports ofBulkhead(Bulkhead bulkhead) {
return new BulkheadExports(Array.of(bulkhead));
}


/**
* Creates a new instance of {@link BulkheadExports} with default metrics names prefix and
* {@link Iterable} of bulkheads.
*
* @param bulkheads the bulkheads
*/
public static BulkheadExports ofIterable(Iterable<Bulkhead> bulkheads) {
return new BulkheadExports(bulkheads);
}

/**
* Creates a new instance of {@link BulkheadExports} with specified metrics names prefix and
* {@link BulkheadRegistry} as a source of bulkheads.
*
* @param prefix the prefix of metrics names
* @param bulkheadRegistry the registry of bulkheads
*/
public static BulkheadExports ofBulkheadRegistry(String prefix, BulkheadRegistry bulkheadRegistry) {
return new BulkheadExports(prefix, bulkheadRegistry);
}

/**
* Creates a new instance of {@link BulkheadExports} with specified metrics names prefix and
* {@link Iterable} of bulkheads.
*
* @param prefix the prefix of metrics names
* @param bulkheads the bulkheads
*/
public static BulkheadExports ofIterable(String prefix, Iterable<Bulkhead> bulkheads) {
return new BulkheadExports(prefix, bulkheads);
}


/**
* Creates a new instance of {@link BulkheadExports} with default metrics names prefix and
* a bulkhead as a source.
*
* @param prefix the prefix of metrics names
* @param bulkhead the bulkhead
*/
public static BulkheadExports ofBulkhead(String prefix, Bulkhead bulkhead) {
return new BulkheadExports(prefix, Array.of(bulkhead));
}


/**
* Creates a new instance of {@link BulkheadExports} with default metric name and
* {@link BulkheadRegistry}.
*
* @param bulkheadRegistry the bulkhead registry
*/
private BulkheadExports(BulkheadRegistry bulkheadRegistry) {
this(bulkheadRegistry::getAllBulkheads);
}

/**
* Creates a new instance of {@link BulkheadExports} with default metric name and
* {@link Iterable} of bulkheads.
*
* @param bulkheads the bulkheads
*/
private BulkheadExports(Iterable<Bulkhead> bulkheads) {
this(() -> bulkheads);
}

/**
* Creates a new instance of {@link BulkheadExports} with default metric name and
* {@link Supplier} of bulkheads
*
* @param bulkheadsSupplier the supplier of bulkheads
*/
private BulkheadExports(Supplier<Iterable<Bulkhead>> bulkheadsSupplier) {
this(DEFAULT_NAME, bulkheadsSupplier);
}

/**
* Creates a new instance of {@link BulkheadExports} with specified metric name and
* {@link BulkheadRegistry}.
*
* @param name the name of metric
* @param bulkheadRegistry the bulkhead registry
*/
public BulkheadExports(String name, BulkheadRegistry bulkheadRegistry) {
this(name, bulkheadRegistry::getAllBulkheads);
}


/**
* Creates a new instance of {@link BulkheadExports} with specified metric name and
* {@link Iterable} of bulkheads.
*
* @param name the name of metric
* @param bulkheads the bulkheads
*/
private BulkheadExports(String name, Iterable<Bulkhead> bulkheads) {
this(name, () -> bulkheads);
}

/**
* Creates a new instance of {@link BulkheadExports} with specified metric name and
* {@link Supplier} of bulkheads
*
* @param name the name of metric
* @param bulkheadsSupplier the supplier of bulkheads
*/
private BulkheadExports(String name, Supplier<Iterable<Bulkhead>> bulkheadsSupplier) {
requireNonNull(name);
requireNonNull(bulkheadsSupplier);

this.name = name;
this.bulkheadsSupplier = bulkheadsSupplier;
}

/**
* {@inheritDoc}
*/
@Override
public List<MetricFamilySamples> collect() {
final GaugeMetricFamily stats = new GaugeMetricFamily(
name,
"Bulkhead Stats",
asList("name", "param"));

for (Bulkhead bulkhead : bulkheadsSupplier.get()) {

final Bulkhead.Metrics metrics = bulkhead.getMetrics();

stats.addMetric(
asList(bulkhead.getName(), "available_concurrent_calls"),
metrics.getAvailableConcurrentCalls());
}

return singletonList(stats);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,26 @@ public static RateLimiterExports ofSupplier(Supplier<Iterable<RateLimiter>> rate
public static RateLimiterExports ofRateLimiterRegistry(RateLimiterRegistry rateLimiterRegistry) {
return new RateLimiterExports(rateLimiterRegistry.getAllRateLimiters());
}

/**
* Creates a new instance of {@link RateLimiterExports} with default metrics names prefix and
* a circuit breaker as a source.
* a rate limiter as a source.
*
* @param RateLimiter the rate limiter
* @param rateLimiter the rate limiter
*/
public static RateLimiterExports ofRateLimiter(RateLimiter RateLimiter) {
return new RateLimiterExports(Array.of(RateLimiter));
public static RateLimiterExports ofRateLimiter(RateLimiter rateLimiter) {
return new RateLimiterExports(Array.of(rateLimiter));
}


/**
* Creates a new instance of {@link RateLimiterExports} with default metrics names prefix and
* {@link Iterable} of rate limiters.
*
* @param RateLimiters the rate limiters
* @param rateLimiters the rate limiters
*/
public static RateLimiterExports ofIterable(Iterable<RateLimiter> RateLimiters) {
return new RateLimiterExports(RateLimiters);
public static RateLimiterExports ofIterable(Iterable<RateLimiter> rateLimiters) {
return new RateLimiterExports(rateLimiters);
}

/**
Expand All @@ -108,21 +109,21 @@ public static RateLimiterExports ofRateLimiterRegistry(String prefix, RateLimite
* {@link Iterable} of rate limiters.
*
* @param prefix the prefix of metrics names
* @param rateLimiter the rate limiters
* @param rateLimiters the rate limiters
*/
public static RateLimiterExports ofIterable(String prefix, Iterable<RateLimiter> rateLimiter) {
return new RateLimiterExports(prefix, rateLimiter);
public static RateLimiterExports ofIterable(String prefix, Iterable<RateLimiter> rateLimiters) {
return new RateLimiterExports(prefix, rateLimiters);
}

/**
* Creates a new instance of {@link RateLimiterExports} with default metrics names prefix and
* a circuit breaker as a source.
* a rate limiter as a source.
*
* @param prefix the prefix of metrics names
* @param RateLimiter the circuit breaker
* @param rateLimiter the rate limiter
*/
public static RateLimiterExports ofRateLimiter(String prefix, RateLimiter RateLimiter) {
return new RateLimiterExports(prefix, Array.of(RateLimiter));
public static RateLimiterExports ofRateLimiter(String prefix, RateLimiter rateLimiter) {
return new RateLimiterExports(prefix, Array.of(rateLimiter));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
*
* Copyright 2018 Valtteri Walldén
*
* 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.prometheus;

import org.junit.Test;

import java.util.function.Supplier;

import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadConfig;
import io.github.resilience4j.bulkhead.BulkheadRegistry;
import io.github.resilience4j.bulkhead.internal.InMemoryBulkheadRegistry;
import io.prometheus.client.CollectorRegistry;
import io.vavr.Tuple;
import io.vavr.collection.HashMap;
import io.vavr.collection.HashSet;
import io.vavr.collection.Map;

import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;

public class BulkheadExportsTest {

@Test
public void testExportsCircuitBreakerStates() {
// Given
final CollectorRegistry registry = new CollectorRegistry();

final Bulkhead bulkhead = Bulkhead.ofDefaults("foo");

BulkheadExports.ofIterable("boo_bulkhead", singletonList(bulkhead)).register(registry);

final Supplier<Map<String, Double>> values = () -> HashSet
.of("available_concurrent_calls")
.map(param ->
Tuple.of(param, registry.getSampleValue(
"boo_bulkhead",
new String[]{"name", "param"},
new String[]{"foo", param})))
.toMap(t -> t);

// When
final Map<String, Double> initialValues = values.get();

// Then
assertThat(initialValues).isEqualTo(HashMap.of("available_concurrent_calls", 25.0));
}

@Test
public void testConstructors() {
final BulkheadRegistry registry = new InMemoryBulkheadRegistry(BulkheadConfig.ofDefaults());

BulkheadExports.ofIterable("boo_bulkheads", singleton(Bulkhead.ofDefaults("foo")));
BulkheadExports.ofBulkheadRegistry("boo_bulkheads", registry);
BulkheadExports.ofSupplier("boo_bulkheads", () -> singleton(Bulkhead.ofDefaults("foo")));

BulkheadExports.ofIterable(singleton(Bulkhead.ofDefaults("foo")));
BulkheadExports.ofBulkheadRegistry(registry);
BulkheadExports.ofSupplier(() -> singleton(Bulkhead.ofDefaults("foo")));
}

@Test(expected = NullPointerException.class)
public void testConstructorWithNullName() {
BulkheadExports.ofSupplier(null, () -> singleton(Bulkhead.ofDefaults("foo")));
}

@Test(expected = NullPointerException.class)
public void testConstructorWithNullSupplier() {
BulkheadExports.ofSupplier("boo_bulkheads", null);
}
}

0 comments on commit 0a979f3

Please sign in to comment.