1 /* 2 * Copyright (C) 2024 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 package com.android.tradefed.log; 17 18 import java.io.PrintWriter; 19 import java.io.StringWriter; 20 import java.text.SimpleDateFormat; 21 import java.util.Date; 22 import java.util.Locale; 23 24 /** 25 * Log class that mirrors the API in main Android sources. 26 * 27 * <p>Default behavior outputs the log to {@link System#out}. Use {@link #setLogOutput(ILogOutput)} 28 * to redirect the log somewhere else. 29 */ 30 public final class Log { 31 32 /** Log Level enum. */ 33 public enum LogLevel { 34 VERBOSE(2, "verbose", 'V'), // $NON-NLS-1$ 35 DEBUG(3, "debug", 'D'), // $NON-NLS-1$ 36 INFO(4, "info", 'I'), // $NON-NLS-1$ 37 WARN(5, "warn", 'W'), // $NON-NLS-1$ 38 ERROR(6, "error", 'E'), // $NON-NLS-1$ 39 ASSERT(7, "assert", 'A'); // $NON-NLS-1$ 40 41 private int mPriorityLevel; 42 private String mStringValue; 43 private char mPriorityLetter; 44 LogLevel(int intPriority, String stringValue, char priorityChar)45 LogLevel(int intPriority, String stringValue, char priorityChar) { 46 mPriorityLevel = intPriority; 47 mStringValue = stringValue; 48 mPriorityLetter = priorityChar; 49 } 50 getByString(String value)51 public static LogLevel getByString(String value) { 52 for (LogLevel mode : values()) { 53 if (mode.mStringValue.equals(value)) { 54 return mode; 55 } 56 } 57 58 return null; 59 } 60 61 /** 62 * Returns the {@link LogLevel} enum matching the specified letter. 63 * 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 * 80 * <p>The letter is passed as a {@link String} argument, but only the first character is 81 * used. 82 * 83 * @param letter the letter matching a <code>LogLevel</code> enum 84 * @return a <code>LogLevel</code> object or <code>null</code> if no match were found. 85 */ getByLetterString(String letter)86 public static LogLevel getByLetterString(String letter) { 87 if (!letter.isEmpty()) { 88 return getByLetter(letter.charAt(0)); 89 } 90 91 return null; 92 } 93 94 /** Returns the letter identifying the priority of the {@link LogLevel}. */ getPriorityLetter()95 public char getPriorityLetter() { 96 return mPriorityLetter; 97 } 98 99 /** Returns the numerical value of the priority. */ getPriority()100 public int getPriority() { 101 return mPriorityLevel; 102 } 103 104 /** Returns a non translated string representing the LogLevel. */ getStringValue()105 public String getStringValue() { 106 return mStringValue; 107 } 108 convertFromDdmlib(com.android.ddmlib.Log.LogLevel level)109 public static LogLevel convertFromDdmlib(com.android.ddmlib.Log.LogLevel level) { 110 switch (level) { 111 case VERBOSE: 112 return VERBOSE; 113 case DEBUG: 114 return DEBUG; 115 case INFO: 116 return INFO; 117 case WARN: 118 return WARN; 119 case ERROR: 120 return ERROR; 121 case ASSERT: 122 return ASSERT; 123 default: 124 return VERBOSE; 125 } 126 } 127 } 128 129 /** 130 * Classes which implement this interface provides methods that deal with outputting log 131 * messages. 132 */ 133 public interface ILogOutput { 134 /** 135 * Sent when a log message needs to be printed. 136 * 137 * @param logLevel The {@link LogLevel} enum representing the priority of the message. 138 * @param tag The tag associated with the message. 139 * @param message The message to display. 140 */ printLog(LogLevel logLevel, String tag, String message)141 public void printLog(LogLevel logLevel, String tag, String message); 142 143 /** 144 * Sent when a log message needs to be printed, and, if possible, displayed to the user in a 145 * dialog box. 146 * 147 * @param logLevel The {@link LogLevel} enum representing the priority of the message. 148 * @param tag The tag associated with the message. 149 * @param message The message to display. 150 */ printAndPromptLog(LogLevel logLevel, String tag, String message)151 public void printAndPromptLog(LogLevel logLevel, String tag, String message); 152 } 153 154 private static LogLevel sLevel = LogLevel.VERBOSE; 155 156 private static ILogOutput sLogOutput; 157 Log()158 private Log() {} 159 160 /** 161 * Outputs a {@link LogLevel#VERBOSE} level message. 162 * 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 * 173 * @param tag The tag associated with the message. 174 * @param message The message to output. 175 */ d(String tag, String message)176 public static void d(String tag, String message) { 177 println(LogLevel.DEBUG, tag, message); 178 } 179 180 /** 181 * Outputs a {@link LogLevel#INFO} level message. 182 * 183 * @param tag The tag associated with the message. 184 * @param message The message to output. 185 */ i(String tag, String message)186 public static void i(String tag, String message) { 187 println(LogLevel.INFO, tag, message); 188 } 189 190 /** 191 * Outputs a {@link LogLevel#WARN} level message. 192 * 193 * @param tag The tag associated with the message. 194 * @param message The message to output. 195 */ w(String tag, String message)196 public static void w(String tag, String message) { 197 println(LogLevel.WARN, tag, message); 198 } 199 200 /** 201 * Outputs a {@link LogLevel#ERROR} level message. 202 * 203 * @param tag The tag associated with the message. 204 * @param message The message to output. 205 */ e(String tag, String message)206 public static void e(String tag, String message) { 207 println(LogLevel.ERROR, tag, message); 208 } 209 210 /** 211 * Outputs a log message and attempts to display it in a dialog. 212 * 213 * @param tag The tag associated with the message. 214 * @param message The message to output. 215 */ logAndDisplay(LogLevel logLevel, String tag, String message)216 public static void logAndDisplay(LogLevel logLevel, String tag, String message) { 217 if (sLogOutput != null) { 218 sLogOutput.printAndPromptLog(logLevel, tag, message); 219 } else { 220 println(logLevel, tag, message); 221 } 222 } 223 224 /** 225 * Outputs a {@link LogLevel#ERROR} level {@link Throwable} information. 226 * 227 * @param tag The tag associated with the message. 228 * @param throwable The {@link Throwable} to output. 229 */ e(String tag, Throwable throwable)230 public static void e(String tag, Throwable throwable) { 231 if (throwable != null) { 232 StringWriter sw = new StringWriter(); 233 PrintWriter pw = new PrintWriter(sw); 234 235 throwable.printStackTrace(pw); 236 println(LogLevel.ERROR, tag, throwable.getMessage() + '\n' + sw.toString()); 237 } 238 } 239 setLevel(LogLevel logLevel)240 static void setLevel(LogLevel logLevel) { 241 sLevel = logLevel; 242 } 243 244 /** 245 * Sets the {@link ILogOutput} to use to print the logs. If not set, {@link System#out} will be 246 * used. 247 * 248 * @param logOutput The {@link ILogOutput} to use to print the log. 249 */ setLogOutput(ILogOutput logOutput)250 public static void setLogOutput(ILogOutput logOutput) { 251 sLogOutput = logOutput; 252 } 253 254 /* currently prints to stdout; could write to a log window */ println(LogLevel logLevel, String tag, String message)255 private static void println(LogLevel logLevel, String tag, String message) { 256 if (logLevel.getPriority() >= sLevel.getPriority()) { 257 if (sLogOutput != null) { 258 sLogOutput.printLog(logLevel, tag, message); 259 } else { 260 printLog(logLevel, tag, message); 261 } 262 } 263 } 264 265 /** 266 * Prints a log message. 267 * 268 * @param logLevel 269 * @param tag 270 * @param message 271 */ printLog(LogLevel logLevel, String tag, String message)272 public static void printLog(LogLevel logLevel, String tag, String message) { 273 System.out.print(getLogFormatString(logLevel, tag, message)); 274 } 275 276 /** 277 * Formats a log message. 278 * 279 * @param logLevel 280 * @param tag 281 * @param message 282 */ getLogFormatString(LogLevel logLevel, String tag, String message)283 public static String getLogFormatString(LogLevel logLevel, String tag, String message) { 284 SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()); 285 return String.format( 286 "%s %c/%s: %s\n", 287 formatter.format(new Date()), logLevel.getPriorityLetter(), tag, message); 288 } 289 } 290