+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * RequestLoggingFilter.java
- *
- * Configure any Servlet context that you want to trace setting
- * this class as a filter in the WEB-INF/web.xml
- *
- * <filter>
- * <filter-name>RequestLogFilter</filter-name>
- * <filter-class>edu.internet2.middleware.commons.log4j.RequestLoggingFilter</filter-class>
- * </filter>
- *
- * The default is to use SimpleAppenderContextImpl as the helper class
- * for the Log4J ThreadLocalAppender. If you want to use another
- * class, specify its name in the filter config as
- *
- * <init-param>
- * <param-name>appenderContextClass</param-name>
- * <param-value>[fill class name in here]</param-value>
- * </init-param>
- *
- * The name of the class specified here must match the name
- * configured to the LocalContext property of the ThreadLocalAppender
- * in the Log4J configuration file.
- *
- * This Filter calls the startRequest() and endRequest() methods
- * of the helper class object to start and stop tracing for the
- * Servlet request. At the end it takes the buffer of data and
- * saves it to a named attribute of the HttpSession object.
- *
- * You can, of course, use this as a model for other code that
- * processes the trace data differently.
- *
- * Dependencies: Log4J
- */
-package edu.internet2.middleware.commons.log4j;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-/**
- * @author Howard Gilbert
- */
-public class RequestLoggingFilter implements Filter {
-
- private static final String FilterInitParamName = "appenderContextClass";
- public static final String REQUESTLOG_ATTRIBUTE = "edu.internet2.middleware.commons.log4j.requestlog";
- ThreadLocalAppenderContext ctx = new SimpleAppenderContextImpl();
-
- /**
- * Extract the helper class name init param (if provided) and create an
- * object of the class.
- *
- * <p>If the class cannot be found or the object cannot be created,
- * print a message but do nothing more.</p>
- */
- public void init(FilterConfig filterConfig) throws ServletException {
- ThreadLocalAppenderContext newctx = null;
- String appenderContextClassname = filterConfig.getInitParameter(FilterInitParamName);
- if (appenderContextClassname==null)
- return;
- try {
- Class appenderContextClass = Class.forName(appenderContextClassname);
- Object o = appenderContextClass.newInstance();
- if (o instanceof ThreadLocalAppenderContext)
- newctx = (ThreadLocalAppenderContext) o;
- } catch (ClassNotFoundException e) {
- } catch (InstantiationException e) {
- } catch (IllegalAccessException e) {
- }
- if (newctx!=null)
- ctx=newctx;
- else
- System.out.println("appenderContext parameter specified invalid classname");
- }
-
- /**
- * For every Http request processed through this context (and
- * mapped by the Filter mapping to this filter) enable thread local
- * request logging on the way in and collect the log data on the way out.
- */
- public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
- if (!(arg0 instanceof HttpServletRequest)) {
- chain.doFilter(arg0, arg1); // only handle HTTP requests
- }
- HttpServletRequest request = (HttpServletRequest) arg0;
- HttpServletResponse response = (HttpServletResponse) arg1;
- HttpSession session = request.getSession();
-
- if (ctx==null) {
- chain.doFilter(arg0,arg1); // do the request while logging
- return;
- }
-
- ctx.startRequest(); // start logging
-
- try {
- chain.doFilter(arg0,arg1); // do the request while logging
- } finally {
- WrappedLog log = ctx.endRequest(); // stop logging, get the data
-
- // Now put the data in a Session attribute
- if (log!=null) {
- if (session!=null) {
- session.setAttribute(REQUESTLOG_ATTRIBUTE, log);
- }
- }
- }
- }
-
- /**
- *
- */
- public void destroy() {
-
- }
-
-}
+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * ShowLog.java
- *
- * Servlet that extracts the ThreadLocal log data from the HttpSession and
- * returns it to the user's browser.
- *
- * Dependencies: The session attribute name must match the name used by the Filter.
- */
-package edu.internet2.middleware.commons.log4j;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-/**
- * @author Howard Gilbert
- */
-public class ShowLog extends HttpServlet {
- public static final String REQUESTLOG_ATTRIBUTE = "edu.internet2.middleware.commons.log4j.requestlog";
-
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- HttpSession session = request.getSession();
- if (session!=null) {
- WrappedLog logBuffer = (WrappedLog) session.getAttribute(REQUESTLOG_ATTRIBUTE);
- response.setContentType("text/plain");
- Writer out = response.getWriter();
- if (logBuffer==null)
- out.write("No Log Data");
- else
- out.write(logBuffer.getLogData());
- }
-
- }
-}
+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * SimpleAppenderContext.java
- *
- * A TheadLocalAppenderContext implementation class serves as the
- * meeting point between a particular instance of ThreadLocalAppender
- * in a Log4J configuration and a particular thread pool request
- * dispatcher (such as a Tomcat application context).
- *
- * In this simple case, the ThreadLocal reference is held in a
- * static variable in this class, and it points to a StringWriter.
- *
- * The ThreadLocalAppender is configured (or defaults since this
- * is the default value) through the LocalContext property. Set
- * that property in the Log4J configuration file with the name of
- * a class that implements ThreadLocalAppenderContext.
- *
- * The request container is also configured with or default do the
- * name of this class. It calls startRequest() when a new request
- * arrives and endRequest() before returning from request processing.
- * An example is the RequestLoggingFilter that makes these calls just
- * before and just after chaining a Servlet GET or POST request on to
- * the next Filter/Servlet in the processing chain.
- *
- * What ties things together is the name of this class, and the
- * fact that the ThreadLocal variable is static in this class. So
- * if you want two differently configured ThreadLocalAppenders to share
- * the same JVM ClassLoader, then you have to create two different classes
- * with two different names and configure at least one new name as the
- * Log4J Appender property or the Filter initialization parameter.
- *
- * Note: The ThreadLocalAppender creates one object of this class.
- * The RequestLoggingFilter creates a separate object. The two
- * objects share only the static variable. Do not make the
- * mistake of assuming that the Filter and log share the same
- * object.
- */
-package edu.internet2.middleware.commons.log4j;
-
-import java.io.StringWriter;
-import java.io.Writer;
-
-
-/**
- * @author Howard Gilbert
- */
-public class SimpleAppenderContextImpl
- implements ThreadLocalAppenderContext {
-
- private static ThreadLocal localWriterReference = new ThreadLocal();
-
- /**
- * @return Null or the Writer for the current thread.
- */
- public Writer getLocalWriter() {
- return (Writer) localWriterReference.get();
- }
-
- /**
- * Called to signal the start of Request processing for this thread.
- */
- public void startRequest() {
- localWriterReference.set(new StringWriter());
- }
-
- /**
- * Called to signal the end of Request processing. Return log data
- * and null out the Writer to stop collecting data.
- *
- * @return A wrapped String containing the log data.
- */
- public WrappedLog endRequest() {
- StringWriter stringWriter =(StringWriter) localWriterReference.get();
- if (stringWriter==null)
- return null;
- String logdata = stringWriter.toString();
- localWriterReference.set(null);
- return new WrappedStringLog(logdata);
- }
-
-
- /**
- * The log Writer could be a file or WebDav network store. So
- * the log data could be a String, or a file name, or a URL.
- * This class handles the simple String case.
- * @author Howard Gilbert
- */
- static class WrappedStringLog implements WrappedLog {
-
- String logdata;
-
- WrappedStringLog(String logdata) {
- this.logdata=logdata;
-
- }
-
- public String getLogData() {
- return logdata;
- }
-
- }
-
-}
+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * ThreadLocalAppender.java
- *
- * This is a Log4J Appender. You add it to your Log4J configuration just
- * like any other appender class. However, it doesn't write the log data
- * to one file or socket like the other appenders. It obtains a Writer
- * from a companion class.
- *
- * We need a companion class to mediate between the Log4J conventions
- * and some Container environment that is dispatching requests to classes
- * using a worker thread pool. Tomcat is a simple example of such a container.
- * This class doesn't know about Tomcat or any other container.
- *
- * An object of this class is created whenever an Appender of this
- * type is added (by program or configuration file) to a Log4J logger.
- * There may be more than one "logger" (that is, there may be more
- * than one point in the category name hierarchy of "a.b.c.d" and
- * each with different levels of logging (DEBUG, INFO) to which
- * thread local request logging is attached. An event will be logged
- * from any of these sources that pass the level criteria. Here, as
- * with the rest of the Log4J environment, the real logging is based
- * on static fields.
- *
- * However, and this is a key feature of the logic, this "static"
- * environment is ThreadLocal. That means that this "static" data
- * really has a different reference and points to a different Writer
- * in each request processing thread. This is why the superficially
- * "static" value doesn't have to be synchronized.
- *
- * All ThreadLocalAppenders that share the same companion class name
- * share the same output buffer. To create a separate buffer with
- * separate data, you need both another companion class (which can
- * be modelled on SimpleAppenderContextImpl, but must have a different
- * name) and a separate Filter to load and activate it.
- *
- * Dependencies: Log4J
- */
-package edu.internet2.middleware.commons.log4j;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.spi.LoggingEvent;
-
-/**
- * Appender that writes to ThreadLocal storage.
- *
- * <p>This is a standard Log4J appender that just happens to get a Writer
- * every time it wants to log data from a companion class. Actually, this
- * class doesn't know anything about ThreadLocal, but the motivation for
- * this is to maintain separate easy to access logs for each request, and
- * that can only be accomplied with a ThreadLocal Writer.</p>
- *
- * <p> Everything here is defined by the Log4J API.</p>
- *
- * @author Howard Gilbert
- */
-public class ThreadLocalAppender extends AppenderSkeleton{
-
- private ThreadLocalAppenderContext appenderContext = new SimpleAppenderContextImpl();
-
- /**
- * A String property that can be set by the Log4J configuration file
- * for this Appender to provide the name of a different companion
- * class implementing the necessary interfaces.
- * <p>
- * Although it is not obvious from any explicit documentation,
- * when Log4J loads an Appender class it uses Bean Introspection
- * to determine any properties of the bean. Subsequent statements
- * in the configuration file (property or xml) can then specify
- * values for the property. In this case, a property named
- * "LocalContext" can be set to the name of a class that implements
- * the ThreadLocalAppenderContext interface.
- * </p><p>
- * If the property is not set, then "SimpleAppenderContextImpl" is used.</p>
- */
- private String localContext = null;
- public String getLocalContext() {
- return localContext;
- }
- public void setLocalContext(String localContext) {
- this.localContext = localContext;
- try {
- Class c = Class.forName(localContext);
- if (ThreadLocalAppenderContext.class.isAssignableFrom(c)) {
- appenderContext = (ThreadLocalAppenderContext) c.newInstance();
- }
- } catch (ClassNotFoundException e) {
- } catch (InstantiationException e) {
- } catch (IllegalAccessException e) {
- }
- if (appenderContext==null)
- System.out.println("ThreadLocalAppender cannot load "+localContext);
- }
- /**
- * The main method called by Log4J when an event must be logged.
- *
- * @param event
- */
- protected void append(LoggingEvent event) {
- if (appenderContext==null)
- return; // No helper class
- Writer logBuffer = appenderContext.getLocalWriter();
- if (logBuffer==null) {
- // If there is no Writer, then we are probably not in a Request.
- // Log4J is static an applies to all the code in all the classes
- // in the source. However, some log statements will appear in
- // init() methods, or constructors, or background threads. If
- // you want to log that, you need an ordinary Log4J static
- // appender. This only logs stuff that happens within the
- // processing path of a Servlet doGet() or similar request.
- return;
- }
- try {
- logBuffer.write(this.layout.format(event));
- } catch (IOException e) {
- // Best effort, but will not occur with StringWriter.
- }
- }
-
- public boolean requiresLayout() {
- return true;
- }
-
- /**
- * Most of the time it is OK to ignore close, but there is some
- * chance that the Writer we are getting is associated with a
- * File or Socket. So just in case, forward the close on to the
- * Writer.
- */
- public void close() {
- if (appenderContext==null)
- return;
- Writer logBuffer = appenderContext.getLocalWriter();
- if (logBuffer==null)
- return;
- try {
- logBuffer.close();
- } catch (IOException e) {
- // In the common case, this is a StringBuffer that doesn't
- // throw exceptions anyway. Otherwise, this is a best effort.
- }
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * ThreadLocalAppenderContext.java
- *
- * An interface describing the services provided by the "helper class"
- * that feeds the ThreadLocal Writer to the Log4J ThreadLocalAppender.
- * It also exposes startRequest() and endRequest() methods to anyone
- * managing the gate through which the threadpool request manager
- * (say Tomcat) dispatches requests (GET or PUT HTTP requests) to an
- * application (a Tomcat context) where you want a separate log file
- * or buffer for every individual request processed.
- *
- * The default implementation of this interface is provided by the
- * SimpleAppenderContextImpl class.
- */
-
-package edu.internet2.middleware.commons.log4j;
-
-import java.io.Writer;
-
-/**
- * Provide ThreadLocalAppender with a Writer into which to put the log data.
- *
- * Provide the Request managment layer (Servlet, Servlet Filter, RMI, ...) methods to signal the start and end of a
- * request. After the startRequest the implementing object should have generated a bucket to hold trace and should
- *
- * <p>
- * The purpose of ThreadLocal logging is to log activity local to a request in an application server (say a Tomcat Web
- * request). The problem is that such threads never belong to the code that is doing the logging, they belong to the
- * external container. So what you have to do is load the ThreadLocal reference on entry to the Servlet/EJB/whatever and
- * then clear the pointer before returning to the container. You can't do that if the ThreadLocal variable belongs to
- * the Appender, because the Appender should, if properly abstracted, only know about log4j. So you have to feed the
- * appender an object (or the name of a class that can create an object) that knows where the ThreadLocal pointer is for
- * this application and can return it. That is what this interface does.
- * </p>
- *
- * <p>
- * You must create a class, familiar with the environment, that implements the class and passes back either null or a
- * ThreadLocal Writer. The name of this class must be the LocalContext parameter of the ThreadLocalAppender
- * configuration. The class must be in the classpath when the Appender is configured.
- * </p>
- *
- * @author Howard Gilbert
- */
-public interface ThreadLocalAppenderContext {
-
- /**
- * Give the Appender a Writer into which to write data.
- *
- * @return Writer
- */
- Writer getLocalWriter();
-
- /**
- * Called by the request manager (say the Servlet Filter) to signal the start of a new request. The implementor must
- * allocate a new Writer to accept data.
- */
- void startRequest();
-
- /**
- * Called by the request manager to signal the end of a request. Returns an IOU that will deliver the log data on
- * request if it is needed (typically when a Servlet wants to display log data to a remote user.)
- *
- * @return WrappedLog object to access log data.
- */
- WrappedLog endRequest();
-
-}
+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed 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.
- */
-
-/*
- * WrappedLog.java
- *
- * IOU object for some Log data.
- *
- * This interface is implemented, for example, by the
- * SimpleAppenderContextImpl.WrappedStringLog class.
- */
-
-package edu.internet2.middleware.commons.log4j;
-
-/**
- * Wrapper to abstract the ThreadLocal log storage.
- *
- * <p>
- * In most cases, the log data will just be a string kept in memory. However, one could imagine it would be a file on
- * disk, or an EhCache hybrid where the last 100 are kept in memory and the overflow of less recently used are written
- * to disk. So after logging is done, we return this IOU that will fetch the log data later when you want to display it.
- *
- * @author Howard Gilbert
- */
-public interface WrappedLog {
-
- String getLogData();
-
-}