Skip to content

Commit c187846

Browse files
committed
Reduce allocations in server conventions
This commit optimizes the default observation conventions to reduce `KeyValues` allocations.
1 parent 51cdff5 commit c187846

File tree

5 files changed

+58
-11
lines changed

5 files changed

+58
-11
lines changed

framework-docs/modules/ROOT/pages/integration/observability.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ By default, the following `KeyValues` are created:
108108
|===
109109
|Name | Description
110110
|`exception` _(required)_|Name of the exception thrown during the exchange, or `KeyValue#NONE_VALUE`} if no exception happened.
111-
|`method` _(required)_|Name of HTTP request method or `"none"` if the request was not received properly.
111+
|`method` _(required)_|Name of HTTP request method or `"none"` if not a well-known method.
112112
|`outcome` _(required)_|Outcome of the HTTP server exchange.
113113
|`status` _(required)_|HTTP response raw status code, or `"UNKNOWN"` if no response was created.
114114
|`uri` _(required)_|URI pattern for the matching handler if available, falling back to `REDIRECTION` for 3xx responses, `NOT_FOUND` for 404 responses, `root` for requests with no path info, and `UNKNOWN` for all other requests.
@@ -141,7 +141,7 @@ By default, the following `KeyValues` are created:
141141
|===
142142
|Name | Description
143143
|`exception` _(required)_|Name of the exception thrown during the exchange, or `"none"` if no exception happened.
144-
|`method` _(required)_|Name of HTTP request method or `"none"` if the request was not received properly.
144+
|`method` _(required)_|Name of HTTP request method or `"none"` if not a well-known method.
145145
|`outcome` _(required)_|Outcome of the HTTP server exchange.
146146
|`status` _(required)_|HTTP response raw status code, or `"UNKNOWN"` if no response was created.
147147
|`uri` _(required)_|URI pattern for the matching handler if available, falling back to `REDIRECTION` for 3xx responses, `NOT_FOUND` for 404 responses, `root` for requests with no path info, and `UNKNOWN` for all other requests.
@@ -174,7 +174,7 @@ Instrumentation uses the `org.springframework.http.client.observation.ClientRequ
174174
[cols="a,a"]
175175
|===
176176
|Name | Description
177-
|`method` _(required)_|Name of HTTP request method or `"none"` if the request could not be created.
177+
|`method` _(required)_|Name of HTTP request method or `"none"` if not a well-known method.
178178
|`uri` _(required)_|URI template used for HTTP request, or `"none"` if none was provided. Only the path part of the URI is considered.
179179
|`client.name` _(required)_|Client name derived from the request URI host.
180180
|`status` _(required)_|HTTP response raw status code, or `"IO_ERROR"` in case of `IOException`, or `"CLIENT_ERROR"` if no response was received.
@@ -203,7 +203,7 @@ Instrumentation uses the `org.springframework.web.reactive.function.client.Clien
203203
[cols="a,a"]
204204
|===
205205
|Name | Description
206-
|`method` _(required)_|Name of HTTP request method or `"none"` if the request could not be created.
206+
|`method` _(required)_|Name of HTTP request method or `"none"` if not a well-known method.
207207
|`uri` _(required)_|URI template used for HTTP request, or `"none"` if none was provided. Only the path part of the URI is considered.
208208
|`client.name` _(required)_|Client name derived from the request URI host.
209209
|`status` _(required)_|HTTP response raw status code, or `"IO_ERROR"` in case of `IOException`, or `"CLIENT_ERROR"` if no response was received.

spring-web/src/main/java/org/springframework/http/server/observation/DefaultServerRequestObservationConvention.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616

1717
package org.springframework.http.server.observation;
1818

19+
import java.util.Set;
20+
import java.util.stream.Collectors;
21+
import java.util.stream.Stream;
22+
1923
import io.micrometer.common.KeyValue;
2024
import io.micrometer.common.KeyValues;
2125

26+
import org.springframework.http.HttpMethod;
2227
import org.springframework.http.HttpStatus;
2328
import org.springframework.http.HttpStatusCode;
2429
import org.springframework.http.server.observation.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
@@ -55,6 +60,8 @@ public class DefaultServerRequestObservationConvention implements ServerRequestO
5560

5661
private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
5762

63+
private static final Set<String> HTTP_METHODS = Stream.of(HttpMethod.values()).map(HttpMethod::name).collect(Collectors.toUnmodifiableSet());
64+
5865

5966
private final String name;
6067

@@ -102,9 +109,13 @@ public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext con
102109
}
103110

