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/02 11:50:06 UTC
svn commit: r1728077 - 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: Tue Feb 2 10:50:05 2016
New Revision: 1728077
URL: http://svn.apache.org/viewvc?rev=1728077&view=rev
Log:
SLING-5459 - Recording of tracer logs
Added:
sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java (with props)
sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java (with props)
sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java (with props)
sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java (with props)
sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java (with props)
sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java (with props)
sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java (with props)
Modified:
sling/trunk/contrib/extensions/tracer/pom.xml
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/TracerContext.java
sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerModelTest.java
sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerTest.java
Modified: sling/trunk/contrib/extensions/tracer/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/pom.xml?rev=1728077&r1=1728076&r2=1728077&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/pom.xml (original)
+++ sling/trunk/contrib/extensions/tracer/pom.xml Tue Feb 2 10:50:05 2016
@@ -88,7 +88,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.1.0</version>
+ <version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
@@ -102,6 +102,28 @@
<version>4.3.1</version>
<scope>provided</scope>
</dependency>
+ <!-- TODO Inline just the cache related classes -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>15.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.json</artifactId>
+ <version>2.0.8</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>3.0.0</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>junit</groupId>
@@ -115,9 +137,16 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+ <version>1.3.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
+ <scope>test</scope>
</dependency>
</dependencies>
Added: 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=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.io.JSONWriter;
+
+class JSONRecording implements Recording {
+ private final String method;
+ private final List<String> queries = new ArrayList<String>();
+ private RequestProgressTracker tracker;
+
+ public JSONRecording(HttpServletRequest r) {
+ this.method = r.getMethod();
+ }
+
+ public void render(JSONWriter jw) throws JSONException {
+ jw.key("method").value(method);
+
+ if (tracker != null) {
+ jw.key("logs");
+ jw.array();
+ Iterator<String> it = tracker.getMessages();
+ while (it.hasNext()) {
+ jw.value(it.next());
+ }
+ jw.endArray();
+ }
+
+ jw.key("queries");
+ jw.array();
+ for (String q : queries) {
+ jw.value(q);
+ }
+ jw.endArray();
+ }
+
+ //~---------------------------------------< Recording >
+
+ @Override
+ public void log(String logger, String format, Object[] params) {
+ if (TracerContext.QUERY_LOGGER.equals(logger)
+ && params != null && params.length == 2) {
+ queries.add((String) params[1]);
+ }
+ }
+
+ @Override
+ public void registerTracker(RequestProgressTracker tracker) {
+ this.tracker = tracker;
+ }
+
+ RequestProgressTracker getTracker() {
+ return tracker;
+ }
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/JSONRecording.java
------------------------------------------------------------------------------
svn:eol-style = native
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=1728077&r1=1728076&r2=1728077&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 Tue Feb 2 10:50:05 2016
@@ -29,6 +29,7 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.Nullable;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@@ -36,6 +37,7 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@@ -108,6 +110,13 @@ public class LogTracer {
)
private static final String PROP_TRACER_ENABLED = "enabled";
+ private static final boolean PROP_TRACER_SERVLET_ENABLED_DEFAULT = false;
+ @Property(label = "Servlet Enabled",
+ description = "Enable the Tracer Servlet",
+ boolValue = PROP_TRACER_SERVLET_ENABLED_DEFAULT
+ )
+ private static final String PROP_TRACER_SERVLET_ENABLED = "servletEnabled";
+
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(LogTracer.class);
private final Map<String, TracerSet> tracers = new HashMap<String, TracerSet>();
@@ -125,6 +134,11 @@ public class LogTracer {
private static final ThreadLocal<TracerContext> requestContextHolder = new ThreadLocal<TracerContext>();
+ @Nullable
+ private TracerLogServlet logServlet;
+
+ private TraceLogRecorder recorder = TraceLogRecorder.DEFAULT;
+
@Activate
private void activate(Map<String, ?> config, BundleContext context) {
this.bundleContext = context;
@@ -132,12 +146,23 @@ public class LogTracer {
boolean enabled = PropertiesUtil.toBoolean(config.get(PROP_TRACER_ENABLED), PROP_TRACER_ENABLED_DEFAULT);
if (enabled) {
registerFilters(context);
- LOG.info("Log tracer enabled. Required filters registered");
+ boolean servletEnabled = PropertiesUtil.toBoolean(config.get(PROP_TRACER_SERVLET_ENABLED),
+ PROP_TRACER_SERVLET_ENABLED_DEFAULT);
+
+ if (servletEnabled) {
+ this.logServlet = new TracerLogServlet(context);
+ recorder = logServlet;
+ }
+ LOG.info("Log tracer enabled. Required filters registered. Tracer servlet enabled {}", servletEnabled);
}
}
@Deactivate
private void deactivate() {
+ if (logServlet != null) {
+ logServlet.unregister();
+ }
+
if (slingFilterRegistration != null) {
slingFilterRegistration.unregister();
slingFilterRegistration = null;
@@ -156,7 +181,7 @@ public class LogTracer {
requestContextHolder.remove();
}
- TracerContext getTracerContext(String tracerSetNames, String tracerConfig) {
+ TracerContext getTracerContext(String tracerSetNames, String tracerConfig, Recording recording) {
//No config or tracer set name provided. So tracing not required
if (tracerSetNames == null && tracerConfig == null) {
return null;
@@ -185,7 +210,7 @@ public class LogTracer {
configs.addAll(ts.getConfigs());
}
- return new TracerContext(configs.toArray(new TracerConfig[configs.size()]));
+ return new TracerContext(configs.toArray(new TracerConfig[configs.size()]), recording);
}
private void initializeTracerSet(Map<String, ?> config) {
@@ -277,8 +302,13 @@ public class LogTracer {
//parameter map
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+
+ //Invoke at start so that header can be set. If done at end there is a chance
+ //that response is committed
+ Recording recording = recorder.startRecording(httpRequest, (HttpServletResponse) servletResponse);
+
TracerContext tracerContext = getTracerContext(httpRequest.getHeader(HEADER_TRACER),
- httpRequest.getHeader(HEADER_TRACER_CONFIG));
+ httpRequest.getHeader(HEADER_TRACER_CONFIG), recording);
try {
if (tracerContext != null) {
enableCollector(tracerContext);
@@ -304,14 +334,15 @@ public class LogTracer {
FilterChain filterChain) throws IOException, ServletException {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) servletRequest;
TracerContext tracerContext = requestContextHolder.get();
-
+ Recording recording = recorder.getRecordingForRequest(slingRequest);
+ recording.registerTracker(slingRequest.getRequestProgressTracker());
boolean createdContext = false;
//Check if the global filter created context based on HTTP headers. If not
//then check from request params
if (tracerContext == null) {
tracerContext = getTracerContext(slingRequest.getParameter(PARAM_TRACER),
- slingRequest.getParameter(PARAM_TRACER_CONFIG));
+ slingRequest.getParameter(PARAM_TRACER_CONFIG), recording);
if (tracerContext != null) {
createdContext = true;
}
Added: 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=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import org.apache.sling.api.request.RequestProgressTracker;
+
+interface Recording {
+ Recording NOOP = new Recording() {
+ @Override
+ public void log(String logger, String format, Object[] params) {
+
+ }
+
+ @Override
+ public void registerTracker(RequestProgressTracker tracker) {
+
+ }
+ };
+
+ void log(String logger, String format, Object[] params);
+
+ /**
+ * Register the {@link RequestProgressTracker} associated with
+ * current request
+ * @param tracker from current request
+ */
+ void registerTracker(RequestProgressTracker tracker);
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/Recording.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: 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=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+interface TraceLogRecorder {
+ TraceLogRecorder DEFAULT = new TraceLogRecorder() {
+ @Override
+ public Recording startRecording(HttpServletRequest request, HttpServletResponse response) {
+ return Recording.NOOP;
+ }
+
+ @Override
+ public Recording getRecordingForRequest(HttpServletRequest request) {
+ return Recording.NOOP;
+ }
+ };
+
+ Recording startRecording(HttpServletRequest request, HttpServletResponse response);
+
+ Recording getRecordingForRequest(HttpServletRequest request);
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TraceLogRecorder.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerContext.java?rev=1728077&r1=1728076&r2=1728077&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerContext.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerContext.java Tue Feb 2 10:50:05 2016
@@ -27,7 +27,7 @@ import org.apache.sling.api.request.Requ
import org.slf4j.helpers.MessageFormatter;
class TracerContext {
- private static final String QUERY_LOGGER = "org.apache.jackrabbit.oak.query.QueryEngineImpl";
+ static final String QUERY_LOGGER = "org.apache.jackrabbit.oak.query.QueryEngineImpl";
/**
* Following queries are internal to Oak and are fired for login/access control
@@ -54,9 +54,11 @@ class TracerContext {
private RequestProgressTracker progressTracker;
private int queryCount;
private final TracerConfig[] tracers;
+ private final Recording recording;
- public TracerContext(TracerConfig[] tracers) {
+ public TracerContext(TracerConfig[] tracers, Recording recording) {
this.tracers = tracers;
+ this.recording = recording;
//Say if the list is like com.foo;level=trace,com.foo.bar;level=info.
// Then first config would result in a match and later config would
@@ -79,6 +81,7 @@ class TracerContext {
}
public boolean log(String logger, String format, Object[] params) {
+ recording.log(logger, format, params);
if (QUERY_LOGGER.equals(logger)
&& params != null && params.length == 2) {
return logQuery((String) params[1]);
Added: 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=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+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 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();
+
+ public static final String CLEAR = "clear";
+
+ private static final String LABEL = "tracer";
+
+ public static final String HEADER_TRACER_RECORDING = "Sling-Tracer-Record";
+
+ public static final String HEADER_TRACER_REQUEST_ID = "Sling-Tracer-Request-Id";
+
+ private final Cache<String, JSONRecording> cache;
+
+ public TracerLogServlet(BundleContext context) {
+ super(LABEL, "Sling Tracer", "Sling", null);
+ //TODO Make things configurable
+ this.cache = CacheBuilder.newBuilder()
+ .maximumSize(100)
+ .expireAfterAccess(10, TimeUnit.MINUTES)
+ .recordStats()
+ .build();
+ register(context);
+ }
+
+ //~-----------------------------------------------< WebConsole Plugin >
+
+ @Override
+ protected void renderContent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ final PrintWriter pw = response.getWriter();
+ if (isHtmlRequest(request)){
+ renderStatus(pw);
+ renderRequests(pw);
+ } else {
+ String requestId = getRequestId(request);
+ prepareJSONResponse(response);
+ JSONWriter jw = new JSONWriter(pw);
+ try {
+ jw.setTidy(true);
+ jw.object();
+ if (requestId != null) {
+ renderRequestData(requestId, jw);
+ }
+ jw.endObject();
+ } catch (JSONException e) {
+ throw new ServletException(e);
+ }
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException {
+ if (req.getParameter(CLEAR) != null) {
+ resetCache();
+ resp.sendRedirect(req.getRequestURI());
+ }
+ }
+
+ @Override
+ protected boolean isHtmlRequest(HttpServletRequest request) {
+ return request.getRequestURI().endsWith(LABEL);
+ }
+
+ private static void prepareJSONResponse(HttpServletResponse response) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ }
+
+ private void renderRequestData(String requestId, JSONWriter jw) throws JSONException {
+ JSONRecording recording = cache.getIfPresent(requestId);
+ if (recording == null){
+ jw.key("error").value("Not found");
+ return;
+ }
+ recording.render(jw);
+ }
+
+ private void renderStatus(PrintWriter pw) {
+ pw.printf("<p class='statline'>Log Tracer Recordings: %d recordings</p>%n", cache.size());
+
+ pw.println("<div class='ui-widget-header ui-corner-top buttonGroup'>");
+ pw.println("<span style='float: left; margin-left: 1em'>Tracer Recordings</span>");
+ pw.println("<form method='POST'><input type='hidden' name='clear' value='clear'><input type='submit' value='Clear' class='ui-state-default ui-corner-all'></form>");
+ pw.println("</div>");
+ }
+
+ private void renderRequests(PrintWriter pw) {
+ if (cache.size() > 0){
+ pw.println("<ul>");
+ for (String id : cache.asMap().keySet()){
+ pw.printf("<li><a href='%s/%s.json'>%s</a></li>", LABEL, id, id);
+ }
+ pw.println("</ul>");
+ }
+
+ }
+
+ private static String getRequestId(HttpServletRequest request) {
+ String requestUri = request.getRequestURI();
+ int lastSlash = requestUri.lastIndexOf('/');
+ int lastDot = requestUri.indexOf('.', lastSlash + 1);
+ if (lastDot > 0){
+ return requestUri.substring(lastSlash + 1, lastDot);
+ }
+ return null;
+ }
+
+ //~-----------------------------------------------< TraceLogRecorder >
+
+ @Override
+ public Recording startRecording(HttpServletRequest request, HttpServletResponse response) {
+ if (request.getHeader(HEADER_TRACER_RECORDING) == null){
+ return Recording.NOOP;
+ }
+
+ if (request.getAttribute(ATTR_REQUEST_ID) != null){
+ //Already processed
+ return getRecordingForRequest(request);
+ }
+
+ String requestId = generateRequestId();
+ JSONRecording recording = record(requestId, request);
+
+ request.setAttribute(ATTR_REQUEST_ID, requestId);
+
+ response.setHeader(HEADER_TRACER_REQUEST_ID, requestId);
+ //TODO Show we also sent tracer version to enable client determine
+ //is server is capable of given version
+ return recording;
+ }
+
+ @Override
+ public Recording getRecordingForRequest(HttpServletRequest request) {
+ String requestId = (String) request.getAttribute(ATTR_REQUEST_ID);
+ if (requestId != null){
+ return getRecording(requestId);
+ }
+ return Recording.NOOP;
+ }
+
+ Recording getRecording(String requestId) {
+ Recording recording = cache.getIfPresent(requestId);
+ return recording == null ? Recording.NOOP : recording;
+ }
+
+ private JSONRecording record(String requestId, HttpServletRequest request) {
+ JSONRecording data = new JSONRecording(request);
+ cache.put(requestId, data);
+ return data;
+ }
+
+ private static String generateRequestId() {
+ return UUID.randomUUID().toString();
+ }
+
+ void resetCache(){
+ cache.invalidateAll();
+ }
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/main/java/org/apache/sling/tracer/internal/TracerLogServlet.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java?rev=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import java.io.StringWriter;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.json.io.JSONWriter;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JSONRecordingTest {
+ private HttpServletRequest request = mock(HttpServletRequest.class);
+
+ @Test
+ public void logQueries() throws Exception{
+ StringWriter sw = new StringWriter();
+
+ when(request.getMethod()).thenReturn("GET");
+ JSONRecording r = new JSONRecording(request);
+
+ r.log(TracerContext.QUERY_LOGGER, "foo bar", new Object[]{"x" , "y"});
+ r.log(TracerContext.QUERY_LOGGER, "foo bar", new Object[]{"x" , "z"});
+
+ JSONWriter jw = new JSONWriter(sw).object();
+ r.render(jw);
+ jw.endObject();
+
+ JSONObject json = new JSONObject(sw.toString());
+ assertEquals("GET", json.get("method"));
+ assertEquals(2, json.getJSONArray("queries").length());
+ }
+
+ @Test
+ public void requestTrackerLogs() throws Exception{
+ StringWriter sw = new StringWriter();
+ JSONRecording r = new JSONRecording(request);
+
+ r.registerTracker(TestUtil.createTracker("x", "y"));
+
+ JSONWriter jw = new JSONWriter(sw).object();
+ r.render(jw);
+ jw.endObject();
+
+ JSONObject json = new JSONObject(sw.toString());
+ assertEquals(2, json.getJSONArray("logs").length());
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/JSONRecordingTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerModelTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerModelTest.java?rev=1728077&r1=1728076&r2=1728077&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerModelTest.java (original)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/LogTracerModelTest.java Tue Feb 2 10:50:05 2016
@@ -86,7 +86,7 @@ public class LogTracerModelTest {
}
private static TracerContext getContext(TracerSet ts) {
- return new TracerContext(ts.getConfigs().toArray(new TracerConfig[ts.getConfigs().size()]));
+ return new TracerContext(ts.getConfigs().toArray(new TracerConfig[ts.getConfigs().size()]), Recording.NOOP);
}
}
\ No newline at end of file
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=1728077&r1=1728076&r2=1728077&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 Tue Feb 2 10:50:05 2016
@@ -25,6 +25,7 @@ import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -39,9 +40,11 @@ import ch.qos.logback.core.read.ListAppe
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.RequestProgressTracker;
import org.apache.sling.testing.mock.osgi.MockOsgi;
import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
import org.apache.sling.testing.mock.osgi.junit.OsgiContextCallback;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
@@ -50,12 +53,15 @@ import org.osgi.framework.InvalidSyntaxE
import org.osgi.framework.ServiceReference;
import org.slf4j.LoggerFactory;
+import static org.apache.sling.tracer.internal.TestUtil.createTracker;
+import static org.apache.sling.tracer.internal.TestUtil.getRequestId;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.slf4j.LoggerFactory.getLogger;
@@ -89,12 +95,25 @@ public class LogTracerTest {
LogTracer tracer = context.registerInjectActivateService(new LogTracer(),
ImmutableMap.<String, Object>of("enabled", "true"));
assertEquals(2, context.getServices(Filter.class, null).length);
+ assertNull(context.getService(Servlet.class));
MockOsgi.deactivate(tracer);
assertNull(context.getService(Filter.class));
}
@Test
+ public void enableTracerLogServlet() throws Exception {
+ LogTracer tracer = context.registerInjectActivateService(new LogTracer(),
+ ImmutableMap.<String, Object>of("enabled", "true", "servletEnabled", "true"));
+ assertEquals(2, context.getServices(Filter.class, null).length);
+ assertNotNull(context.getService(Servlet.class));
+
+ MockOsgi.deactivate(tracer);
+ assertNull(context.getService(Filter.class));
+ assertNull(context.getService(Servlet.class));
+ }
+
+ @Test
public void noTurboFilterRegisteredUnlessTracingRequested() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
@@ -206,12 +225,54 @@ public class LogTracerTest {
rootLogger().setLevel(oldLevel);
}
+ @Test
+ public void recordingWithoutTracing() throws Exception{
+ activateTracerAndServlet();
+ MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(){
+ @Override
+ public RequestProgressTracker getRequestProgressTracker() {
+ return createTracker("x", "y");
+ }
+ };
+ request.setHeader(TracerLogServlet.HEADER_TRACER_RECORDING, "true");
+
+ HttpServletResponse response = mock(HttpServletResponse.class);
+
+ FilterChain chain = new FilterChain() {
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+ //No TurboFilter should be registered if tracing is not requested
+ assertNull(context.getService(TurboFilter.class));
+ }
+ };
+
+ prepareChain(chain).doFilter(request, response);
+
+ String requestId = getRequestId(response);
+ assertNotNull(requestId);
+ Recording r = ((TracerLogServlet)context.getService(Servlet.class)).getRecording(requestId);
+ assertTrue(r instanceof JSONRecording);
+ assertNotNull(((JSONRecording)r).getTracker());
+ }
+
private void activateTracer() {
context.registerInjectActivateService(new LogTracer(),
ImmutableMap.<String, Object>of("enabled", "true"));
}
+ private void activateTracerAndServlet() {
+ context.registerInjectActivateService(new LogTracer(),
+ ImmutableMap.<String, Object>of("enabled", "true", "servletEnabled", "true"));
+ }
+
+ private FilterChain prepareChain(FilterChain end) throws InvalidSyntaxException {
+ Filter servletFilter = getFilter(false);
+ Filter slingFilter = getFilter(true);
+ return new FilterChainImpl(end, servletFilter, slingFilter);
+ }
+
private Filter getFilter(boolean slingFilter) throws InvalidSyntaxException {
Collection<ServiceReference<Filter>> refs =
context.bundleContext().getServiceReferences(Filter.class, null);
@@ -268,5 +329,25 @@ public class LogTracerTest {
}
}
}
+
+ private static class FilterChainImpl implements FilterChain {
+ private final Filter[] filters;
+ private final FilterChain delegate;
+ private int pos;
+
+ public FilterChainImpl(FilterChain delegate, Filter ... filter){
+ this.delegate = delegate;
+ this.filters = filter;
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+ if (pos == filters.length){
+ delegate.doFilter(request, response);
+ } else {
+ filters[pos++].doFilter(request, response, this);
+ }
+ }
+ }
}
Added: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java?rev=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.mockito.ArgumentCaptor;
+
+import static java.util.Arrays.asList;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class TestUtil {
+
+ static RequestProgressTracker createTracker(String ... logs){
+ RequestProgressTracker tracker = mock(RequestProgressTracker.class);
+ when(tracker.getMessages()).thenReturn(asList(logs).iterator());
+ return tracker;
+ }
+
+ static String getRequestId(HttpServletResponse response){
+ ArgumentCaptor<String> requestIdCaptor = ArgumentCaptor.forClass(String.class);
+ verify(response).setHeader(eq(TracerLogServlet.HEADER_TRACER_REQUEST_ID), requestIdCaptor.capture());
+ return requestIdCaptor.getValue();
+ }
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TestUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: 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=1728077&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java (added)
+++ sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java Tue Feb 2 10:50:05 2016
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.tracer.internal;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+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;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import static org.apache.sling.tracer.internal.TestUtil.createTracker;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class TracerLogServletTest {
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private HttpServletRequest request;
+ @Mock
+ private HttpServletResponse response;
+
+ @Test
+ public void noRecordingByDefault() throws Exception{
+ TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext());
+ assertSame(Recording.NOOP, logServlet.startRecording(request, response));
+ assertSame(Recording.NOOP, logServlet.getRecordingForRequest(request));
+ }
+
+ @Test
+ public void recordingWhenRequested() throws Exception{
+ TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext());
+ request = new MockSlingHttpServletRequest();
+
+ Recording recording = logServlet.startRecording(request, response);
+ assertNotNull(recording);
+
+ //Once recording is created then it should be returned
+ Recording recording2 = logServlet.getRecordingForRequest(request);
+ assertSame(recording, recording2);
+
+ //Repeated call should return same recording instance
+ Recording recording3 = logServlet.startRecording(request, response);
+ assertSame(recording, recording3);
+
+ logServlet.resetCache();
+
+ //If recording gets lost then NOOP must be returned
+ Recording recording4 = logServlet.getRecordingForRequest(request);
+ assertSame(Recording.NOOP, recording4);
+ }
+
+ @Test
+ public void jsonRendering() throws Exception{
+ TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext());
+ when(request.getMethod()).thenReturn("GET");
+ when(request.getHeader(TracerLogServlet.HEADER_TRACER_RECORDING)).thenReturn("true");
+
+ Recording recording = logServlet.startRecording(request, response);
+ recording.registerTracker(createTracker("x" ,"y"));
+
+ ArgumentCaptor<String> requestIdCaptor = ArgumentCaptor.forClass(String.class);
+ verify(response).setHeader(eq(TracerLogServlet.HEADER_TRACER_REQUEST_ID), requestIdCaptor.capture());
+
+ StringWriter sw = new StringWriter();
+ when(response.getWriter()).thenReturn(new PrintWriter(sw));
+ when(request.getRequestURI()).thenReturn("/system/console/" + requestIdCaptor.getValue() + ".json" );
+
+ logServlet.renderContent(request, response);
+ JSONObject json = new JSONObject(sw.toString());
+ assertEquals("GET", json.getString("method"));
+ assertEquals(2, json.getJSONArray("logs").length());
+ }
+
+ @Test
+ public void pluginRendering() throws Exception{
+ TracerLogServlet logServlet = new TracerLogServlet(context.bundleContext());
+ when(request.getRequestURI()).thenReturn("/system/console/tracer" );
+
+ StringWriter sw = new StringWriter();
+ when(response.getWriter()).thenReturn(new PrintWriter(sw));
+ logServlet.renderContent(request, response);
+
+ assertThat(sw.toString(), containsString("Log Tracer"));
+ }
+}
Propchange: sling/trunk/contrib/extensions/tracer/src/test/java/org/apache/sling/tracer/internal/TracerLogServletTest.java
------------------------------------------------------------------------------
svn:eol-style = native