From 30d02abff0673722e51001a04de9da6419857d0a Mon Sep 17 00:00:00 2001 From: Ties de Kock Date: Mon, 26 Jun 2023 09:27:30 +0200 Subject: [PATCH 1/3] remove URI from low cardinality/prometheus tags --- .../ripe/rpki/rsyncit/RsyncitApplication.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java index 0813d32..6852af8 100644 --- a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java +++ b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java @@ -1,9 +1,13 @@ package net.ripe.rpki.rsyncit; +import io.micrometer.common.KeyValues; import io.netty.channel.nio.NioEventLoopGroup; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.web.reactive.function.client.ClientRequestObservationContext; +import org.springframework.web.reactive.function.client.ClientRequestObservationConvention; +import org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention; import org.springframework.web.reactive.function.client.WebClient; import net.ripe.rpki.rsyncit.util.http.WebClientBuilderFactory; import net.ripe.rpki.rsyncit.config.AppConfig; @@ -30,4 +34,19 @@ public WebClientBuilderFactory webclientConfigurer(WebClient.Builder baseBuilder return new WebClientBuilderFactory(group, baseBuilder, "rsyncit %s".formatted(appConfig.getInfo().gitCommitId())); } + /** + * Return an observation customiser that only differs in that it omits the URL. + * The hostname for the request is the clientName. + * + * The full URL is in a high cardinality value (which would be used by observability tools) + */ + @Bean + public ClientRequestObservationConvention nonUriClientRequestObservationConvention() { + return new DefaultClientRequestObservationConvention() { + @Override + public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) { + return KeyValues.of(method(context), status(context), clientName(context), exception(context), outcome(context)); + } + }; + } } From 0f27057629cd730fe30899334f1adcdc6cead9f7 Mon Sep 17 00:00:00 2001 From: Ties de Kock Date: Mon, 26 Jun 2023 09:32:33 +0200 Subject: [PATCH 2/3] No need for webclient builder because all use the same config --- .../ripe/rpki/rsyncit/RsyncitApplication.java | 31 +++++++++-- .../rpki/rsyncit/service/SyncService.java | 10 ++-- .../util/http/WebClientBuilderFactory.java | 55 ------------------- 3 files changed, 31 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/net/ripe/rpki/rsyncit/util/http/WebClientBuilderFactory.java diff --git a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java index 6852af8..d643126 100644 --- a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java +++ b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java @@ -1,18 +1,26 @@ package net.ripe.rpki.rsyncit; import io.micrometer.common.KeyValues; +import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; +import io.netty.resolver.ResolvedAddressTypes; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.web.reactive.function.client.ClientRequestObservationContext; import org.springframework.web.reactive.function.client.ClientRequestObservationConvention; import org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention; import org.springframework.web.reactive.function.client.WebClient; -import net.ripe.rpki.rsyncit.util.http.WebClientBuilderFactory; import net.ripe.rpki.rsyncit.config.AppConfig; +import reactor.netty.http.client.HttpClient; +import java.time.Duration; import java.util.Properties; +import java.util.concurrent.TimeUnit; @SpringBootApplication public class RsyncitApplication { @@ -27,11 +35,24 @@ public static void main(String[] args) { } @Bean - public WebClientBuilderFactory webclientConfigurer(WebClient.Builder baseBuilder, AppConfig appConfig) { - // Explicit event loop is required for custom DnsNameResolverBuilder - NioEventLoopGroup group = new NioEventLoopGroup(1); + public WebClient.Builder webclientConfiguration(WebClient.Builder baseBuilder, AppConfig appConfig) { + final var userAgent = "rsyncit %s".formatted(appConfig.getInfo().gitCommitId()); - return new WebClientBuilderFactory(group, baseBuilder, "rsyncit %s".formatted(appConfig.getInfo().gitCommitId())); + var httpClient = HttpClient.create() + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) + .responseTimeout(Duration.ofMillis(5000)) + // remember: read and write timeouts are per read, not for a request. + .doOnConnected(conn -> + conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)) + .addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)) + ).resolver(spec -> + spec.resolvedAddressTypes(ResolvedAddressTypes.IPV6_PREFERRED) + .completeOncePreferredResolved(false)); + + + return baseBuilder + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .defaultHeader(HttpHeaders.USER_AGENT, userAgent); } /** diff --git a/src/main/java/net/ripe/rpki/rsyncit/service/SyncService.java b/src/main/java/net/ripe/rpki/rsyncit/service/SyncService.java index df31fdb..c295ca5 100644 --- a/src/main/java/net/ripe/rpki/rsyncit/service/SyncService.java +++ b/src/main/java/net/ripe/rpki/rsyncit/service/SyncService.java @@ -9,9 +9,9 @@ import net.ripe.rpki.rsyncit.rrdp.State; import net.ripe.rpki.rsyncit.rsync.RsyncWriter; import net.ripe.rpki.rsyncit.util.Time; -import net.ripe.rpki.rsyncit.util.http.WebClientBuilderFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -21,24 +21,24 @@ @Getter public class SyncService { - private final WebClientBuilderFactory webClientFactory; + private final WebClient webClient; private final AppConfig appConfig; private final State state; private final RRDPFetcherMetrics metrics; @Autowired - public SyncService(WebClientBuilderFactory webClientFactory, + public SyncService(WebClient webClient, AppConfig appConfig, MeterRegistry meterRegistry) { - this.webClientFactory = webClientFactory; this.appConfig = appConfig; + this.webClient = webClient; this.metrics = new RRDPFetcherMetrics(meterRegistry); this.state = new State(); } public void sync() { var config = appConfig.getConfig(); - var rrdpFetcher = new RrdpFetcher(config, webClientFactory.builder().build(), state); + var rrdpFetcher = new RrdpFetcher(config, webClient, state); var t = Time.timed(rrdpFetcher::fetchObjects); final RrdpFetcher.FetchResult fetchResult = t.getResult(); diff --git a/src/main/java/net/ripe/rpki/rsyncit/util/http/WebClientBuilderFactory.java b/src/main/java/net/ripe/rpki/rsyncit/util/http/WebClientBuilderFactory.java deleted file mode 100644 index fea64c5..0000000 --- a/src/main/java/net/ripe/rpki/rsyncit/util/http/WebClientBuilderFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.ripe.rpki.rsyncit.util.http; - -import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.handler.timeout.ReadTimeoutHandler; -import io.netty.handler.timeout.WriteTimeoutHandler; -import io.netty.resolver.ResolvedAddressTypes; -import io.netty.resolver.dns.DnsNameResolverBuilder; -import org.springframework.http.HttpHeaders; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; -import reactor.netty.http.client.HttpClient; - -import java.time.Duration; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * Customise a spring-configured WebClient.Builder with rpki-monitoring specific settings. - * - * @param eventLoopGroup to run in - * @param baseBuilder to customise - * @param userAgent to set in headers - */ -public record WebClientBuilderFactory(EventLoopGroup eventLoopGroup, WebClient.Builder baseBuilder, String userAgent) { - - private HttpClient initialHttpClientConfig() { - return HttpClient.create() - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) - .responseTimeout(Duration.ofMillis(5000)) - // remember: read and write timeouts are per read, not for a request. - .doOnConnected(conn -> - conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)) - .addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)) - ); - } - - private WebClient.Builder forHttpClient(HttpClient httpClient) { - return baseBuilder - .clientConnector(new ReactorClientHttpConnector(httpClient)) - .defaultHeader(HttpHeaders.USER_AGENT, userAgent); - - } - - public WebClient.Builder builder() { - return forHttpClient( - initialHttpClientConfig() - .resolver(spec -> - spec.resolvedAddressTypes(ResolvedAddressTypes.IPV6_PREFERRED) - .completeOncePreferredResolved(false) - ) - ); - } -} From 24bb51e851c4338f3649e5714d4804cf61b56cc0 Mon Sep 17 00:00:00 2001 From: Mikhail Puzanov Date: Tue, 27 Jun 2023 14:48:04 +0200 Subject: [PATCH 3/3] Fix WebClient bean --- src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java index d643126..e28a9a0 100644 --- a/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java +++ b/src/main/java/net/ripe/rpki/rsyncit/RsyncitApplication.java @@ -35,7 +35,7 @@ public static void main(String[] args) { } @Bean - public WebClient.Builder webclientConfiguration(WebClient.Builder baseBuilder, AppConfig appConfig) { + public WebClient webclientConfiguration(WebClient.Builder baseBuilder, AppConfig appConfig) { final var userAgent = "rsyncit %s".formatted(appConfig.getInfo().gitCommitId()); var httpClient = HttpClient.create() @@ -52,7 +52,8 @@ public WebClient.Builder webclientConfiguration(WebClient.Builder baseBuilder, A return baseBuilder .clientConnector(new ReactorClientHttpConnector(httpClient)) - .defaultHeader(HttpHeaders.USER_AGENT, userAgent); + .defaultHeader(HttpHeaders.USER_AGENT, userAgent) + .build(); } /**