Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate WebMvcTags to ServerRequestObservationConvention #586

Merged
merged 37 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1270277
Initial test case
Laurens-W Sep 4, 2024
6f27d4e
WIP
Laurens-W Sep 5, 2024
1dbb42e
Merge branch 'main' into spring-webmvctags-to-observations
timtebeek Sep 6, 2024
9320b73
Apply suggestions from code review
Laurens-W Sep 9, 2024
5261925
WIP
Laurens-W Sep 9, 2024
b2a9ef5
Apply suggestions from code review
Laurens-W Sep 9, 2024
9cf1904
WIP
Laurens-W Sep 9, 2024
723355c
WIP
Laurens-W Sep 10, 2024
458653f
WIP
Laurens-W Sep 10, 2024
8c96e1e
WIP
Laurens-W Sep 11, 2024
124c91c
WIP
Laurens-W Sep 11, 2024
84fe00d
Suggestions
Laurens-W Sep 11, 2024
ef0f44c
WIP
Laurens-W Sep 19, 2024
64860a1
Working setup
Laurens-W Sep 19, 2024
957d8ea
Merge branch 'main' into spring-webmvctags-to-observations
Laurens-W Sep 19, 2024
ad130cf
Apply suggestions from code review
Laurens-W Sep 19, 2024
c8dfc23
Format and apply suggestion
Laurens-W Sep 19, 2024
f54c69e
More progress
Laurens-W Sep 24, 2024
534b043
Naming and imports
Laurens-W Sep 24, 2024
2c06389
Adopt classpathFromResources & add tomcat-embedded-core
timtebeek Sep 24, 2024
2391101
Fix most warnings and issues
Laurens-W Sep 24, 2024
7f8985d
Fix type issues and warnings
Laurens-W Sep 25, 2024
0375470
More edge cases
Laurens-W Sep 25, 2024
3c39aa3
More edge cases, extra test coverage
Laurens-W Sep 25, 2024
d93762b
Merge branch 'main' into spring-webmvctags-to-observations
Laurens-W Sep 25, 2024
1aa0d1a
Remove jetbrains notnull
Laurens-W Sep 25, 2024
2198911
Reduce document example test case and add additional test cases for e…
Laurens-W Sep 26, 2024
8338048
Apply review feedback
Laurens-W Sep 27, 2024
ac6e98b
Merge branch 'main' into spring-webmvctags-to-observations
timtebeek Sep 30, 2024
bb2c9f6
Apply formatter to tests
timtebeek Sep 30, 2024
daf9e1e
Merge branch 'main' into spring-webmvctags-to-observations
timtebeek Sep 30, 2024
2e55442
Reduce imports and classpath
Laurens-W Sep 30, 2024
34553b4
Use method matcher
Laurens-W Oct 4, 2024
e4632a5
By default use high cardinality keys as low might cause issues with i…
Laurens-W Oct 7, 2024
c46349d
Consistently use the same version suffix for classpath resources
timtebeek Oct 8, 2024
8031c75
Demonstrate failure on any empty method
timtebeek Oct 8, 2024
e246ced
Fix class cast issue
Laurens-W Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ recipeDependencies {

parserClasspath("org.apache.httpcomponents.core5:httpcore5:5.1.+")
parserClasspath("org.apache.httpcomponents.client5:httpclient5:5.1.+")

parserClasspath("jakarta.servlet:jakarta.servlet-api:6.1.+")
parserClasspath("io.micrometer:micrometer-commons:1.11.+")
parserClasspath("io.micrometer:micrometer-core:1.11.12")
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
}

val rewriteVersion = rewriteRecipe.rewriteVersion.get()
Expand Down Expand Up @@ -237,6 +241,7 @@ dependencies {
"testWithSpringBoot_2_7RuntimeOnly"("jakarta.xml.bind:jakarta.xml.bind-api:2.3.3")

"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.boot:spring-boot-starter:3.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.boot:spring-boot-starter-actuator:3.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.boot:spring-boot-starter-test:3.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework:spring-context:6.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework:spring-web:6.0.+")
Expand All @@ -249,6 +254,7 @@ dependencies {
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.security:spring-security-config:6.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.security:spring-security-web:6.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("org.springframework.security:spring-security-ldap:6.0.+")
"testWithSpringBoot_3_0RuntimeOnly"("jakarta.servlet:jakarta.servlet-api:6.1.+")

"testWithSpringBoot_3_2RuntimeOnly"("org.springframework.boot:spring-boot-starter:3.2.+")
"testWithSpringBoot_3_2RuntimeOnly"("org.springframework.boot:spring-boot-starter-test:3.2.+")
Expand Down

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions src/main/resources/META-INF/rewrite/spring-boot-30.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ recipeList:
- org.openrewrite.java.spring.boot3.UpgradeSpringDoc_2
- org.openrewrite.java.spring.boot3.MigrateDropWizardDependencies
- org.openrewrite.java.spring.boot3.RemoveSolrAutoConfigurationExclude
- org.openrewrite.java.spring.boot3.MigrateWebMvcTagsToObservationConvention
- org.openrewrite.java.spring.batch.SpringBatch4To5Migration
- org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_0
- org.openrewrite.java.spring.kafka.UpgradeSpringKafka_3_0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.openrewrite.java.spring.boot3;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.java;

class MigrateWebMvcTagsToObservationConventionTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new MigrateWebMvcTagsToObservationConvention()).parser(JavaParser.fromJavaVersion().classpath(
"micrometer-core",
"spring-boot",
"spring-context",
"spring-beans",
"spring-web",
"jakarta.servlet-api"));
}

