001: package org.apache.mina.util;
002:
003: import org.slf4j.MDC;
004: import org.slf4j.helpers.BasicMDCAdapter;
005:
006: import java.util.logging.Formatter;
007: import java.util.logging.LogRecord;
008: import java.util.Set;
009: import java.util.Arrays;
010:
011: /**
012: * Implementation of {@link java.util.logging.Formatter} that generates xml in the log4j format.
013: * <p>
014: * The generated xml corresponds 100% with what is generated by
015: * log4j's <a href=http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html">XMLLayout</a>
016: * <p>
017: * The MDC properties will only be correct when <code>format</code> is called from the same thread
018: * that generated the LogRecord.
019: * <p>
020: * The file and line attributes in the locationInfo element will always be "?"
021: * since java.util.logging.LogRecord does not provide that info.
022: * <p>
023: * The implementation is heavily based on org.apache.log4j.xml.XMLLayout
024: * </p>
025: */
026: public class Log4jXmlFormatter extends Formatter {
027:
028: private final int DEFAULT_SIZE = 256;
029: private final int UPPER_LIMIT = 2048;
030:
031: private StringBuffer buf = new StringBuffer(DEFAULT_SIZE);
032: private boolean locationInfo = false;
033: private boolean properties = false;
034:
035: /**
036: * The <b>LocationInfo</b> option takes a boolean value. By default,
037: * it is set to false which means there will be no location
038: * information output by this layout. If the the option is set to
039: * true, then the file name and line number of the statement at the
040: * origin of the log statement will be output.
041: *
042: * @param flag whether locationInfo should be output by this layout
043: */
044: public void setLocationInfo(boolean flag) {
045: locationInfo = flag;
046: }
047:
048: /**
049: * Returns the current value of the <b>LocationInfo</b> option.
050: *
051: * @return whether locationInfo will be output by this layout
052: */
053: public boolean getLocationInfo() {
054: return locationInfo;
055: }
056:
057: /**
058: * Sets whether MDC key-value pairs should be output, default false.
059: *
060: * @param flag new value.
061: */
062: public void setProperties(final boolean flag) {
063: properties = flag;
064: }
065:
066: /**
067: * Gets whether MDC key-value pairs should be output.
068: *
069: * @return true if MDC key-value pairs are output.
070: */
071: public boolean getProperties() {
072: return properties;
073: }
074:
075: public String format(final LogRecord record) {
076: // Reset working buffer. If the buffer is too large, then we need a new
077: // one in order to avoid the penalty of creating a large array.
078: if (buf.capacity() > UPPER_LIMIT) {
079: buf = new StringBuffer(DEFAULT_SIZE);
080: } else {
081: buf.setLength(0);
082: }
083: buf.append("<log4j:event logger=\"");
084: buf.append(Transform.escapeTags(record.getLoggerName()));
085: buf.append("\" timestamp=\"");
086: buf.append(record.getMillis());
087: buf.append("\" level=\"");
088:
089: buf.append(Transform.escapeTags(record.getLevel().getName()));
090: buf.append("\" thread=\"");
091: buf.append(String.valueOf(record.getThreadID()));
092: buf.append("\">\r\n");
093:
094: buf.append("<log4j:message><![CDATA[");
095: // Append the rendered message. Also make sure to escape any
096: // existing CDATA sections.
097: Transform.appendEscapingCDATA(buf, record.getMessage());
098: buf.append("]]></log4j:message>\r\n");
099:
100: if (record.getThrown() != null) {
101: String[] s = Transform.getThrowableStrRep(record
102: .getThrown());
103: if (s != null) {
104: buf.append("<log4j:throwable><![CDATA[");
105: for (String value : s) {
106: Transform.appendEscapingCDATA(buf, value);
107: buf.append("\r\n");
108: }
109: buf.append("]]></log4j:throwable>\r\n");
110: }
111: }
112:
113: if (locationInfo) {
114: buf.append("<log4j:locationInfo class=\"");
115: buf.append(Transform
116: .escapeTags(record.getSourceClassName()));
117: buf.append("\" method=\"");
118: buf.append(Transform.escapeTags(record
119: .getSourceMethodName()));
120: buf.append("\" file=\"?\" line=\"?\"/>\r\n");
121: }
122:
123: if (properties) {
124: if (MDC.getMDCAdapter() instanceof BasicMDCAdapter) {
125: BasicMDCAdapter mdcAdapter = (BasicMDCAdapter) MDC
126: .getMDCAdapter();
127: Set keySet = mdcAdapter.getKeys();
128: if (keySet != null && keySet.size() > 0) {
129: buf.append("<log4j:properties>\r\n");
130: Object[] keys = keySet.toArray();
131: Arrays.sort(keys);
132: for (Object key1 : keys) {
133: String key = key1.toString();
134: Object val = mdcAdapter.get(key);
135: if (val != null) {
136: buf.append("<log4j:data name=\"");
137: buf.append(Transform.escapeTags(key));
138: buf.append("\" value=\"");
139: buf.append(Transform.escapeTags(String
140: .valueOf(val)));
141: buf.append("\"/>\r\n");
142: }
143: }
144: buf.append("</log4j:properties>\r\n");
145: }
146: }
147: }
148: buf.append("</log4j:event>\r\n\r\n");
149:
150: return buf.toString();
151: }
152:
153: }
|