104111
protected KeyValue method(ServerRequestObservationContext context) {
105-
return (context.getCarrier() != null) ?
106-
KeyValue.of(LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod()) :
107-
METHOD_UNKNOWN;
112+
if (context.getCarrier() != null) {
113+
String httpMethod = context.getCarrier().getMethod();
114+
if (HTTP_METHODS.contains(httpMethod)) {
115+
return KeyValue.of(LowCardinalityKeyNames.METHOD, httpMethod);
116+
}
117+
}
118+
return METHOD_UNKNOWN;
108119
}
109120

110121
protected KeyValue status(ServerRequestObservationContext context) {

spring-web/src/main/java/org/springframework/http/server/reactive/observation/DefaultServerRequestObservationConvention.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package org.springframework.http.server.reactive.observation;
1818

19+
import java.util.Set;
20+
1921
import io.micrometer.common.KeyValue;
2022
import io.micrometer.common.KeyValues;
2123

24+
import org.springframework.http.HttpMethod;
2225
import org.springframework.http.HttpStatus;
2326
import org.springframework.http.HttpStatusCode;
2427
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation.HighCardinalityKeyNames;
@@ -55,6 +58,8 @@ public class DefaultServerRequestObservationConvention implements ServerRequestO
5558

5659
private static final KeyValue HTTP_URL_UNKNOWN = KeyValue.of(HighCardinalityKeyNames.HTTP_URL, "UNKNOWN");
5760

61+
private static final Set<HttpMethod> HTTP_METHODS = Set.of(HttpMethod.values());
62+
5863

5964
private final String name;
6065

@@ -102,9 +107,13 @@ public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext con
102107
}
103108

104109
protected KeyValue method(ServerRequestObservationContext context) {
105-
return (context.getCarrier() != null) ?
106-
KeyValue.of(LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod().name()) :
107-
METHOD_UNKNOWN;
110+
if (context.getCarrier() != null) {
111+
HttpMethod method = context.getCarrier().getMethod();
112+
if (HTTP_METHODS.contains(method)) {
113+
return KeyValue.of(LowCardinalityKeyNames.METHOD, method.name());
114+
}
115+
}
116+
return METHOD_UNKNOWN;
108117
}
109118

110119
protected KeyValue status(ServerRequestObservationContext context) {

spring-web/src/test/java/org/springframework/http/server/observation/DefaultServerRequestObservationConventionTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -124,4 +124,17 @@ void addsKeyValuesForNotFoundExchange() {
124124
.contains(KeyValue.of("http.url", "/test/notFound"));
125125
}
126126

127+
@Test
128+
void addsKeyValuesForUnknownHttpMethodExchange() {
129+
this.request.setMethod("SPRING");
130+
this.request.setRequestURI("/test");
131+
this.response.setStatus(404);
132+
133+
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).hasSize(5)
134+
.contains(KeyValue.of("method", "UNKNOWN"), KeyValue.of("uri", "NOT_FOUND"), KeyValue.of("status", "404"),
135+
KeyValue.of("exception", "none"), KeyValue.of("outcome", "CLIENT_ERROR"));
136+
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).hasSize(1)
137+
.contains(KeyValue.of("http.url", "/test"));
138+
}
139+
127140
}

spring-web/src/test/java/org/springframework/http/server/reactive/observation/DefaultServerRequestObservationConventionTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.micrometer.observation.Observation;
2121
import org.junit.jupiter.api.Test;
2222

23+
import org.springframework.http.HttpMethod;
2324
import org.springframework.web.server.ServerWebExchange;
2425
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
2526
import org.springframework.web.testfixture.server.MockServerWebExchange;
@@ -172,4 +173,17 @@ void supportsNullStatusCode() {
172173
KeyValue.of("exception", "none"), KeyValue.of("outcome", "UNKNOWN"));
173174
}
174175

176+
@Test
177+
void addsKeyValuesForUnknownHttpMethodExchange() {
178+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.method(HttpMethod.valueOf("SPRING"), "/test"));
179+
ServerRequestObservationContext context = new ServerRequestObservationContext(exchange.getRequest(), exchange.getResponse(), exchange.getAttributes());
180+
exchange.getResponse().setRawStatusCode(404);
181+
182+
assertThat(this.convention.getLowCardinalityKeyValues(context)).hasSize(5)
183+
.contains(KeyValue.of("method", "UNKNOWN"), KeyValue.of("uri", "NOT_FOUND"), KeyValue.of("status", "404"),
184+
KeyValue.of("exception", "none"), KeyValue.of("outcome", "CLIENT_ERROR"));
185+
assertThat(this.convention.getHighCardinalityKeyValues(context)).hasSize(1)
186+
.contains(KeyValue.of("http.url", "/test"));
187+
}
188+
175189
}

0 commit comments

Comments
 (0)