summaryrefslogtreecommitdiffstats
path: root/jdisc_http_service/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'jdisc_http_service/src/main/java/com')
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLog.java14
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogInterface.java (renamed from jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogHandler.java)4
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogSampler.java37
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONAccessLog.java6
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONFormatter.java94
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLog.java13
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogEntry.java181
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/VespaAccessLog.java28
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java129
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java5
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/VoidRequestLog.java14
11 files changed, 179 insertions, 346 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLog.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLog.java
index cdb4febb775..5c1a549070c 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLog.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLog.java
@@ -9,14 +9,13 @@ import com.yahoo.component.provider.ComponentRegistry;
* Logs to all the configured access logs.
*
* @author Tony Vaagenes
- * @author bjorncs
*/
-public class AccessLog implements RequestLog {
+public class AccessLog {
- private final ComponentRegistry<RequestLogHandler> implementers;
+ private ComponentRegistry<AccessLogInterface> implementers;
@Inject
- public AccessLog(ComponentRegistry<RequestLogHandler> implementers) {
+ public AccessLog(ComponentRegistry<AccessLogInterface> implementers) {
this.implementers = implementers;
}
@@ -24,10 +23,9 @@ public class AccessLog implements RequestLog {
return new AccessLog(new ComponentRegistry<>());
}
- @Override
- public void log(RequestLogEntry entry) {
- for (RequestLogHandler handler: implementers.allComponents()) {
- handler.log(entry);
+ public void log(AccessLogEntry accessLogEntry) {
+ for (AccessLogInterface log: implementers.allComponents()) {
+ log.log(accessLogEntry);
}
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogHandler.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogInterface.java
index 85df08e4abb..2523174abef 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogHandler.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogInterface.java
@@ -4,6 +4,6 @@ package com.yahoo.container.logging;
/**
* @author Tony Vaagenes
*/
-public interface RequestLogHandler {
- void log(RequestLogEntry entry);
+public interface AccessLogInterface {
+ void log(AccessLogEntry accessLogEntry);
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogSampler.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogSampler.java
new file mode 100644
index 00000000000..12d29c2f333
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/AccessLogSampler.java
@@ -0,0 +1,37 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.logging;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Samples entries from access log. It first samples every query until it have some data, and then sub-samples
+ * much less frequently to reduce CPU usage and latency impact. It only samples successful requests and requests
+ * that starts with /search.
+ *
+ * @author dybis
+ */
+public class AccessLogSampler implements AccessLogInterface {
+
+ private final AtomicLong accessLineCounter = new AtomicLong(0);
+ private final CircularArrayAccessLogKeeper circularArrayAccessLogKeeper;
+
+ public AccessLogSampler(CircularArrayAccessLogKeeper circularArrayAccessLogKeeper) {
+ this.circularArrayAccessLogKeeper = circularArrayAccessLogKeeper;
+ }
+
+ @Override
+ public void log(AccessLogEntry accessLogEntry) {
+ if (accessLogEntry.getStatusCode() != 200) {
+ return;
+ }
+ String uriString = accessLogEntry.getRawPath();
+ if (! uriString.startsWith("/search")) {
+ return;
+ }
+ final long count = accessLineCounter.incrementAndGet();
+ if (count >= CircularArrayAccessLogKeeper.SIZE && count % CircularArrayAccessLogKeeper.SIZE != 0) {
+ return;
+ }
+ circularArrayAccessLogKeeper.addUri(uriString);
+ }
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONAccessLog.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONAccessLog.java
index aa2df959a4c..5a188d68e89 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONAccessLog.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONAccessLog.java
@@ -11,7 +11,7 @@ import java.util.logging.Level;
* @author frodelu
* @author Tony Vaagenes
*/
-public final class JSONAccessLog implements RequestLogHandler {
+public final class JSONAccessLog implements AccessLogInterface {
private final AccessLogHandler logHandler;
private final JSONFormatter formatter;
@@ -22,8 +22,8 @@ public final class JSONAccessLog implements RequestLogHandler {
}
@Override
- public void log(RequestLogEntry entry) {
- logHandler.access.log(Level.INFO, formatter.format(entry) + '\n');
+ public void log(AccessLogEntry logEntry) {
+ logHandler.access.log(Level.INFO, formatter.format(logEntry) + '\n');
}
// TODO: This is never called. We should have a DI provider and call this method from its deconstruct.
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONFormatter.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONFormatter.java
index dc0acc4fbac..b6ceaa08007 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONFormatter.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JSONFormatter.java
@@ -12,7 +12,8 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.Principal;
-import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -41,76 +42,76 @@ public class JSONFormatter {
}
/**
- * The main method for formatting the associated {@link RequestLogEntry} as a Vespa JSON access log string
+ * The main method for formatting the associated {@link AccessLogEntry} as a Vespa JSON access log string
*
* @return The Vespa JSON access log string without trailing newline
*/
- public String format(RequestLogEntry entry) {
+ public String format(AccessLogEntry accessLogEntry) {
ByteArrayOutputStream logLine = new ByteArrayOutputStream();
try {
JsonGenerator generator = generatorFactory.createGenerator(logLine, JsonEncoding.UTF8);
generator.writeStartObject();
- String peerAddress = entry.peerAddress().get();
- generator.writeStringField("ip", peerAddress);
- long time = entry.timestamp().get().toEpochMilli();
- generator.writeNumberField("time", toTimestampInSeconds(time));
- generator.writeNumberField("duration", durationAsSeconds(entry.duration().get().toMillis()));
- generator.writeNumberField("responsesize", entry.contentSize().orElse(0));
- generator.writeNumberField("code", entry.statusCode().orElse(0));
- generator.writeStringField("method", entry.httpMethod().orElse(""));
- generator.writeStringField("uri", getNormalizedURI(entry.rawPath().get(), entry.rawQuery().orElse(null)));
- generator.writeStringField("version", entry.httpVersion().orElse(""));
- generator.writeStringField("agent", entry.userAgent().orElse(""));
- generator.writeStringField("host", entry.hostString().orElse(""));
- generator.writeStringField("scheme", entry.scheme().orElse(null));
- generator.writeNumberField("localport", entry.localPort().getAsInt());
-
- String connectionId = entry.connectionId().orElse(null);
+ generator.writeStringField("ip", accessLogEntry.getIpV4Address());
+ generator.writeNumberField("time", toTimestampInSeconds(accessLogEntry.getTimeStampMillis()));
+ generator.writeNumberField("duration", durationAsSeconds(accessLogEntry.getDurationBetweenRequestResponseMillis()));
+ generator.writeNumberField("responsesize", accessLogEntry.getReturnedContentSize());
+ generator.writeNumberField("code", accessLogEntry.getStatusCode());
+ generator.writeStringField("method", accessLogEntry.getHttpMethod());
+ generator.writeStringField("uri", getNormalizedURI(accessLogEntry.getRawPath(), accessLogEntry.getRawQuery().orElse(null)));
+ generator.writeStringField("version", accessLogEntry.getHttpVersion());
+ generator.writeStringField("agent", accessLogEntry.getUserAgent());
+ generator.writeStringField("host", accessLogEntry.getHostString());
+ generator.writeStringField("scheme", accessLogEntry.getScheme());
+ generator.writeNumberField("localport", accessLogEntry.getLocalPort());
+
+ String connectionId = accessLogEntry.getConnectionId().orElse(null);
if (connectionId != null) {
generator.writeStringField("connection", connectionId);
}
- Principal principal = entry.userPrincipal().orElse(null);
+ Principal principal = accessLogEntry.getUserPrincipal();
if (principal != null) {
generator.writeStringField("user-principal", principal.getName());
}
- String remoteAddress = entry.remoteAddress().orElse(null);
- int remotePort = entry.remotePort().orElse(0);
+ Principal sslPrincipal = accessLogEntry.getSslPrincipal();
+ if (sslPrincipal != null) {
+ generator.writeStringField("ssl-principal", sslPrincipal.getName());
+ }
+
// Only add remote address/port fields if relevant
- if (remoteAddressDiffers(peerAddress, remoteAddress)) {
- generator.writeStringField("remoteaddr", remoteAddress);
- if (remotePort > 0) {
- generator.writeNumberField("remoteport", remotePort);
+ if (remoteAddressDiffers(accessLogEntry.getIpV4Address(), accessLogEntry.getRemoteAddress())) {
+ generator.writeStringField("remoteaddr", accessLogEntry.getRemoteAddress());
+ if (accessLogEntry.getRemotePort() > 0) {
+ generator.writeNumberField("remoteport", accessLogEntry.getRemotePort());
}
}
// Only add peer address/port fields if relevant
- if (peerAddress != null) {
- generator.writeStringField("peeraddr", peerAddress);
+ if (accessLogEntry.getPeerAddress() != null) {
+ generator.writeStringField("peeraddr", accessLogEntry.getPeerAddress());
- int peerPort = entry.peerPort().getAsInt();
- if (peerPort > 0 && peerPort != remotePort) {
+ int peerPort = accessLogEntry.getPeerPort();
+ if (peerPort > 0 && peerPort != accessLogEntry.getRemotePort()) {
generator.writeNumberField("peerport", peerPort);
}
}
- TraceNode trace = entry.traceNode().orElse(null);
+ TraceNode trace = accessLogEntry.getTrace();
if (trace != null) {
long timestamp = trace.timestamp();
if (timestamp == 0L) {
- timestamp = time;
+ timestamp = accessLogEntry.getTimeStampMillis();
}
trace.accept(new TraceRenderer(generator, timestamp));
}
// Only add search sub block of this is a search request
- if (isSearchRequest(entry)) {
- HitCounts hitCounts = entry.hitCounts().get();
+ if (isSearchRequest(accessLogEntry)) {
generator.writeObjectFieldStart("search");
- generator.writeNumberField("totalhits", getTotalHitCount(hitCounts));
- generator.writeNumberField("hits", getRetrievedHitCount(hitCounts));
- Coverage c = hitCounts.getCoverage();
+ generator.writeNumberField("totalhits", getTotalHitCount(accessLogEntry.getHitCounts()));
+ generator.writeNumberField("hits", getRetrievedHitCount(accessLogEntry.getHitCounts()));
+ Coverage c = accessLogEntry.getHitCounts().getCoverage();
if (c != null) {
generator.writeObjectFieldStart(COVERAGE);
generator.writeNumberField(COVERAGE_COVERAGE, c.getResultPercentage());
@@ -134,17 +135,16 @@ public class JSONFormatter {
// Add key/value access log entries. Keys with single values are written as single
// string value fields while keys with multiple values are written as string arrays
- Collection<String> keys = entry.extraAttributeKeys();
- if (!keys.isEmpty()) {
+ Map<String,List<String>> keyValues = accessLogEntry.getKeyValues();
+ if (keyValues != null && !keyValues.isEmpty()) {
generator.writeObjectFieldStart("attributes");
- for (String key : keys) {
- Collection<String> values = entry.extraAttributeValues(key);
- if (values.size() == 1) {
- generator.writeStringField(key, values.iterator().next());
+ for (Map.Entry<String,List<String>> entry : keyValues.entrySet()) {
+ if (entry.getValue().size() == 1) {
+ generator.writeStringField(entry.getKey(), entry.getValue().get(0));
} else {
- generator.writeFieldName(key);
+ generator.writeFieldName(entry.getKey());
generator.writeStartArray();
- for (String s : values) {
+ for (String s : entry.getValue()) {
generator.writeString(s);
}
generator.writeEndArray();
@@ -168,8 +168,8 @@ public class JSONFormatter {
return remoteAddress != null && !Objects.equals(ipV4Address, remoteAddress);
}
- private boolean isSearchRequest(RequestLogEntry entry) {
- return entry != null && entry.hitCounts().isPresent();
+ private boolean isSearchRequest(AccessLogEntry logEntry) {
+ return logEntry != null && (logEntry.getHitCounts() != null);
}
private long getTotalHitCount(HitCounts counts) {
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLog.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLog.java
deleted file mode 100644
index 2090ba1b9f1..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLog.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.logging;
-
-/**
- * Access logging for requests
- *
- * @author bjorncs
- */
-public interface RequestLog {
-
- void log(RequestLogEntry entry);
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogEntry.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogEntry.java
deleted file mode 100644
index b771ea11ed0..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/RequestLogEntry.java
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.logging;
-
-import com.yahoo.yolean.trace.TraceNode;
-
-import java.security.Principal;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.OptionalInt;
-import java.util.OptionalLong;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * A immutable request log entry
- *
- * @author bjorncs
- */
-public class RequestLogEntry {
-
- private final String connectionId;
- private final Instant timestamp;
- private final Duration duration;
- private final int localPort;
- private final String peerAddress;
- private final int peerPort;
- private final String remoteAddress;
- private final int remotePort;
- private final String userAgent;
- private final String referer;
- private final String httpMethod;
- private final String httpVersion;
- private final String hostString;
- private final int statusCode;
- private final long contentSize;
- private final String scheme;
- private final String rawPath;
- private final String rawQuery;
- private final Principal userPrincipal;
- private final HitCounts hitCounts;
- private final TraceNode traceNode;
- private final Map<String, Collection<String>> extraAttributes;
-
- private RequestLogEntry(Builder builder) {
- this.connectionId = builder.connectionId;
- this.timestamp = builder.timestamp;
- this.duration = builder.duration;
- this.localPort = builder.localPort;
- this.peerAddress = builder.peerAddress;
- this.peerPort = builder.peerPort;
- this.remoteAddress = builder.remoteAddress;
- this.remotePort = builder.remotePort;
- this.userAgent = builder.userAgent;
- this.referer = builder.referer;
- this.httpMethod = builder.httpMethod;
- this.httpVersion = builder.httpVersion;
- this.hostString = builder.hostString;
- this.statusCode = builder.statusCode;
- this.contentSize = builder.contentSize;
- this.scheme = builder.scheme;
- this.rawPath = builder.rawPath;
- this.rawQuery = builder.rawQuery;
- this.userPrincipal = builder.userPrincipal;
- this.hitCounts = builder.hitCounts;
- this.traceNode = builder.traceNode;
- this.extraAttributes = copyExtraAttributes(builder.extraAttributes);
- }
-
- public Optional<String> connectionId() { return Optional.ofNullable(connectionId); }
- public Optional<Instant> timestamp() { return Optional.ofNullable(timestamp); }
- public Optional<Duration> duration() { return Optional.ofNullable(duration); }
- public OptionalInt localPort() { return optionalInt(localPort); }
- public Optional<String> peerAddress() { return Optional.ofNullable(peerAddress); }
- public OptionalInt peerPort() { return optionalInt(peerPort); }
- public Optional<String> remoteAddress() { return Optional.ofNullable(remoteAddress); }
- public OptionalInt remotePort() { return optionalInt(remotePort); }
- public Optional<String> userAgent() { return Optional.ofNullable(userAgent); }
- public Optional<String> referer() { return Optional.ofNullable(referer); }
- public Optional<String> httpMethod() { return Optional.ofNullable(httpMethod); }
- public Optional<String> httpVersion() { return Optional.ofNullable(httpVersion); }
- public Optional<String> hostString() { return Optional.ofNullable(hostString); }
- public OptionalInt statusCode() { return optionalInt(statusCode); }
- public OptionalLong contentSize() { return optionalLong(contentSize); }
- public Optional<String> scheme() { return Optional.ofNullable(scheme); }
- public Optional<String> rawPath() { return Optional.ofNullable(rawPath); }
- public Optional<String> rawQuery() { return Optional.ofNullable(rawQuery); }
- public Optional<Principal> userPrincipal() { return Optional.ofNullable(userPrincipal); }
- public Optional<HitCounts> hitCounts() { return Optional.ofNullable(hitCounts); }
- public Optional<TraceNode> traceNode() { return Optional.ofNullable(traceNode); }
- public Collection<String> extraAttributeKeys() { return Collections.unmodifiableCollection(extraAttributes.keySet()); }
- public Collection<String> extraAttributeValues(String key) { return Collections.unmodifiableCollection(extraAttributes.get(key)); }
-
- private static OptionalInt optionalInt(int value) {
- if (value == -1) return OptionalInt.empty();
- return OptionalInt.of(value);
- }
-
- private static OptionalLong optionalLong(long value) {
- if (value == -1) return OptionalLong.empty();
- return OptionalLong.of(value);
- }
-
- private static Map<String, Collection<String>> copyExtraAttributes(Map<String, Collection<String>> extraAttributes) {
- Map<String, Collection<String>> copy = new HashMap<>();
- extraAttributes.forEach((key, value) -> copy.put(key, new ArrayList<>(value)));
- return copy;
- }
-
- public static class Builder {
-
- private String connectionId;
- private Instant timestamp;
- private Duration duration;
- private int localPort = -1;
- private String peerAddress;
- private int peerPort = -1;
- private String remoteAddress;
- private int remotePort = -1;
- private String userAgent;
- private String referer;
- private String httpMethod;
- private String httpVersion;
- private String hostString;
- private int statusCode = -1;
- private long contentSize = -1;
- private String scheme;
- private String rawPath;
- private String rawQuery;
- private Principal userPrincipal;
- private HitCounts hitCounts;
- private TraceNode traceNode;
- private final Map<String, Collection<String>> extraAttributes = new HashMap<>();
-
- public Builder connectionId(String connectionId) { this.connectionId = requireNonNull(connectionId); return this; }
- public Builder timestamp(Instant timestamp) { this.timestamp = requireNonNull(timestamp); return this; }
- public Builder duration(Duration duration) { this.duration = requireNonNull(duration); return this; }
- public Builder localPort(int localPort) { this.localPort = requireNonNegative(localPort); return this; }
- public Builder peerAddress(String peerAddress) { this.peerAddress = requireNonNull(peerAddress); return this; }
- public Builder peerPort(int peerPort) { this.peerPort = requireNonNegative(peerPort); return this; }
- public Builder remoteAddress(String remoteAddress) { this.remoteAddress = requireNonNull(remoteAddress); return this; }
- public Builder remotePort(int remotePort) { this.remotePort = requireNonNegative(remotePort); return this; }
- public Builder userAgent(String userAgent) { this.userAgent = requireNonNull(userAgent); return this; }
- public Builder referer(String referer) { this.referer = requireNonNull(referer); return this; }
- public Builder httpMethod(String httpMethod) { this.httpMethod = requireNonNull(httpMethod); return this; }
- public Builder httpVersion(String httpVersion) { this.httpVersion = requireNonNull(httpVersion); return this; }
- public Builder hostString(String hostString) { this.hostString = requireNonNull(hostString); return this; }
- public Builder statusCode(int statusCode) { this.statusCode = requireNonNegative(statusCode); return this; }
- public Builder contentSize(long contentSize) { this.contentSize = requireNonNegative(contentSize); return this; }
- public Builder scheme(String scheme) { this.scheme = requireNonNull(scheme); return this; }
- public Builder rawPath(String rawPath) { this.rawPath = requireNonNull(rawPath); return this; }
- public Builder rawQuery(String rawQuery) { this.rawQuery = requireNonNull(rawQuery); return this; }
- public Builder userPrincipal(Principal userPrincipal) { this.userPrincipal = requireNonNull(userPrincipal); return this; }
- public Builder hitCounts(HitCounts hitCounts) { this.hitCounts = requireNonNull(hitCounts); return this; }
- public Builder traceNode(TraceNode traceNode) { this.traceNode = requireNonNull(traceNode); return this; }
- public Builder addExtraAttribute(String key, String value) {
- this.extraAttributes.computeIfAbsent(requireNonNull(key), __ -> new ArrayList<>()).add(requireNonNull(value));
- return this;
- }
- public Builder addExtraAttributes(String key, Collection<String> values) {
- this.extraAttributes.computeIfAbsent(requireNonNull(key), __ -> new ArrayList<>()).addAll(requireNonNull(values));
- return this;
- }
- public RequestLogEntry build() { return new RequestLogEntry(this); }
-
- private static int requireNonNegative(int value) {
- if (value < 0) throw new IllegalArgumentException("Value must be non-negative: " + value);
- return value;
- }
-
- private static long requireNonNegative(long value) {
- if (value < 0) throw new IllegalArgumentException("Value must be non-negative: " + value);
- return value;
- }
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/VespaAccessLog.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/VespaAccessLog.java
index 1040846dda3..054fc0fcbf7 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/VespaAccessLog.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/VespaAccessLog.java
@@ -12,7 +12,7 @@ import java.util.logging.Level;
* @author Bjorn Borud
* @author Oyvind Bakksjo
*/
-public final class VespaAccessLog implements RequestLogHandler {
+public final class VespaAccessLog implements AccessLogInterface {
private static final ThreadLocal<SimpleDateFormat> dateFormat = ThreadLocal.withInitial(VespaAccessLog::createDateFormat);
@@ -92,20 +92,20 @@ public final class VespaAccessLog implements RequestLogHandler {
}
@Override
- public void log(RequestLogEntry entry) {
+ public void log(final AccessLogEntry accessLogEntry) {
writeLog(
- entry.peerAddress().get(),
- null,
+ accessLogEntry.getIpV4Address(),
+ accessLogEntry.getUser(),
getRequest(
- entry.httpMethod().orElse(null),
- entry.rawPath().orElse(null),
- entry.rawQuery().orElse(null),
- entry.httpVersion().orElse(null)),
- entry.referer().orElse(null),
- entry.userAgent().orElse(null),
- entry.duration().get().toMillis(),
- entry.contentSize().orElse(0L),
- entry.hitCounts().orElse(null),
- entry.statusCode().orElse(0));
+ accessLogEntry.getHttpMethod(),
+ accessLogEntry.getRawPath(),
+ accessLogEntry.getRawQuery().orElse(null),
+ accessLogEntry.getHttpVersion()),
+ accessLogEntry.getReferer(),
+ accessLogEntry.getUserAgent(),
+ accessLogEntry.getDurationBetweenRequestResponseMillis(),
+ accessLogEntry.getReturnedContentSize(),
+ accessLogEntry.getHitCounts(),
+ accessLogEntry.getStatusCode());
}
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
index e82373fdaae..32790534f86 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
@@ -4,22 +4,20 @@ package com.yahoo.jdisc.http.server.jetty;
import com.google.common.base.Objects;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.AccessLogEntry;
-import com.yahoo.container.logging.RequestLog;
-import com.yahoo.container.logging.RequestLogEntry;
import com.yahoo.jdisc.http.ServerConfig;
import com.yahoo.jdisc.http.servlet.ServletRequest;
import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
-import java.time.Duration;
-import java.time.Instant;
+import java.security.cert.X509Certificate;
import java.util.List;
+import java.util.Optional;
import java.util.OptionalInt;
import java.util.UUID;
-import java.util.function.BiConsumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -32,19 +30,19 @@ import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnectorLoca
* @author Oyvind Bakksjo
* @author bjorncs
*/
-class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty.server.RequestLog {
+class AccessLogRequestLog extends AbstractLifeCycle implements RequestLog {
private static final Logger logger = Logger.getLogger(AccessLogRequestLog.class.getName());
// HTTP headers that are logged as extra key-value-pairs in access log entries
private static final List<String> LOGGED_REQUEST_HEADERS = List.of("Vespa-Client-Version");
- private final RequestLog requestLog;
+ private final AccessLog accessLog;
private final List<String> remoteAddressHeaders;
private final List<String> remotePortHeaders;
- AccessLogRequestLog(RequestLog requestLog, ServerConfig.AccessLog config) {
- this.requestLog = requestLog;
+ AccessLogRequestLog(AccessLog accessLog, ServerConfig.AccessLog config) {
+ this.accessLog = accessLog;
this.remoteAddressHeaders = config.remoteAddressHeaders();
this.remotePortHeaders = config.remotePortHeaders();
}
@@ -52,67 +50,83 @@ class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty
@Override
public void log(Request request, Response response) {
try {
- RequestLogEntry.Builder builder = new RequestLogEntry.Builder();
-
- String peerAddress = request.getRemoteAddr();
- int peerPort = request.getRemotePort();
- long startTime = request.getTimeStamp();
- long endTime = System.currentTimeMillis();
- builder.peerAddress(peerAddress)
- .peerPort(peerPort)
- .localPort(getConnectorLocalPort(request))
- .timestamp(Instant.ofEpochMilli(startTime))
- .duration(Duration.ofMillis(endTime - startTime))
- .contentSize(response.getHttpChannel().getBytesWritten())
- .statusCode(response.getCommittedMetaData().getStatus());
-
- addNonNullValue(builder, request.getMethod(), RequestLogEntry.Builder::httpMethod);
- addNonNullValue(builder, request.getRequestURI(), RequestLogEntry.Builder::rawPath);
- addNonNullValue(builder, request.getProtocol(), RequestLogEntry.Builder::httpVersion);
- addNonNullValue(builder, request.getScheme(), RequestLogEntry.Builder::scheme);
- addNonNullValue(builder, request.getHeader("User-Agent"), RequestLogEntry.Builder::userAgent);
- addNonNullValue(builder, request.getHeader("Host"), RequestLogEntry.Builder::hostString);
- addNonNullValue(builder, request.getHeader("Referer"), RequestLogEntry.Builder::referer);
- addNonNullValue(builder, request.getQueryString(), RequestLogEntry.Builder::rawQuery);
-
- Principal principal = (Principal) request.getAttribute(ServletRequest.JDISC_REQUEST_PRINCIPAL);
- addNonNullValue(builder, principal, RequestLogEntry.Builder::userPrincipal);
-
- String requestFilterId = (String) request.getAttribute(ServletRequest.JDISC_REQUEST_CHAIN);
- addNonNullValue(builder, requestFilterId, (b, chain) -> b.addExtraAttribute("request-chain", chain));
-
- String responseFilterId = (String) request.getAttribute(ServletRequest.JDISC_RESPONSE_CHAIN);
- addNonNullValue(builder, responseFilterId, (b, chain) -> b.addExtraAttribute("response-chain", chain));
+ AccessLogEntry accessLogEntry = Optional.ofNullable(request.getAttribute(JDiscHttpServlet.ATTRIBUTE_NAME_ACCESS_LOG_ENTRY))
+ .map(AccessLogEntry.class::cast)
+ .orElseGet(AccessLogEntry::new);
+
+ accessLogEntry.setRawPath(request.getRequestURI());
+ String queryString = request.getQueryString();
+ if (queryString != null) {
+ accessLogEntry.setRawQuery(queryString);
+ }
- UUID connectionId = (UUID) request.getAttribute(JettyConnectionLogger.CONNECTION_ID_REQUEST_ATTRIBUTE);
- addNonNullValue(builder, connectionId, (b, uuid) -> b.connectionId(uuid.toString()));
+ accessLogEntry.setUserAgent(request.getHeader("User-Agent"));
+ accessLogEntry.setHttpMethod(request.getMethod());
+ accessLogEntry.setHostString(request.getHeader("Host"));
+ accessLogEntry.setReferer(request.getHeader("Referer"));
+ String peerAddress = request.getRemoteAddr();
+ accessLogEntry.setIpV4Address(peerAddress);
+ accessLogEntry.setPeerAddress(peerAddress);
String remoteAddress = getRemoteAddress(request);
if (!Objects.equal(remoteAddress, peerAddress)) {
- builder.remoteAddress(remoteAddress);
+ accessLogEntry.setRemoteAddress(remoteAddress);
}
+
+ int peerPort = request.getRemotePort();
+ accessLogEntry.setPeerPort(peerPort);
int remotePort = getRemotePort(request);
if (remotePort != peerPort) {
- builder.remotePort(remotePort);
+ accessLogEntry.setRemotePort(remotePort);
+ }
+ accessLogEntry.setHttpVersion(request.getProtocol());
+ accessLogEntry.setScheme(request.getScheme());
+ accessLogEntry.setLocalPort(getConnectorLocalPort(request));
+ Principal principal = (Principal) request.getAttribute(ServletRequest.JDISC_REQUEST_PRINCIPAL);
+ if (principal != null) {
+ accessLogEntry.setUserPrincipal(principal);
+ }
+ X509Certificate[] clientCert = (X509Certificate[]) request.getAttribute(ServletRequest.SERVLET_REQUEST_X509CERT);
+ if (clientCert != null && clientCert.length > 0) {
+ accessLogEntry.setSslPrincipal(clientCert[0].getSubjectX500Principal());
+ }
+ String sslSessionId = (String) request.getAttribute(ServletRequest.SERVLET_REQUEST_SSL_SESSION_ID);
+ if (sslSessionId != null) {
+ accessLogEntry.addKeyValue("ssl-session-id", sslSessionId);
}
+ String cipherSuite = (String) request.getAttribute(ServletRequest.SERVLET_REQUEST_CIPHER_SUITE);
+ if (cipherSuite != null) {
+ accessLogEntry.addKeyValue("cipher-suite", cipherSuite);
+ }
+ String requestFilterId = (String) request.getAttribute(ServletRequest.JDISC_REQUEST_CHAIN);
+ if (requestFilterId != null) {
+ accessLogEntry.addKeyValue("request-chain", requestFilterId);
+ }
+ String responseFilterId = (String) request.getAttribute(ServletRequest.JDISC_RESPONSE_CHAIN);
+ if (responseFilterId != null) {
+ accessLogEntry.addKeyValue("response-chain", responseFilterId);
+ }
+
+ long startTime = request.getTimeStamp();
+ long endTime = System.currentTimeMillis();
+ accessLogEntry.setTimeStamp(startTime);
+ accessLogEntry.setDurationBetweenRequestResponse(endTime - startTime);
+ accessLogEntry.setReturnedContentSize(response.getHttpChannel().getBytesWritten());
+ accessLogEntry.setStatusCode(response.getCommittedMetaData().getStatus());
+
LOGGED_REQUEST_HEADERS.forEach(header -> {
String value = request.getHeader(header);
if (value != null) {
- builder.addExtraAttribute(header, value);
+ accessLogEntry.addKeyValue(header, value);
}
});
- AccessLogEntry accessLogEntry = (AccessLogEntry) request.getAttribute(JDiscHttpServlet.ATTRIBUTE_NAME_ACCESS_LOG_ENTRY);
- if (accessLogEntry != null) {
- var extraAttributes = accessLogEntry.getKeyValues();
- if (extraAttributes != null) {
- extraAttributes.forEach(builder::addExtraAttributes);
- }
- addNonNullValue(builder, accessLogEntry.getHitCounts(), RequestLogEntry.Builder::hitCounts);
- addNonNullValue(builder, accessLogEntry.getTrace(), RequestLogEntry.Builder::traceNode);
+ UUID connectionId = (UUID) request.getAttribute(JettyConnectionLogger.CONNECTION_ID_REQUEST_ATTRIBUTE);
+ if (connectionId != null) {
+ accessLogEntry.setConnectionId(connectionId.toString());
}
- requestLog.log(builder.build());
+ accessLog.log(accessLogEntry);
} catch (Exception e) {
// Catching any exceptions here as it is unclear how Jetty handles exceptions from a RequestLog.
logger.log(Level.SEVERE, "Failed to log access log entry: " + e.getMessage(), e);
@@ -146,11 +160,4 @@ class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty
}
}
- private static <T> void addNonNullValue(
- RequestLogEntry.Builder builder, T value, BiConsumer<RequestLogEntry.Builder, T> setter) {
- if (value != null) {
- setter.accept(builder, value);
- }
- }
-
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 510c561c10f..1e077c32ea1 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -7,7 +7,6 @@ import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.ConnectionLog;
-import com.yahoo.container.logging.RequestLog;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.ServerConfig;
@@ -74,7 +73,7 @@ public class JettyHttpServer extends AbstractServerProvider {
ComponentRegistry<ConnectorFactory> connectorFactories,
ComponentRegistry<ServletHolder> servletHolders,
FilterInvoker filterInvoker,
- RequestLog requestLog,
+ AccessLog accessLog,
ConnectionLog connectionLog) {
super(container);
if (connectorFactories.allComponents().isEmpty())
@@ -84,7 +83,7 @@ public class JettyHttpServer extends AbstractServerProvider {
server = new Server();
server.setStopTimeout((long)(serverConfig.stopTimeout() * 1000.0));
- server.setRequestLog(new AccessLogRequestLog(requestLog, serverConfig.accessLog()));
+ server.setRequestLog(new AccessLogRequestLog(accessLog, serverConfig.accessLog()));
setupJmx(server, serverConfig);
configureJettyThreadpool(server, serverConfig);
JettyConnectionLogger connectionLogger = new JettyConnectionLogger(serverConfig.connectionLog(), connectionLog);
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/VoidRequestLog.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/VoidRequestLog.java
deleted file mode 100644
index 9db5ba99115..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/VoidRequestLog.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.yahoo.container.logging.RequestLog;
-import com.yahoo.container.logging.RequestLogEntry;
-
-/**
- * @author bjorncs
- */
-public class VoidRequestLog implements RequestLog {
-
- @Override public void log(RequestLogEntry entry) {}
-
-}