This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-tracer.git
commit be4ea09c5d70891c32cd447054bceb6d441b9df0 Author: Chetan Mehrotra <[email protected]> AuthorDate: Wed Feb 10 09:59:39 2016 +0000 SLING-5504 - Reduce memory footprint of stored recording data Support sending of gzip response if the client supports that. This would avoid deflating the in memory compressed json data git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1729569 13f79535-47bb-0310-9956-ffa450edef68 --- .../sling/tracer/internal/JSONRecording.java | 16 ++++++--- .../apache/sling/tracer/internal/LogTracer.java | 16 +++++++-- .../sling/tracer/internal/TracerLogServlet.java | 40 ++++++++++++++++++++-- .../sling/tracer/internal/LogTracerTest.java | 35 +++++++++++++++---- .../tracer/internal/TracerLogServletTest.java | 32 +++++++++++++++++ 5 files changed, 122 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java b/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java index e823a96..f8f785e 100644 --- a/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java +++ b/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java @@ -51,6 +51,8 @@ import org.slf4j.LoggerFactory; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MessageFormatter; +import static com.google.common.base.Preconditions.checkArgument; + class JSONRecording implements Recording, Comparable<JSONRecording> { private static final Logger log = LoggerFactory.getLogger(JSONRecording.class); private final String method; @@ -73,16 +75,16 @@ class JSONRecording implements Recording, Comparable<JSONRecording> { public boolean render(Writer w) throws IOException { if (json != null) { - Reader r = new InputStreamReader(getInputStream(), "UTF-8"); + Reader r = new InputStreamReader(getInputStream(false), "UTF-8"); IOUtils.copy(r, w); return true; } return false; } - public boolean render(OutputStream os) throws IOException { + public boolean render(OutputStream os, boolean compressed) throws IOException { if (json != null) { - IOUtils.copyLarge(getInputStream(), os); + IOUtils.copyLarge(getInputStream(compressed), os); return true; } return false; @@ -200,8 +202,14 @@ class JSONRecording implements Recording, Comparable<JSONRecording> { jw.endArray(); } - private InputStream getInputStream() throws IOException { + private InputStream getInputStream(boolean compressed) throws IOException { InputStream is = new ByteArrayInputStream(json); + + if (compressed) { + checkArgument(compress, "Cannot provide compressed response with compression disabled"); + return is; + } + if (compress) { is = new GZIPInputStream(is); } diff --git a/src/main/java/org/apache/sling/tracer/internal/LogTracer.java b/src/main/java/org/apache/sling/tracer/internal/LogTracer.java index 17993f1..3cb42d7 100644 --- a/src/main/java/org/apache/sling/tracer/internal/LogTracer.java +++ b/src/main/java/org/apache/sling/tracer/internal/LogTracer.java @@ -138,6 +138,13 @@ public class LogTracer { ) private static final String PROP_TRACER_SERVLET_COMPRESS = "recordingCompressionEnabled"; + static final boolean PROP_TRACER_SERVLET_GZIP_RESPONSE_DEFAULT = true; + @Property(label = "GZip Response", + description = "If enabled the response sent would be compressed", + boolValue = PROP_TRACER_SERVLET_GZIP_RESPONSE_DEFAULT + ) + private static final String PROP_TRACER_SERVLET_GZIP_RESPONSE = "gzipResponse"; + private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(LogTracer.class); private final Map<String, TracerSet> tracers = new HashMap<String, TracerSet>(); @@ -177,10 +184,13 @@ public class LogTracer { PROP_TRACER_SERVLET_CACHE_DURATION_DEFAULT); boolean compressionEnabled = PropertiesUtil.toBoolean(config.get(PROP_TRACER_SERVLET_COMPRESS), PROP_TRACER_SERVLET_COMPRESS_DEFAULT); - this.logServlet = new TracerLogServlet(context, cacheSize, cacheDuration, compressionEnabled); + boolean gzipResponse = PropertiesUtil.toBoolean(config.get(PROP_TRACER_SERVLET_GZIP_RESPONSE), + PROP_TRACER_SERVLET_GZIP_RESPONSE_DEFAULT); + + this.logServlet = new TracerLogServlet(context, cacheSize, cacheDuration, compressionEnabled, gzipResponse); recorder = logServlet; - LOG.info("Tracer recoding enabled with cacheSize {} MB, expiry {} secs, compression {}", - cacheSize, cacheDuration, compressionEnabled); + LOG.info("Tracer recoding enabled with cacheSize {} MB, expiry {} secs, compression {}, gzip response {}", + cacheSize, cacheDuration, compressionEnabled, gzipResponse); } LOG.info("Log tracer enabled. Required filters registered. Tracer servlet enabled {}", servletEnabled); } diff --git a/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java b/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java index 1e31013..b8081e5 100644 --- a/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java +++ b/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java @@ -66,19 +66,24 @@ class TracerLogServlet extends SimpleWebConsolePlugin implements TraceLogRecorde private final long cacheDurationInSecs; + private final boolean gzipResponse; + public TracerLogServlet(BundleContext context){ this(context, LogTracer.PROP_TRACER_SERVLET_CACHE_SIZE_DEFAULT, LogTracer.PROP_TRACER_SERVLET_CACHE_DURATION_DEFAULT, - LogTracer.PROP_TRACER_SERVLET_COMPRESS_DEFAULT + LogTracer.PROP_TRACER_SERVLET_COMPRESS_DEFAULT, + LogTracer.PROP_TRACER_SERVLET_GZIP_RESPONSE_DEFAULT ); } - public TracerLogServlet(BundleContext context, int cacheSizeInMB, long cacheDurationInSecs, boolean compressionEnabled) { + public TracerLogServlet(BundleContext context, int cacheSizeInMB, long cacheDurationInSecs, + boolean compressionEnabled, boolean gzipResponse) { super(LABEL, "Sling Tracer", "Sling", null); this.compressRecording = compressionEnabled; this.cacheDurationInSecs = cacheDurationInSecs; this.cacheSizeInMB = cacheSizeInMB; + this.gzipResponse = compressionEnabled && gzipResponse; this.cache = CacheBuilder.newBuilder() .maximumWeight(cacheSizeInMB * FileUtils.ONE_MB) .weigher(new Weigher<String, JSONRecording>() { @@ -97,6 +102,10 @@ class TracerLogServlet extends SimpleWebConsolePlugin implements TraceLogRecorde return compressRecording; } + public boolean isGzipResponse() { + return gzipResponse; + } + int getCacheSizeInMB() { return cacheSizeInMB; } @@ -121,7 +130,8 @@ class TracerLogServlet extends SimpleWebConsolePlugin implements TraceLogRecorde if (requestId != null) { JSONRecording recording = cache.getIfPresent(requestId); if (recording != null){ - responseDone = recording.render(response.getOutputStream()); + boolean shouldGZip = prepareForGZipResponse(request, response); + responseDone = recording.render(response.getOutputStream(), shouldGZip); } } @@ -152,6 +162,30 @@ class TracerLogServlet extends SimpleWebConsolePlugin implements TraceLogRecorde return request.getRequestURI().endsWith(LABEL); } + private boolean prepareForGZipResponse(HttpServletRequest request, HttpServletResponse response) { + if (!gzipResponse) { + return false; + } + + String acceptEncoding = request.getHeader("Accept-Encoding"); + boolean acceptsGzip = acceptEncoding != null && accepts(acceptEncoding, "gzip"); + + if (acceptsGzip) { + response.setHeader("Content-Encoding", "gzip"); + } + return acceptsGzip; + } + + /** + * Returns true if the given accept header accepts the given value. + * @param acceptHeader The accept header. + * @param toAccept The value to be accepted. + * @return True if the given accept header accepts the given value. + */ + private static boolean accepts(String acceptHeader, String toAccept) { + return acceptHeader.contains(toAccept) || acceptHeader.contains("*/*"); + } + private static void prepareJSONResponse(HttpServletResponse response) { response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); diff --git a/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java b/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java index 296c168..ec4a867 100644 --- a/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java +++ b/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java @@ -123,22 +123,43 @@ public class LogTracerTest { @Test public void enableTracerLogServletWithConfig() throws Exception { LogTracer tracer = context.registerInjectActivateService(new LogTracer(), - ImmutableMap.<String, Object>of( - "enabled", "true", - "servletEnabled", "true", - "recordingCacheSizeInMB", "17", - "recordingCacheDurationInSecs", "100", - "recordingCompressionEnabled", "false" - )); + ImmutableMap.<String, Object>builder() + .put("enabled", "true") + .put("servletEnabled", "true") + .put("recordingCacheSizeInMB", "17") + .put("recordingCacheDurationInSecs", "100") + .put("recordingCompressionEnabled", "false") + .put("gzipResponse", "true") + .build() + ); assertEquals(2, context.getServices(Filter.class, null).length); assertNotNull(context.getService(Servlet.class)); TracerLogServlet logServlet = (TracerLogServlet) context.getService(Servlet.class); assertEquals(false, logServlet.isCompressRecording()); + assertEquals(false, logServlet.isGzipResponse()); assertEquals(17, logServlet.getCacheSizeInMB()); assertEquals(100, logServlet.getCacheDurationInSecs()); } + @Test + public void enableTracerLogServletWithConfigGzip() throws Exception { + LogTracer tracer = context.registerInjectActivateService(new LogTracer(), + ImmutableMap.<String, Object>builder() + .put("enabled", "true") + .put("servletEnabled", "true") + .put("recordingCompressionEnabled", "true") + .put("gzipResponse", "true") + .build() + ); + assertEquals(2, context.getServices(Filter.class, null).length); + assertNotNull(context.getService(Servlet.class)); + + TracerLogServlet logServlet = (TracerLogServlet) context.getService(Servlet.class); + assertEquals(true, logServlet.isCompressRecording()); + assertEquals(true, logServlet.isGzipResponse()); + } + @Test public void noTurboFilterRegisteredUnlessTracingRequested() throws Exception { diff --git a/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java b/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java index 61c1a9f..546a406 100644 --- a/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java +++ b/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java @@ -19,16 +19,19 @@ package org.apache.sling.tracer.internal; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.zip.GZIPInputStream; import javax.annotation.Nonnull; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; import org.apache.sling.commons.json.JSONObject; import org.apache.sling.testing.mock.osgi.junit.OsgiContext; import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest; @@ -117,6 +120,35 @@ public class TracerLogServletTest { } @Test + public void gzipResponse() throws Exception{ + TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext()); + when(request.getMethod()).thenReturn("GET"); + when(request.getHeader(TracerLogServlet.HEADER_TRACER_RECORDING)).thenReturn("true"); + when(request.getHeader("Accept-Encoding")).thenReturn("gzip, deflate"); + + Recording recording = logServlet.startRecording(request, response); + recording.registerTracker(createTracker("x" ,"y")); + logServlet.endRecording(request, recording); + + ArgumentCaptor<String> requestIdCaptor = ArgumentCaptor.forClass(String.class); + verify(response).setHeader(eq(TracerLogServlet.HEADER_TRACER_REQUEST_ID), requestIdCaptor.capture()); + verify(response).setHeader(TracerLogServlet.HEADER_TRACER_PROTOCOL_VERSION, + String.valueOf(TracerLogServlet.TRACER_PROTOCOL_VERSION)); + + ByteArrayServletOutputStream sos = new ByteArrayServletOutputStream(); + when(response.getOutputStream()).thenReturn(sos); + when(request.getRequestURI()).thenReturn("/system/console/" + requestIdCaptor.getValue() + ".json" ); + + logServlet.renderContent(request, response); + byte[] data = IOUtils.toByteArray(new GZIPInputStream(new ByteArrayInputStream(sos.baos.toByteArray()))); + JSONObject json = new JSONObject(new String(data, "UTF-8")); + assertEquals("GET", json.getString("method")); + assertEquals(2, json.getJSONArray("requestProgressLogs").length()); + + verify(response).setHeader("Content-Encoding" , "gzip"); + } + + @Test public void pluginRendering() throws Exception{ TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext()); when(request.getRequestURI()).thenReturn("/system/console/tracer" ); -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
