diff options
author | Bjørn Christian Seime <bjorncs@vespa.ai> | 2024-06-06 11:08:45 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@vespa.ai> | 2024-06-06 11:40:41 +0200 |
commit | cf00a65940560c8fbfe32a015f4ef50942e997d8 (patch) | |
tree | 277661ff338df1834daaa955b0f225eb5f3d7417 | |
parent | d6818209d90b407dc1a9bde5cae4269c071eea2d (diff) |
Move parsing of configuration string to config model
5 files changed, 87 insertions, 28 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java index f8b739c638b..9c9e20062f8 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.container.http.ssl; +import ai.vespa.utils.BytesQuantity; import com.yahoo.config.model.api.EndpointCertificateSecrets; import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.security.tls.TlsContext; @@ -21,6 +22,8 @@ import java.util.TreeSet; */ public class HostedSslConnectorFactory extends ConnectorFactory { + private record EntityLoggingEntry(String prefix, double sampleRate, BytesQuantity maxEntitySize) {} + private final SslClientAuth clientAuth; private final List<String> tlsCiphersOverride; private final boolean proxyProtocolEnabled; @@ -28,7 +31,7 @@ public class HostedSslConnectorFactory extends ConnectorFactory { private final List<String> remoteAddressHeaders; private final List<String> remotePortHeaders; private final Set<String> knownServerNames; - private final Set<String> requestPrefixForLoggingContent; + private final List<EntityLoggingEntry> entityLoggingEntries; public static Builder builder(String name, int listenPort) { return new Builder(name, listenPort); } @@ -41,12 +44,22 @@ public class HostedSslConnectorFactory extends ConnectorFactory { this.remoteAddressHeaders = List.copyOf(builder.remoteAddressHeaders); this.remotePortHeaders = List.copyOf(builder.remotePortHeaders); this.knownServerNames = Collections.unmodifiableSet(new TreeSet<>(builder.knownServerNames)); - builder.requestPrefixForLoggingContent.forEach(prefix -> { - var regex = "^.*:[01](\\.\\d+)?:\\d+[a-zA-Z]+$"; - if (!prefix.matches(regex)) - throw new IllegalArgumentException("Invalid prefix '%s, must match regex '%s'".formatted(prefix, regex)); - }); - this.requestPrefixForLoggingContent = Collections.unmodifiableSet(new TreeSet<>(builder.requestPrefixForLoggingContent)); + this.entityLoggingEntries = builder.requestPrefixForLoggingContent.stream() + .map(prefix -> { + var parts = prefix.split(":"); + if (parts.length != 3) { + throw new IllegalArgumentException("Expected string of format 'prefix:sample-rate:max-entity-size', got '%s'".formatted(prefix)); + } + var pathPrefix = parts[0]; + if (pathPrefix.isBlank()) + throw new IllegalArgumentException("Path prefix must not be blank"); + var sampleRate = Double.parseDouble(parts[1]); + if (sampleRate < 0 || sampleRate > 1) + throw new IllegalArgumentException("Sample rate must be in range [0, 1], got '%s'".formatted(sampleRate)); + var maxEntitySize = BytesQuantity.fromString(parts[2]); + return new EntityLoggingEntry(pathPrefix, sampleRate, maxEntitySize); + }) + .toList(); } private static SslProvider createSslProvider(Builder builder) { @@ -79,9 +92,14 @@ public class HostedSslConnectorFactory extends ConnectorFactory { .idleTimeout(Duration.ofSeconds(30).toSeconds()) .maxConnectionLife(endpointConnectionTtl != null ? endpointConnectionTtl.toSeconds() : 0) .accessLog(new ConnectorConfig.AccessLog.Builder() - .remoteAddressHeaders(remoteAddressHeaders) - .remotePortHeaders(remotePortHeaders) - .contentPathPrefixes(requestPrefixForLoggingContent)) + .remoteAddressHeaders(remoteAddressHeaders) + .remotePortHeaders(remotePortHeaders) + .content(entityLoggingEntries.stream() + .map(e -> new ConnectorConfig.AccessLog.Content.Builder() + .pathPrefix(e.prefix) + .sampleRate(e.sampleRate) + .maxSize(e.maxEntitySize.toBytes())) + .toList())) .serverName.known(knownServerNames); } diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index bf9a177c28e..ef00a1e3087 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -1047,16 +1047,51 @@ "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder remoteAddressHeaders(java.util.Collection)", "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder remotePortHeaders(java.lang.String)", "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder remotePortHeaders(java.util.Collection)", - "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder contentPathPrefixes(java.lang.String)", - "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder contentPathPrefixes(java.util.Collection)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder content(com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder content(java.util.function.Consumer)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Builder content(java.util.List)", "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog build()" ], "fields" : [ "public java.util.List remoteAddressHeaders", "public java.util.List remotePortHeaders", - "public java.util.List contentPathPrefixes" + "public java.util.List content" ] }, + "com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder" : { + "superClass" : "java.lang.Object", + "interfaces" : [ + "com.yahoo.config.ConfigBuilder" + ], + "attributes" : [ + "public", + "final" + ], + "methods" : [ + "public void <init>()", + "public void <init>(com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder pathPrefix(java.lang.String)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder maxSize(long)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder sampleRate(double)", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content build()" + ], + "fields" : [ ] + }, + "com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content" : { + "superClass" : "com.yahoo.config.InnerNode", + "interfaces" : [ ], + "attributes" : [ + "public", + "final" + ], + "methods" : [ + "public void <init>(com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content$Builder)", + "public java.lang.String pathPrefix()", + "public long maxSize()", + "public double sampleRate()" + ], + "fields" : [ ] + }, "com.yahoo.jdisc.http.ConnectorConfig$AccessLog" : { "superClass" : "com.yahoo.config.InnerNode", "interfaces" : [ ], @@ -1070,8 +1105,8 @@ "public java.lang.String remoteAddressHeaders(int)", "public java.util.List remotePortHeaders()", "public java.lang.String remotePortHeaders(int)", - "public java.util.List contentPathPrefixes()", - "public java.lang.String contentPathPrefixes(int)" + "public java.util.List content()", + "public com.yahoo.jdisc.http.ConnectorConfig$AccessLog$Content content(int)" ], "fields" : [ ] }, diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java index 670fb3f41ee..31fd55bb987 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java @@ -10,6 +10,7 @@ import com.yahoo.jdisc.handler.ContentChannel; import com.yahoo.jdisc.handler.DelegatedRequestHandler; import com.yahoo.jdisc.handler.RequestHandler; import com.yahoo.jdisc.handler.ResponseHandler; +import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.HttpHeaders; import com.yahoo.jdisc.http.HttpRequest; @@ -71,16 +72,10 @@ public class AccessLoggingRequestHandler extends AbstractRequestHandler implemen this.jettyRequest = jettyRequest; this.delegateRequestHandler = delegateRequestHandler; this.accessLogEntry = accessLogEntry; - var contentPathPrefixes = getConnector(jettyRequest).connectorConfig().accessLog().contentPathPrefixes(); - this.pathPrefixes = contentPathPrefixes.stream() - .map(s -> s.split(":")[0]) - .toList(); - this.samplingRate = contentPathPrefixes.stream() - .map(s -> Double.parseDouble(s.split(":")[1])) - .toList(); - this.maxSize = contentPathPrefixes.stream() - .map(s -> BytesQuantity.fromString(s.split(":")[2]).toBytes()) - .toList(); + var cfg = getConnector(jettyRequest).connectorConfig().accessLog().content(); + this.pathPrefixes = cfg.stream().map(e -> e.pathPrefix()).toList(); + this.samplingRate = cfg.stream().map(e -> e.sampleRate()).toList(); + this.maxSize = cfg.stream().map(e -> e.maxSize()).toList(); } @Override diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def index b11081cad92..44750b15324 100644 --- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def +++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def @@ -156,4 +156,6 @@ accessLog.remoteAddressHeaders[] string accessLog.remotePortHeaders[] string # Path prefixes for which content should be logged -accessLog.contentPathPrefixes[] string +accessLog.content[].pathPrefix string +accessLog.content[].maxSize long +accessLog.content[].sampleRate double diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java index 5905061212f..792d3a6e436 100644 --- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java +++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.http.server.jetty; +import ai.vespa.utils.BytesQuantity; import com.google.inject.AbstractModule; import com.google.inject.Module; import com.yahoo.container.logging.ConnectionLog; @@ -745,8 +746,16 @@ public class HttpServerTest { new ServerConfig.Builder(), new ConnectorConfig.Builder().accessLog( new ConnectorConfig.AccessLog.Builder() - .contentPathPrefixes("/search:1:1k") - .contentPathPrefixes("/document/v1:0.001:1M")), + .content(List.of( + new ConnectorConfig.AccessLog.Content.Builder() + .pathPrefix("/search") + .maxSize(BytesQuantity.ofKB(1).toBytes()) + .sampleRate(1), + new ConnectorConfig.AccessLog.Content.Builder() + .pathPrefix("/document/v1") + .maxSize(BytesQuantity.ofMB(1).toBytes()) + .sampleRate(0.001) + ))), binder -> binder.bind(RequestLog.class).toInstance(requestLogMock)); driver.client().newPost("/search/").setContent("abcdef").execute().expectStatusCode(is(OK)); RequestLogEntry entry = requestLogMock.poll(Duration.ofSeconds(5)); |