You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ch...@apache.org on 2016/02/10 07:52:58 UTC

svn commit: r1729535 - in /sling/trunk/contrib/extensions/tracer: ./ src/main/java/org/apache/sling/tracer/internal/ src/test/java/org/apache/sling/tracer/internal/

Author: chetanm
Date: Wed Feb 10 06:52:58 2016
New Revision: 1729535

URL: http://svn.apache.org/viewvc?rev=1729535&view=rev
Log:
SLING-5504 - Reduce memory footprint of stored recording data

-- Make cache size by memory configurable. Defaults to 50MB and expiry in 15 mins
-- Change the recording logic such that recording is added to cache at end. As Guava calculates the entry size at time of put and recording size is only calculated at end. So now recorder would be called at end of request processing

Modified:
    sling/trunk/contrib/extensions/tracer/pom.xml
    sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java
    sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/LogTracer.java
    sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java
    sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java
    sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java
    sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java
    sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java

Modified: sling/trunk/contrib/extensions/tracer/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/pom.xml?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/pom.xml (original)
+++ sling/trunk/contrib/extensions/tracer/pom.xml Wed Feb 10 06:52:58 2016
@@ -74,7 +74,7 @@
       <!-- the used logback version is only compatible with SLF4J 1.6 -->
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
-      <version>1.6.0</version>
+      <version>1.7.5</version>
       <scope>provided</scope>
     </dependency>
     <dependency>

Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java Wed Feb 10 06:52:58 2016
@@ -95,6 +95,10 @@ class JSONRecording implements Recording
         return uri;
     }
 
+    public String getRequestId() {
+        return requestId;
+    }
+
     //~---------------------------------------< Recording >
 
     @Override
@@ -112,7 +116,6 @@ class JSONRecording implements Recording
         this.tracker = tracker;
     }
 
