@Override
    public void write(ConnectionLogEntry record, OutputStream outputStream) throws IOException {
        try (JsonGenerator generator = createJsonGenerator(outputStream)) {
            generator.writeStartObject();
            generator.writeStringField("id", record.id());
            generator.writeStringField("timestamp", record.timestamp().toString());

            writeOptionalSeconds(generator, "duration", unwrap(record.durationSeconds()));
            writeOptionalString(generator, "peerAddress", unwrap(record.peerAddress()));
            writeOptionalInteger(generator, "peerPort", unwrap(record.peerPort()));
            writeOptionalString(generator, "localAddress", unwrap(record.localAddress()));
            writeOptionalInteger(generator, "localPort", unwrap(record.localPort()));

            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());
            String sslCipherSuite = unwrap(record.sslCipherSuite());
            String sslPeerSubject = unwrap(record.sslPeerSubject());
            Instant sslPeerNotBefore = unwrap(record.sslPeerNotBefore());
            Instant sslPeerNotAfter = unwrap(record.sslPeerNotAfter());
            String sslSniServerName = unwrap(record.sslSniServerName());
            String sslPeerIssuerSubject = unwrap(record.sslPeerIssuerSubject());
            String sslPeerFingerprint = unwrap(record.sslPeerFingerprint());
            Long sslBytesReceived = unwrap(record.sslBytesReceived());
            Long sslBytesSent = unwrap(record.sslBytesSent());
            ConnectionLogEntry.SslHandshakeFailure sslHandshakeFailure = unwrap(record.sslHandshakeFailure());
            List<String> sslSubjectAlternativeNames = record.sslSubjectAlternativeNames();

            if (isAnyValuePresent(
                    sslProtocol, sslSessionId, sslCipherSuite, sslPeerSubject, sslPeerNotBefore, sslPeerNotAfter,
                    sslSniServerName, sslHandshakeFailure, sslPeerIssuerSubject, sslPeerFingerprint,
                    sslBytesReceived, sslBytesSent)) {
                generator.writeObjectFieldStart("ssl");

                writeOptionalString(generator, "protocol", sslProtocol);
                writeOptionalString(generator, "sessionId", sslSessionId);
                writeOptionalString(generator, "cipherSuite", sslCipherSuite);
                writeOptionalString(generator, "peerSubject", sslPeerSubject);
                writeOptionalString(generator, "peerIssuerSubject", sslPeerIssuerSubject);
                writeOptionalTimestamp(generator, "peerNotBefore", sslPeerNotBefore);
                writeOptionalTimestamp(generator, "peerNotAfter", sslPeerNotAfter);
                writeOptionalString(generator, "peerFingerprint", sslPeerFingerprint);
                writeOptionalString(generator, "sniServerName", sslSniServerName);
                writeOptionalLong(generator, "bytesReceived", sslBytesReceived);
                writeOptionalLong(generator, "bytesSent", sslBytesSent);

                if (sslHandshakeFailure != null) {
                    generator.writeObjectFieldStart("handshake-failure");
                    generator.writeArrayFieldStart("exception");
                    for (ExceptionEntry entry : sslHandshakeFailure.exceptionChain()) {
                        generator.writeStartObject();
                        generator.writeStringField("cause", entry.name());
                        generator.writeStringField("message", entry.message());
                        generator.writeEndObject();
                    }
                    generator.writeEndArray();
                    generator.writeStringField("type", sslHandshakeFailure.type());
                    generator.writeEndObject();
                }
                if (!sslSubjectAlternativeNames.isEmpty()) {
                    generator.writeArrayFieldStart("san");
                    for (String sanEntry : sslSubjectAlternativeNames) {
                        generator.writeString(sanEntry);
                    }
                    generator.writeEndArray();
                }
                generator.writeEndObject();
            }
        }
    }
@Test
     void test_serialization() throws IOException {
        var id = UUID.randomUUID();
        var instant = Instant.parse("2021-01-13T12:12:12Z");
        ConnectionLogEntry entry = ConnectionLogEntry.builder(id, instant)
                .withPeerPort(1234)
                .withSslHandshakeFailure(new ConnectionLogEntry.SslHandshakeFailure("UNKNOWN",
                        List.of(
                                new ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry("javax.net.ssl.SSLHandshakeException", "message"),
                                new ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry("java.io.IOException", "cause message"))))
                .withSslSubjectAlternativeNames(List.of("sandns", "sanemail"))
                .build();
        String expectedJson = "{" +
                "\"id\":\""+id.toString()+"\"," +
                "\"timestamp\":\"2021-01-13T12:12:12Z\"," +
                "\"peerPort\":1234," +
                "\"ssl\":{\"handshake-failure\":{\"exception\":[" +
                "{\"cause\":\"javax.net.ssl.SSLHandshakeException\",\"message\":\"message\"}," +
                "{\"cause\":\"java.io.IOException\",\"message\":\"cause message\"}" +
                "],\"type\":\"UNKNOWN\"},\"san\":[\"sandns\",\"sanemail\"]}}";

        JsonConnectionLogWriter writer = new JsonConnectionLogWriter();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        writer.write(entry, out);
        String actualJson = out.toString(StandardCharsets.UTF_8);
        JsonTestHelper.assertJsonEquals(actualJson, expectedJson);
    }