1 /* 2 * Copyright (C) 2007 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.ddmlib; 18 19 import java.io.PrintWriter; 20 import java.io.StringWriter; 21 import java.text.SimpleDateFormat; 22 import java.util.Date; 23 24 /** 25 * Log class that mirrors the API in main Android sources. 26 * <p/>Default behavior outputs the log to {@link System#out}. Use 27 * {@link #setLogOutput(com.android.ddmlib.Log.ILogOutput)} to redirect the log somewhere else. 28 */ 29 public final class Log { 30 31 /** 32 * Log Level enum. 33 */ 34 public enum LogLevel { 35 VERBOSE(2, "verbose", 'V'), //$NON-NLS-1$ 36 DEBUG(3, "debug", 'D'), //$NON-NLS-1$ 37 INFO(4, "info", 'I'), //$NON-NLS-1$ 38 WARN(5, "warn", 'W'), //$NON-NLS-1$ 39 ERROR(6, "error", 'E'), //$NON-NLS-1$ 40 ASSERT(7, "assert", 'A'); //$NON-NLS-1$ 41 42 private int mPriorityLevel; 43 private String mStringValue; 44 private char mPriorityLetter; 45 LogLevel(int intPriority, String stringValue, char priorityChar)46 LogLevel(int intPriority, String stringValue, char priorityChar) { 47 mPriorityLevel = intPriority; 48 mStringValue = stringValue; 49 mPriorityLetter = priorityChar; 50 } 51 getByString(String value)52 public static LogLevel getByString(String value) { 53 for (LogLevel mode : values()) { 54 if (mode.mStringValue.equals(value)) { 55 return mode; 56 } 57 } 58 59 return null; 60 } 61 62 /** 63 * Returns the {@link LogLevel} enum matching the specified letter. 64 * @param letter the letter matching a <code>LogLevel</code> enum 65 * @return a <code>LogLevel</code> object or <code>null</code> if no match were found. 66 */ getByLetter(char letter)67 public static LogLevel getByLetter(char letter) { 68 for (LogLevel mode : values()) { 69 if (mode.mPriorityLetter == letter) { 70 return mode; 71 } 72 } 73 74 return null; 75 } 76 77 /** 78 * Returns the {@link LogLevel} enum matching the specified letter. 79 * <p/> 80 * The letter is passed as a {@link String} argument, but only the first character 81 * is used. 82 * @param letter the letter matching a <code>LogLevel</code> enum 83 * @return a <code>LogLevel</code> object or <code>null</code> if no match were found. 84 */ getByLetterString(String letter)85 public static LogLevel getByLetterString(String letter) { 86 if (letter.length() > 0) { 87 return getByLetter(letter.charAt(0)); 88 } 89 90 return null; 91 } 92 93 /** 94 * Returns the letter identifying the priority of the {@link LogLevel}. 95 */ getPriorityLetter()96 public char getPriorityLetter() { 97 return mPriorityLetter; 98 } 99 100 /** 101 * Returns the numerical value of the priority. 102 */ getPriority()103 public int getPriority() { 104 return mPriorityLevel; 105 } 106 107 /** 108 * Returns a non translated string representing the LogLevel. 109 */ getStringValue()110 public String getStringValue() { 111 return mStringValue; 112 } 113 } 114 115 /** 116 * Classes which implement this interface provides methods that deal with outputting log 117 * messages. 118 */ 119 public interface ILogOutput { 120 /** 121 * Sent when a log message needs to be printed. 122 * @param logLevel The {@link LogLevel} enum representing the priority of the message. 123 * @param tag The tag associated with the message. 124 * @param message The message to display. 125 */ printLog(LogLevel logLevel, String tag, String message)126 public void printLog(LogLevel logLevel, String tag, String message); 127 128 /** 129 * Sent when a log message needs to be printed, and, if possible, displayed to the user 130 * in a dialog box. 131 * @param logLevel The {@link LogLevel} enum representing the priority of the message. 132 * @param tag The tag associated with the message. 133 * @param message The message to display. 134 */ printAndPromptLog(LogLevel logLevel, String tag, String message)135 public void printAndPromptLog(LogLevel logLevel, String tag, String message); 136 } 137 138 private static LogLevel mLevel = DdmPreferences.getLogLevel(); 139 140 private static ILogOutput sLogOutput; 141 142 private static final char[] mSpaceLine = new char[72]; 143 private static final char[] mHexDigit = new char[] 144 { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; 145 static { 146 /* prep for hex dump */ 147 int i = mSpaceLine.length-1; 148 while (i >= 0) 149 mSpaceLine[i--] = ' '; 150 mSpaceLine[0] = mSpaceLine[1] = mSpaceLine[2] = mSpaceLine[3] = '0'; 151 mSpaceLine[4] = '-'; 152 } 153 154 static final class Config { 155 static final boolean LOGV = true; 156 static final boolean LOGD = true; 157 }; 158 Log()159 private Log() {} 160 161 /** 162 * Outputs a {@link LogLevel#VERBOSE} level message. 163 * @param tag The tag associated with the message. 164 * @param message The message to output. 165 */ v(String tag, String message)166 public static void v(String tag, String message) { 167 println(LogLevel.VERBOSE, tag, message); 168 } 169 170 /** 171 * Outputs a {@link LogLevel#DEBUG} level message. 172 * @param tag The tag associated with the message. 173 * @param message The message to output. 174 */ d(String tag, String message)175 public static void d(String tag, String message) { 176 println(LogLevel.DEBUG, tag, message); 177 } 178 179 /** 180 * Outputs a {@link LogLevel#INFO} level message. 181 * @param tag The tag associated with the message. 182 * @param message The message to output. 183 */ i(String tag, String message)184 public static void i(String tag, String message) { 185 println(LogLevel.INFO, tag, message); 186 } 187 188 /** 189 * Outputs a {@link LogLevel#WARN} level message. 190 * @param tag The tag associated with the message. 191 * @param message The message to output. 192 */ w(String tag, String message)193 public static void w(String tag, String message) { 194 println(LogLevel.WARN, tag, message); 195 } 196 197 /** 198 * Outputs a {@link LogLevel#ERROR} level message. 199 * @param tag The tag associated with the message. 200 * @param message The message to output. 201 */ e(String tag, String message)202 public static void e(String tag, String message) { 203 println(LogLevel.ERROR, tag, message); 204 } 205 206 /** 207 * Outputs a log message and attempts to display it in a dialog. 208 * @param tag The tag associated with the message. 209 * @param message The message to output. 210 */ logAndDisplay(LogLevel logLevel, String tag, String message)211 public static void logAndDisplay(LogLevel logLevel, String tag, String message) { 212 if (sLogOutput != null) { 213 sLogOutput.printAndPromptLog(logLevel, tag, message); 214 } else { 215 println(logLevel, tag, message); 216 } 217 } 218 219 /** 220 * Outputs a {@link LogLevel#ERROR} level {@link Throwable} information. 221 * @param tag The tag associated with the message. 222 * @param throwable The {@link Throwable} to output. 223 */ e(String tag, Throwable throwable)224 public static void e(String tag, Throwable throwable) { 225 if (throwable != null) { 226 StringWriter sw = new StringWriter(); 227 PrintWriter pw = new PrintWriter(sw); 228 229 throwable.printStackTrace(pw); 230 println(LogLevel.ERROR, tag, throwable.getMessage() + '\n' + sw.toString()); 231 } 232 } 233 setLevel(LogLevel logLevel)234 static void setLevel(LogLevel logLevel) { 235 mLevel = logLevel; 236 } 237 238 /** 239 * Sets the {@link ILogOutput} to use to print the logs. If not set, {@link System#out} 240 * will be used. 241 * @param logOutput The {@link ILogOutput} to use to print the log. 242 */ setLogOutput(ILogOutput logOutput)243 public static void setLogOutput(ILogOutput logOutput) { 244 sLogOutput = logOutput; 245 } 246 247 /** 248 * Show hex dump. 249 * <p/> 250 * Local addition. Output looks like: 251 * 1230- 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef 252 * <p/> 253 * Uses no string concatenation; creates one String object per line. 254 */ hexDump(String tag, LogLevel level, byte[] data, int offset, int length)255 static void hexDump(String tag, LogLevel level, byte[] data, int offset, int length) { 256 257 int kHexOffset = 6; 258 int kAscOffset = 55; 259 char[] line = new char[mSpaceLine.length]; 260 int addr, baseAddr, count; 261 int i, ch; 262 boolean needErase = true; 263 264 //Log.w(tag, "HEX DUMP: off=" + offset + ", length=" + length); 265 266 baseAddr = 0; 267 while (length != 0) { 268 if (length > 16) { 269 // full line 270 count = 16; 271 } else { 272 // partial line; re-copy blanks to clear end 273 count = length; 274 needErase = true; 275 } 276 277 if (needErase) { 278 System.arraycopy(mSpaceLine, 0, line, 0, mSpaceLine.length); 279 needErase = false; 280 } 281 282 // output the address (currently limited to 4 hex digits) 283 addr = baseAddr; 284 addr &= 0xffff; 285 ch = 3; 286 while (addr != 0) { 287 line[ch] = mHexDigit[addr & 0x0f]; 288 ch--; 289 addr >>>= 4; 290 } 291 292 // output hex digits and ASCII chars 293 ch = kHexOffset; 294 for (i = 0; i < count; i++) { 295 byte val = data[offset + i]; 296 297 line[ch++] = mHexDigit[(val >>> 4) & 0x0f]; 298 line[ch++] = mHexDigit[val & 0x0f]; 299 ch++; 300 301 if (val >= 0x20 && val < 0x7f) 302 line[kAscOffset + i] = (char) val; 303 else 304 line[kAscOffset + i] = '.'; 305 } 306 307 println(level, tag, new String(line)); 308 309 // advance to next chunk of data 310 length -= count; 311 offset += count; 312 baseAddr += count; 313 } 314 315 } 316 317 /** 318 * Dump the entire contents of a byte array with DEBUG priority. 319 */ hexDump(byte[] data)320 static void hexDump(byte[] data) { 321 hexDump("ddms", LogLevel.DEBUG, data, 0, data.length); 322 } 323 324 /* currently prints to stdout; could write to a log window */ println(LogLevel logLevel, String tag, String message)325 private static void println(LogLevel logLevel, String tag, String message) { 326 if (logLevel.getPriority() >= mLevel.getPriority()) { 327 if (sLogOutput != null) { 328 sLogOutput.printLog(logLevel, tag, message); 329 } else { 330 printLog(logLevel, tag, message); 331 } 332 } 333 } 334 335 /** 336 * Prints a log message. 337 * @param logLevel 338 * @param tag 339 * @param message 340 */ printLog(LogLevel logLevel, String tag, String message)341 public static void printLog(LogLevel logLevel, String tag, String message) { 342 System.out.print(getLogFormatString(logLevel, tag, message)); 343 } 344 345 /** 346 * Formats a log message. 347 * @param logLevel 348 * @param tag 349 * @param message 350 */ getLogFormatString(LogLevel logLevel, String tag, String message)351 public static String getLogFormatString(LogLevel logLevel, String tag, String message) { 352 SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss"); 353 return String.format("%s %c/%s: %s\n", formatter.format(new Date()), 354 logLevel.getPriorityLetter(), tag, message); 355 } 356 } 357 358 359