-    @Override
     public void done() {
         try {
             if (json == null) {

Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/LogTracer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/LogTracer.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/LogTracer.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/LogTracer.java Wed Feb 10 06:52:58 2016
@@ -117,6 +117,27 @@ public class LogTracer {
     )
     private static final String PROP_TRACER_SERVLET_ENABLED = "servletEnabled";
 
+    static final int PROP_TRACER_SERVLET_CACHE_SIZE_DEFAULT = 50;
+    @Property(label = "Recording Cache Size",
+            description = "Recording cache size in MB which would be used to temporary cache the recording data",
+            intValue = PROP_TRACER_SERVLET_CACHE_SIZE_DEFAULT
+    )
+    private static final String PROP_TRACER_SERVLET_CACHE_SIZE = "recordingCacheSizeInMB";
+
+    static final long PROP_TRACER_SERVLET_CACHE_DURATION_DEFAULT = 60 * 15;
+    @Property(label = "Recording Cache Duration",
+            description = "Time in seconds upto which the recording data would be held in memory before expiry",
+            longValue = PROP_TRACER_SERVLET_CACHE_DURATION_DEFAULT
+    )
+    private static final String PROP_TRACER_SERVLET_CACHE_DURATION = "recordingCacheDurationInSecs";
+
+    static final boolean PROP_TRACER_SERVLET_COMPRESS_DEFAULT = true;
+    @Property(label = "Compress Recording",
+            description = "Enable compression for recoding held in memory",
+            boolValue = PROP_TRACER_SERVLET_COMPRESS_DEFAULT
+    )
+    private static final String PROP_TRACER_SERVLET_COMPRESS = "recordingCompressionEnabled";
+
     private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(LogTracer.class);
 
     private final Map<String, TracerSet> tracers = new HashMap<String, TracerSet>();
@@ -150,8 +171,16 @@ public class LogTracer {
                     PROP_TRACER_SERVLET_ENABLED_DEFAULT);
 
             if (servletEnabled) {
-                this.logServlet = new TracerLogServlet(context);
+                int cacheSize = PropertiesUtil.toInteger(config.get(PROP_TRACER_SERVLET_CACHE_SIZE),
+                        PROP_TRACER_SERVLET_CACHE_SIZE_DEFAULT);
+                long cacheDuration = PropertiesUtil.toLong(config.get(PROP_TRACER_SERVLET_CACHE_DURATION),
+                        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);
                 recorder = logServlet;
+                LOG.info("Tracer recoding enabled with cacheSize {} MB, expiry {} secs, compression {}",
+                        cacheSize, cacheDuration, compressionEnabled);
             }
             LOG.info("Log tracer enabled. Required filters registered. Tracer servlet enabled {}", servletEnabled);
         }
@@ -318,7 +347,7 @@ public class LogTracer {
                 if (tracerContext != null) {
                     disableCollector();
                 }
-                recording.done();
+                recorder.endRecording(recording);
             }
         }
 

Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java Wed Feb 10 06:52:58 2016
@@ -34,11 +34,6 @@ interface Recording {
         public void registerTracker(RequestProgressTracker tracker) {
 
         }
-
-        @Override
-        public void done() {
-
-        }
     };
 
     void log(Level level, String logger, FormattingTuple tuple);
@@ -49,9 +44,4 @@ interface Recording {
      * @param tracker from current request
      */
     void registerTracker(RequestProgressTracker tracker);
-
-    /**
-     * Invoked at the end of request processing
-     */
-    void done();
 }

Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java Wed Feb 10 06:52:58 2016
@@ -33,9 +33,16 @@ interface TraceLogRecorder {
         public Recording getRecordingForRequest(HttpServletRequest request) {
             return Recording.NOOP;
         }
+
+        @Override
+        public void endRecording(Recording recording) {
+
+        }
     };
 
     Recording startRecording(HttpServletRequest request, HttpServletResponse response);
 
     Recording getRecordingForRequest(HttpServletRequest request);
+
+    void endRecording(Recording recording);
 }

Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java Wed Feb 10 06:52:58 2016
@@ -25,19 +25,22 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.Nonnull;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.Weigher;
+import org.apache.commons.io.FileUtils;
 import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.json.io.JSONWriter;
 import org.osgi.framework.BundleContext;
 
 class TracerLogServlet extends SimpleWebConsolePlugin implements TraceLogRecorder {
-    static final String ATTR_REQUEST_ID = TracerLogServlet.class.getName();
+    static final String ATTR_RECORDING = TracerLogServlet.class.getName();
 
     public static final String CLEAR = "clear";
 
@@ -53,19 +56,51 @@ class TracerLogServlet extends SimpleWeb
 
     private final Cache<String, JSONRecording> cache;
 
-    private boolean compressRecording = true;
+    private final boolean compressRecording;
 
-    public TracerLogServlet(BundleContext context) {
+    private final int cacheSizeInMB;
+
+    private final long cacheDurationInSecs;
+
+    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
+        );
+    }
+
+    public TracerLogServlet(BundleContext context, int cacheSizeInMB, long cacheDurationInSecs, boolean compressionEnabled) {
         super(LABEL, "Sling Tracer", "Sling", null);
-        //TODO Make things configurable
+        this.compressRecording = compressionEnabled;
+        this.cacheDurationInSecs = cacheDurationInSecs;
+        this.cacheSizeInMB = cacheSizeInMB;
         this.cache = CacheBuilder.newBuilder()
-                .maximumSize(100)
-                .expireAfterAccess(10, TimeUnit.MINUTES)
+                .maximumWeight(cacheSizeInMB * FileUtils.ONE_MB)
+                .weigher(new Weigher<String, JSONRecording>() {
+                    @Override
+                    public int weigh(@Nonnull  String key, @Nonnull JSONRecording value) {
+                        return (int)value.size();
+                    }
+                })
+                .expireAfterAccess(cacheDurationInSecs, TimeUnit.SECONDS)
                 .recordStats()
                 .build();
         register(context);
     }
 
+    boolean isCompressRecording() {
+        return compressRecording;
+    }
+
+    int getCacheSizeInMB() {
+        return cacheSizeInMB;
+    }
+
+    long getCacheDurationInSecs() {
+        return cacheDurationInSecs;
+    }
+
     //~-----------------------------------------------< WebConsole Plugin >
 
     @Override
@@ -119,8 +154,9 @@ class TracerLogServlet extends SimpleWeb
     }
 
     private void renderStatus(PrintWriter pw) {
-        pw.printf("<p class='statline'>Log Tracer Recordings: %d recordings, %s memory</p>%n", cache.size(),
-                memorySize());
+        pw.printf("<p class='statline'>Log Tracer Recordings: %d recordings, %s memory " +
+                "(Max %dMB, Expired in %d secs)</p>%n", cache.size(),
+                memorySize(), cacheSizeInMB, cacheDurationInSecs);
 
         pw.println("<div class='ui-widget-header ui-corner-top buttonGroup'>");
         pw.println("<span style='float: left; margin-left: 1em'>Tracer Recordings</span>");
@@ -167,7 +203,7 @@ class TracerLogServlet extends SimpleWeb
             return Recording.NOOP;
         }
 
