Skip to content

Commit

Permalink
Introduce HttpJakartaServletRequestTags
Browse files Browse the repository at this point in the history
Prior to this commit, `HttpRequestTags` would provide Tags for both
"javax.*" and "jakarta.*" variants of `HttpServletRequest`. While the
`HttpServletRequestTagsProvider` and
`HttpJakartaServletRequestTagsProvider` are separate interfaces, they
both use `HttpRequestTags` and import all types exposed on its methods.

It is strongly advised not to import both "javax.*" and "jakarta.*"
variants in a typical application and the current arrangement prevents
this best practice.

This commit deprecates Jakarta methods variants in `HttpRequestTags` and
moves them to `HttpJakartaServletRequestTags`. This allows a clean
dependency setup for Jakarta apps and a migration path for all in the
meantime.

Closes gh-3804
  • Loading branch information
bclozel committed Jun 26, 2023
1 parent 0ae8d45 commit 131d50d
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public class DefaultHttpJakartaServletRequestTagsProvider implements HttpJakarta

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response) {
return Tags.of(HttpRequestTags.method(request), HttpRequestTags.status(response),
HttpRequestTags.outcome(response));
return Tags.of(HttpJakartaServletRequestTags.method(request), HttpJakartaServletRequestTags.status(response),
HttpJakartaServletRequestTags.outcome(response));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2023 VMware, Inc.
*
* 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 io.micrometer.core.instrument.binder.http;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import io.micrometer.common.lang.Nullable;
import io.micrometer.common.util.StringUtils;
import io.micrometer.core.annotation.Incubating;
import io.micrometer.core.instrument.Tag;

/**
* Tags for {@link jakarta.servlet.http.HttpServletRequest HTTP Jakarta requests}.
*
* @author Jon Schneider
* @author Brian Clozel
* @since 1.12.0
*/
@Incubating(since = "1.12.0")
public class HttpJakartaServletRequestTags {

private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");

private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN");

private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN");

private HttpJakartaServletRequestTags() {
}

/**
* Creates a {@code method} tag based on the {@link HttpServletRequest#getMethod()
* method} of the given {@code request}.
* @param request the request
* @return the method tag whose value is a capitalized method (e.g. GET).
*/
public static Tag method(@Nullable HttpServletRequest request) {
return (request != null) ? Tag.of("method", request.getMethod()) : METHOD_UNKNOWN;
}

/**
* Creates a {@code status} tag based on the status of the given {@code response}.
* @param response the HTTP response
* @return the status tag derived from the status of the response
*/
public static Tag status(@Nullable HttpServletResponse response) {
return (response != null) ? Tag.of("status", Integer.toString(response.getStatus())) : STATUS_UNKNOWN;
}

/**
* Creates an {@code exception} tag based on the {@link Class#getSimpleName() simple
* name} of the class of the given {@code exception}.
* @param exception the exception, may be {@code null}
* @return the exception tag derived from the exception
*/
public static Tag exception(@Nullable Throwable exception) {
if (exception != null) {
String simpleName = exception.getClass().getSimpleName();
return Tag.of("exception",
StringUtils.isNotBlank(simpleName) ? simpleName : exception.getClass().getName());
}
return EXCEPTION_NONE;
}

/**
* Creates an {@code outcome} tag based on the status of the given {@code response}.
* @param response the HTTP response
* @return the outcome tag derived from the status of the response
*/
public static Tag outcome(@Nullable HttpServletResponse response) {
Outcome outcome = (response != null) ? Outcome.forStatus(response.getStatus()) : Outcome.UNKNOWN;
return outcome.asTag();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ public static Tag method(HttpServletRequest request) {
* @param request the request
* @return the method tag whose value is a capitalized method (e.g. GET).
* @since 1.10.0
* @deprecated since 1.12.0 in favor of
* {@link HttpJakartaServletRequestTags#method(jakarta.servlet.http.HttpServletRequest)}
*/
@Deprecated
public static Tag method(jakarta.servlet.http.HttpServletRequest request) {
return (request != null) ? Tag.of("method", request.getMethod()) : METHOD_UNKNOWN;
return HttpJakartaServletRequestTags.method(request);
}

/**
Expand All @@ -76,9 +79,12 @@ public static Tag status(HttpServletResponse response) {
* @param response the HTTP response
* @return the status tag derived from the status of the response
* @since 1.10.0
* @deprecated since 1.12.0 in favor of
* {@link HttpJakartaServletRequestTags#status(jakarta.servlet.http.HttpServletResponse)}
*/
@Deprecated
public static Tag status(jakarta.servlet.http.HttpServletResponse response) {
return (response != null) ? Tag.of("status", Integer.toString(response.getStatus())) : STATUS_UNKNOWN;
return HttpJakartaServletRequestTags.status(response);
}

/**
Expand Down Expand Up @@ -111,10 +117,12 @@ public static Tag outcome(HttpServletResponse response) {
* @param response the HTTP response
* @return the outcome tag derived from the status of the response
* @since 1.10.0
* @deprecated since 1.12.0 in favor of
* {@link HttpJakartaServletRequestTags#outcome(jakarta.servlet.http.HttpServletResponse)}
*/
@Deprecated
public static Tag outcome(jakarta.servlet.http.HttpServletResponse response) {
Outcome outcome = (response != null) ? Outcome.forStatus(response.getStatus()) : Outcome.UNKNOWN;
return outcome.asTag();
return HttpJakartaServletRequestTags.outcome(response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright 2023 VMware, Inc.
*
* 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 io.micrometer.core.instrument.binder.http;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* Tests for {@link HttpJakartaServletRequestTags} and {@link HttpRequestTags}.
*
* @author Brian Clozel
*/
class HttpJakartaServletRequestTagsTest {

@Test
void nullRequestShouldContributeUnknownMethodTag() {
Tag unknownMethod = Tag.of("method", "UNKNOWN");
HttpServletRequest jakartaRequest = null;
Tag result = HttpJakartaServletRequestTags.method(jakartaRequest);
assertThat(result).isEqualTo(unknownMethod);

javax.servlet.http.HttpServletRequest javaxRequest = null;
result = HttpRequestTags.method(javaxRequest);
assertThat(result).isEqualTo(unknownMethod);
}

@Test
void requestShouldContributeMethodTag() {
Tag httpGet = Tag.of("method", "GET");
HttpServletRequest jakartaRequest = mockJakartaRequest("GET");
Tag result = HttpJakartaServletRequestTags.method(jakartaRequest);
assertThat(result).isEqualTo(httpGet);

javax.servlet.http.HttpServletRequest javaxRequest = mockJavaxRequest("GET");
result = HttpRequestTags.method(javaxRequest);
assertThat(result).isEqualTo(httpGet);
}

@Test
void nullResponseShouldContributeUnknownStatusTag() {
Tag unknownStatus = Tag.of("status", "UNKNOWN");
HttpServletResponse jakartaResponse = null;
Tag result = HttpJakartaServletRequestTags.status(jakartaResponse);
assertThat(result).isEqualTo(unknownStatus);

javax.servlet.http.HttpServletResponse javaxResponse = null;
result = HttpRequestTags.status(javaxResponse);
assertThat(result).isEqualTo(unknownStatus);
}

@Test
void responseShouldContributeStatusTag() {
Tag httpOk = Tag.of("status", "200");
HttpServletResponse jakartaResponse = mockJakartaResponse(200);
Tag result = HttpJakartaServletRequestTags.status(jakartaResponse);
assertThat(result).isEqualTo(httpOk);

javax.servlet.http.HttpServletResponse javaxResponse = mockJavaxResponse(200);
result = HttpRequestTags.status(javaxResponse);
assertThat(result).isEqualTo(httpOk);
}

@Test
void nullExceptionShouldContributeNoneExceptionTag() {
Tag exceptionNone = Tag.of("exception", "None");
Tag result = HttpJakartaServletRequestTags.exception(null);
assertThat(result).isEqualTo(exceptionNone);
}

@Test
void exceptionShouldContributeExceptionTag() {
Tag illegalStateTag = Tag.of("exception", "IllegalStateException");
Tag result = HttpJakartaServletRequestTags.exception(new IllegalStateException());
assertThat(result).isEqualTo(illegalStateTag);
}

@Test
void nullResponseShouldContributeUnknownOutcomeTag() {
Tag unknownOutcome = Tag.of("outcome", "UNKNOWN");
HttpServletResponse jakartaResponse = null;
Tag result = HttpJakartaServletRequestTags.outcome(jakartaResponse);
assertThat(result).isEqualTo(unknownOutcome);

javax.servlet.http.HttpServletResponse javaxResponse = null;
result = HttpRequestTags.outcome(javaxResponse);
assertThat(result).isEqualTo(unknownOutcome);
}

@Test
void responseShouldContributeOutcomeTag() {
Tag unknownOutcome = Tag.of("outcome", "SUCCESS");
HttpServletResponse jakartaResponse = mockJakartaResponse(200);
Tag result = HttpJakartaServletRequestTags.outcome(jakartaResponse);
assertThat(result).isEqualTo(unknownOutcome);

javax.servlet.http.HttpServletResponse javaxResponse = mockJavaxResponse(200);
result = HttpRequestTags.outcome(javaxResponse);
assertThat(result).isEqualTo(unknownOutcome);
}

private HttpServletRequest mockJakartaRequest(String method) {
HttpServletRequest jakartaRequest = mock(HttpServletRequest.class);
when(jakartaRequest.getMethod()).thenReturn(method);
return jakartaRequest;
}

private javax.servlet.http.HttpServletRequest mockJavaxRequest(String method) {
javax.servlet.http.HttpServletRequest javaxRequest = mock(javax.servlet.http.HttpServletRequest.class);
when(javaxRequest.getMethod()).thenReturn(method);
return javaxRequest;
}

private HttpServletResponse mockJakartaResponse(int status) {
HttpServletResponse jakartaResponse = mock(HttpServletResponse.class);
when(jakartaResponse.getStatus()).thenReturn(status);
return jakartaResponse;
}

private javax.servlet.http.HttpServletResponse mockJavaxResponse(int status) {
javax.servlet.http.HttpServletResponse javaxResponse = mock(javax.servlet.http.HttpServletResponse.class);
when(javaxResponse.getStatus()).thenReturn(status);
return javaxResponse;
}

}

0 comments on commit 131d50d

Please sign in to comment.