diff --git a/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationDocumentation.java b/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationDocumentation.java
index 44f06737c0c..b70826c8782 100644
--- a/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationDocumentation.java
+++ b/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationDocumentation.java
@@ -25,8 +25,9 @@ import org.springframework.http.client.ClientHttpRequestFactory;
/**
- * Documented {@link io.micrometer.common.KeyValue KeyValues} for {@link ClientHttpRequestFactory HTTP client observations}.
+ * Documented {@link io.micrometer.common.KeyValue KeyValues} for {@link ClientHttpRequestFactory HTTP client} observations.
*
This class is used by automated tools to document KeyValues attached to the HTTP client observations.
+ *
* @author Brian Clozel
* @since 6.0
*/
@@ -38,7 +39,7 @@ public enum ClientHttpObservationDocumentation implements ObservationDocumentati
HTTP_REQUEST {
@Override
public Class extends ObservationConvention extends Observation.Context>> getDefaultConvention() {
- return DefaultClientHttpObservationConvention.class;
+ return DefaultClientRequestObservationConvention.class;
}
@Override
diff --git a/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationContext.java b/spring-web/src/main/java/org/springframework/http/client/observation/ClientRequestObservationContext.java
similarity index 83%
rename from spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationContext.java
rename to spring-web/src/main/java/org/springframework/http/client/observation/ClientRequestObservationContext.java
index d5957d1a54a..c84a45f7e89 100644
--- a/spring-web/src/main/java/org/springframework/http/client/observation/ClientHttpObservationContext.java
+++ b/spring-web/src/main/java/org/springframework/http/client/observation/ClientRequestObservationContext.java
@@ -19,19 +19,18 @@ package org.springframework.http.client.observation;
import io.micrometer.observation.transport.RequestReplySenderContext;
import org.springframework.http.client.ClientHttpRequest;
-import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
/**
* Context that holds information for metadata collection
- * during the {@link ClientHttpRequestFactory client HTTP} observations.
+ * during the {@link ClientHttpObservationDocumentation#HTTP_REQUEST client HTTP exchanges} observations.
*
This context also extends {@link RequestReplySenderContext} for propagating tracing
* information with the HTTP client exchange.
* @author Brian Clozel
* @since 6.0
*/
-public class ClientHttpObservationContext extends RequestReplySenderContext {
+public class ClientRequestObservationContext extends RequestReplySenderContext {
@Nullable
private String uriTemplate;
@@ -40,8 +39,8 @@ public class ClientHttpObservationContext extends RequestReplySenderContext {
+public interface ClientRequestObservationConvention extends ObservationConvention {
@Override
default boolean supportsContext(Observation.Context context) {
- return context instanceof ClientHttpObservationContext;
+ return context instanceof ClientRequestObservationContext;
}
}
diff --git a/spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientHttpObservationConvention.java b/spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientRequestObservationConvention.java
similarity index 68%
rename from spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientHttpObservationConvention.java
rename to spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientRequestObservationConvention.java
index 9fcedf226f1..8c5b728dbc9 100644
--- a/spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientHttpObservationConvention.java
+++ b/spring-web/src/main/java/org/springframework/http/client/observation/DefaultClientRequestObservationConvention.java
@@ -21,18 +21,19 @@ import java.io.IOException;
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.observation.HttpOutcome;
import org.springframework.util.StringUtils;
/**
- * Default implementation for a {@link ClientHttpObservationConvention},
- * extracting information from the {@link ClientHttpObservationContext}.
+ * Default implementation for a {@link ClientRequestObservationConvention},
+ * extracting information from the {@link ClientRequestObservationContext}.
*
* @author Brian Clozel
* @since 6.0
*/
-public class DefaultClientHttpObservationConvention implements ClientHttpObservationConvention {
+public class DefaultClientRequestObservationConvention implements ClientRequestObservationConvention {
private static final String DEFAULT_NAME = "http.client.requests";
@@ -44,18 +45,23 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
private static final KeyValue STATUS_CLIENT_ERROR = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "CLIENT_ERROR");
+ private static final KeyValue HTTP_OUTCOME_SUCCESS = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "SUCCESS");
+
+ private static final KeyValue HTTP_OUTCOME_UNKNOWN = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "UNKNOWN");
+
private static final KeyValue EXCEPTION_NONE = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
private static final KeyValue HTTP_URL_NONE = KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "none");
private static final KeyValue CLIENT_NAME_NONE = KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, "none");
+
private final String name;
/**
* Create a convention with the default name {@code "http.client.requests"}.
*/
- public DefaultClientHttpObservationConvention() {
+ public DefaultClientRequestObservationConvention() {
this(DEFAULT_NAME);
}
@@ -63,7 +69,7 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
* Create a convention with a custom name.
* @param name the observation name
*/
- public DefaultClientHttpObservationConvention(String name) {
+ public DefaultClientRequestObservationConvention(String name) {
this.name = name;
}
@@ -73,23 +79,23 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
}
@Override
- public String getContextualName(ClientHttpObservationContext context) {
+ public String getContextualName(ClientRequestObservationContext context) {
return "http " + context.getCarrier().getMethod().name().toLowerCase();
}
@Override
- public KeyValues getLowCardinalityKeyValues(ClientHttpObservationContext context) {
+ public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {
return KeyValues.of(uri(context), method(context), status(context), exception(context), outcome(context));
}
- protected KeyValue uri(ClientHttpObservationContext context) {
+ protected KeyValue uri(ClientRequestObservationContext context) {
if (context.getUriTemplate() != null) {
return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.URI, context.getUriTemplate());
}
return URI_NONE;
}
- protected KeyValue method(ClientHttpObservationContext context) {
+ protected KeyValue method(ClientRequestObservationContext context) {
if (context.getCarrier() != null) {
return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod().name());
}
@@ -98,7 +104,7 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
}
}
- protected KeyValue status(ClientHttpObservationContext context) {
+ protected KeyValue status(ClientRequestObservationContext context) {
ClientHttpResponse response = context.getResponse();
if (response == null) {
return STATUS_CLIENT_ERROR;
@@ -111,7 +117,7 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
}
}
- protected KeyValue exception(ClientHttpObservationContext context) {
+ protected KeyValue exception(ClientRequestObservationContext context) {
Throwable error = context.getError();
if (error != null) {
String simpleName = error.getClass().getSimpleName();
@@ -121,36 +127,51 @@ public class DefaultClientHttpObservationConvention implements ClientHttpObserva
return EXCEPTION_NONE;
}
- protected static KeyValue outcome(ClientHttpObservationContext context) {
+ protected static KeyValue outcome(ClientRequestObservationContext context) {
if (context.getResponse() != null) {
try {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(context.getResponse().getStatusCode());
- return httpOutcome.asKeyValue();
+ return HttpOutcome.forStatus(context.getResponse().getStatusCode());
}
catch (IOException ex) {
// Continue
}
}
- return HttpOutcome.UNKNOWN.asKeyValue();
+ return HTTP_OUTCOME_UNKNOWN;
}
@Override
- public KeyValues getHighCardinalityKeyValues(ClientHttpObservationContext context) {
+ public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) {
return KeyValues.of(requestUri(context), clientName(context));
}
- protected KeyValue requestUri(ClientHttpObservationContext context) {
+ protected KeyValue requestUri(ClientRequestObservationContext context) {
if (context.getCarrier() != null) {
return KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().getURI().toASCIIString());
}
return HTTP_URL_NONE;
}
- protected KeyValue clientName(ClientHttpObservationContext context) {
+ protected KeyValue clientName(ClientRequestObservationContext context) {
if (context.getCarrier() != null && context.getCarrier().getURI().getHost() != null) {
return KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, context.getCarrier().getURI().getHost());
}
return CLIENT_NAME_NONE;
}
+ static class HttpOutcome {
+
+ static KeyValue forStatus(HttpStatusCode statusCode) {
+ if (statusCode.is2xxSuccessful()) {
+ return HTTP_OUTCOME_SUCCESS;
+ }
+ else if (statusCode instanceof HttpStatus status){
+ return KeyValue.of("outcome", status.series().name());
+ }
+ else {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ }
+
+ }
+
}
diff --git a/spring-web/src/main/java/org/springframework/http/observation/DefaultServerRequestObservationConvention.java b/spring-web/src/main/java/org/springframework/http/observation/DefaultServerRequestObservationConvention.java
new file mode 100644
index 00000000000..38ce54a4532
--- /dev/null
+++ b/spring-web/src/main/java/org/springframework/http/observation/DefaultServerRequestObservationConvention.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2002-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.http.observation;
+
+import io.micrometer.common.KeyValue;
+import io.micrometer.common.KeyValues;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.util.StringUtils;
+
+/**
+ * Default {@link ServerRequestObservationConvention}.
+ * @author Brian Clozel
+ * @since 6.0
+ */
+public class DefaultServerRequestObservationConvention implements ServerRequestObservationConvention {
+
+ private static final String DEFAULT_NAME = "http.server.requests";
+
+ private static final KeyValue METHOD_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, "UNKNOWN");
+
+ private static final KeyValue STATUS_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "UNKNOWN");
+
+ private static final KeyValue HTTP_OUTCOME_SUCCESS = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "SUCCESS");
+
+ private static final KeyValue HTTP_OUTCOME_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "UNKNOWN");
+
+ private static final KeyValue URI_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "UNKNOWN");
+
+ private static final KeyValue URI_ROOT = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "root");
+
+ private static final KeyValue URI_NOT_FOUND = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "NOT_FOUND");
+
+ private static final KeyValue URI_REDIRECTION = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "REDIRECTION");
+
+ private static final KeyValue EXCEPTION_NONE = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
+
+ private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
+
+ private final String name;
+
+ /**
+ * Create a convention with the default name {@code "http.server.requests"}.
+ */
+ public DefaultServerRequestObservationConvention() {
+ this(DEFAULT_NAME);
+ }
+
+ /**
+ * Create a convention with a custom name.
+ * @param name the observation name
+ */
+ public DefaultServerRequestObservationConvention(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getContextualName(ServerRequestObservationContext context) {
+ return "http " + context.getCarrier().getMethod().toLowerCase();
+ }
+
+ @Override
+ public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
+ return KeyValues.of(method(context), uri(context), status(context), exception(context), outcome(context));
+ }
+
+ @Override
+ public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext context) {
+ return KeyValues.of(uriExpanded(context));
+ }
+
+ protected KeyValue method(ServerRequestObservationContext context) {
+ return (context.getCarrier() != null) ? KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod()) : METHOD_UNKNOWN;
+ }
+
+ protected KeyValue status(ServerRequestObservationContext context) {
+ return (context.getResponse() != null) ? KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatus())) : STATUS_UNKNOWN;
+ }
+
+ protected KeyValue uri(ServerRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ String pattern = context.getPathPattern();
+ if (pattern != null) {
+ if (pattern.isEmpty()) {
+ return URI_ROOT;
+ }
+ return KeyValue.of("uri", pattern);
+ }
+ if (context.getResponse() != null) {
+ HttpStatus status = HttpStatus.resolve(context.getResponse().getStatus());
+ if (status != null) {
+ if (status.is3xxRedirection()) {
+ return URI_REDIRECTION;
+ }
+ if (status == HttpStatus.NOT_FOUND) {
+ return URI_NOT_FOUND;
+ }
+ }
+ }
+ }
+ return URI_UNKNOWN;
+ }
+
+ protected KeyValue exception(ServerRequestObservationContext context) {
+ Throwable error = context.getError();
+ if (error != null) {
+ String simpleName = error.getClass().getSimpleName();
+ return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
+ StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
+ }
+ return EXCEPTION_NONE;
+ }
+
+ protected KeyValue outcome(ServerRequestObservationContext context) {
+ if (context.getResponse() != null) {
+ HttpStatusCode statusCode = HttpStatusCode.valueOf(context.getResponse().getStatus());
+ return HttpOutcome.forStatus(statusCode);
+ }
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+
+ protected KeyValue uriExpanded(ServerRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ return KeyValue.of(ServerHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().getRequestURI());
+ }
+ return HTTP_URL_UNKNOWN;
+ }
+
+
+ static class HttpOutcome {
+
+ static KeyValue forStatus(HttpStatusCode statusCode) {
+ if (statusCode.is2xxSuccessful()) {
+ return HTTP_OUTCOME_SUCCESS;
+ }
+ else if (statusCode instanceof HttpStatus status){
+ return KeyValue.of("outcome", status.series().name());
+ }
+ else {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ }
+
+ }
+
+}
diff --git a/spring-web/src/main/java/org/springframework/http/observation/HttpOutcome.java b/spring-web/src/main/java/org/springframework/http/observation/HttpOutcome.java
deleted file mode 100644
index c9440669a8f..00000000000
--- a/spring-web/src/main/java/org/springframework/http/observation/HttpOutcome.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2002-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.http.observation;
-
-import io.micrometer.common.KeyValue;
-
-import org.springframework.http.HttpStatusCode;
-
-/**
- * The outcome of an HTTP request.
- * Used as the {@code "outcome"} {@link io.micrometer.common.KeyValue}
- * for HTTP {@link io.micrometer.observation.Observation observations}.
- *
- * @author Brian Clozel
- * @author Andy Wilkinson
- * @since 6.0
- */
-public enum HttpOutcome {
-
- /**
- * Outcome of the request was informational.
- */
- INFORMATIONAL,
-
- /**
- * Outcome of the request was success.
- */
- SUCCESS,
-
- /**
- * Outcome of the request was redirection.
- */
- REDIRECTION,
-
- /**
- * Outcome of the request was client error.
- */
- CLIENT_ERROR,
-
- /**
- * Outcome of the request was server error.
- */
- SERVER_ERROR,
-
- /**
- * Outcome of the request was unknown.
- */
- UNKNOWN;
-
- private final KeyValue keyValue;
-
- HttpOutcome() {
- this.keyValue = KeyValue.of("outcome", name());
- }
-
- /**
- * Returns the {@code Outcome} as a {@link KeyValue} named {@code outcome}.
- * @return the {@code outcome} {@code KeyValue}
- */
- public KeyValue asKeyValue() {
- return this.keyValue;
- }
-
- /**
- * Return the {@code HttpOutcome} for the given HTTP {@code status} code.
- * @param status the HTTP status code
- * @return the matching HttpOutcome
- */
- public static HttpOutcome forStatus(HttpStatusCode status) {
- if (status.is1xxInformational()) {
- return INFORMATIONAL;
- }
- else if (status.is2xxSuccessful()) {
- return SUCCESS;
- }
- else if (status.is3xxRedirection()) {
- return REDIRECTION;
- }
- else if (status.is4xxClientError()) {
- return CLIENT_ERROR;
- }
- else if (status.is5xxServerError()) {
- return SERVER_ERROR;
- }
- return UNKNOWN;
- }
-}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationDocumentation.java b/spring-web/src/main/java/org/springframework/http/observation/ServerHttpObservationDocumentation.java
similarity index 93%
rename from spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationDocumentation.java
rename to spring-web/src/main/java/org/springframework/http/observation/ServerHttpObservationDocumentation.java
index a468da62f99..a8918e5f3ec 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationDocumentation.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/ServerHttpObservationDocumentation.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.http.observation;
import io.micrometer.common.docs.KeyName;
import io.micrometer.observation.Observation;
@@ -25,10 +25,11 @@ import io.micrometer.observation.docs.ObservationDocumentation;
* Documented {@link io.micrometer.common.KeyValue KeyValues} for the HTTP server observations
* for Servlet-based web applications.
*
This class is used by automated tools to document KeyValues attached to the HTTP server observations.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public enum HttpRequestsObservationDocumentation implements ObservationDocumentation {
+public enum ServerHttpObservationDocumentation implements ObservationDocumentation {
/**
* HTTP server request observations.
@@ -36,7 +37,7 @@ public enum HttpRequestsObservationDocumentation implements ObservationDocumenta
HTTP_REQUESTS {
@Override
public Class extends ObservationConvention extends Observation.Context>> getDefaultConvention() {
- return DefaultHttpRequestsObservationConvention.class;
+ return DefaultServerRequestObservationConvention.class;
}
@Override
diff --git a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationContext.java b/spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationContext.java
similarity index 78%
rename from spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationContext.java
rename to spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationContext.java
index 6007e88e18d..b2e288c67c8 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationContext.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationContext.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.http.observation;
import io.micrometer.observation.transport.RequestReplyReceiverContext;
import jakarta.servlet.http.HttpServletRequest;
@@ -23,18 +23,20 @@ import jakarta.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
/**
- * Context that holds information for metadata collection during observations for Servlet web application.
+ * Context that holds information for metadata collection during observations
+ * for {@link ServerHttpObservationDocumentation#HTTP_REQUESTS Servlet HTTP exchanges}.
*
This context also extends {@link RequestReplyReceiverContext} for propagating
* tracing information with the HTTP server exchange.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public class HttpRequestsObservationContext extends RequestReplyReceiverContext {
+public class ServerRequestObservationContext extends RequestReplyReceiverContext {
@Nullable
private String pathPattern;
- public HttpRequestsObservationContext(HttpServletRequest request, HttpServletResponse response) {
+ public ServerRequestObservationContext(HttpServletRequest request, HttpServletResponse response) {
super(HttpServletRequest::getHeader);
setCarrier(request);
setResponse(response);
diff --git a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationConvention.java b/spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationConvention.java
similarity index 70%
rename from spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationConvention.java
rename to spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationConvention.java
index bac16c6dd46..be2bf1d6e7d 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationConvention.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/ServerRequestObservationConvention.java
@@ -14,21 +14,22 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.http.observation;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationConvention;
/**
- * Interface for an {@link ObservationConvention} related to Servlet HTTP exchanges.
+ * Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_REQUESTS Servlet HTTP exchanges}.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public interface HttpRequestsObservationConvention extends ObservationConvention {
+public interface ServerRequestObservationConvention extends ObservationConvention {
@Override
default boolean supportsContext(Observation.Context context) {
- return context instanceof HttpRequestsObservationContext;
+ return context instanceof ServerRequestObservationContext;
}
}
diff --git a/spring-web/src/main/java/org/springframework/http/observation/package-info.java b/spring-web/src/main/java/org/springframework/http/observation/package-info.java
index 87a33f2d274..73b05998c39 100644
--- a/spring-web/src/main/java/org/springframework/http/observation/package-info.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/package-info.java
@@ -1,5 +1,5 @@
/**
- * Base support for HTTP {@link io.micrometer.observation.Observation}.
+ * Instrumentation for {@link io.micrometer.observation.Observation observing} HTTP applications.
*/
@NonNullApi
@NonNullFields
diff --git a/spring-web/src/main/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConvention.java b/spring-web/src/main/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConvention.java
new file mode 100644
index 00000000000..f7701ffee89
--- /dev/null
+++ b/spring-web/src/main/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConvention.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2002-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.http.observation.reactive;
+
+import io.micrometer.common.KeyValue;
+import io.micrometer.common.KeyValues;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.util.StringUtils;
+import org.springframework.web.util.pattern.PathPattern;
+
+/**
+ * Default {@link ServerRequestObservationConvention}.
+ *
+ * @author Brian Clozel
+ * @since 6.0
+ */
+public class DefaultServerRequestObservationConvention implements ServerRequestObservationConvention {
+
+ private static final String DEFAULT_NAME = "http.server.requests";
+
+ private static final KeyValue METHOD_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, "UNKNOWN");
+
+ private static final KeyValue STATUS_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "UNKNOWN");
+
+ private static final KeyValue HTTP_OUTCOME_SUCCESS = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "SUCCESS");
+
+ private static final KeyValue HTTP_OUTCOME_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "UNKNOWN");
+
+ private static final KeyValue URI_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "UNKNOWN");
+
+ private static final KeyValue URI_ROOT = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "root");
+
+ private static final KeyValue URI_NOT_FOUND = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "NOT_FOUND");
+
+ private static final KeyValue URI_REDIRECTION = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, "REDIRECTION");
+
+ private static final KeyValue EXCEPTION_NONE = KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
+
+ private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(ServerHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
+
+ private final String name;
+
+ /**
+ * Create a convention with the default name {@code "http.server.requests"}.
+ */
+ public DefaultServerRequestObservationConvention() {
+ this(DEFAULT_NAME);
+ }
+
+ /**
+ * Create a convention with a custom name.
+ *
+ * @param name the observation name
+ */
+ public DefaultServerRequestObservationConvention(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getContextualName(ServerRequestObservationContext context) {
+ return "http " + context.getCarrier().getMethod().name().toLowerCase();
+ }
+
+ @Override
+ public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
+ return KeyValues.of(method(context), uri(context), status(context), exception(context), outcome(context));
+ }
+
+ @Override
+ public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext context) {
+ return KeyValues.of(httpUrl(context));
+ }
+
+ protected KeyValue method(ServerRequestObservationContext context) {
+ return (context.getCarrier() != null) ? KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod().name()) : METHOD_UNKNOWN;
+ }
+
+ protected KeyValue status(ServerRequestObservationContext context) {
+ if (context.isConnectionAborted()) {
+ return STATUS_UNKNOWN;
+ }
+ return (context.getResponse() != null) ? KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatusCode().value())) : STATUS_UNKNOWN;
+ }
+
+ protected KeyValue uri(ServerRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ PathPattern pattern = context.getPathPattern();
+ if (pattern != null) {
+ if (pattern.toString().isEmpty()) {
+ return URI_ROOT;
+ }
+ return KeyValue.of("uri", pattern.toString());
+ }
+ if (context.getResponse() != null) {
+ HttpStatus status = HttpStatus.resolve(context.getResponse().getStatusCode().value());
+ if (status != null) {
+ if (status.is3xxRedirection()) {
+ return URI_REDIRECTION;
+ }
+ if (status == HttpStatus.NOT_FOUND) {
+ return URI_NOT_FOUND;
+ }
+ }
+ }
+ }
+ return URI_UNKNOWN;
+ }
+
+ protected KeyValue exception(ServerRequestObservationContext context) {
+ Throwable error = context.getError();
+ if (error != null) {
+ String simpleName = error.getClass().getSimpleName();
+ return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
+ StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
+ }
+ return EXCEPTION_NONE;
+ }
+
+ protected KeyValue outcome(ServerRequestObservationContext context) {
+ if (context.isConnectionAborted()) {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ if (context.getResponse() != null) {
+ return HttpOutcome.forStatus(context.getResponse().getStatusCode());
+ }
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+
+ protected KeyValue httpUrl(ServerRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ String uriExpanded = context.getCarrier().getPath().toString();
+ return KeyValue.of(ServerHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, uriExpanded);
+ }
+ return HTTP_URL_UNKNOWN;
+ }
+
+ static class HttpOutcome {
+
+ static KeyValue forStatus(HttpStatusCode statusCode) {
+ if (statusCode.is2xxSuccessful()) {
+ return HTTP_OUTCOME_SUCCESS;
+ }
+ else if (statusCode instanceof HttpStatus status){
+ return KeyValue.of("outcome", status.series().name());
+ }
+ else {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ }
+
+ }
+
+}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationDocumentation.java b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerHttpObservationDocumentation.java
similarity index 93%
rename from spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationDocumentation.java
rename to spring-web/src/main/java/org/springframework/http/observation/reactive/ServerHttpObservationDocumentation.java
index 2bd8485d81f..317ff30b25a 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationDocumentation.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerHttpObservationDocumentation.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.http.observation.reactive;
import io.micrometer.common.docs.KeyName;
import io.micrometer.observation.Observation;
@@ -25,10 +25,11 @@ import io.micrometer.observation.docs.ObservationDocumentation;
* Documented {@link io.micrometer.common.KeyValue KeyValues} for the HTTP server observations
* for reactive web applications.
* This class is used by automated tools to document KeyValues attached to the HTTP server observations.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public enum HttpRequestsObservationDocumentation implements ObservationDocumentation {
+public enum ServerHttpObservationDocumentation implements ObservationDocumentation {
/**
* HTTP server request observations.
@@ -36,7 +37,7 @@ public enum HttpRequestsObservationDocumentation implements ObservationDocumenta
HTTP_REQUESTS {
@Override
public Class extends ObservationConvention extends Observation.Context>> getDefaultConvention() {
- return DefaultHttpRequestsObservationConvention.class;
+ return DefaultServerRequestObservationConvention.class;
}
@Override
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationContext.java b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationContext.java
similarity index 78%
rename from spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationContext.java
rename to spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationContext.java
index 0a98560f0e7..7e00e9a5aa8 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationContext.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationContext.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.http.observation.reactive;
import io.micrometer.observation.transport.RequestReplyReceiverContext;
@@ -25,20 +25,22 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
/**
- * Context that holds information for metadata collection during observations for reactive web applications.
+ * Context that holds information for metadata collection during observations
+ * for {@link ServerHttpObservationDocumentation#HTTP_REQUESTS reactive HTTP exchanges}.
*
This context also extends {@link RequestReplyReceiverContext} for propagating
* tracing information with the HTTP server exchange.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public class HttpRequestsObservationContext extends RequestReplyReceiverContext {
+public class ServerRequestObservationContext extends RequestReplyReceiverContext {
@Nullable
private PathPattern pathPattern;
private boolean connectionAborted;
- public HttpRequestsObservationContext(ServerWebExchange exchange) {
+ public ServerRequestObservationContext(ServerWebExchange exchange) {
super((request, key) -> request.getHeaders().getFirst(key));
setCarrier(exchange.getRequest());
setResponse(exchange.getResponse());
@@ -74,7 +76,13 @@ public class HttpRequestsObservationContext extends RequestReplyReceiverContext<
return this.connectionAborted;
}
- void setConnectionAborted(boolean connectionAborted) {
+ /**
+ * Set whether the current connection was aborted by the client, resulting
+ * in a {@link reactor.core.publisher.SignalType#CANCEL cancel signal} on the reactive chain,
+ * or an {@code AbortedException} when reading the request.
+ * @param connectionAborted if the connection has been aborted
+ */
+ public void setConnectionAborted(boolean connectionAborted) {
this.connectionAborted = connectionAborted;
}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationConvention.java b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationConvention.java
similarity index 69%
rename from spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationConvention.java
rename to spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationConvention.java
index 4364d1a27ef..cbe51d15b4c 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationConvention.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/reactive/ServerRequestObservationConvention.java
@@ -14,21 +14,22 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.http.observation.reactive;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationConvention;
/**
- * Interface for an {@link ObservationConvention} related to reactive HTTP exchanges.
+ * Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_REQUESTS reactive HTTP exchanges}.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public interface HttpRequestsObservationConvention extends ObservationConvention {
+public interface ServerRequestObservationConvention extends ObservationConvention {
@Override
default boolean supportsContext(Observation.Context context) {
- return context instanceof HttpRequestsObservationContext;
+ return context instanceof ServerRequestObservationContext;
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/package-info.java b/spring-web/src/main/java/org/springframework/http/observation/reactive/package-info.java
similarity index 66%
rename from spring-web/src/main/java/org/springframework/web/observation/package-info.java
rename to spring-web/src/main/java/org/springframework/http/observation/reactive/package-info.java
index 4cc30c56be3..473d6d16164 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/package-info.java
+++ b/spring-web/src/main/java/org/springframework/http/observation/reactive/package-info.java
@@ -1,9 +1,9 @@
/**
- * Instrumentation for {@link io.micrometer.observation.Observation observing} web applications.
+ * Instrumentation for {@link io.micrometer.observation.Observation observing} reactive HTTP applications.
*/
@NonNullApi
@NonNullFields
-package org.springframework.web.observation;
+package org.springframework.http.observation.reactive;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
index bf68ae3cf40..01e1a164b28 100644
--- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
+++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
@@ -43,10 +43,10 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.client.observation.ClientHttpObservationContext;
-import org.springframework.http.client.observation.ClientHttpObservationConvention;
import org.springframework.http.client.observation.ClientHttpObservationDocumentation;
-import org.springframework.http.client.observation.DefaultClientHttpObservationConvention;
+import org.springframework.http.client.observation.ClientRequestObservationContext;
+import org.springframework.http.client.observation.ClientRequestObservationConvention;
+import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
import org.springframework.http.client.support.InterceptingHttpAccessor;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
@@ -125,7 +125,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
private static final boolean kotlinSerializationProtobufPresent;
- private static final ClientHttpObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultClientHttpObservationConvention();
+ private static final ClientRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultClientRequestObservationConvention();
static {
ClassLoader classLoader = RestTemplate.class.getClassLoader();
@@ -155,7 +155,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
@Nullable
- private ClientHttpObservationConvention observationConvention;
+ private ClientRequestObservationConvention observationConvention;
/**
@@ -358,13 +358,13 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
/**
* Configure an {@link ObservationConvention} that sets the name of the
* {@link Observation observation} as well as its {@link io.micrometer.common.KeyValues}
- * extracted from the {@link ClientHttpObservationContext}.
- * If none set, the {@link DefaultClientHttpObservationConvention default convention} will be used.
+ * extracted from the {@link ClientRequestObservationContext}.
+ * If none set, the {@link DefaultClientRequestObservationConvention default convention} will be used.
* @param observationConvention the observation convention to use
* @since 6.0
* @see #setObservationRegistry(ObservationRegistry)
*/
- public void setObservationConvention(ClientHttpObservationConvention observationConvention) {
+ public void setObservationConvention(ClientRequestObservationConvention observationConvention) {
Assert.notNull(observationConvention, "observationConvention must not be null");
this.observationConvention = observationConvention;
}
@@ -853,7 +853,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
ResourceAccessException exception = createResourceAccessException(url, method, ex);
throw exception;
}
- ClientHttpObservationContext observationContext = new ClientHttpObservationContext(request);
+ ClientRequestObservationContext observationContext = new ClientRequestObservationContext(request);
observationContext.setUriTemplate(uriTemplate);
Observation observation = ClientHttpObservationDocumentation.HTTP_REQUEST.observation(this.observationConvention,
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry).start();
diff --git a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationFilter.java b/spring-web/src/main/java/org/springframework/web/filter/ServerHttpObservationFilter.java
similarity index 66%
rename from spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationFilter.java
rename to spring-web/src/main/java/org/springframework/web/filter/ServerHttpObservationFilter.java
index fc6fab63637..58b99aa129b 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/HttpRequestsObservationFilter.java
+++ b/spring-web/src/main/java/org/springframework/web/filter/ServerHttpObservationFilter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.web.filter;
import java.io.IOException;
import java.util.Optional;
@@ -28,45 +28,49 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
+import org.springframework.http.observation.DefaultServerRequestObservationConvention;
+import org.springframework.http.observation.ServerHttpObservationDocumentation;
+import org.springframework.http.observation.ServerRequestObservationContext;
+import org.springframework.http.observation.ServerRequestObservationConvention;
import org.springframework.lang.Nullable;
-import org.springframework.web.filter.OncePerRequestFilter;
/**
* {@link jakarta.servlet.Filter} that creates {@link Observation observations}
* for HTTP exchanges. This collects information about the execution time and
- * information gathered from the {@link HttpRequestsObservationContext}.
- * Web Frameworks can fetch the current {@link HttpRequestsObservationContext context}
+ * information gathered from the {@link ServerRequestObservationContext}.
+ *
Web Frameworks can fetch the current {@link ServerRequestObservationContext context}
* as a {@link #CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE request attribute} and contribute
* additional information to it.
- * The configured {@link HttpRequestsObservationConvention} will use this context to collect
+ * The configured {@link ServerRequestObservationConvention} will use this context to collect
* {@link io.micrometer.common.KeyValue metadata} and attach it to the observation.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public class HttpRequestsObservationFilter extends OncePerRequestFilter {
+public class ServerHttpObservationFilter extends OncePerRequestFilter {
/**
- * Name of the request attribute holding the {@link HttpRequestsObservationContext context} for the current observation.
+ * Name of the request attribute holding the {@link ServerRequestObservationContext context} for the current observation.
*/
- public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = HttpRequestsObservationFilter.class.getName() + ".context";
+ public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerHttpObservationFilter.class.getName() + ".context";
- private static final HttpRequestsObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultHttpRequestsObservationConvention();
+ private static final ServerRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultServerRequestObservationConvention();
- private static final String CURRENT_OBSERVATION_ATTRIBUTE = HttpRequestsObservationFilter.class.getName() + ".observation";
+ private static final String CURRENT_OBSERVATION_ATTRIBUTE = ServerHttpObservationFilter.class.getName() + ".observation";
private final ObservationRegistry observationRegistry;
- private final HttpRequestsObservationConvention observationConvention;
+ private final ServerRequestObservationConvention observationConvention;
/**
* Create an {@code HttpRequestsObservationFilter} that records observations
* against the given {@link ObservationRegistry}. The default
- * {@link DefaultHttpRequestsObservationConvention convention} will be used.
+ * {@link DefaultServerRequestObservationConvention convention} will be used.
* @param observationRegistry the registry to use for recording observations
*/
- public HttpRequestsObservationFilter(ObservationRegistry observationRegistry) {
+ public ServerHttpObservationFilter(ObservationRegistry observationRegistry) {
this(observationRegistry, DEFAULT_OBSERVATION_CONVENTION);
}
@@ -76,18 +80,18 @@ public class HttpRequestsObservationFilter extends OncePerRequestFilter {
* @param observationRegistry the registry to use for recording observations
* @param observationConvention the convention to use for all recorded observations
*/
- public HttpRequestsObservationFilter(ObservationRegistry observationRegistry, HttpRequestsObservationConvention observationConvention) {
+ public ServerHttpObservationFilter(ObservationRegistry observationRegistry, ServerRequestObservationConvention observationConvention) {
this.observationRegistry = observationRegistry;
this.observationConvention = observationConvention;
}
/**
- * Get the current {@link HttpRequestsObservationContext observation context} from the given request, if available.
+ * Get the current {@link ServerRequestObservationContext observation context} from the given request, if available.
* @param request the current request
* @return the current observation context
*/
- public static Optional findObservationContext(HttpServletRequest request) {
- return Optional.ofNullable((HttpRequestsObservationContext) request.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
+ public static Optional findObservationContext(HttpServletRequest request) {
+ return Optional.ofNullable((ServerRequestObservationContext) request.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
}
@Override
@@ -124,8 +128,8 @@ public class HttpRequestsObservationFilter extends OncePerRequestFilter {
private Observation createOrFetchObservation(HttpServletRequest request, HttpServletResponse response) {
Observation observation = (Observation) request.getAttribute(CURRENT_OBSERVATION_ATTRIBUTE);
if (observation == null) {
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(request, response);
- observation = HttpRequestsObservationDocumentation.HTTP_REQUESTS.observation(this.observationConvention,
+ ServerRequestObservationContext context = new ServerRequestObservationContext(request, response);
+ observation = ServerHttpObservationDocumentation.HTTP_REQUESTS.observation(this.observationConvention,
DEFAULT_OBSERVATION_CONVENTION, () -> context, this.observationRegistry).start();
request.setAttribute(CURRENT_OBSERVATION_ATTRIBUTE, observation);
request.setAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observation.getContext());
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilter.java b/spring-web/src/main/java/org/springframework/web/filter/reactive/ServerHttpObservationFilter.java
similarity index 66%
rename from spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilter.java
rename to spring-web/src/main/java/org/springframework/web/filter/reactive/ServerHttpObservationFilter.java
index 8e5bd463b5a..e34908f01c9 100644
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilter.java
+++ b/spring-web/src/main/java/org/springframework/web/filter/reactive/ServerHttpObservationFilter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.web.filter.reactive;
import java.util.Optional;
import java.util.Set;
@@ -24,6 +24,10 @@ import io.micrometer.observation.ObservationRegistry;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
+import org.springframework.http.observation.reactive.DefaultServerRequestObservationConvention;
+import org.springframework.http.observation.reactive.ServerHttpObservationDocumentation;
+import org.springframework.http.observation.reactive.ServerRequestObservationContext;
+import org.springframework.http.observation.reactive.ServerRequestObservationConvention;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
@@ -33,39 +37,39 @@ import org.springframework.web.server.WebFilterChain;
/**
* {@link org.springframework.web.server.WebFilter} that creates {@link Observation observations}
* for HTTP exchanges. This collects information about the execution time and
- * information gathered from the {@link HttpRequestsObservationContext}.
- * Web Frameworks can fetch the current {@link HttpRequestsObservationContext context}
+ * information gathered from the {@link ServerRequestObservationContext}.
+ *
Web Frameworks can fetch the current {@link ServerRequestObservationContext context}
* as a {@link #CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE request attribute} and contribute
* additional information to it.
- * The configured {@link HttpRequestsObservationConvention} will use this context to collect
+ * The configured {@link ServerRequestObservationConvention} will use this context to collect
* {@link io.micrometer.common.KeyValue metadata} and attach it to the observation.
*
* @author Brian Clozel
* @since 6.0
*/
-public class HttpRequestsObservationWebFilter implements WebFilter {
+public class ServerHttpObservationFilter implements WebFilter {
/**
- * Name of the request attribute holding the {@link HttpRequestsObservationContext context} for the current observation.
+ * Name of the request attribute holding the {@link ServerRequestObservationContext context} for the current observation.
*/
- public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = HttpRequestsObservationWebFilter.class.getName() + ".context";
+ public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerHttpObservationFilter.class.getName() + ".context";
- private static final HttpRequestsObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultHttpRequestsObservationConvention();
+ private static final ServerRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultServerRequestObservationConvention();
private static final Set DISCONNECTED_CLIENT_EXCEPTIONS = Set.of("AbortedException",
"ClientAbortException", "EOFException", "EofException");
private final ObservationRegistry observationRegistry;
- private final HttpRequestsObservationConvention observationConvention;
+ private final ServerRequestObservationConvention observationConvention;
/**
* Create an {@code HttpRequestsObservationWebFilter} that records observations
* against the given {@link ObservationRegistry}. The default
- * {@link DefaultHttpRequestsObservationConvention convention} will be used.
+ * {@link DefaultServerRequestObservationConvention convention} will be used.
* @param observationRegistry the registry to use for recording observations
*/
- public HttpRequestsObservationWebFilter(ObservationRegistry observationRegistry) {
+ public ServerHttpObservationFilter(ObservationRegistry observationRegistry) {
this(observationRegistry, DEFAULT_OBSERVATION_CONVENTION);
}
@@ -75,29 +79,29 @@ public class HttpRequestsObservationWebFilter implements WebFilter {
* @param observationRegistry the registry to use for recording observations
* @param observationConvention the convention to use for all recorded observations
*/
- public HttpRequestsObservationWebFilter(ObservationRegistry observationRegistry, HttpRequestsObservationConvention observationConvention) {
+ public ServerHttpObservationFilter(ObservationRegistry observationRegistry, ServerRequestObservationConvention observationConvention) {
this.observationRegistry = observationRegistry;
this.observationConvention = observationConvention;
}
/**
- * Get the current {@link HttpRequestsObservationContext observation context} from the given request, if available.
+ * Get the current {@link ServerRequestObservationContext observation context} from the given request, if available.
* @param exchange the current exchange
* @return the current observation context
*/
- public static Optional findObservationContext(ServerWebExchange exchange) {
+ public static Optional findObservationContext(ServerWebExchange exchange) {
return Optional.ofNullable(exchange.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
}
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
- HttpRequestsObservationContext observationContext = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange);
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
return chain.filter(exchange).transformDeferred(call -> filter(exchange, observationContext, call));
}
- private Publisher filter(ServerWebExchange exchange, HttpRequestsObservationContext observationContext, Mono call) {
- Observation observation = HttpRequestsObservationDocumentation.HTTP_REQUESTS.observation(this.observationConvention,
+ private Publisher filter(ServerWebExchange exchange, ServerRequestObservationContext observationContext, Mono call) {
+ Observation observation = ServerHttpObservationDocumentation.HTTP_REQUESTS.observation(this.observationConvention,
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry);
observation.start();
return call.doOnEach(signal -> {
diff --git a/spring-web/src/main/java/org/springframework/web/observation/DefaultHttpRequestsObservationConvention.java b/spring-web/src/main/java/org/springframework/web/observation/DefaultHttpRequestsObservationConvention.java
deleted file mode 100644
index d4b0e17de62..00000000000
--- a/spring-web/src/main/java/org/springframework/web/observation/DefaultHttpRequestsObservationConvention.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2002-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.web.observation;
-
-import io.micrometer.common.KeyValue;
-import io.micrometer.common.KeyValues;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.http.HttpStatusCode;
-import org.springframework.http.observation.HttpOutcome;
-import org.springframework.util.StringUtils;
-
-/**
- * Default {@link HttpRequestsObservationConvention}.
- * @author Brian Clozel
- * @since 6.0
- */
-public class DefaultHttpRequestsObservationConvention implements HttpRequestsObservationConvention {
-
- private static final String DEFAULT_NAME = "http.server.requests";
-
- private static final KeyValue METHOD_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.METHOD, "UNKNOWN");
-
- private static final KeyValue STATUS_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.STATUS, "UNKNOWN");
-
- private static final KeyValue URI_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "UNKNOWN");
-
- private static final KeyValue URI_ROOT = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "root");
-
- private static final KeyValue URI_NOT_FOUND = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "NOT_FOUND");
-
- private static final KeyValue URI_REDIRECTION = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "REDIRECTION");
-
- private static final KeyValue EXCEPTION_NONE = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
-
- private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
-
- private final String name;
-
- /**
- * Create a convention with the default name {@code "http.server.requests"}.
- */
- public DefaultHttpRequestsObservationConvention() {
- this(DEFAULT_NAME);
- }
-
- /**
- * Create a convention with a custom name.
- * @param name the observation name
- */
- public DefaultHttpRequestsObservationConvention(String name) {
- this.name = name;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getContextualName(HttpRequestsObservationContext context) {
- return "http " + context.getCarrier().getMethod().toLowerCase();
- }
-
- @Override
- public KeyValues getLowCardinalityKeyValues(HttpRequestsObservationContext context) {
- return KeyValues.of(method(context), uri(context), status(context), exception(context), outcome(context));
- }
-
- @Override
- public KeyValues getHighCardinalityKeyValues(HttpRequestsObservationContext context) {
- return KeyValues.of(uriExpanded(context));
- }
-
- protected KeyValue method(HttpRequestsObservationContext context) {
- return (context.getCarrier() != null) ? KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod()) : METHOD_UNKNOWN;
- }
-
- protected KeyValue status(HttpRequestsObservationContext context) {
- return (context.getResponse() != null) ? KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatus())) : STATUS_UNKNOWN;
- }
-
- protected KeyValue uri(HttpRequestsObservationContext context) {
- if (context.getCarrier() != null) {
- String pattern = context.getPathPattern();
- if (pattern != null) {
- if (pattern.isEmpty()) {
- return URI_ROOT;
- }
- return KeyValue.of("uri", pattern);
- }
- if (context.getResponse() != null) {
- HttpStatus status = HttpStatus.resolve(context.getResponse().getStatus());
- if (status != null) {
- if (status.is3xxRedirection()) {
- return URI_REDIRECTION;
- }
- if (status == HttpStatus.NOT_FOUND) {
- return URI_NOT_FOUND;
- }
- }
- }
- }
- return URI_UNKNOWN;
- }
-
- protected KeyValue exception(HttpRequestsObservationContext context) {
- Throwable error = context.getError();
- if (error != null) {
- String simpleName = error.getClass().getSimpleName();
- return KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
- StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
- }
- return EXCEPTION_NONE;
- }
-
- protected KeyValue outcome(HttpRequestsObservationContext context) {
- if (context.getResponse() != null) {
- HttpStatusCode statusCode = HttpStatusCode.valueOf(context.getResponse().getStatus());
- HttpOutcome httpOutcome = HttpOutcome.forStatus(statusCode);
- return httpOutcome.asKeyValue();
- }
- return HttpOutcome.UNKNOWN.asKeyValue();
- }
-
- protected KeyValue uriExpanded(HttpRequestsObservationContext context) {
- if (context.getCarrier() != null) {
- return KeyValue.of(HttpRequestsObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().getRequestURI());
- }
- return HTTP_URL_UNKNOWN;
- }
-
-}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConvention.java b/spring-web/src/main/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConvention.java
deleted file mode 100644
index 259eb07bfc7..00000000000
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConvention.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2002-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.web.observation.reactive;
-
-import io.micrometer.common.KeyValue;
-import io.micrometer.common.KeyValues;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.http.observation.HttpOutcome;
-import org.springframework.util.StringUtils;
-import org.springframework.web.util.pattern.PathPattern;
-
-/**
- * Default {@link HttpRequestsObservationConvention}.
- *
- * @author Brian Clozel
- * @since 6.0
- */
-public class DefaultHttpRequestsObservationConvention implements HttpRequestsObservationConvention {
-
- private static final String DEFAULT_NAME = "http.server.requests";
-
- private static final KeyValue METHOD_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.METHOD, "UNKNOWN");
-
- private static final KeyValue STATUS_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.STATUS, "UNKNOWN");
-
- private static final KeyValue URI_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "UNKNOWN");
-
- private static final KeyValue URI_ROOT = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "root");
-
- private static final KeyValue URI_NOT_FOUND = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "NOT_FOUND");
-
- private static final KeyValue URI_REDIRECTION = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.URI, "REDIRECTION");
-
- private static final KeyValue EXCEPTION_NONE = KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
-
- private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(HttpRequestsObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
-
- private final String name;
-
- /**
- * Create a convention with the default name {@code "http.server.requests"}.
- */
- public DefaultHttpRequestsObservationConvention() {
- this(DEFAULT_NAME);
- }
-
- /**
- * Create a convention with a custom name.
- *
- * @param name the observation name
- */
- public DefaultHttpRequestsObservationConvention(String name) {
- this.name = name;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getContextualName(HttpRequestsObservationContext context) {
- return "http " + context.getCarrier().getMethod().name().toLowerCase();
- }
-
- @Override
- public KeyValues getLowCardinalityKeyValues(HttpRequestsObservationContext context) {
- return KeyValues.of(method(context), uri(context), status(context), exception(context), outcome(context));
- }
-
- @Override
- public KeyValues getHighCardinalityKeyValues(HttpRequestsObservationContext context) {
- return KeyValues.of(httpUrl(context));
- }
-
- protected KeyValue method(HttpRequestsObservationContext context) {
- return (context.getCarrier() != null) ? KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod().name()) : METHOD_UNKNOWN;
- }
-
- protected KeyValue status(HttpRequestsObservationContext context) {
- if (context.isConnectionAborted()) {
- return STATUS_UNKNOWN;
- }
- return (context.getResponse() != null) ? KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatusCode().value())) : STATUS_UNKNOWN;
- }
-
- protected KeyValue uri(HttpRequestsObservationContext context) {
- if (context.getCarrier() != null) {
- PathPattern pattern = context.getPathPattern();
- if (pattern != null) {
- if (pattern.toString().isEmpty()) {
- return URI_ROOT;
- }
- return KeyValue.of("uri", pattern.toString());
- }
- if (context.getResponse() != null) {
- HttpStatus status = HttpStatus.resolve(context.getResponse().getStatusCode().value());
- if (status != null) {
- if (status.is3xxRedirection()) {
- return URI_REDIRECTION;
- }
- if (status == HttpStatus.NOT_FOUND) {
- return URI_NOT_FOUND;
- }
- }
- }
- }
- return URI_UNKNOWN;
- }
-
- protected KeyValue exception(HttpRequestsObservationContext context) {
- Throwable error = context.getError();
- if (error != null) {
- String simpleName = error.getClass().getSimpleName();
- return KeyValue.of(HttpRequestsObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
- StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
- }
- return EXCEPTION_NONE;
- }
-
- protected KeyValue outcome(HttpRequestsObservationContext context) {
- if (context.isConnectionAborted()) {
- return HttpOutcome.UNKNOWN.asKeyValue();
- }
- if (context.getResponse() != null) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(context.getResponse().getStatusCode());
- return httpOutcome.asKeyValue();
- }
- return HttpOutcome.UNKNOWN.asKeyValue();
- }
-
- protected KeyValue httpUrl(HttpRequestsObservationContext context) {
- if (context.getCarrier() != null) {
- String uriExpanded = context.getCarrier().getPath().toString();
- return KeyValue.of(HttpRequestsObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, uriExpanded);
- }
- return HTTP_URL_UNKNOWN;
- }
-
-}
diff --git a/spring-web/src/main/java/org/springframework/web/observation/reactive/package-info.java b/spring-web/src/main/java/org/springframework/web/observation/reactive/package-info.java
deleted file mode 100644
index 75a10dd5aa6..00000000000
--- a/spring-web/src/main/java/org/springframework/web/observation/reactive/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Instrumentation for {@link io.micrometer.observation.Observation observing} reactive web applications.
- */
-@NonNullApi
-@NonNullFields
-package org.springframework.web.observation.reactive;
-
-import org.springframework.lang.NonNullApi;
-import org.springframework.lang.NonNullFields;
diff --git a/spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientHttpObservationConventionTests.java b/spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientRequestObservationConventionTests.java
similarity index 80%
rename from spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientHttpObservationConventionTests.java
rename to spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientRequestObservationConventionTests.java
index 8b1bc238f56..3373126a7dd 100644
--- a/spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientHttpObservationConventionTests.java
+++ b/spring-web/src/test/java/org/springframework/http/client/observation/DefaultClientRequestObservationConventionTests.java
@@ -34,15 +34,15 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
- * Tests for {@link DefaultClientHttpObservationConvention}.
+ * Tests for {@link DefaultClientRequestObservationConvention}.
*
* @author Brian Clozel
*/
-class DefaultClientHttpObservationConventionTests {
+class DefaultClientRequestObservationConventionTests {
private final MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, "/test");
- private final DefaultClientHttpObservationConvention observationConvention = new DefaultClientHttpObservationConvention();
+ private final DefaultClientRequestObservationConvention observationConvention = new DefaultClientRequestObservationConvention();
@Test
void shouldHaveName() {
@@ -51,20 +51,20 @@ class DefaultClientHttpObservationConventionTests {
@Test
void shouldHaveContextualName() {
- ClientHttpObservationContext context = new ClientHttpObservationContext(this.request);
+ ClientRequestObservationContext context = new ClientRequestObservationContext(this.request);
assertThat(this.observationConvention.getContextualName(context)).isEqualTo("http get");
}
@Test
void supportsOnlyClientHttpObservationContext() {
- ClientHttpObservationContext context = new ClientHttpObservationContext(this.request);
+ ClientRequestObservationContext context = new ClientRequestObservationContext(this.request);
assertThat(this.observationConvention.supportsContext(context)).isTrue();
assertThat(this.observationConvention.supportsContext(new Observation.Context())).isFalse();
}
@Test
void addsKeyValuesForRequestWithUriTemplate() {
- ClientHttpObservationContext context = createContext(
+ ClientRequestObservationContext context = createContext(
new MockClientHttpRequest(HttpMethod.GET, "/resource/{id}", 42), new MockClientHttpResponse());
context.setUriTemplate("/resource/{id}");
assertThat(this.observationConvention.getLowCardinalityKeyValues(context))
@@ -76,7 +76,7 @@ class DefaultClientHttpObservationConventionTests {
@Test
void addsKeyValuesForRequestWithoutUriTemplate() {
- ClientHttpObservationContext context = createContext(
+ ClientRequestObservationContext context = createContext(
new MockClientHttpRequest(HttpMethod.GET, "/resource/42"), new MockClientHttpResponse());
assertThat(this.observationConvention.getLowCardinalityKeyValues(context))
.contains(KeyValue.of("method", "GET"), KeyValue.of("uri", "none"));
@@ -86,7 +86,7 @@ class DefaultClientHttpObservationConventionTests {
@Test
void addsClientNameForRequestWithHost() {
- ClientHttpObservationContext context = createContext(
+ ClientRequestObservationContext context = createContext(
new MockClientHttpRequest(HttpMethod.GET, "https://localhost:8080/resource/42"),
new MockClientHttpResponse());
assertThat(this.observationConvention.getHighCardinalityKeyValues(context)).contains(KeyValue.of("client.name", "localhost"));
@@ -94,15 +94,15 @@ class DefaultClientHttpObservationConventionTests {
@Test
void addsKeyValueForNonResolvableStatus() throws Exception {
- ClientHttpObservationContext context = new ClientHttpObservationContext(this.request);
+ ClientRequestObservationContext context = new ClientRequestObservationContext(this.request);
ClientHttpResponse response = mock(ClientHttpResponse.class);
context.setResponse(response);
given(response.getStatusCode()).willThrow(new IOException("test error"));
assertThat(this.observationConvention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("status", "IO_ERROR"));
}
- private ClientHttpObservationContext createContext(ClientHttpRequest request, ClientHttpResponse response) {
- ClientHttpObservationContext context = new ClientHttpObservationContext(request);
+ private ClientRequestObservationContext createContext(ClientHttpRequest request, ClientHttpResponse response) {
+ ClientRequestObservationContext context = new ClientRequestObservationContext(request);
context.setResponse(response);
return context;
}
diff --git a/spring-web/src/test/java/org/springframework/web/observation/DefaultHttpRequestsObservationConventionTests.java b/spring-web/src/test/java/org/springframework/http/observation/DefaultServerRequestObservationConventionTests.java
similarity index 91%
rename from spring-web/src/test/java/org/springframework/web/observation/DefaultHttpRequestsObservationConventionTests.java
rename to spring-web/src/test/java/org/springframework/http/observation/DefaultServerRequestObservationConventionTests.java
index 14ac6c3abed..920c54e1d4a 100644
--- a/spring-web/src/test/java/org/springframework/web/observation/DefaultHttpRequestsObservationConventionTests.java
+++ b/spring-web/src/test/java/org/springframework/http/observation/DefaultServerRequestObservationConventionTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.http.observation;
import io.micrometer.common.KeyValue;
import io.micrometer.observation.Observation;
@@ -26,18 +26,18 @@ import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link DefaultHttpRequestsObservationConvention}.
+ * Tests for {@link DefaultServerRequestObservationConvention}.
* @author Brian Clozel
*/
-class DefaultHttpRequestsObservationConventionTests {
+class DefaultServerRequestObservationConventionTests {
- private final DefaultHttpRequestsObservationConvention convention = new DefaultHttpRequestsObservationConvention();
+ private final DefaultServerRequestObservationConvention convention = new DefaultServerRequestObservationConvention();
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test/resource");
private final MockHttpServletResponse response = new MockHttpServletResponse();
- private final HttpRequestsObservationContext context = new HttpRequestsObservationContext(this.request, this.response);
+ private final ServerRequestObservationContext context = new ServerRequestObservationContext(this.request, this.response);
@Test
diff --git a/spring-web/src/test/java/org/springframework/http/observation/HttpOutcomeTests.java b/spring-web/src/test/java/org/springframework/http/observation/HttpOutcomeTests.java
deleted file mode 100644
index e30b6645da1..00000000000
--- a/spring-web/src/test/java/org/springframework/http/observation/HttpOutcomeTests.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2002-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.http.observation;
-
-
-import io.micrometer.common.KeyValue;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import org.springframework.http.HttpStatusCode;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link HttpOutcome}.
- *
- * @author Brian Clozel
- */
-class HttpOutcomeTests {
-
- @ParameterizedTest
- @ValueSource(ints = {100, 101, 102})
- void shouldResolveInformational(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.INFORMATIONAL);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "INFORMATIONAL"));
- }
-
- @ParameterizedTest
- @ValueSource(ints = {200, 202, 226})
- void shouldResolveSuccess(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.SUCCESS);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "SUCCESS"));
- }
-
- @ParameterizedTest
- @ValueSource(ints = {300, 302, 303})
- void shouldResolveRedirection(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.REDIRECTION);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "REDIRECTION"));
- }
-
- @ParameterizedTest
- @ValueSource(ints = {400, 404, 405})
- void shouldResolveClientError(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.CLIENT_ERROR);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "CLIENT_ERROR"));
- }
-
- @ParameterizedTest
- @ValueSource(ints = {500, 502, 503})
- void shouldResolveServerError(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.SERVER_ERROR);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "SERVER_ERROR"));
- }
-
- @ParameterizedTest
- @ValueSource(ints = {600, 799, 855})
- void shouldResolveUnknown(int code) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(HttpStatusCode.valueOf(code));
- assertThat(httpOutcome).isEqualTo(HttpOutcome.UNKNOWN);
- assertThat(httpOutcome.asKeyValue()).isEqualTo(KeyValue.of("outcome", "UNKNOWN"));
- }
-
-}
diff --git a/spring-web/src/test/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConventionTests.java b/spring-web/src/test/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConventionTests.java
similarity index 85%
rename from spring-web/src/test/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConventionTests.java
rename to spring-web/src/test/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConventionTests.java
index fdd4728de5a..e2d5e8538dd 100644
--- a/spring-web/src/test/java/org/springframework/web/observation/reactive/DefaultHttpRequestsObservationConventionTests.java
+++ b/spring-web/src/test/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConventionTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.http.observation.reactive;
import io.micrometer.common.KeyValue;
import io.micrometer.observation.Observation;
@@ -29,12 +29,12 @@ import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link DefaultHttpRequestsObservationConvention}.
+ * Tests for {@link DefaultServerRequestObservationConvention}.
* @author Brian Clozel
*/
-class DefaultHttpRequestsObservationConventionTests {
+class DefaultServerRequestObservationConventionTests {
- private final DefaultHttpRequestsObservationConvention convention = new DefaultHttpRequestsObservationConvention();
+ private final DefaultServerRequestObservationConvention convention = new DefaultServerRequestObservationConvention();
@Test
@@ -45,14 +45,14 @@ class DefaultHttpRequestsObservationConventionTests {
@Test
void shouldHaveContextualName() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
assertThat(convention.getContextualName(context)).isEqualTo("http get");
}
@Test
void supportsOnlyHttpRequestsObservationContext() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
assertThat(this.convention.supportsContext(context)).isTrue();
assertThat(this.convention.supportsContext(new Observation.Context())).isFalse();
}
@@ -61,7 +61,7 @@ class DefaultHttpRequestsObservationConventionTests {
void addsKeyValuesForExchange() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
exchange.getResponse().setRawStatusCode(201);
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
assertThat(this.convention.getLowCardinalityKeyValues(context)).hasSize(5)
.contains(KeyValue.of("method", "POST"), KeyValue.of("uri", "UNKNOWN"), KeyValue.of("status", "201"),
@@ -74,7 +74,7 @@ class DefaultHttpRequestsObservationConventionTests {
void addsKeyValuesForExchangeWithPathPattern() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
exchange.getResponse().setRawStatusCode(200);
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
PathPattern pathPattern = getPathPattern("/test/{name}");
context.setPathPattern(pathPattern);
@@ -89,7 +89,7 @@ class DefaultHttpRequestsObservationConventionTests {
@Test
void addsKeyValuesForErrorExchange() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
context.setError(new IllegalArgumentException("custom error"));
exchange.getResponse().setRawStatusCode(500);
@@ -103,7 +103,7 @@ class DefaultHttpRequestsObservationConventionTests {
@Test
void addsKeyValuesForRedirectExchange() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/redirect"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
exchange.getResponse().setRawStatusCode(302);
exchange.getResponse().getHeaders().add("Location", "https://example.org/other");
@@ -117,7 +117,7 @@ class DefaultHttpRequestsObservationConventionTests {
@Test
void addsKeyValuesForNotFoundExchange() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/notFound"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
exchange.getResponse().setRawStatusCode(404);
assertThat(this.convention.getLowCardinalityKeyValues(context)).hasSize(5)
@@ -130,7 +130,7 @@ class DefaultHttpRequestsObservationConventionTests {
@Test
void addsKeyValuesForCancelledExchange() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
- HttpRequestsObservationContext context = new HttpRequestsObservationContext(exchange);
+ ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
context.setConnectionAborted(true);
exchange.getResponse().setRawStatusCode(200);
diff --git a/spring-web/src/test/java/org/springframework/web/client/RestTemplateObservationTests.java b/spring-web/src/test/java/org/springframework/web/client/RestTemplateObservationTests.java
index dafb6295778..b85de7fc2f2 100644
--- a/spring-web/src/test/java/org/springframework/web/client/RestTemplateObservationTests.java
+++ b/spring-web/src/test/java/org/springframework/web/client/RestTemplateObservationTests.java
@@ -37,7 +37,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.client.observation.ClientHttpObservationContext;
+import org.springframework.http.client.observation.ClientRequestObservationContext;
import org.springframework.http.converter.HttpMessageConverter;
import static org.assertj.core.api.Assertions.assertThat;
@@ -192,15 +192,15 @@ class RestTemplateObservationTests {
.hasObservationWithNameEqualTo("http.client.requests").that();
}
- static class ContextAssertionObservationHandler implements ObservationHandler {
+ static class ContextAssertionObservationHandler implements ObservationHandler {
@Override
public boolean supportsContext(Observation.Context context) {
- return context instanceof ClientHttpObservationContext;
+ return context instanceof ClientRequestObservationContext;
}
@Override
- public void onStart(ClientHttpObservationContext context) {
+ public void onStart(ClientRequestObservationContext context) {
assertThat(context.getCarrier()).isNotNull();
}
}
diff --git a/spring-web/src/test/java/org/springframework/web/observation/HttpRequestsObservationFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/ServerHttpObservationFilterTests.java
similarity index 79%
rename from spring-web/src/test/java/org/springframework/web/observation/HttpRequestsObservationFilterTests.java
rename to spring-web/src/test/java/org/springframework/web/filter/ServerHttpObservationFilterTests.java
index 8f2e59874da..a574faeac44 100644
--- a/spring-web/src/test/java/org/springframework/web/observation/HttpRequestsObservationFilterTests.java
+++ b/spring-web/src/test/java/org/springframework/web/filter/ServerHttpObservationFilterTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation;
+package org.springframework.web.filter;
import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert;
@@ -23,6 +23,7 @@ import jakarta.servlet.ServletException;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
+import org.springframework.http.observation.ServerRequestObservationContext;
import org.springframework.web.testfixture.servlet.MockFilterChain;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
@@ -31,14 +32,14 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
- * Tests for {@link HttpRequestsObservationFilter}.
+ * Tests for {@link ServerHttpObservationFilter}.
* @author Brian Clozel
*/
-class HttpRequestsObservationFilterTests {
+class ServerHttpObservationFilterTests {
private final TestObservationRegistry observationRegistry = TestObservationRegistry.create();
- private final HttpRequestsObservationFilter filter = new HttpRequestsObservationFilter(this.observationRegistry);
+ private final ServerHttpObservationFilter filter = new ServerHttpObservationFilter(this.observationRegistry);
private final MockFilterChain mockFilterChain = new MockFilterChain();
@@ -51,8 +52,8 @@ class HttpRequestsObservationFilterTests {
void filterShouldFillObservationContext() throws Exception {
this.filter.doFilter(this.request, this.response, this.mockFilterChain);
- HttpRequestsObservationContext context = (HttpRequestsObservationContext) this.request
- .getAttribute(HttpRequestsObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
+ ServerRequestObservationContext context = (ServerRequestObservationContext) this.request
+ .getAttribute(ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
assertThat(context).isNotNull();
assertThat(context.getCarrier()).isEqualTo(this.request);
assertThat(context.getResponse()).isEqualTo(this.response);
@@ -66,8 +67,8 @@ class HttpRequestsObservationFilterTests {
this.request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, customError);
this.filter.doFilter(this.request, this.response, this.mockFilterChain);
- HttpRequestsObservationContext context = (HttpRequestsObservationContext) this.request
- .getAttribute(HttpRequestsObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
+ ServerRequestObservationContext context = (ServerRequestObservationContext) this.request
+ .getAttribute(ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
assertThat(context.getError()).isEqualTo(customError);
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SERVER_ERROR");
}
@@ -81,8 +82,8 @@ class HttpRequestsObservationFilterTests {
throw new ServletException(customError);
});
}).isInstanceOf(ServletException.class);
- HttpRequestsObservationContext context = (HttpRequestsObservationContext) this.request
- .getAttribute(HttpRequestsObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
+ ServerRequestObservationContext context = (ServerRequestObservationContext) this.request
+ .getAttribute(ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE);
assertThat(context.getError()).isEqualTo(customError);
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS");
}
diff --git a/spring-web/src/test/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/reactive/ServerHttpObservationFilterTests.java
similarity index 86%
rename from spring-web/src/test/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilterTests.java
rename to spring-web/src/test/java/org/springframework/web/filter/reactive/ServerHttpObservationFilterTests.java
index b091f3b2190..79b2f3bef5f 100644
--- a/spring-web/src/test/java/org/springframework/web/observation/reactive/HttpRequestsObservationWebFilterTests.java
+++ b/spring-web/src/test/java/org/springframework/web/filter/reactive/ServerHttpObservationFilterTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.observation.reactive;
+package org.springframework.web.filter.reactive;
import java.util.Optional;
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+import org.springframework.http.observation.reactive.ServerRequestObservationContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
@@ -34,22 +35,22 @@ import org.springframework.web.testfixture.server.MockServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link HttpRequestsObservationWebFilter}.
+ * Tests for {@link ServerHttpObservationFilter}.
*
* @author Brian Clozel
*/
-class HttpRequestsObservationWebFilterTests {
+class ServerHttpObservationFilterTests {
private final TestObservationRegistry observationRegistry = TestObservationRegistry.create();
- private final HttpRequestsObservationWebFilter filter = new HttpRequestsObservationWebFilter(this.observationRegistry);
+ private final ServerHttpObservationFilter filter = new ServerHttpObservationFilter(this.observationRegistry);
@Test
void filterShouldFillObservationContext() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
exchange.getResponse().setRawStatusCode(200);
WebFilterChain filterChain = createFilterChain(filterExchange -> {
- Optional observationContext = HttpRequestsObservationWebFilter.findObservationContext(filterExchange);
+ Optional observationContext = ServerHttpObservationFilter.findObservationContext(filterExchange);
assertThat(observationContext).isPresent();
assertThat(observationContext.get().getCarrier()).isEqualTo(exchange.getRequest());
assertThat(observationContext.get().getResponse()).isEqualTo(exchange.getResponse());
@@ -68,7 +69,7 @@ class HttpRequestsObservationWebFilterTests {
StepVerifier.create(this.filter.filter(exchange, filterChain))
.expectError(IllegalArgumentException.class)
.verify();
- Optional observationContext = HttpRequestsObservationWebFilter.findObservationContext(exchange);
+ Optional observationContext = ServerHttpObservationFilter.findObservationContext(exchange);
assertThat(observationContext.get().getError()).isInstanceOf(IllegalArgumentException.class);
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SERVER_ERROR");
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationDocumentation.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientHttpObservationDocumentation.java
similarity index 89%
rename from spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationDocumentation.java
rename to spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientHttpObservationDocumentation.java
index 855578bf9d6..73248cae7bd 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationDocumentation.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientHttpObservationDocumentation.java
@@ -22,12 +22,13 @@ import io.micrometer.observation.ObservationConvention;
import io.micrometer.observation.docs.ObservationDocumentation;
/**
- * Documented {@link io.micrometer.common.KeyValue KeyValues} for the {@link WebClient} observations.
+ * Documented {@link io.micrometer.common.KeyValue KeyValues} for the {@link WebClient HTTP client} observations.
* This class is used by automated tools to document KeyValues attached to the HTTP client observations.
+ *
* @author Brian Clozel
* @since 6.0
*/
-public enum ClientObservationDocumentation implements ObservationDocumentation {
+public enum ClientHttpObservationDocumentation implements ObservationDocumentation {
/**
* Observation created for an HTTP client exchange.
@@ -35,17 +36,17 @@ public enum ClientObservationDocumentation implements ObservationDocumentation {
HTTP_REQUEST {
@Override
public Class extends ObservationConvention extends Observation.Context>> getDefaultConvention() {
- return DefaultClientObservationConvention.class;
+ return DefaultClientRequestObservationConvention.class;
}
@Override
public KeyName[] getLowCardinalityKeyNames() {
- return ClientObservationDocumentation.LowCardinalityKeyNames.values();
+ return ClientHttpObservationDocumentation.LowCardinalityKeyNames.values();
}
@Override
public KeyName[] getHighCardinalityKeyNames() {
- return ClientObservationDocumentation.HighCardinalityKeyNames.values();
+ return ClientHttpObservationDocumentation.HighCardinalityKeyNames.values();
}
};
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequestObservationContext.java
similarity index 85%
rename from spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationContext.java
rename to spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequestObservationContext.java
index ea616891df8..36423eb381d 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientObservationContext.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequestObservationContext.java
@@ -22,12 +22,12 @@ import org.springframework.lang.Nullable;
/**
* Context that holds information for metadata collection
- * during the HTTP client observations.
+ * during the {@link ClientHttpObservationDocumentation#HTTP_REQUEST HTTP client exchange observations}.
*
* @author Brian Clozel
* @since 6.0
*/
-public class ClientObservationContext extends RequestReplySenderContext {
+public class ClientRequestObservationContext extends RequestReplySenderContext {
@Nullable
private String uriTemplate;
@@ -35,8 +35,8 @@ public class ClientObservationContext extends RequestReplySenderContext {
+public interface ClientRequestObservationConvention extends ObservationConvention {
@Override
default boolean supportsContext(Observation.Context context) {
- return context instanceof ClientObservationContext;
+ return context instanceof ClientRequestObservationContext;
}
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientObservationConvention.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientObservationConvention.java
deleted file mode 100644
index 080c2eea847..00000000000
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientObservationConvention.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2002-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.web.reactive.function.client;
-
-import java.io.IOException;
-
-import io.micrometer.common.KeyValue;
-import io.micrometer.common.KeyValues;
-import io.micrometer.observation.ObservationConvention;
-
-import org.springframework.http.client.observation.ClientHttpObservationDocumentation;
-import org.springframework.http.observation.HttpOutcome;
-import org.springframework.util.StringUtils;
-
-/**
- * Default implementation for a {@code WebClient} {@link ObservationConvention},
- * extracting information from the {@link ClientObservationContext}.
- *
- * @author Brian Clozel
- * @since 6.0
- */
-public class DefaultClientObservationConvention implements ClientObservationConvention {
-
- private static final String DEFAULT_NAME = "http.client.requests";
-
- private static final KeyValue URI_NONE = KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.URI, "none");
-
- private static final KeyValue METHOD_NONE = KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.METHOD, "none");
-
- private static final KeyValue STATUS_IO_ERROR = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "IO_ERROR");
-
- private static final KeyValue STATUS_CLIENT_ERROR = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "CLIENT_ERROR");
-
- private static final KeyValue EXCEPTION_NONE = KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
-
- private static final KeyValue HTTP_URL_NONE = KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "none");
-
- private static final KeyValue CLIENT_NAME_NONE = KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, "none");
-
- private final String name;
-
-
- /**
- * Create a convention with the default name {@code "http.client.requests"}.
- */
- public DefaultClientObservationConvention() {
- this(DEFAULT_NAME);
- }
-
- /**
- * Create a convention with a custom name.
- * @param name the observation name
- */
- public DefaultClientObservationConvention(String name) {
- this.name = name;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getContextualName(ClientObservationContext context) {
- return "http " + context.getCarrier().method().name().toLowerCase();
- }
-
- @Override
- public KeyValues getLowCardinalityKeyValues(ClientObservationContext context) {
- return KeyValues.of(uri(context), method(context), status(context), exception(context), outcome(context));
- }
-
- protected KeyValue uri(ClientObservationContext context) {
- if (context.getUriTemplate() != null) {
- return KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.URI, context.getUriTemplate());
- }
- return URI_NONE;
- }
-
- protected KeyValue method(ClientObservationContext context) {
- if (context.getCarrier() != null) {
- return KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().method().name());
- }
- else {
- return METHOD_NONE;
- }
- }
-
- protected KeyValue status(ClientObservationContext context) {
- if (context.isAborted()) {
- return STATUS_CLIENT_ERROR;
- }
- ClientResponse response = context.getResponse();
- if (response != null) {
- return KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.STATUS, String.valueOf(response.statusCode().value()));
- }
- if (context.getError() != null && context.getError() instanceof IOException) {
- return STATUS_IO_ERROR;
- }
- return STATUS_CLIENT_ERROR;
- }
-
- protected KeyValue exception(ClientObservationContext context) {
- Throwable error = context.getError();
- if (error != null) {
- String simpleName = error.getClass().getSimpleName();
- return KeyValue.of(ClientObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
- StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
- }
- return EXCEPTION_NONE;
- }
-
- protected KeyValue outcome(ClientObservationContext context) {
- if (context.isAborted()) {
- return HttpOutcome.UNKNOWN.asKeyValue();
- }
- if (context.getResponse() != null) {
- HttpOutcome httpOutcome = HttpOutcome.forStatus(context.getResponse().statusCode());
- return httpOutcome.asKeyValue();
- }
- return HttpOutcome.UNKNOWN.asKeyValue();
- }
-
- @Override
- public KeyValues getHighCardinalityKeyValues(ClientObservationContext context) {
- return KeyValues.of(httpUrl(context), clientName(context));
- }
-
- protected KeyValue httpUrl(ClientObservationContext context) {
- if (context.getCarrier() != null) {
- return KeyValue.of(ClientObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().url().toASCIIString());
- }
- return HTTP_URL_NONE;
- }
-
- protected KeyValue clientName(ClientObservationContext context) {
- if (context.getCarrier() != null && context.getCarrier().url().getHost() != null) {
- return KeyValue.of(ClientObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, context.getCarrier().url().getHost());
- }
- return CLIENT_NAME_NONE;
- }
-
-}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConvention.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConvention.java
new file mode 100644
index 00000000000..69c088e4763
--- /dev/null
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConvention.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2002-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.web.reactive.function.client;
+
+import java.io.IOException;
+
+import io.micrometer.common.KeyValue;
+import io.micrometer.common.KeyValues;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.util.StringUtils;
+
+/**
+ * Default implementation for a {@link ClientRequestObservationConvention},
+ * extracting information from the {@link ClientRequestObservationContext}.
+ *
+ * @author Brian Clozel
+ * @since 6.0
+ */
+public class DefaultClientRequestObservationConvention implements ClientRequestObservationConvention {
+
+ private static final String DEFAULT_NAME = "http.client.requests";
+
+ private static final KeyValue URI_NONE = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.URI, "none");
+
+ private static final KeyValue METHOD_NONE = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, "none");
+
+ private static final KeyValue STATUS_IO_ERROR = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "IO_ERROR");
+
+ private static final KeyValue STATUS_CLIENT_ERROR = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, "CLIENT_ERROR");
+
+ private static final KeyValue HTTP_OUTCOME_SUCCESS = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "SUCCESS");
+
+ private static final KeyValue HTTP_OUTCOME_UNKNOWN = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames.OUTCOME, "UNKNOWN");
+
+ private static final KeyValue EXCEPTION_NONE = KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
+
+ private static final KeyValue HTTP_URL_NONE = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, "none");
+
+ private static final KeyValue CLIENT_NAME_NONE = KeyValue.of(org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, "none");
+
+ private final String name;
+
+
+ /**
+ * Create a convention with the default name {@code "http.client.requests"}.
+ */
+ public DefaultClientRequestObservationConvention() {
+ this(DEFAULT_NAME);
+ }
+
+ /**
+ * Create a convention with a custom name.
+ * @param name the observation name
+ */
+ public DefaultClientRequestObservationConvention(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getContextualName(ClientRequestObservationContext context) {
+ return "http " + context.getCarrier().method().name().toLowerCase();
+ }
+
+ @Override
+ public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {
+ return KeyValues.of(uri(context), method(context), status(context), exception(context), outcome(context));
+ }
+
+ protected KeyValue uri(ClientRequestObservationContext context) {
+ if (context.getUriTemplate() != null) {
+ return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.URI, context.getUriTemplate());
+ }
+ return URI_NONE;
+ }
+
+ protected KeyValue method(ClientRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().method().name());
+ }
+ else {
+ return METHOD_NONE;
+ }
+ }
+
+ protected KeyValue status(ClientRequestObservationContext context) {
+ if (context.isAborted()) {
+ return STATUS_CLIENT_ERROR;
+ }
+ ClientResponse response = context.getResponse();
+ if (response != null) {
+ return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, String.valueOf(response.statusCode().value()));
+ }
+ if (context.getError() != null && context.getError() instanceof IOException) {
+ return STATUS_IO_ERROR;
+ }
+ return STATUS_CLIENT_ERROR;
+ }
+
+ protected KeyValue exception(ClientRequestObservationContext context) {
+ Throwable error = context.getError();
+ if (error != null) {
+ String simpleName = error.getClass().getSimpleName();
+ return KeyValue.of(ClientHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION,
+ StringUtils.hasText(simpleName) ? simpleName : error.getClass().getName());
+ }
+ return EXCEPTION_NONE;
+ }
+
+ protected KeyValue outcome(ClientRequestObservationContext context) {
+ if (context.isAborted()) {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ if (context.getResponse() != null) {
+ return HttpOutcome.forStatus(context.getResponse().statusCode());
+ }
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+
+ @Override
+ public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) {
+ return KeyValues.of(httpUrl(context), clientName(context));
+ }
+
+ protected KeyValue httpUrl(ClientRequestObservationContext context) {
+ if (context.getCarrier() != null) {
+ return KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().url().toASCIIString());
+ }
+ return HTTP_URL_NONE;
+ }
+
+ protected KeyValue clientName(ClientRequestObservationContext context) {
+ if (context.getCarrier() != null && context.getCarrier().url().getHost() != null) {
+ return KeyValue.of(ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME, context.getCarrier().url().getHost());
+ }
+ return CLIENT_NAME_NONE;
+ }
+
+ static class HttpOutcome {
+
+ static KeyValue forStatus(HttpStatusCode statusCode) {
+ if (statusCode.is2xxSuccessful()) {
+ return HTTP_OUTCOME_SUCCESS;
+ }
+ else if (statusCode instanceof HttpStatus status){
+ return KeyValue.of("outcome", status.series().name());
+ }
+ else {
+ return HTTP_OUTCOME_UNKNOWN;
+ }
+ }
+
+ }
+
+}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
index 9ce4e0b87a7..219f7167711 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
@@ -73,7 +73,7 @@ class DefaultWebClient implements WebClient {
private static final Mono NO_HTTP_CLIENT_RESPONSE_ERROR = Mono.error(
() -> new IllegalStateException("The underlying HTTP client completed without emitting a response."));
- private static final DefaultClientObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultClientObservationConvention();
+ private static final DefaultClientRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultClientRequestObservationConvention();
private final ExchangeFunction exchangeFunction;
@@ -92,7 +92,7 @@ class DefaultWebClient implements WebClient {
private final ObservationRegistry observationRegistry;
- private final ClientObservationConvention observationConvention;
+ private final ClientRequestObservationConvention observationConvention;
private final DefaultWebClientBuilder builder;
@@ -101,7 +101,7 @@ class DefaultWebClient implements WebClient {
@Nullable HttpHeaders defaultHeaders, @Nullable MultiValueMap defaultCookies,
@Nullable Consumer> defaultRequest,
@Nullable Map, Function>> statusHandlerMap,
- ObservationRegistry observationRegistry, ClientObservationConvention observationConvention,
+ ObservationRegistry observationRegistry, ClientRequestObservationConvention observationConvention,
DefaultWebClientBuilder builder) {
this.exchangeFunction = exchangeFunction;
@@ -449,12 +449,12 @@ class DefaultWebClient implements WebClient {
@Override
@SuppressWarnings("deprecation")
public Mono exchange() {
- ClientObservationContext observationContext = new ClientObservationContext();
+ ClientRequestObservationContext observationContext = new ClientRequestObservationContext();
ClientRequest request = (this.inserter != null ?
initRequestBuilder().body(this.inserter).build() :
initRequestBuilder().build());
return Mono.defer(() -> {
- Observation observation = ClientObservationDocumentation.HTTP_REQUEST.observation(observationConvention,
+ Observation observation = ClientHttpObservationDocumentation.HTTP_REQUEST.observation(observationConvention,
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry).start();
observationContext.setCarrier(request);
observationContext.setUriTemplate((String) request.attribute(URI_TEMPLATE_ATTRIBUTE).orElse(null));
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java
index 43979e97b1a..a5493f2def1 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java
@@ -113,7 +113,7 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
@Nullable
- private ClientObservationConvention observationConvention;
+ private ClientRequestObservationConvention observationConvention;
public DefaultWebClientBuilder() {
@@ -288,7 +288,7 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
}
@Override
- public WebClient.Builder observationConvention(ClientObservationConvention observationConvention) {
+ public WebClient.Builder observationConvention(ClientRequestObservationConvention observationConvention) {
Assert.notNull(observationConvention, "observationConvention must not be null");
this.observationConvention = observationConvention;
return this;
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java
index 95291810e45..e3998eade85 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java
@@ -347,12 +347,12 @@ public interface WebClient {
/**
* Provide an {@link ObservationConvention} to use for collecting
- * metadata for the current observation. Will use {@link DefaultClientObservationConvention}
+ * metadata for the request observation. Will use {@link DefaultClientRequestObservationConvention}
* if none provided.
* @param observationConvention the observation convention to use
* @since 6.0
*/
- Builder observationConvention(ClientObservationConvention observationConvention);
+ Builder observationConvention(ClientRequestObservationConvention observationConvention);
/**
* Apply the given {@code Consumer} to this builder instance.
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientObservationConventionTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConventionTests.java
similarity index 79%
rename from spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientObservationConventionTests.java
rename to spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConventionTests.java
index be3cf63beba..2e3d3003f04 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientObservationConventionTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientRequestObservationConventionTests.java
@@ -28,13 +28,13 @@ import org.springframework.http.HttpStatus;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link DefaultClientObservationConvention}.
+ * Tests for {@link DefaultClientRequestObservationConvention}.
*
* @author Brian Clozel
*/
-class DefaultClientObservationConventionTests {
+class DefaultClientRequestObservationConventionTests {
- private final DefaultClientObservationConvention observationConvention = new DefaultClientObservationConvention();
+ private final DefaultClientRequestObservationConvention observationConvention = new DefaultClientRequestObservationConvention();
@Test
void shouldHaveName() {
@@ -43,20 +43,20 @@ class DefaultClientObservationConventionTests {
@Test
void shouldHaveContextualName() {
- ClientObservationContext context = new ClientObservationContext();
+ ClientRequestObservationContext context = new ClientRequestObservationContext();
context.setCarrier(ClientRequest.create(HttpMethod.GET, URI.create("/test")).build());
assertThat(this.observationConvention.getContextualName(context)).isEqualTo("http get");
}
@Test
void shouldOnlySupportWebClientObservationContext() {
- assertThat(this.observationConvention.supportsContext(new ClientObservationContext())).isTrue();
+ assertThat(this.observationConvention.supportsContext(new ClientRequestObservationContext())).isTrue();
assertThat(this.observationConvention.supportsContext(new Observation.Context())).isFalse();
}
@Test
void shouldAddKeyValuesForNullExchange() {
- ClientObservationContext context = new ClientObservationContext();
+ ClientRequestObservationContext context = new ClientRequestObservationContext();
assertThat(this.observationConvention.getLowCardinalityKeyValues(context)).hasSize(5)
.contains(KeyValue.of("method", "none"), KeyValue.of("uri", "none"), KeyValue.of("status", "CLIENT_ERROR"),
KeyValue.of("exception", "none"), KeyValue.of("outcome", "UNKNOWN"));
@@ -66,7 +66,7 @@ class DefaultClientObservationConventionTests {
@Test
void shouldAddKeyValuesForExchangeWithException() {
- ClientObservationContext context = new ClientObservationContext();
+ ClientRequestObservationContext context = new ClientRequestObservationContext();
context.setError(new IllegalStateException("Could not create client request"));
assertThat(this.observationConvention.getLowCardinalityKeyValues(context)).hasSize(5)
.contains(KeyValue.of("method", "none"), KeyValue.of("uri", "none"), KeyValue.of("status", "CLIENT_ERROR"),
@@ -79,7 +79,7 @@ class DefaultClientObservationConventionTests {
void shouldAddKeyValuesForRequestWithUriTemplate() {
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("/resource/42"))
.attribute(WebClient.class.getName() + ".uriTemplate", "/resource/{id}").build();
- ClientObservationContext context = createContext(request);
+ ClientRequestObservationContext context = createContext(request);
context.setUriTemplate("/resource/{id}");
assertThat(this.observationConvention.getLowCardinalityKeyValues(context))
.contains(KeyValue.of("exception", "none"), KeyValue.of("method", "GET"), KeyValue.of("uri", "/resource/{id}"),
@@ -90,7 +90,7 @@ class DefaultClientObservationConventionTests {
@Test
void shouldAddKeyValuesForRequestWithoutUriTemplate() {
- ClientObservationContext context = createContext(ClientRequest.create(HttpMethod.GET, URI.create("/resource/42")).build());
+ ClientRequestObservationContext context = createContext(ClientRequest.create(HttpMethod.GET, URI.create("/resource/42")).build());
assertThat(this.observationConvention.getLowCardinalityKeyValues(context))
.contains(KeyValue.of("method", "GET"), KeyValue.of("uri", "none"));
assertThat(this.observationConvention.getHighCardinalityKeyValues(context)).hasSize(2).contains(KeyValue.of("http.url", "/resource/42"));
@@ -98,12 +98,12 @@ class DefaultClientObservationConventionTests {
@Test
void shouldAddClientNameKeyValueForRequestWithHost() {
- ClientObservationContext context = createContext(ClientRequest.create(HttpMethod.GET, URI.create("https://localhost:8080/resource/42")).build());
+ ClientRequestObservationContext context = createContext(ClientRequest.create(HttpMethod.GET, URI.create("https://localhost:8080/resource/42")).build());
assertThat(this.observationConvention.getHighCardinalityKeyValues(context)).contains(KeyValue.of("client.name", "localhost"));
}
- private ClientObservationContext createContext(ClientRequest request) {
- ClientObservationContext context = new ClientObservationContext();
+ private ClientRequestObservationContext createContext(ClientRequest request) {
+ ClientRequestObservationContext context = new ClientRequestObservationContext();
context.setCarrier(request);
context.setResponse(ClientResponse.create(HttpStatus.OK).build());
return context;
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/support/RouterFunctionMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/support/RouterFunctionMapping.java
index 5376aee637f..5f349f8b4a4 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/support/RouterFunctionMapping.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/support/RouterFunctionMapping.java
@@ -32,7 +32,7 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessage
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
-import org.springframework.web.observation.HttpRequestsObservationFilter;
+import org.springframework.web.filter.ServerHttpObservationFilter;
import org.springframework.web.servlet.function.HandlerFunction;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
@@ -223,7 +223,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini
if (matchingPattern != null) {
servletRequest.removeAttribute(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
servletRequest.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, matchingPattern.getPatternString());
- HttpRequestsObservationFilter.findObservationContext(request.servletRequest())
+ ServerHttpObservationFilter.findObservationContext(request.servletRequest())
.ifPresent(context -> context.setPathPattern(matchingPattern.getPatternString()));
}
servletRequest.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerFunction);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java
index 4c7009f1bb2..6c9dce05553 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java
@@ -34,7 +34,7 @@ import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
-import org.springframework.web.observation.HttpRequestsObservationFilter;
+import org.springframework.web.filter.ServerHttpObservationFilter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
@@ -356,7 +356,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
HttpServletRequest request) {
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatchingPattern);
- HttpRequestsObservationFilter.findObservationContext(request)
+ ServerHttpObservationFilter.findObservationContext(request)
.ifPresent(context -> context.setPathPattern(bestMatchingPattern));
request.setAttribute(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java
index 727382096d2..8c0c3a4f369 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java
@@ -44,8 +44,8 @@ import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.filter.ServerHttpObservationFilter;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.observation.HttpRequestsObservationFilter;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.mvc.condition.NameValueExpression;
@@ -173,7 +173,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, result.getMatrixVariables());
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern.getPatternString());
- HttpRequestsObservationFilter.findObservationContext(request)
+ ServerHttpObservationFilter.findObservationContext(request)
.ifPresent(context -> context.setPathPattern(bestPattern.getPatternString()));
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
@@ -196,7 +196,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
- HttpRequestsObservationFilter.findObservationContext(request)
+ ServerHttpObservationFilter.findObservationContext(request)
.ifPresent(context -> context.setPathPattern(bestPattern));
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/support/RouterFunctionMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/support/RouterFunctionMappingTests.java
index 28b8f91d760..ead0a1e538b 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/support/RouterFunctionMappingTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/support/RouterFunctionMappingTests.java
@@ -26,8 +26,8 @@ import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.web.observation.HttpRequestsObservationContext;
-import org.springframework.web.observation.HttpRequestsObservationFilter;
+import org.springframework.http.observation.ServerRequestObservationContext;
+import org.springframework.web.filter.ServerHttpObservationFilter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.function.HandlerFunction;
@@ -174,15 +174,15 @@ class RouterFunctionMappingTests {
assertThat(result).isNotNull();
assertThat(request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)).isEqualTo("/match");
- assertThat(HttpRequestsObservationFilter.findObservationContext(request))
+ assertThat(ServerHttpObservationFilter.findObservationContext(request))
.hasValueSatisfying(context -> assertThat(context.getPathPattern()).isEqualTo("/match"));
assertThat(request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)).isEqualTo(handlerFunction);
}
private MockHttpServletRequest createTestRequest(String path) {
MockHttpServletRequest request = new MockHttpServletRequest("GET", path);
- request.setAttribute(HttpRequestsObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE,
- new HttpRequestsObservationContext(request, new MockHttpServletResponse()));
+ request.setAttribute(ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE,
+ new ServerRequestObservationContext(request, new MockHttpServletResponse()));
ServletRequestPathUtils.parseAndCache(request);
return request;
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java
index a3cf9695ec9..5dcf68759d3 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java
@@ -33,6 +33,7 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
+import org.springframework.http.observation.ServerRequestObservationContext;
import org.springframework.http.server.RequestPath;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
@@ -46,11 +47,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.StaticWebApplicationContext;
+import org.springframework.web.filter.ServerHttpObservationFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
-import org.springframework.web.observation.HttpRequestsObservationContext;
-import org.springframework.web.observation.HttpRequestsObservationFilter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
@@ -295,8 +295,8 @@ class RequestMappingInfoHandlerMappingTests {
void handleMatchBestMatchingPatternAttributeInObservationContext(TestRequestMappingInfoHandlerMapping mapping) {
RequestMappingInfo key = RequestMappingInfo.paths("/{path1}/2", "/**").build();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/1/2");
- HttpRequestsObservationContext observationContext = new HttpRequestsObservationContext(request, new MockHttpServletResponse());
- request.setAttribute(HttpRequestsObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
+ ServerRequestObservationContext observationContext = new ServerRequestObservationContext(request, new MockHttpServletResponse());
+ request.setAttribute(ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
mapping.handleMatch(key, "/1/2", request);
assertThat(request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)).isEqualTo("/{path1}/2");