2062a80013c4d7a4a4f2f931ba102bf2f8fc9b4d
[jalview.git] / srcjar2 / org / apache / log4j / xml / XMLLayout.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 // Contributors:   Mathias Bogaert
19
20 package org.apache.log4j.xml;
21
22 import org.apache.log4j.Layout;
23 import org.apache.log4j.helpers.Transform;
24 import org.apache.log4j.spi.LocationInfo;
25 import org.apache.log4j.spi.LoggingEvent;
26
27 import java.util.Set;
28 import java.util.Arrays;
29
30 /**
31  * The output of the XMLLayout consists of a series of log4j:event
32  * elements as defined in the <a
33  * href="log4j.dtd">log4j.dtd</a>. It does not output a
34  * complete well-formed XML file. The output is designed to be
35  * included as an <em>external entity</em> in a separate file to form
36  * a correct XML file.
37  *
38  * <p>For example, if <code>abc</code> is the name of the file where
39  * the XMLLayout ouput goes, then a well-formed XML file would be:
40  *
41   <pre>
42    &lt;?xml version="1.0" ?&gt;
43  
44   &lt;!DOCTYPE log4j:eventSet PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd" [&lt;!ENTITY data SYSTEM "abc"&gt;]&gt;
45  
46   &lt;log4j:eventSet version="1.2" xmlns:log4j="http://jakarta.apache.org/log4j/"&gt;
47         &nbsp;&nbsp;&data;
48   &lt;/log4j:eventSet&gt;
49   </pre>
50  
51  * <p>This approach enforces the independence of the XMLLayout and the
52  * appender where it is embedded.
53  *
54  * <p>The <code>version</code> attribute helps components to correctly
55  * intrepret output generated by XMLLayout. The value of this
56  * attribute should be "1.1" for output generated by log4j versions
57  * prior to log4j 1.2 (final release) and "1.2" for relase 1.2 and
58  * later.
59  *
60  * Appenders using this layout should have their encoding
61  * set to UTF-8 or UTF-16, otherwise events containing
62  * non ASCII characters could result in corrupted
63  * log files. 
64  *
65  * @author Ceki  G&uuml;lc&uuml;
66  * @since 0.9.0 
67  * */
68 public class XMLLayout extends Layout {
69
70   private  final int DEFAULT_SIZE = 256;
71   private final int UPPER_LIMIT = 2048;
72
73   private StringBuffer buf = new StringBuffer(DEFAULT_SIZE);
74   private boolean locationInfo = false;
75   private boolean properties = false;
76  
77   /**
78    * The <b>LocationInfo</b> option takes a boolean value. By default,
79    * it is set to false which means there will be no location
80    * information output by this layout. If the the option is set to
81    * true, then the file name and line number of the statement at the
82    * origin of the log statement will be output.
83    *
84    * <p>If you are embedding this layout within an {@link
85    * org.apache.log4j.net.SMTPAppender} then make sure to set the
86    * <b>LocationInfo</b> option of that appender as well.
87    * */
88   public void setLocationInfo(boolean flag) {
89     locationInfo = flag;
90   }
91   
92   /**
93      Returns the current value of the <b>LocationInfo</b> option.
94    */
95   public boolean getLocationInfo() {
96     return locationInfo;
97   }
98
99     /**
100      * Sets whether MDC key-value pairs should be output, default false.
101      * @param flag new value.
102      * @since 1.2.15
103      */
104   public void setProperties(final boolean flag) {
105       properties = flag;
106   }
107
108     /**
109      * Gets whether MDC key-value pairs should be output.
110      * @return true if MDC key-value pairs are output.
111      * @since 1.2.15
112      */
113   public boolean getProperties() {
114       return properties;
115   }
116
117   /** No options to activate. */
118   public void activateOptions() {
119   }
120
121
122   /**
123    * Formats a {@link org.apache.log4j.spi.LoggingEvent} in conformance with the log4j.dtd.
124    * */
125   public String format(final LoggingEvent event) {
126
127     // Reset working buffer. If the buffer is too large, then we need a new
128     // one in order to avoid the penalty of creating a large array.
129     if(buf.capacity() > UPPER_LIMIT) {
130       buf = new StringBuffer(DEFAULT_SIZE);
131     } else {
132       buf.setLength(0);
133     }
134     
135     // We yield to the \r\n heresy.
136
137     buf.append("<log4j:event logger=\"");
138     buf.append(Transform.escapeTags(event.getLoggerName()));
139     buf.append("\" timestamp=\"");
140     buf.append(event.timeStamp);
141     buf.append("\" level=\"");
142     buf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
143     buf.append("\" thread=\"");
144     buf.append(Transform.escapeTags(event.getThreadName()));
145     buf.append("\">\r\n");
146
147     buf.append("<log4j:message><![CDATA[");
148     // Append the rendered message. Also make sure to escape any
149     // existing CDATA sections.
150     Transform.appendEscapingCDATA(buf, event.getRenderedMessage());
151     buf.append("]]></log4j:message>\r\n");       
152     
153     String ndc = event.getNDC();
154     if(ndc != null) {
155       buf.append("<log4j:NDC><![CDATA[");
156       Transform.appendEscapingCDATA(buf, ndc);
157       buf.append("]]></log4j:NDC>\r\n");       
158     }
159     
160     String[] s = event.getThrowableStrRep();
161     if(s != null) {
162       buf.append("<log4j:throwable><![CDATA[");
163       for(int i = 0; i < s.length; i++) {
164           Transform.appendEscapingCDATA(buf, s[i]);
165               buf.append("\r\n");
166       }
167       buf.append("]]></log4j:throwable>\r\n");
168     }
169     
170     if(locationInfo) { 
171       LocationInfo locationInfo = event.getLocationInformation();       
172       buf.append("<log4j:locationInfo class=\"");
173       buf.append(Transform.escapeTags(locationInfo.getClassName()));
174       buf.append("\" method=\"");
175       buf.append(Transform.escapeTags(locationInfo.getMethodName()));
176       buf.append("\" file=\"");
177       buf.append(Transform.escapeTags(locationInfo.getFileName()));
178       buf.append("\" line=\"");
179       buf.append(locationInfo.getLineNumber());
180       buf.append("\"/>\r\n");
181     }
182
183     if (properties) {
184         Set keySet = event.getPropertyKeySet();
185         if (keySet.size() > 0) {
186             buf.append("<log4j:properties>\r\n");
187             Object[] keys = keySet.toArray();
188             Arrays.sort(keys);
189             for (int i = 0; i < keys.length; i++) {
190                 String key = keys[i].toString();
191                 Object val = event.getMDC(key);
192                 if (val != null) {
193                     buf.append("<log4j:data name=\"");
194                     buf.append(Transform.escapeTags(key));
195                     buf.append("\" value=\"");
196                     buf.append(Transform.escapeTags(String.valueOf(val)));
197                     buf.append("\"/>\r\n");
198                 }
199             }
200             buf.append("</log4j:properties>\r\n");
201         }
202     }
203     
204     buf.append("</log4j:event>\r\n\r\n");
205     
206     return buf.toString();
207   }
208   
209   /**
210      The XMLLayout prints and does not ignore exceptions. Hence the
211      return value <code>false</code>.
212   */
213   public boolean ignoresThrowable() {
214     return false;
215   }
216 }