1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.logging; 18 19 import android.util.Log; 20 21 import com.android.internal.util.FastPrintWriter; 22 23 import java.io.PrintWriter; 24 import java.io.StringWriter; 25 import java.util.logging.Formatter; 26 import java.util.logging.Handler; 27 import java.util.logging.Level; 28 import java.util.logging.LogRecord; 29 import java.util.logging.Logger; 30 31 /** 32 * Implements a {@link java.util.logging.Logger} handler that writes to the Android log. The 33 * implementation is rather straightforward. The name of the logger serves as 34 * the log tag. Only the log levels need to be converted appropriately. For 35 * this purpose, the following mapping is being used: 36 * 37 * <table> 38 * <tr> 39 * <th>logger level</th> 40 * <th>Android level</th> 41 * </tr> 42 * <tr> 43 * <td> 44 * SEVERE 45 * </td> 46 * <td> 47 * ERROR 48 * </td> 49 * </tr> 50 * <tr> 51 * <td> 52 * WARNING 53 * </td> 54 * <td> 55 * WARN 56 * </td> 57 * </tr> 58 * <tr> 59 * <td> 60 * INFO 61 * </td> 62 * <td> 63 * INFO 64 * </td> 65 * </tr> 66 * <tr> 67 * <td> 68 * CONFIG 69 * </td> 70 * <td> 71 * DEBUG 72 * </td> 73 * </tr> 74 * <tr> 75 * <td> 76 * FINE, FINER, FINEST 77 * </td> 78 * <td> 79 * VERBOSE 80 * </td> 81 * </tr> 82 * </table> 83 */ 84 public class AndroidHandler extends Handler { 85 /** 86 * Holds the formatter for all Android log handlers. 87 */ 88 private static final Formatter THE_FORMATTER = new Formatter() { 89 @Override 90 public String format(LogRecord r) { 91 Throwable thrown = r.getThrown(); 92 if (thrown != null) { 93 StringWriter sw = new StringWriter(); 94 PrintWriter pw = new FastPrintWriter(sw, false, 256); 95 sw.write(r.getMessage()); 96 sw.write("\n"); 97 thrown.printStackTrace(pw); 98 pw.flush(); 99 return sw.toString(); 100 } else { 101 return r.getMessage(); 102 } 103 } 104 }; 105 106 /** 107 * Constructs a new instance of the Android log handler. 108 */ AndroidHandler()109 public AndroidHandler() { 110 setFormatter(THE_FORMATTER); 111 } 112 113 @Override close()114 public void close() { 115 // No need to close, but must implement abstract method. 116 } 117 118 @Override flush()119 public void flush() { 120 // No need to flush, but must implement abstract method. 121 } 122 123 /** 124 * Returns the short logger tag (up to 23 chars) for the given logger name. 125 * Traditionally loggers are named by fully-qualified Java classes; this 126 * method attempts to return a concise identifying part of such names. 127 */ loggerNameToTag(String loggerName)128 private static String loggerNameToTag(String loggerName) { 129 // Anonymous logger. 130 if (loggerName == null) { 131 return "null"; 132 } 133 134 int length = loggerName.length(); 135 if (length <= 23) { 136 return loggerName; 137 } 138 139 int lastPeriod = loggerName.lastIndexOf("."); 140 return length - (lastPeriod + 1) <= 23 141 ? loggerName.substring(lastPeriod + 1) 142 : loggerName.substring(loggerName.length() - 23); 143 } 144 145 @Override publish(LogRecord record)146 public void publish(LogRecord record) { 147 int level = getAndroidLevel(record.getLevel()); 148 String tag = loggerNameToTag(record.getLoggerName()); 149 if (!Log.isLoggable(tag, level)) { 150 return; 151 } 152 153 try { 154 String message = getFormatter().format(record); 155 Log.println(level, tag, message); 156 } catch (RuntimeException e) { 157 Log.e("AndroidHandler", "Error logging message.", e); 158 } 159 } 160 publish(Logger source, String tag, Level level, String message)161 public void publish(Logger source, String tag, Level level, String message) { 162 // TODO: avoid ducking into native 2x; we aren't saving any formatter calls 163 int priority = getAndroidLevel(level); 164 if (!Log.isLoggable(tag, priority)) { 165 return; 166 } 167 168 try { 169 Log.println(priority, tag, message); 170 } catch (RuntimeException e) { 171 Log.e("AndroidHandler", "Error logging message.", e); 172 } 173 } 174 175 /** 176 * Converts a {@link java.util.logging.Logger} logging level into an Android one. 177 * 178 * @param level The {@link java.util.logging.Logger} logging level. 179 * 180 * @return The resulting Android logging level. 181 */ getAndroidLevel(Level level)182 static int getAndroidLevel(Level level) { 183 int value = level.intValue(); 184 if (value >= 1000) { // SEVERE 185 return Log.ERROR; 186 } else if (value >= 900) { // WARNING 187 return Log.WARN; 188 } else if (value >= 800) { // INFO 189 return Log.INFO; 190 } else { 191 return Log.DEBUG; 192 } 193 } 194 } 195