Skip to content

Commit 6989b50

Browse files
authored
Micrometer (OpenFeign#1188)
* Add support for micrometrics metrics * Update documentation with metrics information
1 parent 7b3acf2 commit 6989b50

15 files changed

Lines changed: 796 additions & 39 deletions

File tree

README.md

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ This is a map with current key features provided by feign:
2626
![MindMap overview](src/docs/overview.png)
2727

2828
# Roadmap
29-
## Feign 11 and beyond
29+
## Feign 11 and beyond
3030
Making _API_ clients easier
3131

32-
Short Term - What we're working on now. ⏰
32+
Short Term - What we're working on now. ⏰
3333
---
3434
* Response Caching
3535
* Support caching of api responses. Allow for users to define under what conditions a response is eligible for caching and what type of caching mechanism should be used.
@@ -42,22 +42,20 @@ Short Term - What we're working on now. ⏰
4242
* `Retry` API refactor
4343
* Refactor the `Retry` API to support user-supplied conditions and better control over back-off policies. **This may result in non-backward-compatible breaking changes**
4444

45-
Medium Term - What's up next. ⏲
45+
Medium Term - What's up next. ⏲
4646
---
47-
* Metric API
48-
* Provide a first-class Metrics API that users can tap into to gain insight into the request/response lifecycle. Possibly provide better [OpenTracing](https://opentracing.io/) support.
4947
* Async execution support via `CompletableFuture`
5048
* Allow for `Future` chaining and executor management for the request/response lifecycle. **Implementation will require non-backward-compatible breaking changes**. However this feature is required before Reactive execution can be considered.
5149
* Reactive execution support via [Reactive Streams](https://www.reactive-streams.org/)
5250
* For JDK 9+, consider a native implementation that uses `java.util.concurrent.Flow`.
5351
* Support for [Project Reactor](https://projectreactor.io/) and [RxJava 2+](https://github.com/ReactiveX/RxJava) implementations on JDK 8.
5452

55-
Long Term - The future ☁️
53+
Long Term - The future ☁️
5654
---
5755
* Additional Circuit Breaker Support.
5856
* Support additional Circuit Breaker implementations like [Resilience4J](https://resilience4j.readme.io/) and Spring Circuit Breaker
5957

60-
---
58+
---
6159

6260
### Basics
6361

@@ -91,7 +89,7 @@ public class MyApp {
9189
GitHub github = Feign.builder()
9290
.decoder(new GsonDecoder())
9391
.target(GitHub.class, "https://api.github.com");
94-
92+
9593
// Fetch and print a list of the contributors to this library.
9694
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
9795
for (Contributor contributor : contributors) {
@@ -125,22 +123,22 @@ should work. Feign's default contract defines the following annotations:
125123
> ```java
126124
> @RequestLine("POST /repos/{owner}/{repo}/issues")
127125
> void createIssue(URI host, Issue issue, @Param("owner") String owner, @Param("repo") String repo);
128-
> ```
129-
>
126+
> ```
127+
>
130128
131129
### Templates and Expressions
132130
133131
Feign `Expressions` represent Simple String Expressions (Level 1) as defined by [URI Template - RFC 6570](https://tools.ietf.org/html/rfc6570). `Expressions` are expanded using
134-
their corresponding `Param` annotated method parameters.
132+
their corresponding `Param` annotated method parameters.
135133
136134
*Example*
137135
138136
```java
139137
public interface GitHub {
140-
138+
141139
@RequestLine("GET /repos/{owner}/{repo}/contributors")
142140
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository);
143-
141+
144142
class Contributor {
145143
String login;
146144
int contributions;
@@ -152,10 +150,10 @@ public class MyApp {
152150
GitHub github = Feign.builder()
153151
.decoder(new GsonDecoder())
154152
.target(GitHub.class, "https://api.github.com");
155-
153+
156154
/* The owner and repository parameters will be used to expand the owner and repo expressions
157155
* defined in the RequestLine.
158-
*
156+
*
159157
* the resulting uri will be https://api.github.com/repos/OpenFeign/feign/contributors
160158
*/
161159
github.contributors("OpenFeign", "feign");
@@ -222,8 +220,8 @@ http://localhost:8080/test
222220
See [Advanced Usage](#advanced-usage) for more examples.
223221
224222
> **What about slashes? `/`**
225-
>
226-
> @RequestLine templates do not encode slash `/` characters by default. To change this behavior, set the `decodeSlash` property on the `@RequestLine` to `false`.
223+
>
224+
> @RequestLine templates do not encode slash `/` characters by default. To change this behavior, set the `decodeSlash` property on the `@RequestLine` to `false`.
227225
228226
> **What about plus? `+`**
229227
>
@@ -232,7 +230,7 @@ See [Advanced Usage](#advanced-usage) for more examples.
232230
> `+` symbol should not represent a space and is explicitly encoded as `%2B` when found on a query string.
233231
>
234232
> If you wish to use `+` as a space, then use the literal ` ` character or encode the value directly as `%20`
235-
233+
236234
##### Custom Expansion
237235
238236
The `@Param` annotation has an optional property `expander` allowing for complete control over the individual parameter's expansion.
@@ -246,17 +244,17 @@ public interface Expander {
246244
The result of this method adheres to the same rules stated above. If the result is `null` or an empty string,
247245
the value is omitted. If the value is not pct-encoded, it will be. See [Custom @Param Expansion](#custom-param-expansion) for more examples.
248246
249-
#### Request Headers Expansion
247+
#### Request Headers Expansion
250248
251-
`Headers` and `HeaderMap` templates follow the same rules as [Request Parameter Expansion](#request-parameter-expansion)
249+
`Headers` and `HeaderMap` templates follow the same rules as [Request Parameter Expansion](#request-parameter-expansion)
252250
with the following alterations:
253251
254252
* Unresolved expressions are omitted. If the result is an empty header value, the entire header is removed.
255253
* No pct-encoding is performed.
256254
257255
See [Headers](#headers) for examples.
258256
259-
> **A Note on `@Param` parameters and their names**:
257+
> **A Note on `@Param` parameters and their names**:
260258
>
261259
> All expressions with the same name, regardless of their position on the `@RequestLine`, `@QueryMap`, `@BodyTemplate`, or `@Headers` will resolve to the same value.
262260
> In the following example, the value of `contentType`, will be used to resolve both the header and path expression:
@@ -268,12 +266,12 @@ See [Headers](#headers) for examples.
268266
> String getDocumentByType(@Param("contentType") String type);
269267
> }
270268
>```
271-
>
269+
>
272270
> Keep this in mind when designing your interfaces.
273271
274272
#### Request Body Expansion
275273
276-
`Body` templates follow the same rules as [Request Parameter Expansion](#request-parameter-expansion)
274+
`Body` templates follow the same rules as [Request Parameter Expansion](#request-parameter-expansion)
277275
with the following alterations:
278276
279277
* Unresolved expressions are omitted.
@@ -311,7 +309,7 @@ public class CloudService {
311309
CloudDNS cloudDNS = Feign.builder()
312310
.target(new CloudIdentityTarget<CloudDNS>(user, apiKey));
313311
}
314-
312+
315313
class CloudIdentityTarget extends Target<CloudDNS> {
316314
/* implementation of a Target */
317315
}
@@ -571,7 +569,7 @@ public class Example {
571569
LoginClient client = Feign.builder()
572570
.encoder(new GsonEncoder())
573571
.target(LoginClient.class, "https://foo.com");
574-
572+
575573
client.login(new Credentials("denominator", "secret"));
576574
}
577575
}
@@ -648,11 +646,11 @@ These approaches specify header entries as part of the api and do not require an
648646
when building the Feign client.
649647
650648
#### Setting headers per target
651-
To customize headers for each request method on a Target, a RequestInterceptor can be used. RequestInterceptors can be
652-
shared across Target instances and are expected to be thread-safe. RequestInterceptors are applied to all request
649+
To customize headers for each request method on a Target, a RequestInterceptor can be used. RequestInterceptors can be
650+
shared across Target instances and are expected to be thread-safe. RequestInterceptors are applied to all request
653651
methods on a Target.
654652
655-
If you need per method customization, a custom Target is required, as the a RequestInterceptor does not have access to
653+
If you need per method customization, a custom Target is required, as the a RequestInterceptor does not have access to
656654
the current method metadata.
657655
658656
For an example of setting headers using a `RequestInterceptor`, see the `Request Interceptors` section.
@@ -664,7 +662,7 @@ Headers can be set as part of a custom `Target`.
664662
public DynamicAuthTokenTarget(Class<T> clazz,
665663
UrlAndTokenProvider provider,
666664
ThreadLocal<String> requestIdProvider);
667-
665+
668666
@Override
669667
public Request apply(RequestTemplate input) {
670668
TokenIdAndPublicURL urlAndToken = provider.get();
@@ -677,7 +675,7 @@ Headers can be set as part of a custom `Target`.
677675
return input.request();
678676
}
679677
}
680-
678+
681679
public class Example {
682680
public static void main(String[] args) {
683681
Bank bank = Feign.builder()
@@ -755,7 +753,7 @@ public class Example {
755753
}
756754
```
757755
758-
> **A Note on JavaLogger**:
756+
> **A Note on JavaLogger**:
759757
> Avoid using of default ```JavaLogger()``` constructor - it was marked as deprecated and will be removed soon.
760758
761759
The SLF4JLogger (see above) may also be of interest.
@@ -898,12 +896,49 @@ public class Example {
898896
```
899897
900898
`Retryer`s are responsible for determining if a retry should occur by returning either a `true` or
901-
`false` from the method `continueOrPropagate(RetryableException e);` A `Retryer` instance will be
899+
`false` from the method `continueOrPropagate(RetryableException e);` A `Retryer` instance will be
902900
created for each `Client` execution, allowing you to maintain state bewteen each request if desired.
903901
904902
If the retry is determined to be unsuccessful, the last `RetryException` will be thrown. To throw the original
905903
cause that led to the unsuccessful retry, build your Feign client with the `exceptionPropagationPolicy()` option.
906904
905+
### Metrics
906+
By default, feign won't collect any metrics.
907+
908+
But, it's possible to add metric collection capabilities to any feign client.
909+
910+
Metric Capabilities provide a first-class Metrics API that users can tap into to gain insight into the request/response lifecycle.
911+
912+
#### Dropwizard Metrics 5
913+
914+
```
915+
public class MyApp {
916+
public static void main(String[] args) {
917+
GitHub github = Feign.builder()
918+
.addCapability(new Metrics5Capability())
919+
.target(GitHub.class, "https://api.github.com");
920+
921+
github.contributors("OpenFeign", "feign");
922+
// metrics will be available from this point onwards
923+
}
924+
}
925+
```
926+
927+
#### Micrometer
928+
929+
```
930+
public class MyApp {
931+
public static void main(String[] args) {
932+
GitHub github = Feign.builder()
933+
.addCapability(new MicrometerCapability())
934+
.target(GitHub.class, "https://api.github.com");
935+
936+
github.contributors("OpenFeign", "feign");
937+
// metrics will be available from this point onwards
938+
}
939+
}
940+
```
941+
907942
#### Static and Default Methods
908943
Interfaces targeted by Feign may have static or default methods (if using Java 8+).
909944
These allows Feign clients to contain logic that is not expressly defined by the underlying API.
@@ -956,7 +991,7 @@ public class MyApp {
956991
GitHub github = AsyncFeign.asyncBuilder()
957992
.decoder(new GsonDecoder())
958993
.target(GitHub.class, "https://api.github.com");
959-
994+
960995
// Fetch and print a list of the contributors to this library.
961996
CompletableFuture<List<Contributor>> contributors = github.contributors("OpenFeign", "feign");
962997
for (Contributor contributor : contributors.get(1, TimeUnit.SECONDS)) {

dropwizard-metrics5/src/test/java/feign/metrics5/Metrics5CapabilityTest.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,11 @@ public void addMetricsCapability() {
5656
"Expect all metric names to include method name:" + metricName,
5757
metricName.getTags(),
5858
hasEntry("method", "get")));
59-
registry.getMetrics().keySet().forEach(
60-
metricName -> assertThat(
61-
"Expect all metric names to include host name:" + metricName,
62-
metricName.getTags(),
63-
// hostname is null due to feign-mock shortfalls
64-
hasEntry("host", null)));
59+
registry.getMetrics().keySet().forEach(metricName -> assertThat(
60+
"Expect all metric names to include host name:" + metricName,
61+
metricName.getTags(),
62+
// hostname is null due to feign-mock shortfalls
63+
hasEntry("host", null)));
6564
}
6665

6766
}

micrometer/pom.xml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2012-2020 The Feign Authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7+
in compliance with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software distributed under the License
12+
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13+
or implied. See the License for the specific language governing permissions and limitations under
14+
the License.
15+
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
18+
<modelVersion>4.0.0</modelVersion>
19+
<parent>
20+
<groupId>io.github.openfeign</groupId>
21+
<artifactId>parent</artifactId>
22+
<version>10.9-SNAPSHOT</version>
23+
</parent>
24+
<artifactId>feign-micrometer</artifactId>
25+
<name>Feign Micrometer</name>
26+
<description>Feign Micrometer Application Metrics</description>
27+
28+
<properties>
29+
<main.basedir>${project.basedir}/..</main.basedir>
30+
</properties>
31+
32+
<dependencies>
33+
<dependency>
34+
<groupId>${project.groupId}</groupId>
35+
<artifactId>feign-core</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>${project.groupId}</groupId>
39+
<artifactId>feign-mock</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>io.micrometer</groupId>
44+
<artifactId>micrometer-core</artifactId>
45+
<version>1.3.5</version>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.hamcrest</groupId>
49+
<artifactId>java-hamcrest</artifactId>
50+
<version>2.0.0.0</version>
51+
<scope>test</scope>
52+
</dependency>
53+
</dependencies>
54+
</project>

0 commit comments

Comments
 (0)