Reorganize server observability packages
Prior to this commit, the server observability support would create a cycle in Java packages. This commit refactors the current arrangement to solve this by: * "flattening" the reactive HTTP instrumentation; this removes the dependency to the `ServerWebExchange` and `PathPattern` types * moving the `observation` package under `org.springframework.http.server` and `org.springframework.http.server.reactive` See gh-29477
This commit is contained in:
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation;
|
||||
package org.springframework.http.server.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.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||
import org.springframework.http.observation.ServerHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||
import org.springframework.http.server.observation.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||
import org.springframework.http.server.observation.ServerHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation;
|
||||
package org.springframework.http.server.observation;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.common.docs.KeyName;
|
||||
@@ -33,9 +33,9 @@ import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
public enum ServerHttpObservationDocumentation implements ObservationDocumentation {
|
||||
|
||||
/**
|
||||
* HTTP exchanges observations for Servlet-based servers.
|
||||
* HTTP request observations for Servlet-based servers.
|
||||
*/
|
||||
HTTP_SERVLET_SERVER_EXCHANGES {
|
||||
HTTP_SERVLET_SERVER_REQUESTS {
|
||||
@Override
|
||||
public Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {
|
||||
return DefaultServerRequestObservationConvention.class;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation;
|
||||
package org.springframework.http.server.observation;
|
||||
|
||||
import io.micrometer.observation.transport.RequestReplyReceiverContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -23,10 +23,10 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Context that holds information for metadata collection during observations
|
||||
* for {@link ServerHttpObservationDocumentation#HTTP_SERVLET_SERVER_EXCHANGES Servlet HTTP exchanges}.
|
||||
* Context that holds information for metadata collection regarding
|
||||
* {@link ServerHttpObservationDocumentation#HTTP_SERVLET_SERVER_REQUESTS Servlet HTTP requests} observations.
|
||||
* <p>This context also extends {@link RequestReplyReceiverContext} for propagating
|
||||
* tracing information with the HTTP server exchange.
|
||||
* tracing information during HTTP request processing.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation;
|
||||
package org.springframework.http.server.observation;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
|
||||
/**
|
||||
* Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_SERVLET_SERVER_EXCHANGES Servlet HTTP exchanges}.
|
||||
* Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_SERVLET_SERVER_REQUESTS Servlet HTTP requests}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Instrumentation for {@link io.micrometer.observation.Observation observing} HTTP applications.
|
||||
* Instrumentation for {@link io.micrometer.observation.Observation observing} HTTP server applications.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.http.observation;
|
||||
package org.springframework.http.server.observation;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -14,17 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation.reactive;
|
||||
package org.springframework.http.server.reactive.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.reactive.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||
import org.springframework.http.observation.reactive.ServerHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
|
||||
/**
|
||||
* Default {@link ServerRequestObservationConvention}.
|
||||
@@ -117,12 +116,12 @@ public class DefaultServerRequestObservationConvention implements ServerRequestO
|
||||
|
||||
protected KeyValue uri(ServerRequestObservationContext context) {
|
||||
if (context.getCarrier() != null) {
|
||||
PathPattern pattern = context.getPathPattern();
|
||||
String pattern = context.getPathPattern();
|
||||
if (pattern != null) {
|
||||
if (pattern.toString().isEmpty()) {
|
||||
if (pattern.isEmpty()) {
|
||||
return URI_ROOT;
|
||||
}
|
||||
return KeyValue.of(LowCardinalityKeyNames.URI, pattern.toString());
|
||||
return KeyValue.of(LowCardinalityKeyNames.URI, pattern);
|
||||
}
|
||||
if (context.getResponse() != null && context.getResponse().getStatusCode() != null) {
|
||||
HttpStatus status = HttpStatus.resolve(context.getResponse().getStatusCode().value());
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation.reactive;
|
||||
package org.springframework.http.server.reactive.observation;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.common.docs.KeyName;
|
||||
@@ -33,9 +33,9 @@ import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
public enum ServerHttpObservationDocumentation implements ObservationDocumentation {
|
||||
|
||||
/**
|
||||
* HTTP exchanges observations for reactive servers.
|
||||
* HTTP request observations for reactive servers.
|
||||
*/
|
||||
HTTP_REACTIVE_SERVER_EXCHANGES {
|
||||
HTTP_REACTIVE_SERVER_REQUESTS {
|
||||
@Override
|
||||
public Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {
|
||||
return DefaultServerRequestObservationConvention.class;
|
||||
@@ -14,46 +14,47 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation.reactive;
|
||||
package org.springframework.http.server.reactive.observation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import io.micrometer.observation.transport.RequestReplyReceiverContext;
|
||||
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
|
||||
/**
|
||||
* Context that holds information for metadata collection during observations
|
||||
* for {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_EXCHANGES reactive HTTP exchanges}.
|
||||
* Context that holds information for metadata collection regarding
|
||||
* {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_REQUESTS reactive HTTP requests} observations.
|
||||
* <p>This context also extends {@link RequestReplyReceiverContext} for propagating
|
||||
* tracing information with the HTTP server exchange.
|
||||
* tracing information during HTTP request processing.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
*/
|
||||
public class ServerRequestObservationContext extends RequestReplyReceiverContext<ServerHttpRequest, ServerHttpResponse> {
|
||||
|
||||
private final ServerWebExchange serverWebExchange;
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
@Nullable
|
||||
private PathPattern pathPattern;
|
||||
private String pathPattern;
|
||||
|
||||
private boolean connectionAborted;
|
||||
|
||||
public ServerRequestObservationContext(ServerWebExchange exchange) {
|
||||
super((request, key) -> request.getHeaders().getFirst(key));
|
||||
this.serverWebExchange = exchange;
|
||||
setCarrier(exchange.getRequest());
|
||||
setResponse(exchange.getResponse());
|
||||
public ServerRequestObservationContext(ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> attributes) {
|
||||
super((req, key) -> req.getHeaders().getFirst(key));
|
||||
setCarrier(request);
|
||||
setResponse(response);
|
||||
this.attributes = Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current {@link ServerWebExchange HTTP exchange}.
|
||||
* Return an immutable map of the current request attributes.
|
||||
*/
|
||||
public ServerWebExchange getServerWebExchange() {
|
||||
return this.serverWebExchange;
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
|
||||
* @return the path pattern, or {@code null} if none found
|
||||
*/
|
||||
@Nullable
|
||||
public PathPattern getPathPattern() {
|
||||
public String getPathPattern() {
|
||||
return this.pathPattern;
|
||||
}
|
||||
|
||||
@@ -72,7 +73,7 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
|
||||
* <p>Path patterns must have a low cardinality for the entire application.
|
||||
* @param pathPattern the path pattern, for example {@code "/projects/{name}"}.
|
||||
*/
|
||||
public void setPathPattern(@Nullable PathPattern pathPattern) {
|
||||
public void setPathPattern(@Nullable String pathPattern) {
|
||||
this.pathPattern = pathPattern;
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.observation.reactive;
|
||||
package org.springframework.http.server.reactive.observation;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
|
||||
/**
|
||||
* Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_EXCHANGES reactive HTTP exchanges}.
|
||||
* Interface for an {@link ObservationConvention} for {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_REQUESTS reactive HTTP requests}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Instrumentation for {@link io.micrometer.observation.Observation observing} reactive HTTP applications.
|
||||
* Instrumentation for {@link io.micrometer.observation.Observation observing} reactive HTTP server applications.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.http.observation.reactive;
|
||||
package org.springframework.http.server.reactive.observation;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -27,10 +27,10 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
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.http.server.observation.DefaultServerRequestObservationConvention;
|
||||
import org.springframework.http.server.observation.ServerHttpObservationDocumentation;
|
||||
import org.springframework.http.server.observation.ServerRequestObservationContext;
|
||||
import org.springframework.http.server.observation.ServerRequestObservationConvention;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ public class ServerHttpObservationFilter extends OncePerRequestFilter {
|
||||
Observation observation = (Observation) request.getAttribute(CURRENT_OBSERVATION_ATTRIBUTE);
|
||||
if (observation == null) {
|
||||
ServerRequestObservationContext context = new ServerRequestObservationContext(request, response);
|
||||
observation = ServerHttpObservationDocumentation.HTTP_SERVLET_SERVER_EXCHANGES.observation(this.observationConvention,
|
||||
observation = ServerHttpObservationDocumentation.HTTP_SERVLET_SERVER_REQUESTS.observation(this.observationConvention,
|
||||
DEFAULT_OBSERVATION_CONVENTION, () -> context, this.observationRegistry).start();
|
||||
request.setAttribute(CURRENT_OBSERVATION_ATTRIBUTE, observation);
|
||||
if (!observation.isNoop()) {
|
||||
|
||||
@@ -25,11 +25,11 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccess
|
||||
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.http.server.reactive.observation.DefaultServerRequestObservationConvention;
|
||||
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation;
|
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
|
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
@@ -96,13 +96,14 @@ public class ServerHttpObservationFilter implements WebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange);
|
||||
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange.getRequest(),
|
||||
exchange.getResponse(), exchange.getAttributes());
|
||||
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
|
||||
return chain.filter(exchange).transformDeferred(call -> filter(exchange, observationContext, call));
|
||||
}
|
||||
|
||||
private Publisher<Void> filter(ServerWebExchange exchange, ServerRequestObservationContext observationContext, Mono<Void> call) {
|
||||
Observation observation = ServerHttpObservationDocumentation.HTTP_REACTIVE_SERVER_EXCHANGES.observation(this.observationConvention,
|
||||
Observation observation = ServerHttpObservationDocumentation.HTTP_REACTIVE_SERVER_REQUESTS.observation(this.observationConvention,
|
||||
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry);
|
||||
observation.start();
|
||||
return call.doOnEach(signal -> {
|
||||
|
||||
Reference in New Issue
Block a user