View Javadoc

1   package org.apache.mina.util;
2   
3   import org.slf4j.MDC;
4   import org.slf4j.helpers.BasicMDCAdapter;
5   
6   import java.util.logging.Formatter;
7   import java.util.logging.LogRecord;
8   import java.util.Set;
9   import java.util.Arrays;
10  
11  /**
12   * Implementation of {@link java.util.logging.Formatter} that generates xml in the log4j format.
13   * <p>
14   * The generated xml corresponds 100% with what is generated by
15   * log4j's <a href=http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html">XMLLayout</a>
16   * <p>
17   * The MDC properties will only be correct when <code>format</code> is called from the same thread
18   * that generated the LogRecord.
19   * <p>
20   * The file and line attributes in the locationInfo element will always be "?"
21   * since java.util.logging.LogRecord does not provide that info.
22   * <p>
23   * The implementation is heavily based on org.apache.log4j.xml.XMLLayout
24   * </p>
25   */
26  public class Log4jXmlFormatter extends Formatter {
27  
28      private final int DEFAULT_SIZE = 256;
29      private final int UPPER_LIMIT = 2048;
30  
31      private StringBuffer buf = new StringBuffer(DEFAULT_SIZE);
32      private boolean locationInfo = false;
33      private boolean properties = false;
34  
35      /**
36       * The <b>LocationInfo</b> option takes a boolean value. By default,
37       * it is set to false which means there will be no location
38       * information output by this layout. If the the option is set to
39       * true, then the file name and line number of the statement at the
40       * origin of the log statement will be output.
41       *
42       * @param flag whether locationInfo should be output by this layout
43       */
44      public void setLocationInfo(boolean flag) {
45          locationInfo = flag;
46      }
47  
48      /**
49       * Returns the current value of the <b>LocationInfo</b> option.
50       *
51       * @return whether locationInfo will be output by this layout
52       */
53      public boolean getLocationInfo() {
54          return locationInfo;
55      }
56  
57      /**
58       * Sets whether MDC key-value pairs should be output, default false.
59       *
60       * @param flag new value.
61       */
62      public void setProperties(final boolean flag) {
63          properties = flag;
64      }
65  
66      /**
67       * Gets whether MDC key-value pairs should be output.
68       *
69       * @return true if MDC key-value pairs are output.
70       */
71      public boolean getProperties() {
72          return properties;
73      }
74  
75      public String format(final LogRecord record) {
76          // Reset working buffer. If the buffer is too large, then we need a new
77          // one in order to avoid the penalty of creating a large array.
78          if (buf.capacity() > UPPER_LIMIT) {
79              buf = new StringBuffer(DEFAULT_SIZE);
80          } else {
81              buf.setLength(0);
82          }
83          buf.append("<log4j:event logger=\"");
84          buf.append(Transform.escapeTags(record.getLoggerName()));
85          buf.append("\" timestamp=\"");
86          buf.append(record.getMillis());
87          buf.append("\" level=\"");
88  
89          buf.append(Transform.escapeTags(record.getLevel().getName()));
90          buf.append("\" thread=\"");
91          buf.append(String.valueOf(record.getThreadID()));
92          buf.append("\">\r\n");
93  
94          buf.append("<log4j:message><![CDATA[");
95          // Append the rendered message. Also make sure to escape any
96          // existing CDATA sections.
97          Transform.appendEscapingCDATA(buf, record.getMessage());
98          buf.append("]]></log4j:message>\r\n");
99  
100         if (record.getThrown() != null) {
101             String[] s = Transform.getThrowableStrRep(record.getThrown());
102             if (s != null) {
103                 buf.append("<log4j:throwable><![CDATA[");
104                 for (String value : s) {
105                     Transform.appendEscapingCDATA(buf, value);
106                     buf.append("\r\n");
107                 }
108                 buf.append("]]></log4j:throwable>\r\n");
109             }
110         }
111 
112         if (locationInfo) {
113             buf.append("<log4j:locationInfo class=\"");
114             buf.append(Transform.escapeTags(record.getSourceClassName()));
115             buf.append("\" method=\"");
116             buf.append(Transform.escapeTags(record.getSourceMethodName()));
117             buf.append("\" file=\"?\" line=\"?\"/>\r\n");
118         }
119 
120         if (properties) {
121             if (MDC.getMDCAdapter() instanceof BasicMDCAdapter) {
122                 BasicMDCAdapter mdcAdapter = (BasicMDCAdapter) MDC.getMDCAdapter();
123                 Set keySet = mdcAdapter.getKeys();
124                 if (keySet != null && keySet.size() > 0) {
125                     buf.append("<log4j:properties>\r\n");
126                     Object[] keys = keySet.toArray();
127                     Arrays.sort(keys);
128                     for (Object key1 : keys) {
129                         String key = key1.toString();
130                         Object val = mdcAdapter.get(key);
131                         if (val != null) {
132                             buf.append("<log4j:data name=\"");
133                             buf.append(Transform.escapeTags(key));
134                             buf.append("\" value=\"");
135                             buf.append(Transform.escapeTags(String.valueOf(val)));
136                             buf.append("\"/>\r\n");
137                         }
138                     }
139                     buf.append("</log4j:properties>\r\n");
140                 }
141             }
142         }
143         buf.append("</log4j:event>\r\n\r\n");
144 
145         return buf.toString();
146     }
147 
148 }