Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* Default implementation of {@link RestTemplateExchangeTagsProvider}.
*
* @author Jon Schneider
* @author Nishant Raut
* @since 2.0.0
*/
public class DefaultRestTemplateExchangeTagsProvider
Expand All @@ -41,7 +42,8 @@ public Iterable<Tag> getTags(String urlTemplate, HttpRequest request,
: RestTemplateExchangeTags.uri(request));
return Arrays.asList(RestTemplateExchangeTags.method(request), uriTag,
RestTemplateExchangeTags.status(response),
RestTemplateExchangeTags.clientName(request));
RestTemplateExchangeTags.clientName(request),
RestTemplateExchangeTags.outcome(response));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.micrometer.core.instrument.Tag;

import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
Expand All @@ -33,12 +34,25 @@
*
* @author Andy Wilkinson
* @author Jon Schneider
* @author Nishant Raut
* @since 2.0.0
*/
public final class RestTemplateExchangeTags {

private static final Pattern STRIP_URI_PATTERN = Pattern.compile("^https?://[^/]+/");

private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");

private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL");

private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");

private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION");

private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");

private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");

private RestTemplateExchangeTags() {
}

Expand Down Expand Up @@ -115,4 +129,44 @@ public static Tag clientName(HttpRequest request) {
return Tag.of("clientName", host);
}

/**
* Creates a {@code outcome} {@code Tag} derived from the
* {@link ClientHttpResponse#getStatusCode() status} of the given {@code response}.
* @param response the response
* @return the outcome tag
* @since 2.2.0
*/
public static Tag outcome(ClientHttpResponse response) {
if (response != null) {
HttpStatus status = extractStatus(response);
if (status != null) {
if (status.is1xxInformational()) {
return OUTCOME_INFORMATIONAL;
}
if (status.is2xxSuccessful()) {
return OUTCOME_SUCCESS;
}
if (status.is3xxRedirection()) {
return OUTCOME_REDIRECTION;
}
if (status.is4xxClientError()) {
return OUTCOME_CLIENT_ERROR;
}
}
return OUTCOME_SERVER_ERROR;
}
return OUTCOME_UNKNOWN;
}

private static HttpStatus extractStatus(ClientHttpResponse response) {

try {
return response.getStatusCode();
}
catch (IOException ex) {
return null;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Default implementation of {@link WebClientExchangeTagsProvider}.
*
* @author Brian Clozel
* @author Nishant Raut
* @since 2.1.0
*/
public class DefaultWebClientExchangeTagsProvider
Expand All @@ -40,7 +41,8 @@ public Iterable<Tag> tags(ClientRequest request, ClientResponse response,
Tag clientName = WebClientExchangeTags.clientName(request);
if (response != null) {
return Arrays.asList(method, uri, clientName,
WebClientExchangeTags.status(response));
WebClientExchangeTags.status(response),
WebClientExchangeTags.outcome(response));
}
else {
return Arrays.asList(method, uri, clientName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import io.micrometer.core.instrument.Tag;

import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
Expand All @@ -31,6 +32,7 @@
* performed by a {@link WebClient}.
*
* @author Brian Clozel
* @author Nishant Raut
* @since 2.1.0
*/
public final class WebClientExchangeTags {
Expand All @@ -47,6 +49,18 @@ public final class WebClientExchangeTags {

private static final Tag CLIENT_NAME_NONE = Tag.of("clientName", "none");

private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");

private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL");

private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");

private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION");

private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");

private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");

private WebClientExchangeTags() {
}

Expand Down Expand Up @@ -111,4 +125,33 @@ public static Tag clientName(ClientRequest request) {
return Tag.of("clientName", host);
}

/**
* Creates a {@code outcome} {@code Tag} derived from the
* {@link ClientResponse#statusCode() status} of the given {@code response}.
* @param response the response
* @return the outcome tag
* @since 2.2.0
*/
public static Tag outcome(ClientResponse response) {
if (response != null) {
HttpStatus status = response.statusCode();
if (status != null) {
if (status.is1xxInformational()) {
return OUTCOME_INFORMATIONAL;
}
if (status.is2xxSuccessful()) {
return OUTCOME_SUCCESS;
}
if (status.is3xxRedirection()) {
return OUTCOME_REDIRECTION;
}
if (status.is4xxClientError()) {
return OUTCOME_CLIENT_ERROR;
}
}
return OUTCOME_SERVER_ERROR;
}
return OUTCOME_UNKNOWN;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2012-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.boot.actuate.metrics.web.client;

import io.micrometer.core.instrument.Tag;
import org.junit.Test;

import org.springframework.http.HttpStatus;
import org.springframework.mock.http.client.MockClientHttpResponse;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for {@link RestTemplateExchangeTags}.
*
* @author Nishant Raut
*/
public class RestTemplateExchangeTagsTests {

private MockClientHttpResponse response;

@Test
public void outcomeTagIsUnknownWhenResponseStatusIsNull() {
Tag tag = RestTemplateExchangeTags.outcome(null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}

@Test
public void outcomeTagIsInformationalWhenResponseIs1xx() {
this.response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.CONTINUE);
Tag tag = RestTemplateExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}

@Test
public void outcomeTagIsSuccessWhenResponseIs2xx() {
this.response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.OK);
Tag tag = RestTemplateExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}

@Test
public void outcomeTagIsRedirectionWhenResponseIs3xx() {
this.response = new MockClientHttpResponse("foo".getBytes(),
HttpStatus.MOVED_PERMANENTLY);
Tag tag = RestTemplateExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}

@Test
public void outcomeTagIsClientErrorWhenResponseIs4xx() {
this.response = new MockClientHttpResponse("foo".getBytes(),
HttpStatus.BAD_REQUEST);
Tag tag = RestTemplateExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}

@Test
public void outcomeTagIsServerErrorWhenResponseIs5xx() {
this.response = new MockClientHttpResponse("foo".getBytes(),
HttpStatus.BAD_GATEWAY);
Tag tag = RestTemplateExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* Tests for {@link DefaultWebClientExchangeTagsProvider}
*
* @author Brian Clozel
* @author Nishant Raut
*/
public class DefaultWebClientExchangeTagsProviderTests {

Expand Down Expand Up @@ -66,7 +67,7 @@ public void tagsShouldBePopulated() {
Iterable<Tag> tags = this.tagsProvider.tags(this.request, this.response, null);
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"),
Tag.of("uri", "/projects/{project}"), Tag.of("clientName", "example.org"),
Tag.of("status", "200"));
Tag.of("status", "200"), Tag.of("outcome", "SUCCESS"));
}

@Test
Expand All @@ -76,7 +77,8 @@ public void tagsWhenNoUriTemplateShouldProvideUriPath() {
Iterable<Tag> tags = this.tagsProvider.tags(request, this.response, null);
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"),
Tag.of("uri", "/projects/spring-boot"),
Tag.of("clientName", "example.org"), Tag.of("status", "200"));
Tag.of("clientName", "example.org"), Tag.of("status", "200"),
Tag.of("outcome", "SUCCESS"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* Tests for {@link WebClientExchangeTags}
*
* @author Brian Clozel
* @author Nishant Raut
*/
public class WebClientExchangeTagsTests {

Expand Down Expand Up @@ -113,4 +114,45 @@ public void statusWhenClientException() {
.isEqualTo(Tag.of("status", "CLIENT_ERROR"));
}

@Test
public void outcomeTagIsUnknownWhenResponseStatusIsNull() {
Tag tag = WebClientExchangeTags.outcome(null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}

@Test
public void outcomeTagIsInformationalWhenResponseIs1xx() {
given(this.response.statusCode()).willReturn(HttpStatus.CONTINUE);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}

@Test
public void outcomeTagIsSuccessWhenResponseIs2xx() {
given(this.response.statusCode()).willReturn(HttpStatus.OK);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}

@Test
public void outcomeTagIsRedirectionWhenResponseIs3xx() {
given(this.response.statusCode()).willReturn(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}

@Test
public void outcomeTagIsClientErrorWhenResponseIs4xx() {
given(this.response.statusCode()).willReturn(HttpStatus.BAD_REQUEST);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}

@Test
public void outcomeTagIsServerErrorWhenResponseIs5xx() {
given(this.response.statusCode()).willReturn(HttpStatus.BAD_GATEWAY);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}

}