[slf4j-dev] svn commit: r1283 - in slf4j/trunk: slf4j-ext/src/main/java/org/slf4j/ext slf4j-site/src/site/pages
rgoers at slf4j.org
rgoers at slf4j.org
Fri Feb 27 00:18:59 CET 2009
Author: rgoers
Date: Fri Feb 27 00:18:58 2009
New Revision: 1283
Modified:
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventData.java
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventException.java
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventLogger.java
slf4j/trunk/slf4j-site/src/site/pages/extensions.html
Log:
Fix style and add documentation
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventData.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventData.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventData.java Fri Feb 27 00:18:58 2009
@@ -18,176 +18,229 @@
*
* @author Ralph Goers
*/
-public class EventData implements Serializable
-{
- private Map<String, Object> eventData = new HashMap<String,Object>();
- public static final String EVENT_MESSAGE = "EventMessage";
- public static final String EVENT_TYPE = "EventType";
- public static final String EVENT_DATETIME = "EventDateTime";
- public static final String EVENT_ID = "EventId";
-
- /**
- * Default Constructor
- */
- public EventData()
- {
- }
-
- /**
- * Constructor to create event data from a Map.
- * @param map The event data.
- */
- public EventData(Map<String, Object> map)
- {
- eventData.putAll(map);
- }
-
- /**
- * Construct from a serialized form of the Map containing the RequestInfo elements
- * @param xml The serialized form of the RequestInfo Map.
- */
- public EventData(String xml)
- {
- ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
- try
- {
- XMLDecoder decoder = new XMLDecoder(bais);
- this.eventData = (Map<String, Object>)decoder.readObject();
+public class EventData implements Serializable {
+ private Map<String, Object> eventData = new HashMap<String, Object>();
+ public static final String EVENT_MESSAGE = "EventMessage";
+ public static final String EVENT_TYPE = "EventType";
+ public static final String EVENT_DATETIME = "EventDateTime";
+ public static final String EVENT_ID = "EventId";
+
+ /**
+ * Default Constructor
+ */
+ public EventData() {
+ }
+
+ /**
+ * Constructor to create event data from a Map.
+ *
+ * @param map The event data.
+ */
+ public EventData(Map<String, Object> map) {
+ eventData.putAll(map);
+ }
+
+ /**
+ * Construct from a serialized form of the Map containing the RequestInfo elements
+ *
+ * @param xml The serialized form of the RequestInfo Map.
+ */
+ public EventData(String xml) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
+ try {
+ XMLDecoder decoder = new XMLDecoder(bais);
+ this.eventData = (Map<String, Object>) decoder.readObject();
+ }
+ catch (Exception e) {
+ throw new EventException("Error decoding " + xml, e);
+ }
+ }
+
+ /**
+ * Serialize all the EventData items into an XML representation.
+ *
+ * @return an XML String containing all the EventDAta items.
+ */
+ public String toXML() {
+ return toXML(eventData);
+ }
+
+ /**
+ * Serialize all the EventData items into an XML representation.
+ *
+ * @return an XML String containing all the EventDAta items.
+ */
+ public static String toXML(Map<String, Object> map) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ XMLEncoder encoder = new XMLEncoder(baos);
+ encoder.setExceptionListener(new ExceptionListener() {
+ public void exceptionThrown(Exception exception) {
+ exception.printStackTrace();
}
- catch (Exception e)
- {
- throw new EventException("Error decoding " + xml, e);
- }
- }
-
- /**
- * Serialize all the EventData items into an XML representation.
- * @return an XML String containing all the EventDAta items.
- */
- public String toXML()
- {
- return toXML(eventData);
- }
-
- /**
- * Serialize all the EventData items into an XML representation.
- * @return an XML String containing all the EventDAta items.
- */
- public static String toXML(Map<String, Object>map)
- {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try
- {
- XMLEncoder encoder = new XMLEncoder(baos);
- encoder.setExceptionListener(new ExceptionListener()
- {
- public void exceptionThrown(Exception exception)
- {
- exception.printStackTrace();
- }
- });
- encoder.writeObject(map);
- encoder.close();
- return baos.toString();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return null;
- }
- }
-
- public String getEventId()
- {
- return (String)this.eventData.get(EVENT_ID);
- }
-
- public void setEventId(String eventId)
- {
- if (eventId == null)
- {
- throw new IllegalArgumentException("eventId cannot be null");
- }
- this.eventData.put(EVENT_ID, eventId);
- }
-
- public String getMessage()
- {
- return (String)this.eventData.get(EVENT_MESSAGE);
- }
-
- public void setMessage(String message)
- {
- this.eventData.put(EVENT_MESSAGE, message);
- }
-
- public Date getEventDateTime()
- {
- return (Date)this.eventData.get(EVENT_DATETIME);
- }
-
- public void setEventDateTime(Date eventDateTime)
- {
- this.eventData.put(EVENT_DATETIME, eventDateTime);
- }
-
- public void setEventType(String eventType)
- {
- this.eventData.put(EVENT_TYPE, eventType);
- }
-
- public String getEventType()
- {
- return (String)this.eventData.get(EVENT_TYPE);
- }
-
-
- public void put(String name, Serializable obj)
- {
- this.eventData.put(name, obj);
- }
-
- public Serializable get(String name)
- {
- return (Serializable) this.eventData.get(name);
- }
-
- public void putAll(Map data)
- {
- this.eventData.putAll(data);
- }
-
- public int getSize()
- {
- return this.eventData.size();
- }
-
- public Iterator getEntrySetIterator()
- {
- return this.eventData.entrySet().iterator();
- }
-
- public Map getEventMap()
- {
- return this.eventData;
- }
-
- public String toString()
- {
- return toXML();
- }
-
- public boolean equals(Object o)
- {
- if (this == o) return true;
- if (!(o instanceof EventData || o instanceof Map)) return false;
- Map<String, Object>map = (o instanceof EventData) ? ((EventData)o).getEventMap() : (Map<String, Object>)o;
-
- return this.eventData.equals(map);
- }
-
- public int hashCode()
- {
- return this.eventData.hashCode();
- }
+ });
+ encoder.writeObject(map);
+ encoder.close();
+ return baos.toString();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the event identifier.
+ * @return The event identifier
+ */
+ public String getEventId() {
+ return (String) this.eventData.get(EVENT_ID);
+ }
+
+ /**
+ * Set the event identifier.
+ * @param eventId The event identifier.
+ */
+ public void setEventId(String eventId) {
+ if (eventId == null) {
+ throw new IllegalArgumentException("eventId cannot be null");
+ }
+ this.eventData.put(EVENT_ID, eventId);
+ }
+
+ /**
+ * Retrieve the message text associated with this event, if any.
+ * @return The message text associated with this event or null if there is none.
+ */
+ public String getMessage() {
+ return (String) this.eventData.get(EVENT_MESSAGE);
+ }
+
+ /**
+ * Set the message text associated with this event.
+ * @param message The message text.
+ */
+ public void setMessage(String message) {
+ this.eventData.put(EVENT_MESSAGE, message);
+ }
+
+ /**
+ * Retrieve the date and time the event occurred.
+ * @return The Date associated with the event.
+ */
+ public Date getEventDateTime() {
+ return (Date) this.eventData.get(EVENT_DATETIME);
+ }
+
+ /**
+ * Set the date and time the event occurred in case it is not the same as when
+ * the event was logged.
+ * @param eventDateTime The event Date.
+ */
+ public void setEventDateTime(Date eventDateTime) {
+ this.eventData.put(EVENT_DATETIME, eventDateTime);
+ }
+
+ /**
+ * Set the type of event that occurred.
+ * @param eventType The type of the event.
+ */
+ public void setEventType(String eventType) {
+ this.eventData.put(EVENT_TYPE, eventType);
+ }
+
+ /**
+ * Retrieve the type of the event.
+ * @return The event type.
+ */
+ public String getEventType() {
+ return (String) this.eventData.get(EVENT_TYPE);
+ }
+
+ /**
+ * Add arbitrary attributes about the event.
+ * @param name The attribute's key.
+ * @param obj The data associated with the key.
+ */
+ public void put(String name, Serializable obj) {
+ this.eventData.put(name, obj);
+ }
+
+ /**
+ * Retrieve an event attribute.
+ * @param name The attribute's key.
+ * @return The value associated with the key or null if the key is not present.
+ */
+ public Serializable get(String name) {
+ return (Serializable) this.eventData.get(name);
+ }
+
+ /**
+ * Populate the event data from a Map.
+ * @param data The Map to copy.
+ */
+ public void putAll(Map data) {
+ this.eventData.putAll(data);
+ }
+
+ /**
+ * Returns the number of attributes in the EventData.
+ * @return the number of attributes in the EventData.
+ */
+ public int getSize() {
+ return this.eventData.size();
+ }
+
+ /**
+ * Returns an Iterator over all the entries in the EventDAta.
+ * @return an Iterator that can be used to access all the event attributes.
+ */
+ public Iterator getEntrySetIterator() {
+ return this.eventData.entrySet().iterator();
+ }
+
+ /**
+ * Retrieve all the attributes in the EventData as a Map. Changes to this map will be
+ * reflected in the EventData.
+ * @return The Map of attributes in this EventData instance.
+ */
+ public Map getEventMap() {
+ return this.eventData;
+ }
+
+ /**
+ * Convert the EventData to a String.
+ * @return The EventData as a String.
+ */
+ @Override
+ public String toString() {
+ return toXML();
+ }
+
+ /**
+ * Compare two EventData objects for equality.
+ * @param o The Object to compare.
+ * @return true if the objects are the same instance or contain all the same keys and their values.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof EventData || o instanceof Map)) {
+ return false;
+ }
+ Map<String, Object> map = (o instanceof EventData) ? ((EventData) o).getEventMap() : (Map<String, Object>) o;
+
+ return this.eventData.equals(map);
+ }
+
+ /**
+ * Compute the hashCode for this EventData instance.
+ * @return The hashcode for this EventData instance.
+ */
+ @Override
+ public int hashCode() {
+ return this.eventData.hashCode();
+ }
}
\ No newline at end of file
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventException.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventException.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventException.java Fri Feb 27 00:18:58 2009
@@ -1,27 +1,39 @@
package org.slf4j.ext;
/**
- *
+ * Exception used to identify issues related to an event that is being logged.
*/
-public class EventException extends RuntimeException
-{
- public EventException()
- {
- super();
- }
+public class EventException extends RuntimeException {
+ /**
+ * Default constructor.
+ */
+ public EventException() {
+ super();
+ }
- public EventException(String exceptionMessage)
- {
- super(exceptionMessage);
- }
+ /**
+ * Constructor that allows an exception message.
+ * @param exceptionMessage The exception message.
+ */
+ public EventException(String exceptionMessage) {
+ super(exceptionMessage);
+ }
- public EventException(Throwable originalException)
- {
- super(originalException);
- }
+ /**
+ * Constructor that chains another Exception or Error.
+ * @param originalException The original exception.
+ */
+ public EventException(Throwable originalException) {
+ super(originalException);
+ }
- public EventException(String exceptionMessage, Throwable originalException)
- {
- super(exceptionMessage, originalException);
- }
+ /**
+ * Constructor that chains another Exception or Error and also allows a message
+ * to be specified.
+ * @param exceptionMessage The exception message.
+ * @param originalException The original excepton.
+ */
+ public EventException(String exceptionMessage, Throwable originalException) {
+ super(exceptionMessage, originalException);
+ }
}
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventLogger.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventLogger.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/ext/EventLogger.java Fri Feb 27 00:18:58 2009
@@ -5,6 +5,8 @@
import org.slf4j.MarkerFactory;
import org.slf4j.spi.LocationAwareLogger;
+import java.util.Map;
+
/**
* Simple Logger used to log events. All events are directed to a logger named "EventLogger"
* with a level of ERROR (the closest to "always" that SLF4J gets) and with an Event marker.
@@ -13,32 +15,30 @@
*/
public class EventLogger {
- private static final String FQCN = EventLogger.class.getName();
-
- static Marker EVENT_MARKER = MarkerFactory.getMarker("EVENT");
-
- private static LoggerWrapper eventLogger =
- eventLogger = new LoggerWrapper(LoggerFactory.getLogger("EventLogger"), FQCN);
+ private static final String FQCN = EventLogger.class.getName();
+ static Marker EVENT_MARKER = MarkerFactory.getMarker("EVENT");
+ private static LoggerWrapper eventLogger =
+ new LoggerWrapper(LoggerFactory.getLogger("EventLogger"), FQCN);
- /**
- * There can only be a single EventLogger.
- */
- private EventLogger() {
- }
-
- /**
- * Logs the event.
- * @param data The EventData.
- */
- public static void logEvent(EventData data)
- {
- if (eventLogger.instanceofLAL) {
- ((LocationAwareLogger) eventLogger.logger).log(EVENT_MARKER, FQCN,
+ /**
+ * There can only be a single EventLogger.
+ */
+ private EventLogger() {
+ }
+
+ /**
+ * Logs the event.
+ *
+ * @param data The EventData.
+ */
+ public static void logEvent(EventData data) {
+ if (eventLogger.instanceofLAL) {
+ ((LocationAwareLogger) eventLogger.logger).log(EVENT_MARKER, FQCN,
LocationAwareLogger.ERROR_INT, data.toXML(), null);
- } else {
- eventLogger.logger.error(EVENT_MARKER, data.toXML(), data);
- }
+ } else {
+ eventLogger.logger.error(EVENT_MARKER, data.toXML(), data);
}
+ }
}
Modified: slf4j/trunk/slf4j-site/src/site/pages/extensions.html
==============================================================================
--- slf4j/trunk/slf4j-site/src/site/pages/extensions.html (original)
+++ slf4j/trunk/slf4j-site/src/site/pages/extensions.html Fri Feb 27 00:18:58 2009
@@ -26,6 +26,7 @@
<ul>
<li><a href="#profiler">Profiler</a></li>
<li><a href="#extended_logger">Extended logger</a></li>
+ <li><a href="#event_logger">Event Logging</a></li>
<li><a href="#javaagent">Logging added with Java agent (requires Java 5)</a></li>
</ul>
@@ -579,6 +580,149 @@
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997) </p>
+ <!-- .............................................................. -->
+
+ <h2><a name="event_logger"></a>Event Logging</h2>
+
+ <p>The EventLogger class provides a simple mechansim for logging events that occur in an application.
+ While the EventLogger is useful as a way of initiating events that should be processed by an audit
+ Logging system, it does not implement any of the features an audit logging system would require
+ such as guaranteed delivery.</p>
+
+ <p>The recommended way of using the EventLogger in a typcial web application is to populate
+ the SLF4J MDC with data that is related to the entire lifespan of the request such as the user's id,
+ the user's ip address, the product name, etc. This can easily be done in a servlet fileter where
+ the MDC can also be cleared at the end of the request. When an event that needs to be recorded
+ occurs an EventData object should be created and populated. Then call EventLogger.logEvent(data)
+ where data is a reference to the EventData object.</p>
+
+ <p class="source">import org.slf4j.MDC;
+import org.apache.commons.lang.time.DateUtils;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.TimeZone;
+
+public class RequestFilter implements Filter
+{
+ private FilterConfig filterConfig;
+ private static String TZ_NAME = "timezoneOffset";
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ this.filterConfig = filterConfig;
+ }
+
+ /**
+ * Sample filter that populates the MDC on every request.
+ */
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
+ FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest)servletRequest;
+ HttpServletResponse response = (HttpServletResponse)servletResponse;
+ MDC.put("ipAddress", request.getRemoteAddr());
+ HttpSession session = request.getSession(false);
+ TimeZone timeZone = null;
+ if (session != null) {
+ // Something should set this after authentication completes
+ String loginId = (String)session.getAttribute("LoginId");
+ if (loginId != null) {
+ MDC.put("loginId", loginId);
+ }
+ // This assumes there is some javascript on the user's page to create the cookie.
+ if (session.getAttribute(TZ_NAME) == null) {
+ if (request.getCookies() != null) {
+ for (Cookie cookie : request.getCookies()) {
+ if (TZ_NAME.equals(cookie.getName())) {
+ int tzOffsetMinutes = Integer.parseInt(cookie.getValue());
+ timeZone = TimeZone.getTimeZone("GMT");
+ timeZone.setRawOffset((int)(tzOffsetMinutes * DateUtils.MILLIS_PER_MINUTE));
+ request.getSession().setAttribute(TZ_NAME, tzOffsetMinutes);
+ cookie.setMaxAge(0);
+ response.addCookie(cookie);
+ }
+ }
+ }
+ }
+ }
+ MDC.put("hostname", servletRequest.getServerName());
+ MDC.put("productName", filterConfig.getInitParameter("ProductName"));
+ MDC.put("locale", servletRequest.getLocale().getDisplayName());
+ if (timeZone == null) {
+ timeZone = TimeZone.getDefault();
+ }
+ MDC.put("timezone", timeZone.getDisplayName());
+ filterChain.doFilter(servletRequest, servletResponse);
+ MDC.clear();
+ }
+
+ public void destroy() {
+ }
+}
+ </p>
+ <p>Sample class that uses EventLogger.</p>
+ <p class="source">import org.slf4j.ext.EventData;
+import org.slf4j.ext.EventLogger;
+
+import java.util.Date;
+import java.util.UUID;
+
+public class MyApp {
+
+ public String doFundsTransfer(Account toAccount, Account fromAccount, long amount) {
+ toAccount.deposit(amount);
+ fromAccount.withdraw(amount);
+ EventData data = new EventData();
+ data.setEventDateTime(new Date());
+ data.setEventType("transfer");
+ String confirm = UUID.randomUUID().toString();
+ data.setEventId(confirm);
+ data.put("toAccount", toAccount);
+ data.put("fromAccount", fromAccount);
+ data.put("amount", amount);
+ EventLogger.logEvent(data);
+ return confirm;
+ }
+}
+ </p>
+ <p>The EventLogger class uses a Logger named "EventLogger". EventLogger uses a logging level
+ of ERROR since SLF4J has no level that represents "always on". The following shows a
+ configuraton using Logback.</p>
+ <p class="source"><configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <appender name="events" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%d{HH:mm:ss.SSS} %X - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <logger name="EventLogger" additivity="false">
+ <level value="INFO"/>
+ <appender appender-ref="events"/>
+ </logger>
+
+ <root level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
+ </p>
+
+ <!-- .............................................................. -->
+
<h2><a name="javaagent"></a>Adding logging with Java agent</h2>
<p><b>NOTE: BETA RELEASE, NOT PRODUCTION QUALITY</b> </p>
More information about the slf4j-dev
mailing list