XMLFormatter.java revision ad41624e761bcf1af9c8008eb45187fc13983717
1f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.logging; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.text.MessageFormat; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Date; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ResourceBundle; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Formatter to convert a {@link LogRecord} into an XML string. The DTD 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * specified in Appendix A to the Java Logging APIs specification is used. 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code XMLFormatter} uses the output handler's encoding if it is specified, 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * otherwise the default platform encoding is used instead. UTF-8 is the 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * recommended encoding. 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class XMLFormatter extends Formatter { 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 33ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes private static final String lineSeperator = LogManager.getSystemLineSeparator(); 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 35f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes private static final String indent = " "; 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new {@code XMLFormatter}. 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public XMLFormatter() { 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(); 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Converts a {@code LogRecord} into an XML string. 469a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson * 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param r 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the log record to be formatted. 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the log record formatted as an XML string. 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 519a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson @SuppressWarnings("nls") 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String format(LogRecord r) { 549a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson // call a method of LogRecord to ensure not null 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project long time = r.getMillis(); 569a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson // format to date 579a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson String date = MessageFormat.format("{0, date} {0, time}", 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project new Object[] { new Date(time) }); 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project StringBuilder sb = new StringBuilder(); 619a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(("<record>")).append(lineSeperator); 629a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<date>")).append(date).append(("</date>")) 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .append(lineSeperator); 649a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<millis>")).append(time).append( 659a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</millis>")).append(lineSeperator); 669a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<sequence>")).append(r.getSequenceNumber()) 679a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson .append(("</sequence>")).append(lineSeperator); 68b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (r.getLoggerName() != null) { 699a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<logger>")).append(r.getLoggerName()) 709a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson .append(("</logger>")).append(lineSeperator); 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 729a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<level>")).append(r.getLevel().getName()) 739a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson .append(("</level>")).append(lineSeperator); 74b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (r.getSourceClassName() != null) { 759a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<class>")) 769a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson .append(r.getSourceClassName()).append(("</class>")) 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .append(lineSeperator); 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 79b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (r.getSourceMethodName() != null) { 809a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<method>")).append( 819a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson r.getSourceMethodName()).append(("</method>")).append( 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project lineSeperator); 83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 849a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<thread>")).append(r.getThreadID()).append( 859a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</thread>")).append(lineSeperator); 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project formatMessages(r, sb); 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Object[] params; 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if ((params = r.getParameters()) != null) { 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (Object element : params) { 909a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<param>")).append(element).append( 919a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</param>")).append(lineSeperator); 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project formatThrowable(r, sb); 959a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(("</record>")).append(lineSeperator); 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return sb.toString(); 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 999a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson @SuppressWarnings("nls") 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private void formatMessages(LogRecord r, StringBuilder sb) { 1019a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson // get localized message if has, but don't call Formatter.formatMessage 1029a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson // to parse pattern string 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ResourceBundle rb = r.getResourceBundle(); 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String pattern = r.getMessage(); 105b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (rb != null && pattern != null) { 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String message; 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project message = rb.getString(pattern); 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (Exception e) { 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project message = null; 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (message == null) { 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project message = pattern; 1159a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<message>")).append(message).append( 1169a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</message>")).append(lineSeperator); 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 1189a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<message>")).append(message).append( 1199a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</message>")).append(lineSeperator); 1209a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<key>")).append(pattern).append( 1219a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</key>")).append(lineSeperator); 1229a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<catalog>")).append( 1239a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson r.getResourceBundleName()).append(("</catalog>")) 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .append(lineSeperator); 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 126b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes } else if (pattern != null) { 1279a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<message>")).append(pattern).append( 1289a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson ("</message>")).append(lineSeperator); 1299a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson } else { 1309a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(("<message/>")); 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1349a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson @SuppressWarnings("nls") 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private void formatThrowable(LogRecord r, StringBuilder sb) { 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Throwable t; 137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if ((t = r.getThrown()) != null) { 1389a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append("<exception>").append(lineSeperator); 1399a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(indent).append("<message>").append( 1409a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson t.toString()).append("</message>").append(lineSeperator); 1419a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson // format throwable's stack trace 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project StackTraceElement[] elements = t.getStackTrace(); 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (StackTraceElement e : elements) { 1449a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(indent).append("<frame>").append( 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project lineSeperator); 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sb.append(indent).append(indent).append(indent).append( 1479a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson "<class>").append(e.getClassName()).append("</class>") 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .append(lineSeperator); 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sb.append(indent).append(indent).append(indent).append( 1509a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson "<method>").append(e.getMethodName()).append( 1519a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson "</method>").append(lineSeperator); 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sb.append(indent).append(indent).append(indent) 1539a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson .append("<line>").append(e.getLineNumber()).append( 1549a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson "</line>").append(lineSeperator); 1559a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append(indent).append("</frame>").append( 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project lineSeperator); 157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1589a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(indent).append("</exception>").append(lineSeperator); 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the header string for a set of log records formatted as XML 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * strings, using the output handler's encoding if it is defined, otherwise 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * using the default platform encoding. 1669a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson * 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param h 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the output handler, may be {@code null}. 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the header string for log records formatted as XML strings. 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1719a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson @SuppressWarnings("nls") 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String getHead(Handler h) { 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String encoding = null; 175b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (h != null) { 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project encoding = h.getEncoding(); 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 178b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (encoding == null) { 179ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes encoding = System.getProperty("file.encoding"); 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project StringBuilder sb = new StringBuilder(); 1829a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append("<?xml version=\"1.0\" encoding=\"").append(encoding).append( 1839a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson "\" standalone=\"no\"?>").append(lineSeperator); 1849a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">").append(lineSeperator); 1859a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson sb.append(("<log>")); 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return sb.toString(); 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the tail string for a set of log records formatted as XML 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * strings. 1929a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson * 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param h 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the output handler, may be {@code null}. 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the tail string for log records formatted as XML strings. 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String getTail(Handler h) { 199f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return "</log>"; 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 202