-        if (request.getAttribute(ATTR_REQUEST_ID) != null){
+        if (request.getAttribute(ATTR_RECORDING) != null){
             //Already processed
             return getRecordingForRequest(request);
         }
@@ -175,8 +211,6 @@ class TracerLogServlet extends SimpleWeb
         String requestId = generateRequestId();
         JSONRecording recording = record(requestId, request);
 
-        request.setAttribute(ATTR_REQUEST_ID, requestId);
-
         response.setHeader(HEADER_TRACER_REQUEST_ID, requestId);
         response.setHeader(HEADER_TRACER_PROTOCOL_VERSION, String.valueOf(TRACER_PROTOCOL_VERSION));
 
@@ -185,11 +219,20 @@ class TracerLogServlet extends SimpleWeb
 
     @Override
     public Recording getRecordingForRequest(HttpServletRequest request) {
-        String requestId = (String) request.getAttribute(ATTR_REQUEST_ID);
-        if (requestId != null){
-            return getRecording(requestId);
+        Recording recording = (Recording) request.getAttribute(ATTR_RECORDING);
+        if (recording == null){
+            recording = Recording.NOOP;
+        }
+        return recording;
+    }
+
+    @Override
+    public void endRecording(Recording recording) {
+        if (recording instanceof JSONRecording) {
+            JSONRecording r = (JSONRecording) recording;
+            r.done();
+            cache.put(r.getRequestId(), r);
         }
-        return Recording.NOOP;
     }
 
     Recording getRecording(String requestId) {
@@ -199,7 +242,7 @@ class TracerLogServlet extends SimpleWeb
 
     private JSONRecording record(String requestId, HttpServletRequest request) {
         JSONRecording data = new JSONRecording(requestId, request, compressRecording);
-        cache.put(requestId, data);
+        request.setAttribute(ATTR_RECORDING, data);
         return data;
     }
 
@@ -211,6 +254,7 @@ class TracerLogServlet extends SimpleWeb
      * Returns a human-readable version of the file size, where the input represents
      * a specific number of bytes. Based on http://stackoverflow.com/a/3758880/1035417
      */
+    @SuppressWarnings("Duplicates")
     private static String humanReadableByteCount(long bytes) {
         if (bytes < 0) {
             return "0";

Modified: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java Wed Feb 10 06:52:58 2016
@@ -110,12 +110,37 @@ public class LogTracerTest {
         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(LogTracer.PROP_TRACER_SERVLET_CACHE_SIZE_DEFAULT, logServlet.getCacheSizeInMB());
+        assertEquals(LogTracer.PROP_TRACER_SERVLET_CACHE_DURATION_DEFAULT, logServlet.getCacheDurationInSecs());
+
         MockOsgi.deactivate(tracer);
         assertNull(context.getService(Filter.class));
         assertNull(context.getService(Servlet.class));
     }
 
     @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"
+                ));
+        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(17, logServlet.getCacheSizeInMB());
+        assertEquals(100, logServlet.getCacheDurationInSecs());
+    }
+
+
+    @Test
     public void noTurboFilterRegisteredUnlessTracingRequested() throws Exception {
         HttpServletRequest request = mock(HttpServletRequest.class);
         HttpServletResponse response = mock(HttpServletResponse.class);

Modified: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java?rev=1729535&r1=1729534&r2=1729535&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java Wed Feb 10 06:52:58 2016
@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
+import javax.annotation.Nonnull;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -98,7 +99,7 @@ public class TracerLogServletTest {
 
         Recording recording = logServlet.startRecording(request, response);
         recording.registerTracker(createTracker("x" ,"y"));
-        recording.done();
+        logServlet.endRecording(recording);
 
         ArgumentCaptor<String> requestIdCaptor = ArgumentCaptor.forClass(String.class);
         verify(response).setHeader(eq(TracerLogServlet.HEADER_TRACER_REQUEST_ID), requestIdCaptor.capture());
@@ -135,7 +136,7 @@ public class TracerLogServletTest {
         }
 
         @Override
-        public void write(byte[] b, int off, int len) throws IOException {
+        public void write(@Nonnull byte[] b, int off, int len) throws IOException {
             baos.write(b, off, len);
         }
     }