@DocumentExample
@Test
void shouldMigrateWebMvcTagsProviderToDefaultServerRequestObservationConvention() {
//language=java
rewriteRun(
java(
"""
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTags;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;

class CustomWebMvcTagsProvider implements WebMvcTagsProvider {

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.status(response), WebMvcTags.outcome(response));

String customHeader = request.getHeader("X-Custom-Header");
if (customHeader != null) {
tags = tags.and("custom.header", customHeader);
}
return tags;
}
}
""",
"""
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.observation.ServerRequestObservationContext;

class CustomWebMvcTagsProvider extends DefaultServerRequestObservationConvention {

@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
HttpServletRequest request = context.getCarrier();
KeyValues values = super.getLowCardinalityKeyValues(context);

String customHeader = request.getHeader("X-Custom-Header");
if (customHeader != null) {
values.and(KeyValue.of("custom.header", customHeader));
}
return values;
}
}
"""
)
);
}

@Test
void shouldMigrateTags_Of() {
//language=java
rewriteRun(
java(
"""
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTags;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;

class CustomWebMvcTagsProvider implements WebMvcTagsProvider {

Tags staticTags = Tags.of("a", "b", "c", "d");
Tag staticTag = Tag.of("a", "b");

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.status(response), WebMvcTags.outcome(response));
tags = Tags.of("a", "b");
tags = Tags.of("a", "b", "c", "d");
tags = Tags.of(Tag.of("a", "b"), staticTag);
tags = Tags.of(staticTags);
return tags;
}
}
""",
"""
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.observation.ServerRequestObservationContext;

class CustomWebMvcTagsProvider extends DefaultServerRequestObservationConvention {

Tags staticTags = Tags.of("a", "b", "c", "d");
Tag staticTag = Tag.of("a", "b");

@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
KeyValues values = super.getLowCardinalityKeyValues(context);
values.and(KeyValue.of("a", "b"));
values.and(KeyValue.of("a", "b"), KeyValue.of("c", "d"));
values.and(KeyValue.of("a", "b"), KeyValue.of(staticTag.getKey(), staticTag.getValue()));
for (Tag tag : staticTags) {
values.and(KeyValue.of(tag.getKey(), tag.getValue()));
}
return values;
}
}
"""
)
);
}

@Test
void shouldMigrateTags_And() {
//language=java
rewriteRun(
java(
"""
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTags;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;

class CustomWebMvcTagsProvider implements WebMvcTagsProvider {

Tags staticTags = Tags.of("a", "b", "c", "d");
Tag staticTag = Tag.of("a", "b");

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.status(response), WebMvcTags.outcome(response));

String customHeader = request.getHeader("X-Custom-Header");
if (customHeader != null) {
tags = tags.and("custom.header", customHeader);
}
if (response.getStatus() >= 400) {
tags = tags.and("error", "true");
}
tags = tags.and("a", "b", "c", "d");
tags = Tags.and(Tag.of("a", "b"), staticTag);
tags = tags.and(staticTags);
return tags;
}
}
""",
"""
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.observation.ServerRequestObservationContext;

class CustomWebMvcTagsProvider extends DefaultServerRequestObservationConvention {

Tags staticTags = Tags.of("a", "b", "c", "d");
Tag staticTag = Tag.of("a", "b");

@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
HttpServletRequest request = context.getCarrier();
HttpServletResponse response = context.getResponse();
KeyValues values = super.getLowCardinalityKeyValues(context);

String customHeader = request.getHeader("X-Custom-Header");
if (customHeader != null) {
values.and(KeyValue.of("custom.header", customHeader));
}
if (response.getStatus() >= 400) {
values.and(KeyValue.of("error", "true"));
}
values.and(KeyValue.of("a", "b"), KeyValue.of("c", "d"));
values.and(KeyValue.of("a", "b"), KeyValue.of(staticTag.getKey(), staticTag.getValue()));
for (Tag tag : staticTags) {
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
values.and(KeyValue.of(tag.getKey(), tag.getValue()));
}
return values;
}
}
"""
)
);
}

@Test
void shouldMigrateReturnTags_Of() {
//language=java
rewriteRun(
java(
"""
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;

class CustomWebMvcTagsProvider implements WebMvcTagsProvider {

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
return Tags.of(Tag.of("a", "b"));
}
}
""",
"""
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.observation.ServerRequestObservationContext;

class CustomWebMvcTagsProvider extends DefaultServerRequestObservationConvention {

@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
KeyValues values = super.getLowCardinalityKeyValues(context);
values.and(KeyValue.of("a", "b"));
return values;
}
}
"""
)
);
}


}
Loading