package com.runjva.logback.xml; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import ch.qos.logback.classic.pattern.ClassOfCallerConverter; import ch.qos.logback.classic.pattern.FileOfCallerConverter; import ch.qos.logback.classic.pattern.LineOfCallerConverter; import ch.qos.logback.classic.pattern.MethodOfCallerConverter; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.classic.spi.ThrowableDataPoint; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.logback.core.CoreConstants; /** *

* XMLLayout creates XML fragments conforming to the log4j.dtd from the Apache * log4j project, and generates output compatible with the log4j XMLLayout * class. Files written with this layout are readable by Chainsaw (note that * output is in 7-bit ASCII so encoding should not be a problem). *

*

* The physical layout is intended to be somewhat readable by human eyes. Each * event generates two lines. The first starts with * *

 * <log4j:event time='2009-02-04 13:00:16,650' logger='com.runjva.logback.xml.XMLLayoutMain'
 * 
* * where the time attribute (which is valid but unused in the log4j XMLLayout) * is used to render a humanly readable form of the timestamp in the ISO8601 * pattern used in PatternLayout dates. The second line starts with * *
 * <log4j:message>A debug message</log4j:message>
 * 
* * which is the message with a prefix common to all lines giving the same * indention hopefully making it readable to the human eye. *

* */ public class XMLLayout extends ch.qos.logback.core.LayoutBase { // The following attributes are listed on // http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html boolean locationInfo = true; boolean properties = true; DateFormat simpleFormat = new SimpleDateFormat( CoreConstants.ISO8601_PATTERN); public String doLayout(LoggingEvent event) { /* * Hey you! * */ java.util.Date then = new java.util.Date(event.getTimeStamp()); StringBuffer sb = new StringBuffer(); sb.append(""); sb.append("\n"); sb.append(""); sb.append(q(event.getFormattedMessage())); sb.append(""); // // not available in slf4j // #CONTENT is lines separated with \n ThrowableProxy throwableProxy = event.getThrowableProxy(); if (throwableProxy != null) { sb.append(""); ThrowableDataPoint[] dataPoints; dataPoints = throwableProxy.getThrowableDataPointArray(); for (int i = 0; i < dataPoints.length; i++) { ThrowableDataPoint throwableDataPoint = dataPoints[i]; sb.append(q(throwableDataPoint.toString())); sb.append(q("\n")); } sb.append(""); } // if (this.getLocationInfo()) { sb.append(""); } /* * * */ if (this.getProperties()) { Map propertyMap = event.getMDCPropertyMap(); if (propertyMap != null) { Set> entrySet = propertyMap.entrySet(); sb.append(""); for (Entry entry : entrySet) { sb.append(""); } sb.append(""); } } sb.append("\n"); // System.err.println(" << " + sb.toString()); return sb.toString(); } public boolean getLocationInfo() { return locationInfo; } /** * setLocationInfo sets the locationInfo flag. If true each event layouted * by XMLLayout include the file name and line number where the log event * was created. If false, no location information is included- * * @param locationInfo * new value to set */ public void setLocationInfo(boolean locationInfo) { // System.out.println("locationInfo= " + locationInfo); this.locationInfo = locationInfo; } public boolean getProperties() { return properties; } /** * setProperties sets the properties flag. If true each event layouted by * XMLLayout include the complete set of key-value pairs in the MDC. If * false, no MDC information is layouted. * * @param properties */ public void setProperties(boolean properties) { // System.err.println("properties=" + properties); this.properties = properties; } /** * q quotes the string s so it can be used directly as an XML payload * without worrying about reserved characters or character encodings as all * non-ASCII characters plus those reserved in XML are rendered as * &#entity; - e.g. renders & as &#35;. * * @param s * @return StringBuffer with a XML representation of s */ private StringBuffer q(String s) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if (ch < 32 || ch == '&' || ch == '<' || ch == '>' || ch > 126) { sb.append("&#" + ((int) ch) + ";"); } else { sb.append(ch); } } return sb; } }