summaryrefslogtreecommitdiffstats
path: root/container-core
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-04-15 09:56:19 +0200
committerGitHub <noreply@github.com>2021-04-15 09:56:19 +0200
commitdd8ad087b63608fc58e21d337a276bfb56faa8e5 (patch)
tree5f3cba91e71efd370bfd61f6e1b59fa74eea3857 /container-core
parent79e96255ec8e6f456607c876769c784f0b70c1a6 (diff)
parentc4e53c75bdc895749034b77d61c40ba5d2139fe7 (diff)
Merge pull request #17425 from vespa-engine/bjorncs/http2-connection-log
Track protocol layers (with versions) in connection log
Diffstat (limited to 'container-core')
-rw-r--r--container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java17
-rw-r--r--container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java32
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java22
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java8
4 files changed, 72 insertions, 7 deletions
diff --git a/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java b/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
index 6afe3b74329..5b30ce5963d 100644
--- a/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
+++ b/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
@@ -33,6 +33,8 @@ public class ConnectionLogEntry {
private final Instant sslPeerNotAfter;
private final String sslSniServerName;
private final SslHandshakeFailure sslHandshakeFailure;
+ private final String httpProtocol;
+ private final String proxyProtocolVersion;
private ConnectionLogEntry(Builder builder) {
@@ -57,6 +59,8 @@ public class ConnectionLogEntry {
this.sslPeerNotAfter = builder.sslPeerNotAfter;
this.sslSniServerName = builder.sslSniServerName;
this.sslHandshakeFailure = builder.sslHandshakeFailure;
+ this.httpProtocol = builder.httpProtocol;
+ this.proxyProtocolVersion = builder.proxyProtocolVersion;
}
public static Builder builder(UUID id, Instant timestamp) {
@@ -84,6 +88,8 @@ public class ConnectionLogEntry {
public Optional<Instant> sslPeerNotAfter() { return Optional.ofNullable(sslPeerNotAfter); }
public Optional<String> sslSniServerName() { return Optional.ofNullable(sslSniServerName); }
public Optional<SslHandshakeFailure> sslHandshakeFailure() { return Optional.ofNullable(sslHandshakeFailure); }
+ public Optional<String> httpProtocol() { return Optional.ofNullable(httpProtocol); }
+ public Optional<String> proxyProtocolVersion() { return Optional.ofNullable(proxyProtocolVersion); }
public static class SslHandshakeFailure {
private final String type;
@@ -133,6 +139,8 @@ public class ConnectionLogEntry {
private Instant sslPeerNotAfter;
private String sslSniServerName;
private SslHandshakeFailure sslHandshakeFailure;
+ private String httpProtocol;
+ private String proxyProtocolVersion;
Builder(UUID id, Instant timestamp) {
@@ -217,9 +225,18 @@ public class ConnectionLogEntry {
this.sslHandshakeFailure = sslHandshakeFailure;
return this;
}
+ public Builder withHttpProtocol(String protocol) {
+ this.httpProtocol = protocol;
+ return this;
+ }
+ public Builder withProxyProtocolVersion(String version) {
+ this.proxyProtocolVersion = version;
+ return this;
+ }
public ConnectionLogEntry build(){
return new ConnectionLogEntry(this);
}
+
}
}
diff --git a/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java b/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
index 158d2ec4ea6..dfdc5f1b55a 100644
--- a/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
+++ b/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
@@ -33,12 +33,32 @@ class JsonConnectionLogWriter implements LogWriter<ConnectionLogEntry> {
writeOptionalInteger(generator, "peerPort", unwrap(record.peerPort()));
writeOptionalString(generator, "localAddress", unwrap(record.localAddress()));
writeOptionalInteger(generator, "localPort", unwrap(record.localPort()));
- writeOptionalString(generator, "remoteAddress", unwrap(record.remoteAddress()));
- writeOptionalInteger(generator, "remotePort", unwrap(record.remotePort()));
- writeOptionalLong(generator, "httpBytesReceived", unwrap(record.httpBytesReceived()));
- writeOptionalLong(generator, "httpBytesSent", unwrap(record.httpBytesSent()));
- writeOptionalLong(generator, "requests", unwrap(record.requests()));
- writeOptionalLong(generator, "responses", unwrap(record.responses()));
+
+ String proxyProtocolVersion = unwrap(record.proxyProtocolVersion());
+ String proxyProtocolRemoteAddress = unwrap(record.remoteAddress());
+ Integer proxyProtocolRemotePort = unwrap(record.remotePort());
+ if (isAnyValuePresent(proxyProtocolVersion, proxyProtocolRemoteAddress, proxyProtocolRemotePort)) {
+ generator.writeObjectFieldStart("proxyProtocol");
+ writeOptionalString(generator, "version", proxyProtocolVersion);
+ writeOptionalString(generator, "remoteAddress", proxyProtocolRemoteAddress);
+ writeOptionalInteger(generator, "remotePort", proxyProtocolRemotePort);
+ generator.writeEndObject();
+ }
+
+ String httpVersion = unwrap(record.httpProtocol());
+ Long httpBytesReceived = unwrap(record.httpBytesReceived());
+ Long httpBytesSent = unwrap(record.httpBytesSent());
+ Long httpRequests = unwrap(record.requests());
+ Long httpResponses = unwrap(record.responses());
+ if (isAnyValuePresent(httpVersion, httpBytesReceived, httpBytesSent, httpRequests, httpResponses)) {
+ generator.writeObjectFieldStart("http");
+ writeOptionalString(generator, "version", httpVersion);
+ writeOptionalLong(generator, "bytesReceived", httpBytesReceived);
+ writeOptionalLong(generator, "responses", httpResponses);
+ writeOptionalLong(generator, "bytesSent", httpBytesSent);
+ writeOptionalLong(generator, "requests", httpRequests);
+ generator.writeEndObject();
+ }
String sslProtocol = unwrap(record.sslProtocol());
String sslSessionId = unwrap(record.sslSessionId());
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
index cd1ca490f61..e7cdb13425f 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
@@ -6,6 +6,7 @@ import com.yahoo.container.logging.ConnectionLogEntry;
import com.yahoo.container.logging.ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry;
import com.yahoo.io.HexDump;
import com.yahoo.jdisc.http.ServerConfig;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.SocketChannelEndPoint;
@@ -94,9 +95,18 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
info = ConnectionInfo.from(endpoint);
connectionInfo.put(IdentityKey.of(endpoint), info);
}
+ String connectionClassName = connection.getClass().getSimpleName(); // For hidden implementations of Connection
if (connection instanceof SslConnection) {
SSLEngine sslEngine = ((SslConnection) connection).getSSLEngine();
sslToConnectionInfo.put(IdentityKey.of(sslEngine), info);
+ } else if (connection instanceof HttpConnection) {
+ info.setHttpProtocol("HTTP/1.1");
+ } else if (connection instanceof HTTP2ServerConnection) {
+ info.setHttpProtocol("HTTP/2.0");
+ } else if (connectionClassName.endsWith("ProxyProtocolV1Connection")) {
+ info.setProxyProtocolVersion("v1");
+ } else if (connectionClassName.endsWith("ProxyProtocolV2Connection")) {
+ info.setProxyProtocolVersion("v2");
}
if (connection.getEndPoint() instanceof ProxyConnectionFactory.ProxyEndPoint) {
InetSocketAddress remoteAddress = connection.getEndPoint().getRemoteAddress();
@@ -227,6 +237,8 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
private Date sslPeerNotAfter;
private List<SNIServerName> sslSniServerNames;
private SSLHandshakeException sslHandshakeException;
+ private String proxyProtocolVersion;
+ private String httpProtocol;
private ConnectionInfo(UUID uuid, long createdAt, InetSocketAddress localAddress, InetSocketAddress peerAddress) {
this.uuid = uuid;
@@ -290,6 +302,10 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
return this;
}
+ synchronized ConnectionInfo setHttpProtocol(String protocol) { this.httpProtocol = protocol; return this; }
+
+ synchronized ConnectionInfo setProxyProtocolVersion(String version) { this.proxyProtocolVersion = version; return this; }
+
synchronized ConnectionLogEntry toLogEntry() {
ConnectionLogEntry.Builder builder = ConnectionLogEntry.builder(uuid, Instant.ofEpochMilli(createdAt));
if (closedAt > 0) {
@@ -348,6 +364,12 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
.orElse("UNKNOWN");
builder.withSslHandshakeFailure(new ConnectionLogEntry.SslHandshakeFailure(type, exceptionChain));
}
+ if (httpProtocol != null) {
+ builder.withHttpProtocol(httpProtocol);
+ }
+ if (proxyProtocolVersion != null) {
+ builder.withProxyProtocolVersion(proxyProtocolVersion);
+ }
return builder.build();
}
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 f5d77b53f12..d35434032ad 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
@@ -520,7 +520,9 @@ public class HttpServerTest {
Path certificateFile = tmpFolder.newFile().toPath();
generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile, TlsClientAuth.WANT);
+ MetricConsumerMock metricConsumer = new MetricConsumerMock();
+ InMemoryConnectionLog connectionLog = new InMemoryConnectionLog();
+ TestDriver driver = createSslTestDriver(certificateFile, privateKeyFile, metricConsumer, connectionLog);
try (CloseableHttpAsyncClient client = createHttp2Client(certificateFile, privateKeyFile)) {
String uri = "https://localhost:" + driver.server().getListenPort() + "/status.html";
SimpleHttpResponse response = client.execute(SimpleHttpRequests.get(uri), null).get();
@@ -528,6 +530,8 @@ public class HttpServerTest {
assertEquals(OK, response.getCode());
}
assertTrue(driver.close());
+ ConnectionLogEntry entry = connectionLog.logEntries().get(0);
+ assertEquals("HTTP/2.0", entry.httpProtocol().get());
}
@Test
@@ -806,7 +810,9 @@ public class HttpServerTest {
assertLogEntryHasRemote(requestLogMock.entries().get(1), proxiedRemoteAddress, proxiedRemotePort);
Assertions.assertThat(connectionLog.logEntries()).hasSize(2);
assertLogEntryHasRemote(connectionLog.logEntries().get(0), proxiedRemoteAddress, proxiedRemotePort);
+ assertEquals("v1", connectionLog.logEntries().get(0).proxyProtocolVersion().get());
assertLogEntryHasRemote(connectionLog.logEntries().get(1), proxiedRemoteAddress, proxiedRemotePort);
+ assertEquals("v2", connectionLog.logEntries().get(1).proxyProtocolVersion().get());
}
@Test