93 changed files with 117 additions and 4580 deletions
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.client; |
||||
|
||||
import io.micrometer.common.KeyValues; |
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; |
||||
import org.springframework.http.client.observation.ClientRequestObservationContext; |
||||
import org.springframework.http.client.observation.ClientRequestObservationConvention; |
||||
|
||||
/** |
||||
* Adapter class that applies {@link RestTemplateExchangeTagsProvider} tags as a |
||||
* {@link ClientRequestObservationConvention}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings({ "removal" }) |
||||
class ClientHttpObservationConventionAdapter implements ClientRequestObservationConvention { |
||||
|
||||
private final String metricName; |
||||
|
||||
private final RestTemplateExchangeTagsProvider tagsProvider; |
||||
|
||||
ClientHttpObservationConventionAdapter(String metricName, RestTemplateExchangeTagsProvider tagsProvider) { |
||||
this.metricName = metricName; |
||||
this.tagsProvider = tagsProvider; |
||||
} |
||||
|
||||
@Override |
||||
@SuppressWarnings("deprecation") |
||||
public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) { |
||||
Iterable<Tag> tags = this.tagsProvider.getTags(context.getUriTemplate(), context.getCarrier(), |
||||
context.getResponse()); |
||||
return KeyValues.of(tags, Tag::getKey, Tag::getValue); |
||||
} |
||||
|
||||
@Override |
||||
public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) { |
||||
return KeyValues.empty(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.metricName; |
||||
} |
||||
|
||||
} |
||||
@ -1,76 +0,0 @@
@@ -1,76 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.client; |
||||
|
||||
import io.micrometer.common.KeyValues; |
||||
import io.micrometer.core.instrument.Tag; |
||||
import io.micrometer.observation.Observation; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; |
||||
import org.springframework.core.Conventions; |
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientRequestObservationContext; |
||||
import org.springframework.web.reactive.function.client.ClientRequestObservationConvention; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
/** |
||||
* Adapter class that applies {@link WebClientExchangeTagsProvider} tags as a |
||||
* {@link ClientRequestObservationConvention}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
class ClientObservationConventionAdapter implements ClientRequestObservationConvention { |
||||
|
||||
private static final String URI_TEMPLATE_ATTRIBUTE = Conventions.getQualifiedAttributeName(WebClient.class, |
||||
"uriTemplate"); |
||||
|
||||
private final String metricName; |
||||
|
||||
private final WebClientExchangeTagsProvider tagsProvider; |
||||
|
||||
ClientObservationConventionAdapter(String metricName, WebClientExchangeTagsProvider tagsProvider) { |
||||
this.metricName = metricName; |
||||
this.tagsProvider = tagsProvider; |
||||
} |
||||
|
||||
@Override |
||||
public boolean supportsContext(Observation.Context context) { |
||||
return context instanceof ClientRequestObservationContext; |
||||
} |
||||
|
||||
@Override |
||||
public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) { |
||||
ClientRequest request = context.getRequest(); |
||||
if (request == null) { |
||||
request = context.getCarrier().attribute(URI_TEMPLATE_ATTRIBUTE, context.getUriTemplate()).build(); |
||||
} |
||||
Iterable<Tag> tags = this.tagsProvider.tags(request, context.getResponse(), context.getError()); |
||||
return KeyValues.of(tags, Tag::getKey, Tag::getValue); |
||||
} |
||||
|
||||
@Override |
||||
public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) { |
||||
return KeyValues.empty(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.metricName; |
||||
} |
||||
|
||||
} |
||||
@ -1,79 +0,0 @@
@@ -1,79 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.reactive; |
||||
|
||||
import java.util.List; |
||||
|
||||
import io.micrometer.common.KeyValues; |
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor; |
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider; |
||||
import org.springframework.http.codec.ServerCodecConfigurer; |
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext; |
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention; |
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange; |
||||
import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; |
||||
import org.springframework.web.server.i18n.LocaleContextResolver; |
||||
import org.springframework.web.server.session.DefaultWebSessionManager; |
||||
import org.springframework.web.server.session.WebSessionManager; |
||||
|
||||
/** |
||||
* Adapter class that applies {@link WebFluxTagsProvider} tags as a |
||||
* {@link ServerRequestObservationConvention}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class ServerRequestObservationConventionAdapter implements ServerRequestObservationConvention { |
||||
|
||||
private final WebSessionManager webSessionManager = new DefaultWebSessionManager(); |
||||
|
||||
private final ServerCodecConfigurer serverCodecConfigurer = ServerCodecConfigurer.create(); |
||||
|
||||
private final LocaleContextResolver localeContextResolver = new AcceptHeaderLocaleContextResolver(); |
||||
|
||||
private final String name; |
||||
|
||||
private final WebFluxTagsProvider tagsProvider; |
||||
|
||||
ServerRequestObservationConventionAdapter(String name, WebFluxTagsProvider tagsProvider) { |
||||
this.name = name; |
||||
this.tagsProvider = tagsProvider; |
||||
} |
||||
|
||||
ServerRequestObservationConventionAdapter(String name, List<WebFluxTagsContributor> contributors) { |
||||
this(name, new DefaultWebFluxTagsProvider(contributors)); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
@Override |
||||
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) { |
||||
DefaultServerWebExchange serverWebExchange = new DefaultServerWebExchange(context.getCarrier(), |
||||
context.getResponse(), this.webSessionManager, this.serverCodecConfigurer, this.localeContextResolver); |
||||
serverWebExchange.getAttributes().putAll(context.getAttributes()); |
||||
Iterable<Tag> tags = this.tagsProvider.httpRequestTags(serverWebExchange, context.getError()); |
||||
return KeyValues.of(tags, Tag::getKey, Tag::getValue); |
||||
} |
||||
|
||||
} |
||||
@ -1,76 +0,0 @@
@@ -1,76 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.servlet; |
||||
|
||||
import java.util.List; |
||||
|
||||
import io.micrometer.common.KeyValues; |
||||
import io.micrometer.core.instrument.Tag; |
||||
import io.micrometer.observation.Observation; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider; |
||||
import org.springframework.http.server.observation.ServerRequestObservationContext; |
||||
import org.springframework.http.server.observation.ServerRequestObservationConvention; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
|
||||
/** |
||||
* Adapter class that applies {@link WebMvcTagsProvider} tags as a |
||||
* {@link ServerRequestObservationConvention}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class ServerRequestObservationConventionAdapter implements ServerRequestObservationConvention { |
||||
|
||||
private final String observationName; |
||||
|
||||
private final WebMvcTagsProvider tagsProvider; |
||||
|
||||
ServerRequestObservationConventionAdapter(String observationName, WebMvcTagsProvider tagsProvider, |
||||
List<WebMvcTagsContributor> contributors) { |
||||
Assert.state((tagsProvider != null) || (contributors != null), |
||||
"adapter should adapt to a WebMvcTagsProvider or a list of contributors"); |
||||
this.observationName = observationName; |
||||
this.tagsProvider = (tagsProvider != null) ? tagsProvider : new DefaultWebMvcTagsProvider(contributors); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.observationName; |
||||
} |
||||
|
||||
@Override |
||||
public boolean supportsContext(Observation.Context context) { |
||||
return context instanceof ServerRequestObservationContext; |
||||
} |
||||
|
||||
@Override |
||||
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) { |
||||
Iterable<Tag> tags = this.tagsProvider.getTags(context.getCarrier(), context.getResponse(), getHandler(context), |
||||
context.getError()); |
||||
return KeyValues.of(tags, Tag::getKey, Tag::getValue); |
||||
} |
||||
|
||||
private Object getHandler(ServerRequestObservationContext context) { |
||||
return context.getCarrier().getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE); |
||||
} |
||||
|
||||
} |
||||
@ -1,57 +0,0 @@
@@ -1,57 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.health; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfigurationReflectionTests.TestHealthIndicator; |
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator; |
||||
import org.springframework.boot.actuate.health.Health.Builder; |
||||
import org.springframework.boot.actuate.health.HealthContributor; |
||||
|
||||
/** |
||||
* Tests for {@link CompositeHealthContributorConfiguration} using reflection to create |
||||
* indicator instances. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class CompositeHealthContributorConfigurationReflectionTests |
||||
extends AbstractCompositeHealthContributorConfigurationTests<HealthContributor, TestHealthIndicator> { |
||||
|
||||
@Override |
||||
protected AbstractCompositeHealthContributorConfiguration<HealthContributor, TestHealthIndicator, TestBean> newComposite() { |
||||
return new ReflectiveTestCompositeHealthContributorConfiguration(); |
||||
} |
||||
|
||||
static class ReflectiveTestCompositeHealthContributorConfiguration |
||||
extends CompositeHealthContributorConfiguration<TestHealthIndicator, TestBean> { |
||||
|
||||
} |
||||
|
||||
static class TestHealthIndicator extends AbstractHealthIndicator { |
||||
|
||||
TestHealthIndicator(TestBean testBean) { |
||||
} |
||||
|
||||
@Override |
||||
protected void doHealthCheck(Builder builder) throws Exception { |
||||
builder.up(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,60 +0,0 @@
@@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.health; |
||||
|
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfigurationReflectionTests.TestReactiveHealthIndicator; |
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; |
||||
import org.springframework.boot.actuate.health.Health; |
||||
import org.springframework.boot.actuate.health.Health.Builder; |
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor; |
||||
|
||||
/** |
||||
* Tests for {@link CompositeReactiveHealthContributorConfiguration} using reflection to |
||||
* create indicator instances. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class CompositeReactiveHealthContributorConfigurationReflectionTests extends |
||||
AbstractCompositeHealthContributorConfigurationTests<ReactiveHealthContributor, TestReactiveHealthIndicator> { |
||||
|
||||
@Override |
||||
protected AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, TestReactiveHealthIndicator, TestBean> newComposite() { |
||||
return new TestCompositeReactiveHealthContributorConfiguration(); |
||||
} |
||||
|
||||
static class TestCompositeReactiveHealthContributorConfiguration |
||||
extends CompositeReactiveHealthContributorConfiguration<TestReactiveHealthIndicator, TestBean> { |
||||
|
||||
} |
||||
|
||||
static class TestReactiveHealthIndicator extends AbstractReactiveHealthIndicator { |
||||
|
||||
TestReactiveHealthIndicator(TestBean testBean) { |
||||
} |
||||
|
||||
@Override |
||||
protected Mono<Health> doHealthCheck(Builder builder) { |
||||
return Mono.just(builder.up().build()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,90 +0,0 @@
@@ -1,90 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.client; |
||||
|
||||
import java.net.URI; |
||||
|
||||
import io.micrometer.common.KeyValue; |
||||
import io.micrometer.observation.Observation; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.client.ClientHttpRequest; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.http.client.observation.ClientRequestObservationContext; |
||||
import org.springframework.mock.http.client.MockClientHttpRequest; |
||||
import org.springframework.mock.http.client.MockClientHttpResponse; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ClientHttpObservationConventionAdapter}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings({ "deprecation", "removal" }) |
||||
class ClientHttpObservationConventionAdapterTests { |
||||
|
||||
private static final String TEST_METRIC_NAME = "test.metric.name"; |
||||
|
||||
private final ClientHttpObservationConventionAdapter convention = new ClientHttpObservationConventionAdapter( |
||||
TEST_METRIC_NAME, new DefaultRestTemplateExchangeTagsProvider()); |
||||
|
||||
private final ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/resource/test")); |
||||
|
||||
private final ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.OK); |
||||
|
||||
private ClientRequestObservationContext context; |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.context = new ClientRequestObservationContext(this.request); |
||||
this.context.setResponse(this.response); |
||||
this.context.setUriTemplate("/resource/{name}"); |
||||
} |
||||
|
||||
@Test |
||||
void shouldUseConfiguredName() { |
||||
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME); |
||||
} |
||||
|
||||
@Test |
||||
void shouldOnlySupportClientHttpObservationContext() { |
||||
assertThat(this.convention.supportsContext(this.context)).isTrue(); |
||||
assertThat(this.convention.supportsContext(new OtherContext())).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void shouldPushTagsAsLowCardinalityKeyValues() { |
||||
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"), |
||||
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"), |
||||
KeyValue.of("method", "GET")); |
||||
} |
||||
|
||||
@Test |
||||
void shouldNotPushAnyHighCardinalityKeyValue() { |
||||
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty(); |
||||
} |
||||
|
||||
static class OtherContext extends Observation.Context { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.client; |
||||
|
||||
import java.net.URI; |
||||
|
||||
import io.micrometer.common.KeyValue; |
||||
import io.micrometer.observation.Observation; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientRequestObservationContext; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ClientObservationConventionAdapter}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings({ "deprecation", "removal" }) |
||||
class ClientObservationConventionAdapterTests { |
||||
|
||||
private static final String TEST_METRIC_NAME = "test.metric.name"; |
||||
|
||||
private final ClientObservationConventionAdapter convention = new ClientObservationConventionAdapter( |
||||
TEST_METRIC_NAME, new DefaultWebClientExchangeTagsProvider()); |
||||
|
||||
private final ClientRequest.Builder requestBuilder = ClientRequest |
||||
.create(HttpMethod.GET, URI.create("/resource/test")) |
||||
.attribute(WebClient.class.getName() + ".uriTemplate", "/resource/{name}"); |
||||
|
||||
private final ClientResponse response = ClientResponse.create(HttpStatus.OK).body("foo").build(); |
||||
|
||||
private ClientRequestObservationContext context; |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.context = new ClientRequestObservationContext(); |
||||
this.context.setCarrier(this.requestBuilder); |
||||
this.context.setResponse(this.response); |
||||
this.context.setUriTemplate("/resource/{name}"); |
||||
} |
||||
|
||||
@Test |
||||
void shouldUseConfiguredName() { |
||||
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME); |
||||
} |
||||
|
||||
@Test |
||||
void shouldOnlySupportClientObservationContext() { |
||||
assertThat(this.convention.supportsContext(this.context)).isTrue(); |
||||
assertThat(this.convention.supportsContext(new OtherContext())).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void shouldPushTagsAsLowCardinalityKeyValues() { |
||||
this.context.setRequest(this.requestBuilder.build()); |
||||
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"), |
||||
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"), |
||||
KeyValue.of("method", "GET")); |
||||
} |
||||
|
||||
@Test |
||||
void doesNotFailWithEmptyRequest() { |
||||
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"), |
||||
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"), |
||||
KeyValue.of("method", "GET")); |
||||
} |
||||
|
||||
@Test |
||||
void shouldNotPushAnyHighCardinalityKeyValue() { |
||||
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty(); |
||||
} |
||||
|
||||
static class OtherContext extends Observation.Context { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,64 +0,0 @@
@@ -1,64 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.reactive; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import io.micrometer.common.KeyValue; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; |
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext; |
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest; |
||||
import org.springframework.mock.http.server.reactive.MockServerHttpResponse; |
||||
import org.springframework.web.reactive.HandlerMapping; |
||||
import org.springframework.web.util.pattern.PathPatternParser; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ServerRequestObservationConventionAdapter}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class ServerRequestObservationConventionAdapterTests { |
||||
|
||||
private static final String TEST_METRIC_NAME = "test.metric.name"; |
||||
|
||||
private final ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter( |
||||
TEST_METRIC_NAME, new DefaultWebFluxTagsProvider()); |
||||
|
||||
@Test |
||||
void shouldUseConfiguredName() { |
||||
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME); |
||||
} |
||||
|
||||
@Test |
||||
void shouldPushTagsAsLowCardinalityKeyValues() { |
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/resource/test").build(); |
||||
MockServerHttpResponse response = new MockServerHttpResponse(); |
||||
ServerRequestObservationContext context = new ServerRequestObservationContext(request, response, |
||||
Map.of(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, |
||||
PathPatternParser.defaultInstance.parse("/resource/{name}"))); |
||||
assertThat(this.convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("status", "200"), |
||||
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"), |
||||
KeyValue.of("method", "GET")); |
||||
} |
||||
|
||||
} |
||||
@ -1,111 +0,0 @@
@@ -1,111 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.autoconfigure.observation.web.servlet; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import io.micrometer.common.KeyValue; |
||||
import io.micrometer.core.instrument.Tag; |
||||
import io.micrometer.core.instrument.Tags; |
||||
import io.micrometer.observation.Observation; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor; |
||||
import org.springframework.http.server.observation.ServerRequestObservationContext; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ServerRequestObservationConventionAdapter} |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class ServerRequestObservationConventionAdapterTests { |
||||
|
||||
private static final String TEST_METRIC_NAME = "test.metric.name"; |
||||
|
||||
private final ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter( |
||||
TEST_METRIC_NAME, new DefaultWebMvcTagsProvider(), Collections.emptyList()); |
||||
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/resource/test"); |
||||
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
|
||||
private final ServerRequestObservationContext context = new ServerRequestObservationContext(this.request, |
||||
this.response); |
||||
|
||||
@Test |
||||
void customNameIsUsed() { |
||||
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME); |
||||
} |
||||
|
||||
@Test |
||||
void onlySupportServerRequestObservationContext() { |
||||
assertThat(this.convention.supportsContext(this.context)).isTrue(); |
||||
assertThat(this.convention.supportsContext(new OtherContext())).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void pushTagsAsLowCardinalityKeyValues() { |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/resource/{name}"); |
||||
this.context.setPathPattern("/resource/{name}"); |
||||
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"), |
||||
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"), |
||||
KeyValue.of("method", "GET")); |
||||
} |
||||
|
||||
@Test |
||||
void doesNotPushAnyHighCardinalityKeyValue() { |
||||
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void pushTagsFromContributors() { |
||||
ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter( |
||||
TEST_METRIC_NAME, null, List.of(new CustomWebMvcContributor())); |
||||
assertThat(convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("custom", "value")); |
||||
} |
||||
|
||||
static class OtherContext extends Observation.Context { |
||||
|
||||
} |
||||
|
||||
static class CustomWebMvcContributor implements WebMvcTagsContributor { |
||||
|
||||
@Override |
||||
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, |
||||
Throwable exception) { |
||||
return Tags.of("custom", "value"); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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 java.util.Arrays; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.http.HttpRequest; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* Default implementation of {@link RestTemplateExchangeTagsProvider}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Nishant Raut |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.client.observation.DefaultClientRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@SuppressWarnings("removal") |
||||
public class DefaultRestTemplateExchangeTagsProvider implements RestTemplateExchangeTagsProvider { |
||||
|
||||
@Override |
||||
public Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) { |
||||
Tag uriTag = (StringUtils.hasText(urlTemplate) ? RestTemplateExchangeTags.uri(urlTemplate) |
||||
: RestTemplateExchangeTags.uri(request)); |
||||
return Arrays.asList(RestTemplateExchangeTags.method(request), uriTag, |
||||
RestTemplateExchangeTags.status(response), RestTemplateExchangeTags.clientName(request), |
||||
RestTemplateExchangeTags.outcome(response)); |
||||
} |
||||
|
||||
} |
||||
@ -1,144 +0,0 @@
@@ -1,144 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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 java.io.IOException; |
||||
import java.net.URI; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.boot.actuate.metrics.http.Outcome; |
||||
import org.springframework.http.HttpRequest; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Factory methods for creating {@link Tag Tags} related to a request-response exchange |
||||
* performed by a {@link RestTemplate}. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @author Jon Schneider |
||||
* @author Nishant Raut |
||||
* @author Brian Clozel |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link DefaultClientRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public final class RestTemplateExchangeTags { |
||||
|
||||
private static final Pattern STRIP_URI_PATTERN = Pattern.compile("^https?://[^/]+/"); |
||||
|
||||
private RestTemplateExchangeTags() { |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code method} {@code Tag} for the {@link HttpRequest#getMethod() method} |
||||
* of the given {@code request}. |
||||
* @param request the request |
||||
* @return the method tag |
||||
*/ |
||||
public static Tag method(HttpRequest request) { |
||||
return Tag.of("method", request.getMethod().name()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} {@code Tag} for the URI of the given {@code request}. |
||||
* @param request the request |
||||
* @return the uri tag |
||||
*/ |
||||
public static Tag uri(HttpRequest request) { |
||||
return Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().toString()))); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} {@code Tag} from the given {@code uriTemplate}. |
||||
* @param uriTemplate the template |
||||
* @return the uri tag |
||||
*/ |
||||
public static Tag uri(String uriTemplate) { |
||||
String uri = (StringUtils.hasText(uriTemplate) ? uriTemplate : "none"); |
||||
return Tag.of("uri", ensureLeadingSlash(stripUri(uri))); |
||||
} |
||||
|
||||
private static String stripUri(String uri) { |
||||
return STRIP_URI_PATTERN.matcher(uri).replaceAll(""); |
||||
} |
||||
|
||||
private static String ensureLeadingSlash(String url) { |
||||
return (url == null || url.startsWith("/")) ? url : "/" + url; |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code status} {@code Tag} derived from the |
||||
* {@link ClientHttpResponse#getStatusCode() status} of the given {@code response}. |
||||
* @param response the response |
||||
* @return the status tag |
||||
*/ |
||||
public static Tag status(ClientHttpResponse response) { |
||||
return Tag.of("status", getStatusMessage(response)); |
||||
} |
||||
|
||||
private static String getStatusMessage(ClientHttpResponse response) { |
||||
try { |
||||
if (response == null) { |
||||
return "CLIENT_ERROR"; |
||||
} |
||||
return String.valueOf(response.getStatusCode().value()); |
||||
} |
||||
catch (IOException ex) { |
||||
return "IO_ERROR"; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create a {@code client.name} {@code Tag} derived from the {@link URI#getHost host} |
||||
* of the {@link HttpRequest#getURI() URI} of the given {@code request}. |
||||
* @param request the request |
||||
* @return the client.name tag |
||||
*/ |
||||
public static Tag clientName(HttpRequest request) { |
||||
String host = request.getURI().getHost(); |
||||
if (host == null) { |
||||
host = "none"; |
||||
} |
||||
return Tag.of("client.name", host); |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@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) { |
||||
try { |
||||
if (response != null) { |
||||
return Outcome.forStatus(response.getStatusCode().value()).asTag(); |
||||
} |
||||
} |
||||
catch (IOException ex) { |
||||
// Continue
|
||||
} |
||||
return Outcome.UNKNOWN.asTag(); |
||||
} |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.springframework.http.HttpRequest; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.http.client.observation.ClientRequestObservationConvention; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Provides {@link Tag Tags} for an exchange performed by a {@link RestTemplate}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link ClientRequestObservationConvention} |
||||
*/ |
||||
@FunctionalInterface |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface RestTemplateExchangeTagsProvider { |
||||
|
||||
/** |
||||
* Provides the tags to be associated with metrics that are recorded for the given |
||||
* {@code request} and {@code response} exchange. |
||||
* @param urlTemplate the source URl template, if available |
||||
* @param request the request |
||||
* @param response the response (may be {@code null} if the exchange failed) |
||||
* @return the tags |
||||
*/ |
||||
Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response); |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.client; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
|
||||
/** |
||||
* Default implementation of {@link WebClientExchangeTagsProvider}. |
||||
* |
||||
* @author Brian Clozel |
||||
* @author Nishant Raut |
||||
* @since 2.1.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.web.reactive.function.client.ClientRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@SuppressWarnings("removal") |
||||
public class DefaultWebClientExchangeTagsProvider implements WebClientExchangeTagsProvider { |
||||
|
||||
@Override |
||||
public Iterable<Tag> tags(ClientRequest request, ClientResponse response, Throwable throwable) { |
||||
Tag method = WebClientExchangeTags.method(request); |
||||
Tag uri = WebClientExchangeTags.uri(request); |
||||
Tag clientName = WebClientExchangeTags.clientName(request); |
||||
Tag status = WebClientExchangeTags.status(response, throwable); |
||||
Tag outcome = WebClientExchangeTags.outcome(response); |
||||
return Arrays.asList(method, uri, clientName, status, outcome); |
||||
} |
||||
|
||||
} |
||||
@ -1,127 +0,0 @@
@@ -1,127 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.boot.actuate.metrics.http.Outcome; |
||||
import org.springframework.http.client.reactive.ClientHttpRequest; |
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
/** |
||||
* Factory methods for creating {@link Tag Tags} related to a request-response exchange |
||||
* performed by a {@link WebClient}. |
||||
* |
||||
* @author Brian Clozel |
||||
* @author Nishant Raut |
||||
* @since 2.1.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public final class WebClientExchangeTags { |
||||
|
||||
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; |
||||
|
||||
private static final Tag IO_ERROR = Tag.of("status", "IO_ERROR"); |
||||
|
||||
private static final Tag CLIENT_ERROR = Tag.of("status", "CLIENT_ERROR"); |
||||
|
||||
private static final Pattern PATTERN_BEFORE_PATH = Pattern.compile("^https?://[^/]+/"); |
||||
|
||||
private static final Tag CLIENT_NAME_NONE = Tag.of("client.name", "none"); |
||||
|
||||
private WebClientExchangeTags() { |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code method} {@code Tag} for the {@link ClientHttpRequest#getMethod() |
||||
* method} of the given {@code request}. |
||||
* @param request the request |
||||
* @return the method tag |
||||
*/ |
||||
public static Tag method(ClientRequest request) { |
||||
return Tag.of("method", request.method().name()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} {@code Tag} for the URI path of the given {@code request}. |
||||
* @param request the request |
||||
* @return the uri tag |
||||
*/ |
||||
public static Tag uri(ClientRequest request) { |
||||
String uri = (String) request.attribute(URI_TEMPLATE_ATTRIBUTE).orElseGet(() -> request.url().toString()); |
||||
return Tag.of("uri", extractPath(uri)); |
||||
} |
||||
|
||||
private static String extractPath(String url) { |
||||
String path = PATTERN_BEFORE_PATH.matcher(url).replaceFirst(""); |
||||
return (path.startsWith("/") ? path : "/" + path); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code status} {@code Tag} derived from the |
||||
* {@link ClientResponse#statusCode()} of the given {@code response} if available, the |
||||
* thrown exception otherwise, or considers the request as Cancelled as a last resort. |
||||
* @param response the response |
||||
* @param throwable the exception |
||||
* @return the status tag |
||||
* @since 2.3.0 |
||||
*/ |
||||
public static Tag status(ClientResponse response, Throwable throwable) { |
||||
if (response != null) { |
||||
return Tag.of("status", String.valueOf(response.statusCode().value())); |
||||
} |
||||
if (throwable != null) { |
||||
return (throwable instanceof IOException) ? IO_ERROR : CLIENT_ERROR; |
||||
} |
||||
return CLIENT_ERROR; |
||||
} |
||||
|
||||
/** |
||||
* Create a {@code client.name} {@code Tag} derived from the |
||||
* {@link java.net.URI#getHost host} of the {@link ClientRequest#url() URL} of the |
||||
* given {@code request}. |
||||
* @param request the request |
||||
* @return the client.name tag |
||||
*/ |
||||
public static Tag clientName(ClientRequest request) { |
||||
String host = request.url().getHost(); |
||||
if (host == null) { |
||||
return CLIENT_NAME_NONE; |
||||
} |
||||
return Tag.of("client.name", host); |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@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) { |
||||
Outcome outcome = (response != null) ? Outcome.forStatus(response.statusCode().value()) : Outcome.UNKNOWN; |
||||
return outcome.asTag(); |
||||
} |
||||
|
||||
} |
||||
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.client; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
|
||||
/** |
||||
* {@link Tag Tags} provider for an exchange performed by a |
||||
* {@link org.springframework.web.reactive.function.client.WebClient}. |
||||
* |
||||
* @author Brian Clozel |
||||
* @since 2.1.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.web.reactive.function.client.ClientRequestObservationConvention} |
||||
*/ |
||||
@FunctionalInterface |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface WebClientExchangeTagsProvider { |
||||
|
||||
/** |
||||
* Provide tags to be associated with metrics for the client exchange. |
||||
* @param request the client request |
||||
* @param response the server response (may be {@code null}) |
||||
* @param throwable the exception (may be {@code null}) |
||||
* @return tags to associate with metrics for the request and response exchange |
||||
*/ |
||||
Iterable<Tag> tags(ClientRequest request, ClientResponse response, Throwable throwable); |
||||
|
||||
} |
||||
@ -1,89 +0,0 @@
@@ -1,89 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import io.micrometer.core.instrument.Tags; |
||||
|
||||
import org.springframework.web.server.ServerWebExchange; |
||||
|
||||
/** |
||||
* Default implementation of {@link WebFluxTagsProvider}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@SuppressWarnings("removal") |
||||
public class DefaultWebFluxTagsProvider implements WebFluxTagsProvider { |
||||
|
||||
private final boolean ignoreTrailingSlash; |
||||
|
||||
private final List<WebFluxTagsContributor> contributors; |
||||
|
||||
public DefaultWebFluxTagsProvider() { |
||||
this(false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link DefaultWebFluxTagsProvider} that will provide tags from the |
||||
* given {@code contributors} in addition to its own. |
||||
* @param contributors the contributors that will provide additional tags |
||||
* @since 2.3.0 |
||||
*/ |
||||
public DefaultWebFluxTagsProvider(List<WebFluxTagsContributor> contributors) { |
||||
this(false, contributors); |
||||
} |
||||
|
||||
public DefaultWebFluxTagsProvider(boolean ignoreTrailingSlash) { |
||||
this(ignoreTrailingSlash, Collections.emptyList()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link DefaultWebFluxTagsProvider} that will provide tags from the |
||||
* given {@code contributors} in addition to its own. |
||||
* @param ignoreTrailingSlash whether trailing slashes should be ignored when |
||||
* determining the {@code uri} tag. |
||||
* @param contributors the contributors that will provide additional tags |
||||
* @since 2.3.0 |
||||
*/ |
||||
public DefaultWebFluxTagsProvider(boolean ignoreTrailingSlash, List<WebFluxTagsContributor> contributors) { |
||||
this.ignoreTrailingSlash = ignoreTrailingSlash; |
||||
this.contributors = contributors; |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable exception) { |
||||
Tags tags = Tags.empty(); |
||||
tags = tags.and(WebFluxTags.method(exchange)); |
||||
tags = tags.and(WebFluxTags.uri(exchange, this.ignoreTrailingSlash)); |
||||
tags = tags.and(WebFluxTags.exception(exception)); |
||||
tags = tags.and(WebFluxTags.status(exchange)); |
||||
tags = tags.and(WebFluxTags.outcome(exchange, exception)); |
||||
for (WebFluxTagsContributor contributor : this.contributors) { |
||||
tags = tags.and(contributor.httpRequestTags(exchange, exception)); |
||||
} |
||||
return tags; |
||||
} |
||||
|
||||
} |
||||
@ -1,191 +0,0 @@
@@ -1,191 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.boot.actuate.metrics.http.Outcome; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.HttpStatusCode; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.reactive.HandlerMapping; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
import org.springframework.web.util.pattern.PathPattern; |
||||
|
||||
/** |
||||
* Factory methods for {@link Tag Tags} associated with a request-response exchange that |
||||
* is handled by WebFlux. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @author Michael McFadyen |
||||
* @author Brian Clozel |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public final class WebFluxTags { |
||||
|
||||
private static final Tag URI_NOT_FOUND = Tag.of("uri", "NOT_FOUND"); |
||||
|
||||
private static final Tag URI_REDIRECTION = Tag.of("uri", "REDIRECTION"); |
||||
|
||||
private static final Tag URI_ROOT = Tag.of("uri", "root"); |
||||
|
||||
private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN"); |
||||
|
||||
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None"); |
||||
|
||||
private static final Pattern FORWARD_SLASHES_PATTERN = Pattern.compile("//+"); |
||||
|
||||
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS = new HashSet<>( |
||||
Arrays.asList("AbortedException", "ClientAbortException", "EOFException", "EofException")); |
||||
|
||||
private WebFluxTags() { |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code method} tag based on the |
||||
* {@link org.springframework.http.server.reactive.ServerHttpRequest#getMethod() |
||||
* method} of the {@link ServerWebExchange#getRequest()} request of the given |
||||
* {@code exchange}. |
||||
* @param exchange the exchange |
||||
* @return the method tag whose value is a capitalized method (e.g. GET). |
||||
*/ |
||||
public static Tag method(ServerWebExchange exchange) { |
||||
return Tag.of("method", exchange.getRequest().getMethod().name()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code status} tag based on the response status of the given |
||||
* {@code exchange}. |
||||
* @param exchange the exchange |
||||
* @return the status tag derived from the response status |
||||
*/ |
||||
public static Tag status(ServerWebExchange exchange) { |
||||
HttpStatusCode status = exchange.getResponse().getStatusCode(); |
||||
if (status == null) { |
||||
status = HttpStatus.OK; |
||||
} |
||||
return Tag.of("status", String.valueOf(status.value())); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the |
||||
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if |
||||
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND} |
||||
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN} |
||||
* for all other requests. |
||||
* @param exchange the exchange |
||||
* @return the uri tag derived from the exchange |
||||
*/ |
||||
public static Tag uri(ServerWebExchange exchange) { |
||||
return uri(exchange, false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the |
||||
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if |
||||
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND} |
||||
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN} |
||||
* for all other requests. |
||||
* @param exchange the exchange |
||||
* @param ignoreTrailingSlash whether to ignore the trailing slash |
||||
* @return the uri tag derived from the exchange |
||||
*/ |
||||
public static Tag uri(ServerWebExchange exchange, boolean ignoreTrailingSlash) { |
||||
PathPattern pathPattern = exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); |
||||
if (pathPattern != null) { |
||||
String patternString = pathPattern.getPatternString(); |
||||
if (ignoreTrailingSlash && patternString.length() > 1) { |
||||
patternString = removeTrailingSlash(patternString); |
||||
} |
||||
if (patternString.isEmpty()) { |
||||
return URI_ROOT; |
||||
} |
||||
return Tag.of("uri", patternString); |
||||
} |
||||
HttpStatusCode status = exchange.getResponse().getStatusCode(); |
||||
if (status != null) { |
||||
if (status.is3xxRedirection()) { |
||||
return URI_REDIRECTION; |
||||
} |
||||
if (status == HttpStatus.NOT_FOUND) { |
||||
return URI_NOT_FOUND; |
||||
} |
||||
} |
||||
String path = getPathInfo(exchange); |
||||
if (path.isEmpty()) { |
||||
return URI_ROOT; |
||||
} |
||||
return URI_UNKNOWN; |
||||
} |
||||
|
||||
private static String getPathInfo(ServerWebExchange exchange) { |
||||
String path = exchange.getRequest().getPath().value(); |
||||
String uri = StringUtils.hasText(path) ? path : "/"; |
||||
String singleSlashes = FORWARD_SLASHES_PATTERN.matcher(uri).replaceAll("/"); |
||||
return removeTrailingSlash(singleSlashes); |
||||
} |
||||
|
||||
private static String removeTrailingSlash(String text) { |
||||
if (!StringUtils.hasLength(text)) { |
||||
return text; |
||||
} |
||||
return text.endsWith("/") ? text.substring(0, text.length() - 1) : text; |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@code exception} tag based on the {@link Class#getSimpleName() simple |
||||
* name} of the class of the given {@code exception}. |
||||
* @param exception the exception, may be {@code null} |
||||
* @return the exception tag derived from the exception |
||||
*/ |
||||
public static Tag exception(Throwable exception) { |
||||
if (exception != null) { |
||||
String simpleName = exception.getClass().getSimpleName(); |
||||
return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName : exception.getClass().getName()); |
||||
} |
||||
return EXCEPTION_NONE; |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@code outcome} tag based on the response status of the given |
||||
* {@code exchange} and the exception thrown during request processing. |
||||
* @param exchange the exchange |
||||
* @param exception the termination signal sent by the publisher |
||||
* @return the outcome tag derived from the response status |
||||
* @since 2.5.0 |
||||
*/ |
||||
public static Tag outcome(ServerWebExchange exchange, Throwable exception) { |
||||
if (exception != null) { |
||||
if (DISCONNECTED_CLIENT_EXCEPTIONS.contains(exception.getClass().getSimpleName())) { |
||||
return Outcome.UNKNOWN.asTag(); |
||||
} |
||||
} |
||||
HttpStatusCode statusCode = exchange.getResponse().getStatusCode(); |
||||
Outcome outcome = (statusCode != null) ? Outcome.forStatus(statusCode.value()) : Outcome.SUCCESS; |
||||
return outcome.asTag(); |
||||
} |
||||
|
||||
} |
||||
@ -1,44 +0,0 @@
@@ -1,44 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.web.server.ServerWebExchange; |
||||
|
||||
/** |
||||
* A contributor of {@link Tag Tags} for WebFlux-based request handling. Typically used by |
||||
* a {@link WebFluxTagsProvider} to provide tags in addition to its defaults. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @since 2.3.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@FunctionalInterface |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface WebFluxTagsContributor { |
||||
|
||||
/** |
||||
* Provides tags to be associated with metrics for the given {@code exchange}. |
||||
* @param exchange the exchange |
||||
* @param ex the current exception (may be {@code null}) |
||||
* @return tags to associate with metrics for the request and response exchange |
||||
*/ |
||||
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex); |
||||
|
||||
} |
||||
@ -1,44 +0,0 @@
@@ -1,44 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
|
||||
import org.springframework.web.server.ServerWebExchange; |
||||
|
||||
/** |
||||
* Provides {@link Tag Tags} for WebFlux-based request handling. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@FunctionalInterface |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface WebFluxTagsProvider { |
||||
|
||||
/** |
||||
* Provides tags to be associated with metrics for the given {@code exchange}. |
||||
* @param exchange the exchange |
||||
* @param ex the current exception (may be {@code null}) |
||||
* @return tags to associate with metrics for the request and response exchange |
||||
*/ |
||||
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex); |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Actuator support for WebFlux metrics. |
||||
*/ |
||||
package org.springframework.boot.actuate.metrics.web.reactive.server; |
||||
@ -1,94 +0,0 @@
@@ -1,94 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.servlet; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import io.micrometer.core.instrument.Tags; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* Default implementation of {@link WebMvcTagsProvider}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@SuppressWarnings("removal") |
||||
public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider { |
||||
|
||||
private final boolean ignoreTrailingSlash; |
||||
|
||||
private final List<WebMvcTagsContributor> contributors; |
||||
|
||||
public DefaultWebMvcTagsProvider() { |
||||
this(false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link DefaultWebMvcTagsProvider} that will provide tags from the |
||||
* given {@code contributors} in addition to its own. |
||||
* @param contributors the contributors that will provide additional tags |
||||
* @since 2.3.0 |
||||
*/ |
||||
public DefaultWebMvcTagsProvider(List<WebMvcTagsContributor> contributors) { |
||||
this(false, contributors); |
||||
} |
||||
|
||||
public DefaultWebMvcTagsProvider(boolean ignoreTrailingSlash) { |
||||
this(ignoreTrailingSlash, Collections.emptyList()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link DefaultWebMvcTagsProvider} that will provide tags from the |
||||
* given {@code contributors} in addition to its own. |
||||
* @param ignoreTrailingSlash whether trailing slashes should be ignored when |
||||
* determining the {@code uri} tag. |
||||
* @param contributors the contributors that will provide additional tags |
||||
* @since 2.3.0 |
||||
*/ |
||||
public DefaultWebMvcTagsProvider(boolean ignoreTrailingSlash, List<WebMvcTagsContributor> contributors) { |
||||
this.ignoreTrailingSlash = ignoreTrailingSlash; |
||||
this.contributors = contributors; |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, |
||||
Throwable exception) { |
||||
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response, this.ignoreTrailingSlash), |
||||
WebMvcTags.exception(exception), WebMvcTags.status(response), WebMvcTags.outcome(response)); |
||||
for (WebMvcTagsContributor contributor : this.contributors) { |
||||
tags = tags.and(contributor.getTags(request, response, handler, exception)); |
||||
} |
||||
return tags; |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) { |
||||
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, null, this.ignoreTrailingSlash)); |
||||
for (WebMvcTagsContributor contributor : this.contributors) { |
||||
tags = tags.and(contributor.getLongRequestTags(request, handler)); |
||||
} |
||||
return tags; |
||||
} |
||||
|
||||
} |
||||
@ -1,193 +0,0 @@
@@ -1,193 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.servlet; |
||||
|
||||
import java.util.regex.Pattern; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
|
||||
import org.springframework.boot.actuate.metrics.http.Outcome; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
import org.springframework.web.util.pattern.PathPattern; |
||||
|
||||
/** |
||||
* Factory methods for {@link Tag Tags} associated with a request-response exchange that |
||||
* is handled by Spring MVC. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @author Brian Clozel |
||||
* @author Michael McFadyen |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public final class WebMvcTags { |
||||
|
||||
private static final String DATA_REST_PATH_PATTERN_ATTRIBUTE = "org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.EFFECTIVE_REPOSITORY_RESOURCE_LOOKUP_PATH"; |
||||
|
||||
private static final Tag URI_NOT_FOUND = Tag.of("uri", "NOT_FOUND"); |
||||
|
||||
private static final Tag URI_REDIRECTION = Tag.of("uri", "REDIRECTION"); |
||||
|
||||
private static final Tag URI_ROOT = Tag.of("uri", "root"); |
||||
|
||||
private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN"); |
||||
|
||||
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None"); |
||||
|
||||
private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN"); |
||||
|
||||
private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN"); |
||||
|
||||
private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$"); |
||||
|
||||
private static final Pattern MULTIPLE_SLASH_PATTERN = Pattern.compile("//+"); |
||||
|
||||
private WebMvcTags() { |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code method} tag based on the {@link HttpServletRequest#getMethod() |
||||
* method} of the given {@code request}. |
||||
* @param request the request |
||||
* @return the method tag whose value is a capitalized method (e.g. GET). |
||||
*/ |
||||
public static Tag method(HttpServletRequest request) { |
||||
return (request != null) ? Tag.of("method", request.getMethod()) : METHOD_UNKNOWN; |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code status} tag based on the status of the given {@code response}. |
||||
* @param response the HTTP response |
||||
* @return the status tag derived from the status of the response |
||||
*/ |
||||
public static Tag status(HttpServletResponse response) { |
||||
return (response != null) ? Tag.of("status", Integer.toString(response.getStatus())) : STATUS_UNKNOWN; |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} tag based on the URI of the given {@code request}. Uses the |
||||
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if |
||||
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND} |
||||
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN} |
||||
* for all other requests. |
||||
* @param request the request |
||||
* @param response the response |
||||
* @return the uri tag derived from the request |
||||
*/ |
||||
public static Tag uri(HttpServletRequest request, HttpServletResponse response) { |
||||
return uri(request, response, false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@code uri} tag based on the URI of the given {@code request}. Uses the |
||||
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if |
||||
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND} |
||||
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN} |
||||
* for all other requests. |
||||
* @param request the request |
||||
* @param response the response |
||||
* @param ignoreTrailingSlash whether to ignore the trailing slash |
||||
* @return the uri tag derived from the request |
||||
*/ |
||||
public static Tag uri(HttpServletRequest request, HttpServletResponse response, boolean ignoreTrailingSlash) { |
||||
if (request != null) { |
||||
String pattern = getMatchingPattern(request); |
||||
if (pattern != null) { |
||||
if (ignoreTrailingSlash && pattern.length() > 1) { |
||||
pattern = TRAILING_SLASH_PATTERN.matcher(pattern).replaceAll(""); |
||||
} |
||||
if (pattern.isEmpty()) { |
||||
return URI_ROOT; |
||||
} |
||||
return Tag.of("uri", pattern); |
||||
} |
||||
if (response != null) { |
||||
HttpStatus status = extractStatus(response); |
||||
if (status != null) { |
||||
if (status.is3xxRedirection()) { |
||||
return URI_REDIRECTION; |
||||
} |
||||
if (status == HttpStatus.NOT_FOUND) { |
||||
return URI_NOT_FOUND; |
||||
} |
||||
} |
||||
} |
||||
String pathInfo = getPathInfo(request); |
||||
if (pathInfo.isEmpty()) { |
||||
return URI_ROOT; |
||||
} |
||||
} |
||||
return URI_UNKNOWN; |
||||
} |
||||
|
||||
private static HttpStatus extractStatus(HttpServletResponse response) { |
||||
try { |
||||
return HttpStatus.valueOf(response.getStatus()); |
||||
} |
||||
catch (IllegalArgumentException ex) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private static String getMatchingPattern(HttpServletRequest request) { |
||||
PathPattern dataRestPathPattern = (PathPattern) request.getAttribute(DATA_REST_PATH_PATTERN_ATTRIBUTE); |
||||
if (dataRestPathPattern != null) { |
||||
return dataRestPathPattern.getPatternString(); |
||||
} |
||||
return (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); |
||||
} |
||||
|
||||
private static String getPathInfo(HttpServletRequest request) { |
||||
String pathInfo = request.getPathInfo(); |
||||
String uri = StringUtils.hasText(pathInfo) ? pathInfo : "/"; |
||||
uri = MULTIPLE_SLASH_PATTERN.matcher(uri).replaceAll("/"); |
||||
return TRAILING_SLASH_PATTERN.matcher(uri).replaceAll(""); |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@code exception} tag based on the {@link Class#getSimpleName() simple |
||||
* name} of the class of the given {@code exception}. |
||||
* @param exception the exception, may be {@code null} |
||||
* @return the exception tag derived from the exception |
||||
*/ |
||||
public static Tag exception(Throwable exception) { |
||||
if (exception != null) { |
||||
String simpleName = exception.getClass().getSimpleName(); |
||||
return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName : exception.getClass().getName()); |
||||
} |
||||
return EXCEPTION_NONE; |
||||
} |
||||
|
||||
/** |
||||
* Creates an {@code outcome} tag based on the status of the given {@code response}. |
||||
* @param response the HTTP response |
||||
* @return the outcome tag derived from the status of the response |
||||
* @since 2.1.0 |
||||
*/ |
||||
public static Tag outcome(HttpServletResponse response) { |
||||
Outcome outcome = (response != null) ? Outcome.forStatus(response.getStatus()) : Outcome.UNKNOWN; |
||||
return outcome.asTag(); |
||||
} |
||||
|
||||
} |
||||
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.servlet; |
||||
|
||||
import io.micrometer.core.instrument.LongTaskTimer; |
||||
import io.micrometer.core.instrument.Tag; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* A contributor of {@link Tag Tags} for Spring MVC-based request handling. Typically used |
||||
* by a {@link WebMvcTagsProvider} to provide tags in addition to its defaults. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @since 2.3.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface WebMvcTagsContributor { |
||||
|
||||
/** |
||||
* Provides tags to be associated with metrics for the given {@code request} and |
||||
* {@code response} exchange. |
||||
* @param request the request |
||||
* @param response the response |
||||
* @param handler the handler for the request or {@code null} if the handler is |
||||
* unknown |
||||
* @param exception the current exception, if any |
||||
* @return tags to associate with metrics for the request and response exchange |
||||
*/ |
||||
Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, |
||||
Throwable exception); |
||||
|
||||
/** |
||||
* Provides tags to be used by {@link LongTaskTimer long task timers}. |
||||
* @param request the HTTP request |
||||
* @param handler the handler for the request or {@code null} if the handler is |
||||
* unknown |
||||
* @return tags to associate with metrics recorded for the request |
||||
*/ |
||||
Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler); |
||||
|
||||
} |
||||
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.servlet; |
||||
|
||||
import io.micrometer.core.instrument.LongTaskTimer; |
||||
import io.micrometer.core.instrument.Tag; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* Provides {@link Tag Tags} for Spring MVC-based request handling. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface WebMvcTagsProvider { |
||||
|
||||
/** |
||||
* Provides tags to be associated with metrics for the given {@code request} and |
||||
* {@code response} exchange. |
||||
* @param request the request |
||||
* @param response the response |
||||
* @param handler the handler for the request or {@code null} if the handler is |
||||
* unknown |
||||
* @param exception the current exception, if any |
||||
* @return tags to associate with metrics for the request and response exchange |
||||
*/ |
||||
Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, |
||||
Throwable exception); |
||||
|
||||
/** |
||||
* Provides tags to be used by {@link LongTaskTimer long task timers}. |
||||
* @param request the HTTP request |
||||
* @param handler the handler for the request or {@code null} if the handler is |
||||
* unknown |
||||
* @return tags to associate with metrics recorded for the request |
||||
*/ |
||||
Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler); |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Actuator support for Spring MVC metrics. |
||||
*/ |
||||
package org.springframework.boot.actuate.metrics.web.servlet; |
||||
@ -1,120 +0,0 @@
@@ -1,120 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.endpoint.web.servlet; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.function.Function; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.StreamSupport; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link DefaultWebMvcTagsProvider}. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class DefaultWebMvcTagsProviderTests { |
||||
|
||||
@Test |
||||
void whenTagsAreProvidedThenDefaultTagsArePresent() { |
||||
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getTags(null, null, null, null)); |
||||
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri"); |
||||
} |
||||
|
||||
@Test |
||||
void givenSomeContributorsWhenTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() { |
||||
Map<String, Tag> tags = asMap( |
||||
new DefaultWebMvcTagsProvider(Arrays.asList(new TestWebMvcTagsContributor("alpha"), |
||||
new TestWebMvcTagsContributor("bravo", "charlie"))) |
||||
.getTags(null, null, null, null)); |
||||
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri", "alpha", "bravo", |
||||
"charlie"); |
||||
} |
||||
|
||||
@Test |
||||
void whenLongRequestTagsAreProvidedThenDefaultTagsArePresent() { |
||||
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getLongRequestTags(null, null)); |
||||
assertThat(tags).containsOnlyKeys("method", "uri"); |
||||
} |
||||
|
||||
@Test |
||||
void givenSomeContributorsWhenLongRequestTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() { |
||||
Map<String, Tag> tags = asMap( |
||||
new DefaultWebMvcTagsProvider(Arrays.asList(new TestWebMvcTagsContributor("alpha"), |
||||
new TestWebMvcTagsContributor("bravo", "charlie"))) |
||||
.getLongRequestTags(null, null)); |
||||
assertThat(tags).containsOnlyKeys("method", "uri", "alpha", "bravo", "charlie"); |
||||
} |
||||
|
||||
@Test |
||||
void trailingSlashIsIncludedByDefault() { |
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/the/uri/"); |
||||
request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "{one}/{two}/"); |
||||
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getTags(request, null, null, null)); |
||||
assertThat(tags.get("uri").getValue()).isEqualTo("{one}/{two}/"); |
||||
} |
||||
|
||||
@Test |
||||
void trailingSlashCanBeIgnored() { |
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/the/uri/"); |
||||
request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "{one}/{two}/"); |
||||
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider(true).getTags(request, null, null, null)); |
||||
assertThat(tags.get("uri").getValue()).isEqualTo("{one}/{two}"); |
||||
} |
||||
|
||||
private Map<String, Tag> asMap(Iterable<Tag> tags) { |
||||
return StreamSupport.stream(tags.spliterator(), false) |
||||
.collect(Collectors.toMap(Tag::getKey, Function.identity())); |
||||
} |
||||
|
||||
private static final class TestWebMvcTagsContributor implements WebMvcTagsContributor { |
||||
|
||||
private final List<String> tagNames; |
||||
|
||||
private TestWebMvcTagsContributor(String... tagNames) { |
||||
this.tagNames = Arrays.asList(tagNames); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, |
||||
Throwable exception) { |
||||
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList(); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) { |
||||
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,184 +0,0 @@
@@ -1,184 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.endpoint.web.servlet; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTags; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
import org.springframework.web.util.pattern.PathPatternParser; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link WebMvcTags}. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @author Brian Clozel |
||||
* @author Michael McFadyen |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class WebMvcTagsTests { |
||||
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
|
||||
@Test |
||||
void uriTagIsDataRestsEffectiveRepositoryLookupPathWhenAvailable() { |
||||
this.request.setAttribute( |
||||
"org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.EFFECTIVE_REPOSITORY_RESOURCE_LOOKUP_PATH", |
||||
new PathPatternParser().parse("/api/cities")); |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/api/{repository}"); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("/api/cities"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsBestMatchingPatternWhenAvailable() { |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/spring/"); |
||||
this.response.setStatus(301); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("/spring/"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenBestMatchingPatternIsEmpty() { |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, ""); |
||||
this.response.setStatus(301); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashRemoveTrailingSlash() { |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/spring/"); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response, true); |
||||
assertThat(tag.getValue()).isEqualTo("/spring"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashKeepSingleSlash() { |
||||
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/"); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response, true); |
||||
assertThat(tag.getValue()).isEqualTo("/"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenRequestHasNoPatternOrPathInfo() { |
||||
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenRequestHasNoPatternAndSlashPathInfo() { |
||||
this.request.setPathInfo("/"); |
||||
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsUnknownWhenRequestHasNoPatternAndNonRootPathInfo() { |
||||
this.request.setPathInfo("/example"); |
||||
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRedirectionWhenResponseStatusIs3xx() { |
||||
this.response.setStatus(301); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsNotFoundWhenResponseStatusIs404() { |
||||
this.response.setStatus(404); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("NOT_FOUND"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagToleratesCustomResponseStatus() { |
||||
this.response.setStatus(601); |
||||
Tag tag = WebMvcTags.uri(this.request, this.response); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagIsUnknownWhenRequestIsNull() { |
||||
Tag tag = WebMvcTags.uri(null, null); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseIsNull() { |
||||
Tag tag = WebMvcTags.outcome(null); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsInformationalWhenResponseIs1xx() { |
||||
this.response.setStatus(100); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseIs2xx() { |
||||
this.response.setStatus(200); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsRedirectionWhenResponseIs3xx() { |
||||
this.response.setStatus(301); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIs4xx() { |
||||
this.response.setStatus(400); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() { |
||||
this.response.setStatus(490); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsServerErrorWhenResponseIs5xx() { |
||||
this.response.setStatus(500); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() { |
||||
this.response.setStatus(701); |
||||
Tag tag = WebMvcTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
} |
||||
@ -1,118 +0,0 @@
@@ -1,118 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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 java.io.IOException; |
||||
import java.net.URI; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.HttpStatusCode; |
||||
import org.springframework.http.client.ClientHttpRequest; |
||||
import org.springframework.http.client.ClientHttpResponse; |
||||
import org.springframework.mock.http.client.MockClientHttpResponse; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link RestTemplateExchangeTags}. |
||||
* |
||||
* @author Nishant Raut |
||||
* @author Brian Clozel |
||||
*/ |
||||
@SuppressWarnings({ "removal" }) |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class RestTemplateExchangeTagsTests { |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseIsNull() { |
||||
Tag tag = RestTemplateExchangeTags.outcome(null); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsInformationalWhenResponseIs1xx() { |
||||
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.CONTINUE); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseIs2xx() { |
||||
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.OK); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsRedirectionWhenResponseIs3xx() { |
||||
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIs4xx() { |
||||
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.BAD_REQUEST); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsServerErrorWhenResponseIs5xx() { |
||||
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.BAD_GATEWAY); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseThrowsIOException() throws Exception { |
||||
ClientHttpResponse response = mock(ClientHttpResponse.class); |
||||
given(response.getStatusCode()).willThrow(IOException.class); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() throws IOException { |
||||
ClientHttpResponse response = mock(ClientHttpResponse.class); |
||||
given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(490)); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() throws IOException { |
||||
ClientHttpResponse response = mock(ClientHttpResponse.class); |
||||
given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(701)); |
||||
Tag tag = RestTemplateExchangeTags.outcome(response); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void clientNameTagIsHostOfRequestUri() { |
||||
ClientHttpRequest request = mock(ClientHttpRequest.class); |
||||
given(request.getURI()).willReturn(URI.create("https://example.org")); |
||||
Tag tag = RestTemplateExchangeTags.clientName(request); |
||||
assertThat(tag).isEqualTo(Tag.of("client.name", "example.org")); |
||||
} |
||||
|
||||
} |
||||
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.reactive.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.URI; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link DefaultWebClientExchangeTagsProvider} |
||||
* |
||||
* @author Brian Clozel |
||||
* @author Nishant Raut |
||||
*/ |
||||
@SuppressWarnings({ "deprecation", "removal" }) |
||||
class DefaultWebClientExchangeTagsProviderTests { |
||||
|
||||
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; |
||||
|
||||
private final WebClientExchangeTagsProvider tagsProvider = new DefaultWebClientExchangeTagsProvider(); |
||||
|
||||
private ClientRequest request; |
||||
|
||||
private ClientResponse response; |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot")) |
||||
.attribute(URI_TEMPLATE_ATTRIBUTE, "https://example.org/projects/{project}") |
||||
.build(); |
||||
this.response = mock(ClientResponse.class); |
||||
given(this.response.statusCode()).willReturn(HttpStatus.OK); |
||||
} |
||||
|
||||
@Test |
||||
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("client.name", "example.org"), Tag.of("status", "200"), Tag.of("outcome", "SUCCESS")); |
||||
} |
||||
|
||||
@Test |
||||
void tagsWhenNoUriTemplateShouldProvideUriPath() { |
||||
ClientRequest request = ClientRequest |
||||
.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot")) |
||||
.build(); |
||||
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("client.name", "example.org"), Tag.of("status", "200"), Tag.of("outcome", "SUCCESS")); |
||||
} |
||||
|
||||
@Test |
||||
void tagsWhenIoExceptionShouldReturnIoErrorStatus() { |
||||
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, new IOException()); |
||||
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), |
||||
Tag.of("client.name", "example.org"), Tag.of("status", "IO_ERROR"), Tag.of("outcome", "UNKNOWN")); |
||||
} |
||||
|
||||
@Test |
||||
void tagsWhenExceptionShouldReturnClientErrorStatus() { |
||||
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, new IllegalArgumentException()); |
||||
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), |
||||
Tag.of("client.name", "example.org"), Tag.of("status", "CLIENT_ERROR"), Tag.of("outcome", "UNKNOWN")); |
||||
} |
||||
|
||||
@Test |
||||
void tagsWhenCancelledRequestShouldReturnClientErrorStatus() { |
||||
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, null); |
||||
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), |
||||
Tag.of("client.name", "example.org"), Tag.of("status", "CLIENT_ERROR"), Tag.of("outcome", "UNKNOWN")); |
||||
} |
||||
|
||||
} |
||||
@ -1,182 +0,0 @@
@@ -1,182 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.reactive.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.URI; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.HttpStatusCode; |
||||
import org.springframework.web.reactive.function.client.ClientRequest; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link WebClientExchangeTags}. |
||||
* |
||||
* @author Brian Clozel |
||||
* @author Nishant Raut |
||||
*/ |
||||
@SuppressWarnings({ "deprecation", "removal" }) |
||||
class WebClientExchangeTagsTests { |
||||
|
||||
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; |
||||
|
||||
private ClientRequest request; |
||||
|
||||
private ClientResponse response; |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot")) |
||||
.attribute(URI_TEMPLATE_ATTRIBUTE, "https://example.org/projects/{project}") |
||||
.build(); |
||||
this.response = mock(ClientResponse.class); |
||||
} |
||||
|
||||
@Test |
||||
void method() { |
||||
assertThat(WebClientExchangeTags.method(this.request)).isEqualTo(Tag.of("method", "GET")); |
||||
} |
||||
|
||||
@Test |
||||
void uriWhenAbsoluteTemplateIsAvailableShouldReturnTemplate() { |
||||
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/{project}")); |
||||
} |
||||
|
||||
@Test |
||||
void uriWhenRelativeTemplateIsAvailableShouldReturnTemplate() { |
||||
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot")) |
||||
.attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}") |
||||
.build(); |
||||
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/{project}")); |
||||
} |
||||
|
||||
@Test |
||||
void uriWhenTemplateIsMissingShouldReturnPath() { |
||||
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot")) |
||||
.build(); |
||||
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/spring-boot")); |
||||
} |
||||
|
||||
@Test |
||||
void uriWhenTemplateIsMissingShouldReturnPathWithQueryParams() { |
||||
this.request = ClientRequest |
||||
.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot?section=docs")) |
||||
.build(); |
||||
assertThat(WebClientExchangeTags.uri(this.request)) |
||||
.isEqualTo(Tag.of("uri", "/projects/spring-boot?section=docs")); |
||||
} |
||||
|
||||
@Test |
||||
void clientName() { |
||||
assertThat(WebClientExchangeTags.clientName(this.request)).isEqualTo(Tag.of("client.name", "example.org")); |
||||
} |
||||
|
||||
@Test |
||||
void status() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.OK); |
||||
assertThat(WebClientExchangeTags.status(this.response, null)).isEqualTo(Tag.of("status", "200")); |
||||
} |
||||
|
||||
@Test |
||||
void statusWhenIOException() { |
||||
assertThat(WebClientExchangeTags.status(null, new IOException())).isEqualTo(Tag.of("status", "IO_ERROR")); |
||||
} |
||||
|
||||
@Test |
||||
void statusWhenClientException() { |
||||
assertThat(WebClientExchangeTags.status(null, new IllegalArgumentException())) |
||||
.isEqualTo(Tag.of("status", "CLIENT_ERROR")); |
||||
} |
||||
|
||||
@Test |
||||
void statusWhenNonStandard() { |
||||
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(490)); |
||||
assertThat(WebClientExchangeTags.status(this.response, null)).isEqualTo(Tag.of("status", "490")); |
||||
} |
||||
|
||||
@Test |
||||
void statusWhenCancelled() { |
||||
assertThat(WebClientExchangeTags.status(null, null)).isEqualTo(Tag.of("status", "CLIENT_ERROR")); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseIsNull() { |
||||
Tag tag = WebClientExchangeTags.outcome(null); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsInformationalWhenResponseIs1xx() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.CONTINUE); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseIs2xx() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.OK); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsRedirectionWhenResponseIs3xx() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIs4xx() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.BAD_REQUEST); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsServerErrorWhenResponseIs5xx() { |
||||
given(this.response.statusCode()).willReturn(HttpStatus.BAD_GATEWAY); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() { |
||||
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(490)); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() { |
||||
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(701)); |
||||
Tag tag = WebClientExchangeTags.outcome(this.response); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
} |
||||
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.function.Function; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.StreamSupport; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest; |
||||
import org.springframework.mock.web.server.MockServerWebExchange; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link DefaultWebFluxTagsProvider}. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class DefaultWebFluxTagsProviderTests { |
||||
|
||||
@Test |
||||
void whenTagsAreProvidedThenDefaultTagsArePresent() { |
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test")); |
||||
Map<String, Tag> tags = asMap(new DefaultWebFluxTagsProvider().httpRequestTags(exchange, null)); |
||||
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri"); |
||||
} |
||||
|
||||
@Test |
||||
void givenSomeContributorsWhenTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() { |
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test")); |
||||
Map<String, Tag> tags = asMap( |
||||
new DefaultWebFluxTagsProvider(Arrays.asList(new TestWebFluxTagsContributor("alpha"), |
||||
new TestWebFluxTagsContributor("bravo", "charlie"))) |
||||
.httpRequestTags(exchange, null)); |
||||
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri", "alpha", "bravo", |
||||
"charlie"); |
||||
} |
||||
|
||||
private Map<String, Tag> asMap(Iterable<Tag> tags) { |
||||
return StreamSupport.stream(tags.spliterator(), false) |
||||
.collect(Collectors.toMap(Tag::getKey, Function.identity())); |
||||
} |
||||
|
||||
private static final class TestWebFluxTagsContributor implements WebFluxTagsContributor { |
||||
|
||||
private final List<String> tagNames; |
||||
|
||||
private TestWebFluxTagsContributor(String... tagNames) { |
||||
this.tagNames = Arrays.asList(tagNames); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) { |
||||
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,220 +0,0 @@
@@ -1,220 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.reactive.server; |
||||
|
||||
import java.io.EOFException; |
||||
|
||||
import io.micrometer.core.instrument.Tag; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||
import org.springframework.http.server.reactive.ServerHttpResponse; |
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest; |
||||
import org.springframework.mock.web.server.MockServerWebExchange; |
||||
import org.springframework.web.reactive.HandlerMapping; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
import org.springframework.web.util.pattern.PathPatternParser; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link WebFluxTags}. |
||||
* |
||||
* @author Brian Clozel |
||||
* @author Michael McFadyen |
||||
* @author Madhura Bhave |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class WebFluxTagsTests { |
||||
|
||||
private MockServerWebExchange exchange; |
||||
|
||||
private final PathPatternParser parser = new PathPatternParser(); |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("")); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsBestMatchingPatternWhenAvailable() { |
||||
this.exchange.getAttributes() |
||||
.put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/spring/")); |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("/spring/"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenBestMatchingPatternIsEmpty() { |
||||
this.exchange.getAttributes().put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("")); |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashRemoveTrailingSlash() { |
||||
this.exchange.getAttributes() |
||||
.put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/spring/")); |
||||
Tag tag = WebFluxTags.uri(this.exchange, true); |
||||
assertThat(tag.getValue()).isEqualTo("/spring"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashKeepSingleSlash() { |
||||
this.exchange.getAttributes().put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/")); |
||||
Tag tag = WebFluxTags.uri(this.exchange, true); |
||||
assertThat(tag.getValue()).isEqualTo("/"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRedirectionWhenResponseStatusIs3xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsNotFoundWhenResponseStatusIs404() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND); |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("NOT_FOUND"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagToleratesCustomResponseStatus() { |
||||
this.exchange.getResponse().setRawStatusCode(601); |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenRequestHasNoPatternOrPathInfo() { |
||||
Tag tag = WebFluxTags.uri(this.exchange); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsRootWhenRequestHasNoPatternAndSlashPathInfo() { |
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/").build(); |
||||
ServerWebExchange exchange = MockServerWebExchange.from(request); |
||||
Tag tag = WebFluxTags.uri(exchange); |
||||
assertThat(tag.getValue()).isEqualTo("root"); |
||||
} |
||||
|
||||
@Test |
||||
void uriTagValueIsUnknownWhenRequestHasNoPatternAndNonRootPathInfo() { |
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/example").build(); |
||||
ServerWebExchange exchange = MockServerWebExchange.from(request); |
||||
Tag tag = WebFluxTags.uri(exchange); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void methodTagToleratesNonStandardHttpMethods() { |
||||
ServerWebExchange exchange = mock(ServerWebExchange.class); |
||||
ServerHttpRequest request = mock(ServerHttpRequest.class); |
||||
given(exchange.getRequest()).willReturn(request); |
||||
given(request.getMethod()).willReturn(HttpMethod.valueOf("CUSTOM")); |
||||
Tag tag = WebFluxTags.method(exchange); |
||||
assertThat(tag.getValue()).isEqualTo("CUSTOM"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseStatusIsNull() { |
||||
this.exchange.getResponse().setStatusCode(null); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseStatusIsAvailableFromUnderlyingServer() { |
||||
ServerWebExchange exchange = mock(ServerWebExchange.class); |
||||
ServerHttpRequest request = mock(ServerHttpRequest.class); |
||||
ServerHttpResponse response = mock(ServerHttpResponse.class); |
||||
given(response.getStatusCode()).willReturn(HttpStatus.OK); |
||||
given(response.getStatusCode().value()).willReturn(null); |
||||
given(exchange.getRequest()).willReturn(request); |
||||
given(exchange.getResponse()).willReturn(response); |
||||
Tag tag = WebFluxTags.outcome(exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsInformationalWhenResponseIs1xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.CONTINUE); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsSuccessWhenResponseIs2xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.OK); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsRedirectionWhenResponseIs3xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIs4xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsServerErrorWhenResponseIs5xx() { |
||||
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() { |
||||
this.exchange.getResponse().setRawStatusCode(490); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() { |
||||
this.exchange.getResponse().setRawStatusCode(701); |
||||
Tag tag = WebFluxTags.outcome(this.exchange, null); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
@Test |
||||
void outcomeTagIsUnknownWhenExceptionIsDisconnectedClient() { |
||||
Tag tag = WebFluxTags.outcome(this.exchange, new EOFException("broken pipe")); |
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN"); |
||||
} |
||||
|
||||
} |
||||
@ -1,63 +0,0 @@
@@ -1,63 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.test.autoconfigure; |
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; |
||||
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.test.context.ApplicationContextFailureProcessor; |
||||
import org.springframework.test.context.TestContext; |
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; |
||||
|
||||
/** |
||||
* Since 3.0.0 this class has been replaced by |
||||
* {@link ConditionReportApplicationContextFailureProcessor} and is not used internally. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 1.4.1 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link ApplicationContextFailureProcessor} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public class SpringBootDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener { |
||||
|
||||
@Override |
||||
public void prepareTestInstance(TestContext testContext) throws Exception { |
||||
try { |
||||
super.prepareTestInstance(testContext); |
||||
} |
||||
catch (Exception ex) { |
||||
outputConditionEvaluationReport(testContext); |
||||
throw ex; |
||||
} |
||||
} |
||||
|
||||
private void outputConditionEvaluationReport(TestContext testContext) { |
||||
try { |
||||
ApplicationContext context = testContext.getApplicationContext(); |
||||
if (context instanceof ConfigurableApplicationContext configurableContext) { |
||||
ConditionEvaluationReport report = ConditionEvaluationReport.get(configurableContext.getBeanFactory()); |
||||
System.err.println(new ConditionEvaluationReportMessage(report)); |
||||
} |
||||
} |
||||
catch (Exception ex) { |
||||
// Allow original failure to be reported
|
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,45 +0,0 @@
@@ -1,45 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.actuate.metrics; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability; |
||||
|
||||
/** |
||||
* Annotation that can be applied to a test class to enable auto-configuration for metrics |
||||
* exporters. |
||||
* |
||||
* @author Chris Bono |
||||
* @since 2.4.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link AutoConfigureObservability @AutoConfigureObservability} |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Inherited |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@AutoConfigureObservability(tracing = false) |
||||
public @interface AutoConfigureMetrics { |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Auto-configuration for handling metrics in tests. |
||||
*/ |
||||
package org.springframework.boot.test.autoconfigure.actuate.metrics; |
||||
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.actuate.metrics; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; |
||||
import io.micrometer.prometheus.PrometheusMeterRegistry; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration test to verify behaviour when |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is not present on the test class. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SpringBootTest |
||||
class AutoConfigureMetricsMissingIntegrationTests { |
||||
|
||||
@Test |
||||
void customizerRunsAndOnlyEnablesSimpleMeterRegistryWhenNoAnnotationPresent( |
||||
@Autowired ApplicationContext applicationContext) { |
||||
assertThat(applicationContext.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class); |
||||
assertThat(applicationContext.getBeansOfType(PrometheusMeterRegistry.class)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void customizerRunsAndSetsExclusionPropertiesWhenNoAnnotationPresent(@Autowired Environment environment) { |
||||
assertThat(environment.getProperty("management.defaults.metrics.export.enabled")).isEqualTo("false"); |
||||
assertThat(environment.getProperty("management.simple.metrics.export.enabled")).isEqualTo("true"); |
||||
} |
||||
|
||||
} |
||||
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.actuate.metrics; |
||||
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration test to verify behaviour when |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is present on the test class. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@SpringBootTest |
||||
@AutoConfigureMetrics |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
class AutoConfigureMetricsPresentIntegrationTests { |
||||
|
||||
@Test |
||||
void customizerDoesNotDisableAvailableMeterRegistriesWhenAnnotationPresent( |
||||
@Autowired ApplicationContext applicationContext) { |
||||
assertThat(applicationContext.getBeansOfType(PrometheusMeterRegistry.class)).hasSize(1); |
||||
} |
||||
|
||||
@Test |
||||
void customizerDoesNotSetExclusionPropertiesWhenAnnotationPresent(@Autowired Environment environment) { |
||||
assertThat(environment.containsProperty("management.defaults.metrics.export.enabled")).isFalse(); |
||||
assertThat(environment.containsProperty("management.simple.metrics.export.enabled")).isFalse(); |
||||
} |
||||
|
||||
} |
||||
@ -1,37 +0,0 @@
@@ -1,37 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.actuate.metrics; |
||||
|
||||
import org.springframework.boot.SpringBootConfiguration; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration; |
||||
|
||||
/** |
||||
* Example {@link SpringBootApplication @SpringBootApplication} for use with |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} tests. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SpringBootConfiguration |
||||
@EnableAutoConfiguration(exclude = { CassandraAutoConfiguration.class, MongoAutoConfiguration.class, |
||||
MongoReactiveAutoConfiguration.class }) |
||||
class AutoConfigureMetricsSpringBootApplication { |
||||
|
||||
} |
||||
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.context; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.test.context.ApplicationContextFailureProcessor; |
||||
import org.springframework.test.context.TestExecutionListener; |
||||
|
||||
/** |
||||
* Callback interface trigger from {@link SpringBootTestContextBootstrapper} that can be |
||||
* used to post-process the list of default {@link TestExecutionListener |
||||
* TestExecutionListeners} to be used by a test. Can be used to add or remove existing |
||||
* listeners. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 1.4.1 |
||||
* @deprecated since 3.0.0 removal in 3.2.0 in favor of |
||||
* {@link ApplicationContextFailureProcessor} |
||||
*/ |
||||
@FunctionalInterface |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public interface DefaultTestExecutionListenersPostProcessor { |
||||
|
||||
/** |
||||
* Post process the list of default {@link TestExecutionListener listeners} to be |
||||
* used. |
||||
* @param listeners the source listeners |
||||
* @return the actual listeners that should be used |
||||
* @since 3.0.0 |
||||
*/ |
||||
List<TestExecutionListener> postProcessDefaultTestExecutionListeners(List<TestExecutionListener> listeners); |
||||
|
||||
} |
||||
@ -1,52 +0,0 @@
@@ -1,52 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.context.bootstrap; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor; |
||||
import org.springframework.test.context.TestContext; |
||||
import org.springframework.test.context.TestExecutionListener; |
||||
import org.springframework.test.context.support.AbstractTestExecutionListener; |
||||
|
||||
/** |
||||
* Test {@link DefaultTestExecutionListenersPostProcessor}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
public class TestDefaultTestExecutionListenersPostProcessor implements DefaultTestExecutionListenersPostProcessor { |
||||
|
||||
@Override |
||||
public List<TestExecutionListener> postProcessDefaultTestExecutionListeners(List<TestExecutionListener> listeners) { |
||||
listeners.add(new ExampleTestExecutionListener()); |
||||
return listeners; |
||||
} |
||||
|
||||
static class ExampleTestExecutionListener extends AbstractTestExecutionListener { |
||||
|
||||
@Override |
||||
public void prepareTestInstance(TestContext testContext) throws Exception { |
||||
Object testInstance = testContext.getTestInstance(); |
||||
if (testInstance instanceof SpringBootTestContextBootstrapperIntegrationTests test) { |
||||
test.defaultTestExecutionListenersPostProcessorCalled = true; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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 |
||||
* |
||||
* https://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.configurationsample; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Alternative to Spring Boot's deprecated |
||||
* {@code @org.springframework.boot.context.properties.ConstructorBinding} for testing |
||||
* (removes the need for a dependency on the real annotation). |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
@Target(ElementType.CONSTRUCTOR) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@ConstructorBinding |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public @interface DeprecatedConstructorBinding { |
||||
|
||||
} |
||||
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.configurationsample.immutable; |
||||
|
||||
/** |
||||
* Simple immutable properties with several constructors. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
@SuppressWarnings("unused") |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public class DeprecatedImmutableMultiConstructorProperties { |
||||
|
||||
private final String name; |
||||
|
||||
/** |
||||
* Test description. |
||||
*/ |
||||
private final String description; |
||||
|
||||
public DeprecatedImmutableMultiConstructorProperties(String name) { |
||||
this(name, null); |
||||
} |
||||
|
||||
@SuppressWarnings("removal") |
||||
@org.springframework.boot.configurationsample.DeprecatedConstructorBinding |
||||
public DeprecatedImmutableMultiConstructorProperties(String name, String description) { |
||||
this.name = name; |
||||
this.description = description; |
||||
} |
||||
|
||||
} |
||||
@ -1,52 +0,0 @@
@@ -1,52 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.context.properties; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Annotation that can be used to indicate which constructor to use when binding |
||||
* configuration properties using constructor arguments rather than by calling setters. A |
||||
* single parameterized constructor implicitly indicates that constructor binding should |
||||
* be used unless the constructor is annotated with `@Autowired`. |
||||
* <p> |
||||
* Note: To use constructor binding the class must be enabled using |
||||
* {@link EnableConfigurationProperties @EnableConfigurationProperties} or configuration |
||||
* property scanning. Constructor binding cannot be used with beans that are created by |
||||
* the regular Spring mechanisms (e.g. |
||||
* {@link org.springframework.stereotype.Component @Component} beans, beans created via |
||||
* {@link org.springframework.context.annotation.Bean @Bean} methods or beans loaded using |
||||
* {@link org.springframework.context.annotation.Import @Import}). |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 2.2.0 |
||||
* @see ConfigurationProperties |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link org.springframework.boot.context.properties.bind.ConstructorBinding} |
||||
*/ |
||||
@Target({ ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
@org.springframework.boot.context.properties.bind.ConstructorBinding |
||||
public @interface ConstructorBinding { |
||||
|
||||
} |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.web.client; |
||||
|
||||
import java.util.function.Supplier; |
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory; |
||||
|
||||
/** |
||||
* A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate |
||||
* based on the available implementations on the classpath. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Moritz Halbritter |
||||
* @since 2.1.0 |
||||
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of |
||||
* {@link ClientHttpRequestFactories} |
||||
*/ |
||||
@Deprecated(since = "3.0.0", forRemoval = true) |
||||
public class ClientHttpRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> { |
||||
|
||||
@Override |
||||
public ClientHttpRequestFactory get() { |
||||
return ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue