• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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