Monthly Archives: May 2023

surefire, failsafe

surefire, failsafe are maven plugin tools.

surefire focus on unit test: mvn surefire:test

failsafe focus on integration-test: mvn failsafe:integration-test

Also need build-helper-maven-plugin to specify the integration test folder

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>${mojo.build-helper-maven-plugin.version}</version>
    <executions>
        <execution>
            <id>add-test-source</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/it/java</source>
                </sources>
            </configuration>
        </execution>
        <execution>
            <id>add-test-resource</id>
            <phase>generate-test-resources</phase>
            <goals>
                <goal>add-test-resource</goal>
            </goals>
            <configuration>
                <resources>
                    <resource>
                        <directory>src/it/resources</directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven-surefire-plugin.version}</version>
    <configuration>
        <reuseForks>true</reuseForks>
        <excludes>
            <exclude>**/*IT.java</exclude>
        </excludes>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>${maven-failsafe-plugin.version}</version>
    <executions>
        <execution>
            <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

 

Add log4j MDC log tags in webflux

Webflux is async. So log4j with MDC tags may not work correctly natively. So adding below to copy MDC context in each operator changes. Hooks is some advanced usage for customizing action in operators.

1. MdcContextLifterConfiguration

@Configuration
public class MdcContextLifterConfiguration {

    private static final String MDC_CONTEXT_REACTOR_KEY =
        MdcContextLifterConfiguration.class.getName();

    @PostConstruct
    private void contextOperatorHook() {
        Hooks.onEachOperator(
            MDC_CONTEXT_REACTOR_KEY,
            Operators.lift((scannable, coreSubscriber) -> new MdcContextLifter<>(coreSubscriber)));
    }

    @PreDestroy
    private void cleanupHook() {
        Hooks.resetOnEachOperator(MDC_CONTEXT_REACTOR_KEY);
    }
}

2. MdcContextLifter

public class MdcContextLifter<T> implements CoreSubscriber<T> {

    CoreSubscriber<T> coreSubscriber;

    public MdcContextLifter(CoreSubscriber<T> coreSubscriber) {
        this.coreSubscriber = coreSubscriber;
    }

    @Override
    public void onSubscribe(Subscription sub) {
        coreSubscriber.onSubscribe(sub);
    }

    @Override
    public void onNext(T item) {
        copyToMdc(coreSubscriber.currentContext());
        coreSubscriber.onNext(item);
    }

    @Override
    public void onError(Throwable err) {
        coreSubscriber.onError(err);
    }

    @Override
    public void onComplete() {
        coreSubscriber.onComplete();
    }

    @Override
    public Context currentContext() {
        return coreSubscriber.currentContext();
    }

    private void copyToMdc(Context context) {
        if (!context.isEmpty()) {
            // TODO filter MDC context to ignore unused context
            Map<String, String> map =
                context.stream()
                    .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString()));
            MDC.setContextMap(map);
        } else {
            MDC.clear();
        }
    }
}

 

Adding tags for micrometer in WebFlux

Try WebFluxTagsProvider, DefaultWebFluxTagsProvider.

@Component
@Primary
public class ObserveWebFilter extends DefaultWebClientExchangeTagsProvider implements WebFluxTagsProvider {

    private static final WebFluxTagsProvider WEB_FLUX_TAGS_PROVIDER = new DefaultWebFluxTagsProvider();


    @Override
    public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
        HttpHeaders headers = exchange.getRequest().getHeaders();
        return Tags.concat(WEB_FLUX_TAGS_PROVIDER.httpRequestTags(exchange, ex), ObserveUtils.tags(headers));
    }

    public Iterable<Tag> tags(ClientRequest request, ClientResponse response, Throwable throwable) {
        HttpHeaders headers = request.headers();
        return Tags.concat(super.tags(request, response, throwable), ObserveUtils.tags(headers));
    }
}