Skip to content

Commit 1319d04

Browse files
hexmindRobWin
authored andcommitted
Issue ReactiveX#531: Time limiter micrometer (ReactiveX#599)
1 parent b29acf8 commit 1319d04

File tree

5 files changed

+394
-3
lines changed

5 files changed

+394
-3
lines changed

resilience4j-micrometer/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ dependencies {
44
compileOnly project(':resilience4j-circuitbreaker')
55
compileOnly project(':resilience4j-retry')
66
compileOnly project(':resilience4j-ratelimiter')
7+
compileOnly project(':resilience4j-timelimiter')
78
testCompile project(':resilience4j-test')
89
testCompile project(':resilience4j-bulkhead')
910
testCompile project(':resilience4j-circuitbreaker')
1011
testCompile project(':resilience4j-ratelimiter')
12+
testCompile project(':resilience4j-timelimiter')
1113
testCompile project(':resilience4j-retry')
1214
testCompile project(':resilience4j-test')
1315
testCompile project(':resilience4j-circuitbreaker')

resilience4j-micrometer/src/main/java/io/github/resilience4j/micrometer/tagged/TaggedRateLimiterMetrics.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@
3535
public class TaggedRateLimiterMetrics extends AbstractMetrics implements MeterBinder {
3636

3737
/**
38-
* Creates a new binder that uses given {@code registry} as source of retries.
38+
* Creates a new binder that uses given {@code registry} as source of rate limiters.
3939
*
40-
* @param rateLimiterRegistry the source of retries
40+
* @param rateLimiterRegistry the source of rate limiters
4141
* @return The {@link TaggedRateLimiterMetrics} instance.
4242
*/
4343
public static TaggedRateLimiterMetrics ofRateLimiterRegistry(RateLimiterRegistry rateLimiterRegistry) {
4444
return new TaggedRateLimiterMetrics(MetricNames.ofDefaults(), rateLimiterRegistry);
4545
}
4646

4747
/**
48-
* Creates a new binder that uses given {@code registry} as source of retries.
48+
* Creates a new binder that uses given {@code registry} as source of rate limiters.
4949
*
5050
* @param names custom metric names
5151
* @param rateLimiterRegistry the source of rate limiters
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright 2019 authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.github.resilience4j.micrometer.tagged;
17+
18+
import io.github.resilience4j.timelimiter.TimeLimiter;
19+
import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
20+
import io.micrometer.core.instrument.Counter;
21+
import io.micrometer.core.instrument.Meter;
22+
import io.micrometer.core.instrument.MeterRegistry;
23+
import io.micrometer.core.instrument.binder.MeterBinder;
24+
25+
import java.util.Arrays;
26+
import java.util.HashSet;
27+
import java.util.List;
28+
import java.util.Objects;
29+
30+
import static java.util.Objects.requireNonNull;
31+
32+
/**
33+
* A micrometer binder that is used to register TimeLimiter exposed events.
34+
*/
35+
public class TaggedTimeLimiterMetrics extends AbstractMetrics implements MeterBinder {
36+
37+
/**
38+
* Creates a new binder that uses given {@code registry} as source of time limiters.
39+
*
40+
* @param timeLimiterRegistry the source of time limiters
41+
* @return The {@link TaggedTimeLimiterMetrics} instance.
42+
*/
43+
public static TaggedTimeLimiterMetrics ofTimeLimiterRegistry(TimeLimiterRegistry timeLimiterRegistry) {
44+
return new TaggedTimeLimiterMetrics(MetricNames.ofDefaults(), timeLimiterRegistry);
45+
}
46+
47+
/**
48+
* Creates a new binder that uses given {@code registry} as source of time limiters.
49+
*
50+
* @param names custom metric names
51+
* @param timeLimiterRegistry the source of time limiters
52+
* @return The {@link TaggedTimeLimiterMetrics} instance.
53+
*/
54+
public static TaggedTimeLimiterMetrics ofTimeLimiterRegistry(MetricNames names, TimeLimiterRegistry timeLimiterRegistry) {
55+
return new TaggedTimeLimiterMetrics(names, timeLimiterRegistry);
56+
}
57+
58+
private final MetricNames names;
59+
private final TimeLimiterRegistry timeLimiterRegistry;
60+
61+
private TaggedTimeLimiterMetrics(MetricNames names, TimeLimiterRegistry timeLimiterRegistry) {
62+
super();
63+
this.names = Objects.requireNonNull(names);
64+
this.timeLimiterRegistry = Objects.requireNonNull(timeLimiterRegistry);
65+
}
66+
67+
@Override
68+
public void bindTo(MeterRegistry registry) {
69+
for (TimeLimiter timeLimiter : timeLimiterRegistry.getAllTimeLimiters()) {
70+
addMetrics(registry, timeLimiter);
71+
}
72+
timeLimiterRegistry.getEventPublisher().onEntryAdded(event -> addMetrics(registry, event.getAddedEntry()));
73+
timeLimiterRegistry.getEventPublisher().onEntryRemoved(event -> removeMetrics(registry, event.getRemovedEntry().getName()));
74+
timeLimiterRegistry.getEventPublisher().onEntryReplaced(event -> {
75+
removeMetrics(registry, event.getOldEntry().getName());
76+
addMetrics(registry, event.getNewEntry());
77+
});
78+
}
79+
80+
private void addMetrics(MeterRegistry registry, TimeLimiter timeLimiter) {
81+
Counter successes = Counter.builder(names.getSuccessfulMetricName())
82+
.description("The number of successful calls")
83+
.tag(TagNames.NAME, timeLimiter.getName())
84+
.register(registry);
85+
Counter failures = Counter.builder(names.getFailedMetricName())
86+
.description("The number of failed calls")
87+
.tag(TagNames.NAME, timeLimiter.getName())
88+
.register(registry);
89+
Counter timeouts = Counter.builder(names.getTimeoutMetricName())
90+
.description("The number of timed out calls")
91+
.tag(TagNames.NAME, timeLimiter.getName())
92+
.register(registry);
93+
94+
timeLimiter.getEventPublisher()
95+
.onSuccess(event -> successes.increment())
96+
.onError(event -> failures.increment())
97+
.onTimeout(event -> timeouts.increment());
98+
99+
List<Meter.Id> ids = Arrays.asList(successes.getId(), failures.getId(), timeouts.getId());
100+
meterIdMap.put(timeLimiter.getName(), new HashSet<>(ids));
101+
}
102+
103+
/**
104+
* Defines possible configuration for metric names.
105+
*/
106+
public static class MetricNames {
107+
108+
private static final String DEFAULT_PREFIX = "resilience4j.timelimiter";
109+
public static final String SUCCESSFUL_METRIC_NAME = DEFAULT_PREFIX + ".successful";
110+
public static final String FAILED_METRIC_NAME = DEFAULT_PREFIX + ".failed";
111+
public static final String TIMEOUT_METRIC_NAME = DEFAULT_PREFIX + ".timeout";
112+
113+
/**
114+
* Returns a builder for creating custom metric names.
115+
* Note that names have default values, so only desired metrics can be renamed.
116+
*
117+
* @return The builder.
118+
*/
119+
public static Builder custom() {
120+
return new Builder();
121+
}
122+
123+
/**
124+
* Returns default metric names.
125+
*
126+
* @return The default {@link MetricNames} instance.
127+
*/
128+
public static MetricNames ofDefaults() {
129+
return new MetricNames();
130+
}
131+
132+
private String successfulMetricName = SUCCESSFUL_METRIC_NAME;
133+
private String failedMetricName = FAILED_METRIC_NAME;
134+
private String timeoutMetricName = TIMEOUT_METRIC_NAME;
135+
136+
/**
137+
* Returns the metric name for successful calls, defaults to {@value SUCCESSFUL_METRIC_NAME}.
138+
*
139+
* @return The successful calls metric name.
140+
*/
141+
public String getSuccessfulMetricName() {
142+
return successfulMetricName;
143+
}
144+
145+
/**
146+
* Returns the metric name for failed calls, defaults to {@value FAILED_METRIC_NAME}.
147+
*
148+
* @return The failed calls metric name.
149+
*/
150+
public String getFailedMetricName() {
151+
return failedMetricName;
152+
}
153+
154+
/**
155+
* Returns the metric name for timed out calls, defaults to {@value TIMEOUT_METRIC_NAME}.
156+
*
157+
* @return The timed out calls metric name.
158+
*/
159+
public String getTimeoutMetricName() {
160+
return timeoutMetricName;
161+
}
162+
163+
/**
164+
* Helps building custom instance of {@link MetricNames}.
165+
*/
166+
public static class Builder {
167+
168+
private final MetricNames metricNames = new MetricNames();
169+
170+
/**
171+
* Overrides the default metric name {@value MetricNames#SUCCESSFUL_METRIC_NAME} with a given one.
172+
*
173+
* @param successfulMetricName The successful calls metric name.
174+
* @return The builder.
175+
*/
176+
public Builder successfulMetricName(String successfulMetricName) {
177+
metricNames.successfulMetricName = requireNonNull(successfulMetricName);
178+
return this;
179+
}
180+
181+
/**
182+
* Overrides the default metric name {@value MetricNames#FAILED_METRIC_NAME} with a given one.
183+
*
184+
* @param failedMetricName The failed calls metric name.
185+
* @return The builder.
186+
*/
187+
public Builder failedMetricName(String failedMetricName) {
188+
metricNames.failedMetricName = requireNonNull(failedMetricName);
189+
return this;
190+
}
191+
192+
/**
193+
* Overrides the default metric name {@value MetricNames#TIMEOUT_METRIC_NAME} with a given one.
194+
*
195+
* @param timeoutMetricName The timed out calls metric name.
196+
* @return The builder.
197+
*/
198+
public Builder timeoutMetricName(String timeoutMetricName) {
199+
metricNames.timeoutMetricName = requireNonNull(timeoutMetricName);
200+
return this;
201+
}
202+
203+
/**
204+
* Builds {@link MetricNames} instance.
205+
*
206+
* @return The built {@link MetricNames} instance.
207+
*/
208+
public MetricNames build() {
209+
return metricNames;
210+
}
211+
}
212+
}
213+
}

resilience4j-micrometer/src/test/java/io/github/resilience4j/micrometer/tagged/MetricsTestHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ static Optional<Counter> findCounterByKindAndNameTags(Collection<Counter> counte
4444
.findAny();
4545
}
4646

47+
static Optional<Counter> findCounterByNamesTag(Collection<Counter> gauges, String name) {
48+
return gauges.stream()
49+
.filter(g -> name.equals(g.getId().getTag(TagNames.NAME)))
50+
.findAny();
51+
}
52+
4753
static Optional<Gauge> findGaugeByNamesTag(Collection<Gauge> gauges, String name) {
4854
return gauges.stream()
4955
.filter(g -> name.equals(g.getId().getTag(TagNames.NAME)))

0 commit comments

Comments
 (0)