| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed 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 com.android.ddmlib; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.Locale; |
| |
| /** |
| * Log class that mirrors the API in main Android sources. |
| * <p/>Default behavior outputs the log to {@link System#out}. Use |
| * {@link #setLogOutput(com.android.ddmlib.Log.ILogOutput)} to redirect the log somewhere else. |
| */ |
| public final class Log { |
| |
| /** |
| * Log Level enum. |
| */ |
| public enum LogLevel { |
| VERBOSE(2, "verbose", 'V'), //$NON-NLS-1$ |
| DEBUG(3, "debug", 'D'), //$NON-NLS-1$ |
| INFO(4, "info", 'I'), //$NON-NLS-1$ |
| WARN(5, "warn", 'W'), //$NON-NLS-1$ |
| ERROR(6, "error", 'E'), //$NON-NLS-1$ |
| ASSERT(7, "assert", 'A'); //$NON-NLS-1$ |
| |
| private int mPriorityLevel; |
| private String mStringValue; |
| private char mPriorityLetter; |
| |
| LogLevel(int intPriority, String stringValue, char priorityChar) { |
| mPriorityLevel = intPriority; |
| mStringValue = stringValue; |
| mPriorityLetter = priorityChar; |
| } |
| |
| public static LogLevel getByString(String value) { |
| for (LogLevel mode : values()) { |
| if (mode.mStringValue.equals(value)) { |
| return mode; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the {@link LogLevel} enum matching the specified letter. |
| * @param letter the letter matching a <code>LogLevel</code> enum |
| * @return a <code>LogLevel</code> object or <code>null</code> if no match were found. |
| */ |
| public static LogLevel getByLetter(char letter) { |
| for (LogLevel mode : values()) { |
| if (mode.mPriorityLetter == letter) { |
| return mode; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the {@link LogLevel} enum matching the specified letter. |
| * <p/> |
| * The letter is passed as a {@link String} argument, but only the first character |
| * is used. |
| * @param letter the letter matching a <code>LogLevel</code> enum |
| * @return a <code>LogLevel</code> object or <code>null</code> if no match were found. |
| */ |
| public static LogLevel getByLetterString(String letter) { |
| if (!letter.isEmpty()) { |
| return getByLetter(letter.charAt(0)); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the letter identifying the priority of the {@link LogLevel}. |
| */ |
| public char getPriorityLetter() { |
| return mPriorityLetter; |
| } |
| |
| /** |
| * Returns the numerical value of the priority. |
| */ |
| public int getPriority() { |
| return mPriorityLevel; |
| } |
| |
| /** |
| * Returns a non translated string representing the LogLevel. |
| */ |
| public String getStringValue() { |
| return mStringValue; |
| } |
| } |
| |
| /** |
| * Classes which implement this interface provides methods that deal with outputting log |
| * messages. |
| */ |
| public interface ILogOutput { |
| /** |
| * Sent when a log message needs to be printed. |
| * @param logLevel The {@link LogLevel} enum representing the priority of the message. |
| * @param tag The tag associated with the message. |
| * @param message The message to display. |
| */ |
| void printLog(LogLevel logLevel, String tag, String message); |
| |
| /** |
| * Sent when a log message needs to be printed, and, if possible, displayed to the user |
| * in a dialog box. |
| * @param logLevel The {@link LogLevel} enum representing the priority of the message. |
| * @param tag The tag associated with the message. |
| * @param message The message to display. |
| */ |
| void printAndPromptLog(LogLevel logLevel, String tag, String message); |
| } |
| |
| private static LogLevel sLevel = DdmPreferences.getLogLevel(); |
| |
| private static ILogOutput sLogOutput; |
| |
| private static final char[] mSpaceLine = new char[72]; |
| private static final char[] mHexDigit = new char[] |
| { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; |
| static { |
| /* prep for hex dump */ |
| int i = mSpaceLine.length-1; |
| while (i >= 0) |
| mSpaceLine[i--] = ' '; |
| mSpaceLine[0] = mSpaceLine[1] = mSpaceLine[2] = mSpaceLine[3] = '0'; |
| mSpaceLine[4] = '-'; |
| } |
| |
| static final class Config { |
| static final boolean LOGV = true; |
| static final boolean LOGD = true; |
| } |
| |
| private Log() {} |
| |
| /** |
| * Outputs a {@link LogLevel#VERBOSE} level message. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void v(String tag, String message) { |
| println(LogLevel.VERBOSE, tag, message); |
| } |
| |
| /** |
| * Outputs a {@link LogLevel#DEBUG} level message. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void d(String tag, String message) { |
| println(LogLevel.DEBUG, tag, message); |
| } |
| |
| /** |
| * Outputs a {@link LogLevel#INFO} level message. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void i(String tag, String message) { |
| println(LogLevel.INFO, tag, message); |
| } |
| |
| /** |
| * Outputs a {@link LogLevel#WARN} level message. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void w(String tag, String message) { |
| println(LogLevel.WARN, tag, message); |
| } |
| |
| /** |
| * Outputs a {@link LogLevel#ERROR} level message. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void e(String tag, String message) { |
| println(LogLevel.ERROR, tag, message); |
| } |
| |
| /** |
| * Outputs a log message and attempts to display it in a dialog. |
| * @param tag The tag associated with the message. |
| * @param message The message to output. |
| */ |
| public static void logAndDisplay(LogLevel logLevel, String tag, String message) { |
| if (sLogOutput != null) { |
| sLogOutput.printAndPromptLog(logLevel, tag, message); |
| } else { |
| println(logLevel, tag, message); |
| } |
| } |
| |
| /** |
| * Outputs a {@link LogLevel#ERROR} level {@link Throwable} information. |
| * @param tag The tag associated with the message. |
| * @param throwable The {@link Throwable} to output. |
| */ |
| public static void e(String tag, Throwable throwable) { |
| if (throwable != null) { |
| StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw); |
| |
| throwable.printStackTrace(pw); |
| println(LogLevel.ERROR, tag, throwable.getMessage() + '\n' + sw.toString()); |
| } |
| } |
| |
| static void setLevel(LogLevel logLevel) { |
| sLevel = logLevel; |
| } |
| |
| /** |
| * Sets the {@link ILogOutput} to use to print the logs. If not set, {@link System#out} |
| * will be used. |
| * @param logOutput The {@link ILogOutput} to use to print the log. |
| */ |
| public static void setLogOutput(ILogOutput logOutput) { |
| sLogOutput = logOutput; |
| } |
| |
| /** |
| * Show hex dump. |
| * <p/> |
| * Local addition. Output looks like: |
| * 1230- 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef |
| * <p/> |
| * Uses no string concatenation; creates one String object per line. |
| */ |
| static void hexDump(String tag, LogLevel level, byte[] data, int offset, int length) { |
| |
| int kHexOffset = 6; |
| int kAscOffset = 55; |
| char[] line = new char[mSpaceLine.length]; |
| int addr, baseAddr, count; |
| int i, ch; |
| boolean needErase = true; |
| |
| //Log.w(tag, "HEX DUMP: off=" + offset + ", length=" + length); |
| |
| baseAddr = 0; |
| while (length != 0) { |
| if (length > 16) { |
| // full line |
| count = 16; |
| } else { |
| // partial line; re-copy blanks to clear end |
| count = length; |
| needErase = true; |
| } |
| |
| if (needErase) { |
| System.arraycopy(mSpaceLine, 0, line, 0, mSpaceLine.length); |
| needErase = false; |
| } |
| |
| // output the address (currently limited to 4 hex digits) |
| addr = baseAddr; |
| addr &= 0xffff; |
| ch = 3; |
| while (addr != 0) { |
| line[ch] = mHexDigit[addr & 0x0f]; |
| ch--; |
| addr >>>= 4; |
| } |
| |
| // output hex digits and ASCII chars |
| ch = kHexOffset; |
| for (i = 0; i < count; i++) { |
| byte val = data[offset + i]; |
| |
| line[ch++] = mHexDigit[(val >>> 4) & 0x0f]; |
| line[ch++] = mHexDigit[val & 0x0f]; |
| ch++; |
| |
| if (val >= 0x20 && val < 0x7f) |
| line[kAscOffset + i] = (char) val; |
| else |
| line[kAscOffset + i] = '.'; |
| } |
| |
| println(level, tag, new String(line)); |
| |
| // advance to next chunk of data |
| length -= count; |
| offset += count; |
| baseAddr += count; |
| } |
| |
| } |
| |
| /** |
| * Dump the entire contents of a byte array with DEBUG priority. |
| */ |
| static void hexDump(byte[] data) { |
| hexDump("ddms", LogLevel.DEBUG, data, 0, data.length); |
| } |
| |
| /* currently prints to stdout; could write to a log window */ |
| private static void println(LogLevel logLevel, String tag, String message) { |
| if (logLevel.getPriority() >= sLevel.getPriority()) { |
| if (sLogOutput != null) { |
| sLogOutput.printLog(logLevel, tag, message); |
| } else { |
| printLog(logLevel, tag, message); |
| } |
| } |
| } |
| |
| /** |
| * Prints a log message. |
| * @param logLevel |
| * @param tag |
| * @param message |
| */ |
| public static void printLog(LogLevel logLevel, String tag, String message) { |
| System.out.print(getLogFormatString(logLevel, tag, message)); |
| } |
| |
| /** |
| * Formats a log message. |
| * @param logLevel |
| * @param tag |
| * @param message |
| */ |
| public static String getLogFormatString(LogLevel logLevel, String tag, String message) { |
| SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss", Locale.getDefault()); |
| return String.format("%s %c/%s: %s\n", formatter.format(new Date()), |
| logLevel.getPriorityLetter(), tag, message); |
| } |
| } |
| |
| |