diff --git a/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java b/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java index 34d6ba89..50a8fa30 100644 --- a/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java +++ b/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java @@ -87,7 +87,9 @@ ResponseEntity bigResponse() throws IOException { generator.writeStartObject(); generator.writeStringProperty("start", "here"); - generator.writeStringProperty("longValue", generateLongString(192*1024)); + for(int i = 0; i < 10; i++) { + generator.writeStringProperty("longValue" + i, generateLongString(25*1024)); + } generator.writeStringProperty("end", "here"); generator.writeEndObject(); diff --git a/examples/gcp-web-without-test-artifacts-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java b/examples/gcp-web-without-test-artifacts-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java index 7726710c..82888fac 100644 --- a/examples/gcp-web-without-test-artifacts-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java +++ b/examples/gcp-web-without-test-artifacts-example/src/main/java/org/entur/example/web/rest/DocumentEndpoint.java @@ -4,10 +4,10 @@ import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.io.CharArrayWriter; +import java.io.IOException; @RestController @RequestMapping("/api/document") @@ -46,5 +46,36 @@ public ResponseEntity errorMethod(@RequestBody MyEntity entity) throws Interrupt } + @GetMapping(value = "/some/bigResponse", produces = "application/json") + ResponseEntity bigResponse() throws IOException { + tools.jackson.core.json.JsonFactory factory = new tools.jackson.core.json.JsonFactory(); + + CharArrayWriter writer = new CharArrayWriter(); + + try (tools.jackson.core.JsonGenerator generator = factory.createGenerator(writer)) { + generator.writeStartObject(); + generator.writeStringProperty("start", "here"); + for(int i = 0; i < 10; i++) { + generator.writeStringProperty("longValue" + i, generateLongString(25*1024)); + } + generator.writeStringProperty("longValue", generateLongString(192*1024)); + generator.writeStringProperty("end", "here"); + generator.writeEndObject(); + } + return new ResponseEntity<>(writer.toString(), HttpStatus.OK); + } + + private String generateLongString(int length) { + StringBuilder builder = new StringBuilder(length); + + int mod = 'z' - 'a'; + + for(int i = 0; i < length; i++) { + char c = (char) ('a' + i % mod); + builder.append(c); + } + return builder.toString(); + } + } \ No newline at end of file diff --git a/examples/gcp-web-without-test-artifacts-example/src/test/java/org/entur/example/web/WebLoggingFormatWithBigResponsesTest.java b/examples/gcp-web-without-test-artifacts-example/src/test/java/org/entur/example/web/WebLoggingFormatWithBigResponsesTest.java new file mode 100644 index 00000000..c5511f8f --- /dev/null +++ b/examples/gcp-web-without-test-artifacts-example/src/test/java/org/entur/example/web/WebLoggingFormatWithBigResponsesTest.java @@ -0,0 +1,27 @@ +package org.entur.example.web; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.resttestclient.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static com.google.common.truth.Truth.assertThat; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@AutoConfigureTestRestTemplate +public class WebLoggingFormatWithBigResponsesTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void useHumanReadablePlainEncoderTest() { + ResponseEntity response = restTemplate.getForEntity("/api/document/some/bigResponse", String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + +} \ No newline at end of file diff --git a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingLogLevelLogstashLogbackSink.java b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingLogLevelLogstashLogbackSink.java index e933c924..92b79480 100644 --- a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingLogLevelLogstashLogbackSink.java +++ b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingLogLevelLogstashLogbackSink.java @@ -1,10 +1,6 @@ package no.entur.logging.cloud.logbook.logbook.test; -import no.entur.logging.cloud.logbook.AbstractLogLevelLogstashLogbackSink; -import no.entur.logging.cloud.logbook.AbstractSinkBuilder; -import no.entur.logging.cloud.logbook.DefaultRemoteHttpMessageContextSupplier; -import no.entur.logging.cloud.logbook.MessageComposer; -import no.entur.logging.cloud.logbook.RemoteHttpMessageContextSupplier; +import no.entur.logging.cloud.logbook.*; import org.slf4j.Marker; import org.zalando.logbook.HttpRequest; import org.zalando.logbook.HttpResponse; @@ -60,14 +56,14 @@ public PrettyPrintingLogLevelLogstashLogbackSink(BiConsumer logC } @Override - protected Marker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed) { - return new PrettyPrintingRequestSingleFieldAppendingMarker(request, body, wellformed); + protected RequestResponseSingleFieldAppendingMarker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed, int truncated) { + return new PrettyPrintingRequestSingleFieldAppendingMarker(request, body, wellformed, truncated); } @Override - protected Marker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, - boolean wellformed) { - return new PrettyPrintingResponseSingleFieldAppendingMarker(response, duration, body, wellformed); + protected RequestResponseSingleFieldAppendingMarker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, + boolean wellformed, int truncated) { + return new PrettyPrintingResponseSingleFieldAppendingMarker(response, duration, body, wellformed, truncated); } } diff --git a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingRequestSingleFieldAppendingMarker.java b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingRequestSingleFieldAppendingMarker.java index bbcb8788..96a0fa84 100644 --- a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingRequestSingleFieldAppendingMarker.java +++ b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingRequestSingleFieldAppendingMarker.java @@ -9,8 +9,8 @@ public class PrettyPrintingRequestSingleFieldAppendingMarker extends RequestSingleFieldAppendingMarker { - public PrettyPrintingRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed) { - super(request, body, wellformed); + public PrettyPrintingRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed, int truncated) { + super(request, body, wellformed, truncated); } @Override diff --git a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingResponseSingleFieldAppendingMarker.java b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingResponseSingleFieldAppendingMarker.java index a7e13f24..2aaa65b9 100644 --- a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingResponseSingleFieldAppendingMarker.java +++ b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingResponseSingleFieldAppendingMarker.java @@ -14,8 +14,8 @@ public class PrettyPrintingResponseSingleFieldAppendingMarker extends ResponseSingleFieldAppendingMarker { - public PrettyPrintingResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed) { - super(response, duration, body, wellformed); + public PrettyPrintingResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed, int truncated) { + super(response, duration, body, wellformed, truncated); } @Override diff --git a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingSink.java b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingSink.java index 033fce02..52a67192 100644 --- a/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingSink.java +++ b/request-response/logbook-test/src/main/java/no/entur/logging/cloud/logbook/logbook/test/PrettyPrintingSink.java @@ -84,8 +84,8 @@ public PrettyPrintingSink(BooleanSupplier logLevelEnabled, BiConsumer 0) { if (request.getOrigin() == Origin.LOCAL) { // trust our own data to be wellformed - if (body.length > maxBodySize) { + if (body.length <= maxBodySize) { writer = new PrettyPrintingLocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; + writer = new PrettyPrintingLocalMaxSizeHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } else { HttpMessageStateSupplier httpMessageStateSupplier = requestHttpMessageStateSupplierSource.get(); - if (body.length > maxBodySize) { - writer = new PrettyPrintingRemoteHttpMessageBodyWriter(jsonMapper, body, - httpMessageStateSupplier); + if (body.length <= maxBodySize) { + writer = new PrettyPrintingRemoteHttpMessageBodyWriter(jsonMapper, body, httpMessageStateSupplier); } else { - writer = new PrettyPrintingRemoteMaxSizeHttpMessageBodyWriter(jsonMapper, body, maxSize, + truncated = body.length - maxBodySize; + + writer = new PrettyPrintingRemoteMaxSizeHttpMessageBodyWriter(jsonMapper, body, maxBodySize, httpMessageStateSupplier); } } @@ -112,8 +113,10 @@ public Marker createRequestMarker(HttpRequest request) { String bodyAsString = request.getBodyAsString(); if (bodyAsString != null && bodyAsString.length() > 0) { if (bodyAsString.length() > maxBodySize) { - String truncated = bodyAsString.substring(0, maxBodySize); - writer = new StringHttpMessageBodyWriter(truncated); + truncated = bodyAsString.length() - maxBodySize; + + String truncatedString = bodyAsString.substring(0, maxBodySize); + writer = new StringHttpMessageBodyWriter(truncatedString); } else { writer = new StringHttpMessageBodyWriter(bodyAsString); } @@ -123,32 +126,37 @@ public Marker createRequestMarker(HttpRequest request) { } } - return new RequestOndemandSingleFieldAppendingMarker(request, writer); + return new RequestOndemandSingleFieldAppendingMarker(request, writer, truncated); } - public Marker createResponseMarker(Correlation correlation, HttpResponse response) { + public RequestResponseSingleFieldAppendingMarker createResponseMarker(Correlation correlation, HttpResponse response) { HttpMessageBodyWriter writer = EmptyHttpMessageBodyWriter.INSTANCE; + int truncated = -1; if (ContentType.isJsonMediaType(response.getContentType())) { try { byte[] body = response.getBody(); if (body != null && body.length > 0) { if (response.getOrigin() == Origin.LOCAL) { // trust our own data to be wellformed - if (body.length > maxBodySize) { + if (body.length <= maxBodySize) { writer = new PrettyPrintingLocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; + writer = new PrettyPrintingLocalMaxSizeHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } else { HttpMessageStateSupplier httpMessageStateSupplier = responseHttpMessageStateSupplierSource .get(); - if (body.length > maxBodySize) { + if (body.length <= maxBodySize) { writer = new PrettyPrintingRemoteHttpMessageBodyWriter(jsonMapper, body, httpMessageStateSupplier); } else { + truncated = body.length - maxBodySize; + writer = new PrettyPrintingRemoteMaxSizeHttpMessageBodyWriter(jsonMapper, body, maxSize, httpMessageStateSupplier); } @@ -163,8 +171,10 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons String bodyAsString = response.getBodyAsString(); if (bodyAsString != null && bodyAsString.length() > 0) { if (bodyAsString.length() > maxBodySize) { - String truncated = bodyAsString.substring(0, maxBodySize); - writer = new StringHttpMessageBodyWriter(truncated); + truncated = bodyAsString.length() - maxBodySize; + + String truncatedString = bodyAsString.substring(0, maxBodySize); + writer = new StringHttpMessageBodyWriter(truncatedString); } else { writer = new StringHttpMessageBodyWriter(bodyAsString); } @@ -174,7 +184,7 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons } } - return new ResponseOndemandSingleFieldAppendingMarker(response, correlation.getDuration(), writer); + return new ResponseOndemandSingleFieldAppendingMarker(response, correlation.getDuration(), writer, truncated); } } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSink.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSink.java index 50b253ae..c0f27f5a 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSink.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSink.java @@ -35,43 +35,46 @@ public AbstractLogLevelLogstashLogbackSink(BiConsumer logConsume this.remoteHttpMessageContextSupplier = remoteHttpMessageContextSupplier; } - public Marker createRequestMarker(HttpRequest request) { + public RequestResponseSingleFieldAppendingMarker createRequestMarker(HttpRequest request) { String contentType = request.getContentType(); boolean isJson = ContentType.isJsonMediaType(contentType); boolean isXml = isXmlMediaType(contentType); if (!isJson && !isXml) { - return newRequestSingleFieldAppendingMarker(request, null, false); + return newRequestSingleFieldAppendingMarker(request, null, false, -1); } String bodyAsString; try { bodyAsString = request.getBodyAsString(); } catch (Exception e) { - return newRequestSingleFieldAppendingMarker(request, null, false); + return newRequestSingleFieldAppendingMarker(request, null, false, -1); } if (bodyAsString == null || bodyAsString.length() == 0) { - return newRequestSingleFieldAppendingMarker(request, null, false); + return newRequestSingleFieldAppendingMarker(request, null, false, -1); } // add sanity check for JSON content, even if mimetype does match if (!isJson || !smellsLikeJson(bodyAsString)) { if (bodyAsString.length() > maxSize) { // TODO add filter + int truncated = bodyAsString.length() - maxSize; String truncatedBody = bodyAsString.substring(0, maxSize); - return newRequestSingleFieldAppendingMarker(request, truncatedBody, false); + return newRequestSingleFieldAppendingMarker(request, truncatedBody, false, truncated); } - return newRequestSingleFieldAppendingMarker(request, bodyAsString, false); + return newRequestSingleFieldAppendingMarker(request, bodyAsString, false, -1); } String body; boolean wellformed; + int truncated = -1; if (request.getOrigin() == Origin.LOCAL) { // trust data from ourselves to be wellformed and not pretty-printed if (bodyAsString.length() > maxSize) { + truncated = bodyAsString.length() - maxSize; try { body = maxSizeJsonFilter.transform(bodyAsString); wellformed = true; @@ -87,6 +90,7 @@ public Marker createRequestMarker(HttpRequest request) { } else { // do not trust data from others to be wellformed if (bodyAsString.length() > maxSize) { + truncated = bodyAsString.length() - maxSize; try { body = maxSizeJsonFilter.transform(bodyAsString); wellformed = true; @@ -105,51 +109,55 @@ public Marker createRequestMarker(HttpRequest request) { } } } - return newRequestSingleFieldAppendingMarker(request, body, wellformed); + return newRequestSingleFieldAppendingMarker(request, body, wellformed, truncated); } - protected abstract Marker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, - boolean wellformed); + protected abstract RequestResponseSingleFieldAppendingMarker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, + boolean wellformed, int truncated); - public Marker createResponseMarker(Correlation correlation, HttpResponse response) { + public RequestResponseSingleFieldAppendingMarker createResponseMarker(Correlation correlation, HttpResponse response) { String contentType = response.getContentType(); boolean isJson = ContentType.isJsonMediaType(contentType); boolean isXml = isXmlMediaType(contentType); if (!isJson && !isXml) { - return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false); + return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false, -1); } String bodyAsString; try { bodyAsString = response.getBodyAsString(); } catch (Exception e) { - return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false); + return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false, -1); } if (bodyAsString == null || bodyAsString.length() == 0) { - return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false); + return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), null, false, -1); } // add sanity check for JSON content, even if mimetype does match if (!isJson || !smellsLikeJson(bodyAsString)) { if(bodyAsString.length() > maxSize) { // TODO add filter + int truncated = bodyAsString.length() - maxSize; + String truncatedBody = bodyAsString.substring(0, maxSize); return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), - truncatedBody, false); + truncatedBody, false, truncated); } return new ResponseSingleFieldAppendingMarker(response, correlation.getDuration(), bodyAsString, - false); + false, -1); } String body; boolean wellformed; + int truncated = -1; if (response.getOrigin() == Origin.LOCAL) { // trust data from ourselves to be wellformed if (bodyAsString.length() > maxSize) { + truncated = bodyAsString.length() - maxSize; try { body = maxSizeJsonFilter.transform(bodyAsString); wellformed = true; @@ -165,6 +173,7 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons } else { // do not trust data from others to be wellformed if (bodyAsString.length() > maxSize) { + truncated = bodyAsString.length() - maxSize; try { body = maxSizeJsonFilter.transform(bodyAsString); wellformed = true; @@ -183,11 +192,11 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons } } } - return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), body, wellformed); + return newResponseSingleFieldAppendingMarker(response, correlation.getDuration(), body, wellformed, truncated); } - protected abstract Marker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, - boolean wellformed); + protected abstract RequestResponseSingleFieldAppendingMarker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, + boolean wellformed, int truncated); /** * diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelSink.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelSink.java index 9c5d2ffc..59d534d0 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelSink.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractLogLevelSink.java @@ -54,43 +54,43 @@ public boolean isActive() { return logLevelEnabled.getAsBoolean(); } - protected void requestMessage(HttpRequest request, StringBuilder messageBuilder) throws IOException { + protected void requestMessage(HttpRequest request, StringBuilder messageBuilder, int truncated) throws IOException { if (request.getOrigin() == Origin.LOCAL) { - client.requestMessage(request, messageBuilder); + client.requestMessage(request, messageBuilder, truncated); } else { - server.requestMessage(request, messageBuilder); + server.requestMessage(request, messageBuilder, truncated); } } protected void responseMessage(Correlation correlation, HttpRequest request, HttpResponse response, - StringBuilder messageBuilder) throws IOException { + StringBuilder messageBuilder, int truncated) throws IOException { if (request.getOrigin() == Origin.LOCAL) { - client.responseMessage(correlation, request, response, messageBuilder); + client.responseMessage(correlation, request, response, messageBuilder, truncated); } else { - server.responseMessage(correlation, request, response, messageBuilder); + server.responseMessage(correlation, request, response, messageBuilder, truncated); } } @Override public void write(final Precorrelation precorrelation, final HttpRequest request) throws IOException { - Marker marker = createRequestMarker(request); + RequestResponseSingleFieldAppendingMarker marker = createRequestMarker(request); StringBuilder stringBuilder = new StringBuilder(256); - requestMessage(request, stringBuilder); + requestMessage(request, stringBuilder, marker != null ? marker.getTruncated() : -1); logConsumer.accept(marker, stringBuilder.toString()); } public void write(Correlation correlation, final HttpRequest request, HttpResponse response) throws IOException { - Marker marker = createResponseMarker(correlation, response); + RequestResponseSingleFieldAppendingMarker marker = createResponseMarker(correlation, response); StringBuilder stringBuilder = new StringBuilder(256); - responseMessage(correlation, request, response, stringBuilder); + responseMessage(correlation, request, response, stringBuilder, marker != null ? marker.getTruncated() : -1); logConsumer.accept(marker, stringBuilder.toString()); } - protected Marker createResponseMarker(Correlation correlation, HttpResponse response) { + protected RequestResponseSingleFieldAppendingMarker createResponseMarker(Correlation correlation, HttpResponse response) { return null; } - protected Marker createRequestMarker(HttpRequest request) { + protected RequestResponseSingleFieldAppendingMarker createRequestMarker(HttpRequest request) { return null; } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractSingleFieldAppendingMarker.java index 9e3a1338..c8a59c1a 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/AbstractSingleFieldAppendingMarker.java @@ -9,15 +9,15 @@ import java.util.List; import java.util.Map; -public abstract class AbstractSingleFieldAppendingMarker extends SingleFieldAppendingMarker { +public abstract class AbstractSingleFieldAppendingMarker extends RequestResponseSingleFieldAppendingMarker { protected String contentType; protected Map> headers; protected String body; protected boolean wellformed; - public AbstractSingleFieldAppendingMarker(String markerName, T message, String body, boolean wellformed) { - super(markerName, "http"); + public AbstractSingleFieldAppendingMarker(String markerName, T message, String body, boolean wellformed, int truncated) { + super(markerName, "http", truncated); this.body = body; this.wellformed = wellformed; diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/LogLevelLogstashLogbackSink.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/LogLevelLogstashLogbackSink.java index aa351806..ca9a4e15 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/LogLevelLogstashLogbackSink.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/LogLevelLogstashLogbackSink.java @@ -61,14 +61,14 @@ public LogLevelLogstashLogbackSink build() { } @Override - protected Marker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed) { - return new RequestSingleFieldAppendingMarker(request, body, wellformed); + protected RequestResponseSingleFieldAppendingMarker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed, int truncated) { + return new RequestSingleFieldAppendingMarker(request, body, wellformed, truncated); } @Override - protected Marker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, - boolean wellformed) { - return new ResponseSingleFieldAppendingMarker(response, duration, body, wellformed); + protected RequestResponseSingleFieldAppendingMarker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, + boolean wellformed, int truncated) { + return new ResponseSingleFieldAppendingMarker(response, duration, body, wellformed, truncated); } } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/MessageComposer.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/MessageComposer.java index a1ac3e5e..4d3baa47 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/MessageComposer.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/MessageComposer.java @@ -72,17 +72,32 @@ protected void constructMessage(HttpRequest request, StringBuilder messageBuilde } } - public void requestMessage(HttpRequest request, StringBuilder messageBuilder) throws IOException { + public void requestMessage(HttpRequest request, StringBuilder messageBuilder, int truncated) throws IOException { String method = request.getMethod(); if(method != null) { messageBuilder.append(method); messageBuilder.append(' '); } constructMessage(request, messageBuilder); + + if(truncated != -1) { + writeTruncated(messageBuilder, truncated); + } + } + + private static void writeTruncated(StringBuilder messageBuilder, int truncated) { + messageBuilder.append(" [truncated ~"); + if(truncated <= 1024) { + messageBuilder.append(truncated); + messageBuilder.append(" bytes]"); + } else { + messageBuilder.append(truncated / 1024); + messageBuilder.append("KB]"); + } } public void responseMessage(Correlation correlation, HttpRequest request, HttpResponse response, - StringBuilder messageBuilder) throws IOException { + StringBuilder messageBuilder, int truncated) throws IOException { messageBuilder.append(response.getStatus()); String reasonPhrase = response.getReasonPhrase(); @@ -99,5 +114,10 @@ public void responseMessage(Correlation correlation, HttpRequest request, HttpRe messageBuilder.append(duration.toMillis()); messageBuilder.append(" ms)"); } + + if(truncated != -1) { + writeTruncated(messageBuilder, truncated); + } + } } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestResponseSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestResponseSingleFieldAppendingMarker.java new file mode 100644 index 00000000..7b5e60fd --- /dev/null +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestResponseSingleFieldAppendingMarker.java @@ -0,0 +1,27 @@ +package no.entur.logging.cloud.logbook; + +import net.logstash.logback.marker.SingleFieldAppendingMarker; + +public abstract class RequestResponseSingleFieldAppendingMarker extends SingleFieldAppendingMarker { + + protected final int truncated; + + public RequestResponseSingleFieldAppendingMarker(String markerName, String fieldName, int truncated) { + super(markerName, fieldName); + this.truncated = truncated; + } + + public boolean isTruncated() { + return truncated != -1; + } + + /** + * Number of bytes or chars which were truncated + * + * @return count + */ + + public int getTruncated() { + return truncated; + } +} diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestSingleFieldAppendingMarker.java index 5b3c5548..d1bebd11 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/RequestSingleFieldAppendingMarker.java @@ -22,8 +22,8 @@ public class RequestSingleFieldAppendingMarker extends AbstractSingleFieldAppend protected String scheme; protected Optional port; - public RequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed) { - super(MARKER_NAME, request, body, wellformed); + public RequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed, int truncated) { + super(MARKER_NAME, request, body, wellformed, truncated); } @Override diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ResponseSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ResponseSingleFieldAppendingMarker.java index 4f9ff5b6..14d106e3 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ResponseSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ResponseSingleFieldAppendingMarker.java @@ -17,8 +17,8 @@ public class ResponseSingleFieldAppendingMarker extends AbstractSingleFieldAppen private String protocol; private int status; - public ResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed) { - super(MARKER_NAME, response, body, wellformed); + public ResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed, int truncated) { + super(MARKER_NAME, response, body, wellformed, truncated); this.duration = duration; } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/AbstractOndemandSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/AbstractOndemandSingleFieldAppendingMarker.java index 9fc77373..7e19fe2a 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/AbstractOndemandSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/AbstractOndemandSingleFieldAppendingMarker.java @@ -1,5 +1,6 @@ package no.entur.logging.cloud.logbook.ondemand; +import no.entur.logging.cloud.logbook.RequestResponseSingleFieldAppendingMarker; import tools.jackson.core.JsonGenerator; import net.logstash.logback.marker.SingleFieldAppendingMarker; import no.entur.logging.cloud.appender.scope.LoggingScopePostProcessing; @@ -10,7 +11,7 @@ import java.util.List; import java.util.Map; -public abstract class AbstractOndemandSingleFieldAppendingMarker extends SingleFieldAppendingMarker implements LoggingScopePostProcessing { +public abstract class AbstractOndemandSingleFieldAppendingMarker extends RequestResponseSingleFieldAppendingMarker implements LoggingScopePostProcessing { protected String contentType; protected Map> headers; @@ -18,8 +19,8 @@ public abstract class AbstractOndemandSingleFieldAppendingMarker logConsume client); } - public Marker createRequestMarker(HttpRequest request) { + public RequestResponseSingleFieldAppendingMarker createRequestMarker(HttpRequest request) { HttpMessageBodyWriter writer = EmptyHttpMessageBodyWriter.INSTANCE; + int truncated = -1; if (ContentType.isJsonMediaType(request.getContentType())) { try { byte[] body = request.getBody(); if (body != null && body.length > 0) { if (request.getOrigin() == Origin.LOCAL) { // trust our own data to be wellformed and not pretty-printed - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new LocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; writer = new MaxSizeLocalHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } else { @@ -85,17 +82,19 @@ public Marker createRequestMarker(HttpRequest request) { if (verify) { HttpMessageStateSupplier httpMessageStateSupplier = requestHttpMessageStateSupplierSource .get(); - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new RemoteHttpMessageBodyWriter(jsonMapper, body, httpMessageStateSupplier); } else { + truncated = body.length - maxBodySize; writer = new MaxSizeRemoteHttpMessageBodyWriter(jsonMapper, body, maxSize, httpMessageStateSupplier); } } else { // trust contents is well formed - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new LocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; writer = new MaxSizeLocalHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } @@ -109,8 +108,10 @@ public Marker createRequestMarker(HttpRequest request) { String bodyAsString = request.getBodyAsString(); if (bodyAsString != null && bodyAsString.length() > 0) { if (bodyAsString.length() > maxBodySize) { - String truncated = bodyAsString.substring(0, maxBodySize); - writer = new StringHttpMessageBodyWriter(truncated); + truncated = bodyAsString.length() - maxBodySize; + + String truncatedString = bodyAsString.substring(0, maxBodySize); + writer = new StringHttpMessageBodyWriter(truncatedString); } else { writer = new StringHttpMessageBodyWriter(bodyAsString); } @@ -120,22 +121,24 @@ public Marker createRequestMarker(HttpRequest request) { } } - return new RequestOndemandSingleFieldAppendingMarker(request, writer); + return new RequestOndemandSingleFieldAppendingMarker(request, writer, truncated); } - public Marker createResponseMarker(Correlation correlation, HttpResponse response) { + public RequestResponseSingleFieldAppendingMarker createResponseMarker(Correlation correlation, HttpResponse response) { HttpMessageBodyWriter writer = EmptyHttpMessageBodyWriter.INSTANCE; + int truncated = -1; if (ContentType.isJsonMediaType(response.getContentType())) { try { byte[] body = response.getBody(); if (body != null && body.length > 0) { if (response.getOrigin() == Origin.LOCAL) { // trust our own data to be wellformed and not pretty-printed - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new LocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; writer = new MaxSizeLocalHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } else { @@ -143,17 +146,19 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons if (verify) { HttpMessageStateSupplier httpMessageStateSupplier = responseHttpMessageStateSupplierSource .get(); - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new RemoteHttpMessageBodyWriter(jsonMapper, body, httpMessageStateSupplier); } else { - writer = new MaxSizeRemoteHttpMessageBodyWriter(jsonMapper, body, maxSize, + truncated = body.length - maxBodySize; + writer = new MaxSizeRemoteHttpMessageBodyWriter(jsonMapper, body, maxBodySize, httpMessageStateSupplier); } } else { // trust contents is well formed - if (body.length < maxBodySize) { + if (body.length <= maxBodySize) { writer = new LocalHttpMessageBodyWriter(body); } else { + truncated = body.length - maxBodySize; writer = new MaxSizeLocalHttpMessageBodyWriter(jsonMapper, body, maxBodySize); } } @@ -167,8 +172,10 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons String bodyAsString = response.getBodyAsString(); if (bodyAsString != null && bodyAsString.length() > 0) { if (bodyAsString.length() > maxBodySize) { - String truncated = bodyAsString.substring(0, maxBodySize); - writer = new StringHttpMessageBodyWriter(truncated); + truncated = bodyAsString.length() - maxBodySize; + + String truncatedString = bodyAsString.substring(0, maxBodySize); + writer = new StringHttpMessageBodyWriter(truncatedString); } else { writer = new StringHttpMessageBodyWriter(bodyAsString); } @@ -178,7 +185,7 @@ public Marker createResponseMarker(Correlation correlation, HttpResponse respons } } - return new ResponseOndemandSingleFieldAppendingMarker(response, correlation.getDuration(), writer); + return new ResponseOndemandSingleFieldAppendingMarker(response, correlation.getDuration(), writer, truncated); } } diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/RequestOndemandSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/RequestOndemandSingleFieldAppendingMarker.java index 5112cfb1..6017c671 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/RequestOndemandSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/RequestOndemandSingleFieldAppendingMarker.java @@ -23,8 +23,8 @@ public class RequestOndemandSingleFieldAppendingMarker extends AbstractOndemandS protected String scheme; protected Optional port; - public RequestOndemandSingleFieldAppendingMarker(HttpRequest request, HttpMessageBodyWriter httpMessageBodyWriter) { - super(MARKER_NAME, request, httpMessageBodyWriter); + public RequestOndemandSingleFieldAppendingMarker(HttpRequest request, HttpMessageBodyWriter httpMessageBodyWriter, int truncated) { + super(MARKER_NAME, request, httpMessageBodyWriter, truncated); } @Override diff --git a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/ResponseOndemandSingleFieldAppendingMarker.java b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/ResponseOndemandSingleFieldAppendingMarker.java index 5e22ea5a..501db80a 100644 --- a/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/ResponseOndemandSingleFieldAppendingMarker.java +++ b/request-response/logbook/src/main/java/no/entur/logging/cloud/logbook/ondemand/ResponseOndemandSingleFieldAppendingMarker.java @@ -5,7 +5,6 @@ import org.zalando.logbook.HttpResponse; import org.zalando.logbook.Origin; -import java.io.IOException; import java.time.Duration; import java.util.Locale; @@ -18,8 +17,8 @@ public class ResponseOndemandSingleFieldAppendingMarker extends AbstractOndemand private String protocol; private int status; - public ResponseOndemandSingleFieldAppendingMarker(HttpResponse response, Duration duration, HttpMessageBodyWriter httpMessageBodyWriter) { - super(MARKER_NAME, response, httpMessageBodyWriter); + public ResponseOndemandSingleFieldAppendingMarker(HttpResponse response, Duration duration, HttpMessageBodyWriter httpMessageBodyWriter, int truncated) { + super(MARKER_NAME, response, httpMessageBodyWriter, truncated); this.duration = duration; } diff --git a/request-response/logbook/src/test/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSinkTest.java b/request-response/logbook/src/test/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSinkTest.java index dbdd8b41..f7800442 100644 --- a/request-response/logbook/src/test/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSinkTest.java +++ b/request-response/logbook/src/test/java/no/entur/logging/cloud/logbook/AbstractLogLevelLogstashLogbackSinkTest.java @@ -26,13 +26,13 @@ public MockLogLevelLogstashLogbackSink(BiConsumer logConsumer, B } @Override - protected Marker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed) { - return mock(Marker.class); + protected RequestResponseSingleFieldAppendingMarker newRequestSingleFieldAppendingMarker(HttpRequest request, String body, boolean wellformed, int truncated) { + return mock(RequestResponseSingleFieldAppendingMarker.class); } @Override - protected Marker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed) { - return mock(Marker.class); + protected RequestResponseSingleFieldAppendingMarker newResponseSingleFieldAppendingMarker(HttpResponse response, Duration duration, String body, boolean wellformed, int truncated) { + return mock(RequestResponseSingleFieldAppendingMarker.class); } } @@ -58,7 +58,7 @@ public void testDoesNotPrintUnknownMimetypes() { when(request.getContentType()).thenReturn("application/unknown"); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(request, null, false); + verify(spy).newRequestSingleFieldAppendingMarker(request, null, false, -1); } @Test @@ -73,7 +73,7 @@ public void testPrintsRemoteJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.REMOTE); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true), eq(-1)); } @Test @@ -88,7 +88,7 @@ public void testPrintsRemoteInvalidJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.REMOTE); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(false)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(false), eq(-1)); } @Test @@ -103,7 +103,7 @@ public void testPrintsLocalJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.LOCAL); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true), eq(-1)); } @Test @@ -125,7 +125,7 @@ public void testPrintsTooLargeLocalJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.LOCAL); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), anyString(), eq(true), eq(1026)); } @Test @@ -147,7 +147,7 @@ public void testPrintsTooLargeRemoteJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.REMOTE); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), eq("{\"Logger\":\"Max body size of 1024 reached, rest of the document has been filtered.\"}"), eq(true)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), eq("{\"Logger\":\"Max body size of 1024 reached, rest of the document has been filtered.\"}"), eq(true), eq(1026)); } @Test @@ -169,7 +169,7 @@ public void testPrintsTooLargeRemoteInvalidJsonMimetype() throws IOException { when(request.getOrigin()).thenReturn(Origin.REMOTE); spy.createRequestMarker(request); - verify(spy).newRequestSingleFieldAppendingMarker(eq(request), eq(json.substring(0, 1024)), eq(false)); + verify(spy).newRequestSingleFieldAppendingMarker(eq(request), eq(json.substring(0, 1024)), eq(false), eq(1026)); } private MockLogLevelLogstashLogbackSink createSink() {