| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.mina.util; |
| |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Formatter; |
| import java.util.logging.LogRecord; |
| |
| import org.slf4j.MDC; |
| |
| /** |
| * Implementation of {@link java.util.logging.Formatter} that generates xml in the log4j format. |
| * <p> |
| * The generated xml corresponds 100% with what is generated by |
| * log4j's <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html">XMLLayout</a> |
| * <p> |
| * The MDC properties will only be correct when <code>format</code> is called from the same thread |
| * that generated the LogRecord. |
| * <p> |
| * The file and line attributes in the locationInfo element will always be "?" |
| * since java.util.logging.LogRecord does not provide that info. |
| * <p> |
| * The implementation is heavily based on org.apache.log4j.xml.XMLLayout |
| * </p> |
| * |
| * @author <a href="http://mina.apache.org">Apache MINA Project</a> |
| */ |
| public class Log4jXmlFormatter extends Formatter { |
| |
| private static final int DEFAULT_SIZE = 256; |
| |
| private static final int UPPER_LIMIT = 2048; |
| |
| private StringBuilder buf = new StringBuilder(DEFAULT_SIZE); |
| |
| private boolean locationInfo = false; |
| |
| private boolean properties = false; |
| |
| /** |
| * The <b>LocationInfo</b> option takes a boolean value. By default, |
| * it is set to false which means there will be no location |
| * information output by this layout. If the the option is set to |
| * true, then the file name and line number of the statement at the |
| * origin of the log statement will be output. |
| * |
| * @param flag whether locationInfo should be output by this layout |
| */ |
| public void setLocationInfo(boolean flag) { |
| locationInfo = flag; |
| } |
| |
| /** |
| * @return the current value of the <b>LocationInfo</b> option. |
| */ |
| public boolean getLocationInfo() { |
| return locationInfo; |
| } |
| |
| /** |
| * Sets whether MDC key-value pairs should be output, default false. |
| * |
| * @param flag new value. |
| */ |
| public void setProperties(final boolean flag) { |
| properties = flag; |
| } |
| |
| /** |
| * Gets whether MDC key-value pairs should be output. |
| * |
| * @return true if MDC key-value pairs are output. |
| */ |
| public boolean getProperties() { |
| return properties; |
| } |
| |
| @Override |
| public String format(final LogRecord record) { |
| // Reset working buffer. If the buffer is too large, then we need a new |
| // one in order to avoid the penalty of creating a large array. |
| if (buf.capacity() > UPPER_LIMIT) { |
| buf = new StringBuilder(DEFAULT_SIZE); |
| } else { |
| buf.setLength(0); |
| } |
| |
| buf.append("<log4j:event logger=\""); |
| buf.append(Transform.escapeTags(record.getLoggerName())); |
| buf.append("\" timestamp=\""); |
| buf.append(record.getMillis()); |
| buf.append("\" level=\""); |
| |
| buf.append(Transform.escapeTags(record.getLevel().getName())); |
| buf.append("\" thread=\""); |
| buf.append(String.valueOf(record.getThreadID())); |
| buf.append("\">\r\n"); |
| |
| buf.append("<log4j:message><![CDATA["); |
| // Append the rendered message. Also make sure to escape any |
| // existing CDATA sections. |
| Transform.appendEscapingCDATA(buf, record.getMessage()); |
| buf.append("]]></log4j:message>\r\n"); |
| |
| if (record.getThrown() != null) { |
| String[] s = Transform.getThrowableStrRep(record.getThrown()); |
| |
| if (s != null) { |
| buf.append("<log4j:throwable><![CDATA["); |
| |
| for (String value : s) { |
| Transform.appendEscapingCDATA(buf, value); |
| buf.append("\r\n"); |
| } |
| |
| buf.append("]]></log4j:throwable>\r\n"); |
| } |
| } |
| |
| if (locationInfo) { |
| buf.append("<log4j:locationInfo class=\""); |
| buf.append(Transform.escapeTags(record.getSourceClassName())); |
| buf.append("\" method=\""); |
| buf.append(Transform.escapeTags(record.getSourceMethodName())); |
| buf.append("\" file=\"?\" line=\"?\"/>\r\n"); |
| } |
| |
| if (properties) { |
| Map<String,String> contextMap = MDC.getCopyOfContextMap(); |
| |
| if (contextMap != null) { |
| Set<String> keySet = contextMap.keySet(); |
| |
| if ((keySet != null) && !keySet.isEmpty()) { |
| buf.append("<log4j:properties>\r\n"); |
| Object[] keys = keySet.toArray(); |
| Arrays.sort(keys); |
| |
| for (Object key1 : keys) { |
| String key = key1 == null ? "" : key1.toString(); |
| Object val = contextMap.get(key); |
| |
| if (val != null) { |
| buf.append("<log4j:data name=\""); |
| buf.append(Transform.escapeTags(key)); |
| buf.append("\" value=\""); |
| buf.append(Transform.escapeTags(String.valueOf(val))); |
| buf.append("\"/>\r\n"); |
| } |
| } |
| |
| buf.append("</log4j:properties>\r\n"); |
| } |
| } |
| } |
| |
| buf.append("</log4j:event>\r\n\r\n"); |
| |
| return buf.toString(); |
| } |
| } |