diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-04-15 09:56:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-15 09:56:19 +0200 |
commit | dd8ad087b63608fc58e21d337a276bfb56faa8e5 (patch) | |
tree | 5f3cba91e71efd370bfd61f6e1b59fa74eea3857 /container-core | |
parent | 79e96255ec8e6f456607c876769c784f0b70c1a6 (diff) | |
parent | c4e53c75bdc895749034b77d61c40ba5d2139fe7 (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')
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 |