1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import org.chromium.base.annotations.RemovableInRelease; 8 9 import java.util.Locale; 10 11 /** 12 * Utility class for Logging. 13 * 14 * <p> 15 * Defines logging access points for each feature. They format and forward the logs to 16 * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify 17 * the origin of logs, and enable or disable logging in different parts of the code. 18 * </p> 19 * <p> 20 * Usage documentation: {@code //docs/android_logging.md}. 21 * </p> 22 */ 23 public class Log { 24 /** Convenience property, same as {@link android.util.Log#ASSERT}. */ 25 public static final int ASSERT = android.util.Log.ASSERT; 26 27 /** Convenience property, same as {@link android.util.Log#DEBUG}. */ 28 public static final int DEBUG = android.util.Log.DEBUG; 29 30 /** Convenience property, same as {@link android.util.Log#ERROR}. */ 31 public static final int ERROR = android.util.Log.ERROR; 32 33 /** Convenience property, same as {@link android.util.Log#INFO}. */ 34 public static final int INFO = android.util.Log.INFO; 35 36 /** Convenience property, same as {@link android.util.Log#VERBOSE}. */ 37 public static final int VERBOSE = android.util.Log.VERBOSE; 38 39 /** Convenience property, same as {@link android.util.Log#WARN}. */ 40 public static final int WARN = android.util.Log.WARN; 41 42 private static final String sTagPrefix = "cr_"; 43 private static final String sDeprecatedTagPrefix = "cr."; 44 Log()45 private Log() { 46 // Static only access 47 } 48 49 /** Returns a formatted log message, using the supplied format and arguments.*/ formatLog(String messageTemplate, Object... params)50 private static String formatLog(String messageTemplate, Object... params) { 51 if (params != null && params.length != 0) { 52 messageTemplate = String.format(Locale.US, messageTemplate, params); 53 } 54 55 return messageTemplate; 56 } 57 58 /** 59 * Returns a normalized tag that will be in the form: "cr_foo". This function is called by the 60 * various Log overrides. If using {@link #isLoggable(String, int)}, you might want to call it 61 * to get the tag that will actually be used. 62 * @see #sTagPrefix 63 */ normalizeTag(String tag)64 public static String normalizeTag(String tag) { 65 if (tag.startsWith(sTagPrefix)) return tag; 66 67 // TODO(dgn) simplify this once 'cr.' is out of the repo (http://crbug.com/533072) 68 int unprefixedTagStart = 0; 69 if (tag.startsWith(sDeprecatedTagPrefix)) { 70 unprefixedTagStart = sDeprecatedTagPrefix.length(); 71 } 72 73 return sTagPrefix + tag.substring(unprefixedTagStart, tag.length()); 74 } 75 76 /** 77 * Returns a formatted log message, using the supplied format and arguments. 78 * The message will be prepended with the filename and line number of the call. 79 */ formatLogWithStack(String messageTemplate, Object... params)80 private static String formatLogWithStack(String messageTemplate, Object... params) { 81 return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params); 82 } 83 84 /** 85 * Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. 86 * 87 * Note: Has no effect on whether logs are sent or not. Use a method with 88 * {@link RemovableInRelease} to log something in Debug builds only. 89 */ isLoggable(String tag, int level)90 public static boolean isLoggable(String tag, int level) { 91 return android.util.Log.isLoggable(tag, level); 92 } 93 94 /** 95 * Sends a {@link android.util.Log#VERBOSE} log message. 96 * 97 * For optimization purposes, only the fixed parameters versions are visible. If you need more 98 * than 7 parameters, consider building your log message using a function annotated with 99 * {@link RemovableInRelease}. 100 * 101 * @param tag Used to identify the source of a log message. Might be modified in the output 102 * (see {@link #normalizeTag(String)}) 103 * @param messageTemplate The message you would like logged. It is to be specified as a format 104 * string. 105 * @param args Arguments referenced by the format specifiers in the format string. If the last 106 * one is a {@link Throwable}, its trace will be printed. 107 */ verbose(String tag, String messageTemplate, Object... args)108 private static void verbose(String tag, String messageTemplate, Object... args) { 109 String message = formatLogWithStack(messageTemplate, args); 110 Throwable tr = getThrowableToLog(args); 111 if (tr != null) { 112 android.util.Log.v(normalizeTag(tag), message, tr); 113 } else { 114 android.util.Log.v(normalizeTag(tag), message); 115 } 116 } 117 118 /** Sends a {@link android.util.Log#VERBOSE} log message. 0 args version. */ 119 @RemovableInRelease 120 @VisibleForTesting v(String tag, String message)121 public static void v(String tag, String message) { 122 verbose(tag, message); 123 } 124 125 /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */ 126 @RemovableInRelease 127 @VisibleForTesting v(String tag, String messageTemplate, Object arg1)128 public static void v(String tag, String messageTemplate, Object arg1) { 129 verbose(tag, messageTemplate, arg1); 130 } 131 132 /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */ 133 @RemovableInRelease 134 @VisibleForTesting v(String tag, String messageTemplate, Object arg1, Object arg2)135 public static void v(String tag, String messageTemplate, Object arg1, Object arg2) { 136 verbose(tag, messageTemplate, arg1, arg2); 137 } 138 139 /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */ 140 @RemovableInRelease 141 @VisibleForTesting v( String tag, String messageTemplate, Object arg1, Object arg2, Object arg3)142 public static void v( 143 String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) { 144 verbose(tag, messageTemplate, arg1, arg2, arg3); 145 } 146 147 /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */ 148 @RemovableInRelease 149 @VisibleForTesting v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4)150 public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 151 Object arg4) { 152 verbose(tag, messageTemplate, arg1, arg2, arg3, arg4); 153 } 154 155 /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */ 156 @RemovableInRelease 157 @VisibleForTesting v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)158 public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 159 Object arg4, Object arg5) { 160 verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5); 161 } 162 163 /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */ 164 @RemovableInRelease 165 @VisibleForTesting v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6)166 public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 167 Object arg4, Object arg5, Object arg6) { 168 verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6); 169 } 170 171 /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */ 172 @RemovableInRelease 173 @VisibleForTesting v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7)174 public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 175 Object arg4, Object arg5, Object arg6, Object arg7) { 176 verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7); 177 } 178 179 /** 180 * Sends a {@link android.util.Log#DEBUG} log message. 181 * 182 * For optimization purposes, only the fixed parameters versions are visible. If you need more 183 * than 7 parameters, consider building your log message using a function annotated with 184 * {@link RemovableInRelease}. 185 * 186 * @param tag Used to identify the source of a log message. Might be modified in the output 187 * (see {@link #normalizeTag(String)}) 188 * @param messageTemplate The message you would like logged. It is to be specified as a format 189 * string. 190 * @param args Arguments referenced by the format specifiers in the format string. If the last 191 * one is a {@link Throwable}, its trace will be printed. 192 */ debug(String tag, String messageTemplate, Object... args)193 private static void debug(String tag, String messageTemplate, Object... args) { 194 String message = formatLogWithStack(messageTemplate, args); 195 Throwable tr = getThrowableToLog(args); 196 if (tr != null) { 197 android.util.Log.d(normalizeTag(tag), message, tr); 198 } else { 199 android.util.Log.d(normalizeTag(tag), message); 200 } 201 } 202 203 /** Sends a {@link android.util.Log#DEBUG} log message. 0 args version. */ 204 @RemovableInRelease 205 @VisibleForTesting d(String tag, String message)206 public static void d(String tag, String message) { 207 debug(tag, message); 208 } 209 210 /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */ 211 @RemovableInRelease 212 @VisibleForTesting d(String tag, String messageTemplate, Object arg1)213 public static void d(String tag, String messageTemplate, Object arg1) { 214 debug(tag, messageTemplate, arg1); 215 } 216 /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */ 217 @RemovableInRelease 218 @VisibleForTesting d(String tag, String messageTemplate, Object arg1, Object arg2)219 public static void d(String tag, String messageTemplate, Object arg1, Object arg2) { 220 debug(tag, messageTemplate, arg1, arg2); 221 } 222 /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */ 223 @RemovableInRelease 224 @VisibleForTesting d( String tag, String messageTemplate, Object arg1, Object arg2, Object arg3)225 public static void d( 226 String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) { 227 debug(tag, messageTemplate, arg1, arg2, arg3); 228 } 229 230 /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */ 231 @RemovableInRelease 232 @VisibleForTesting d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4)233 public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 234 Object arg4) { 235 debug(tag, messageTemplate, arg1, arg2, arg3, arg4); 236 } 237 238 /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */ 239 @RemovableInRelease 240 @VisibleForTesting d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)241 public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 242 Object arg4, Object arg5) { 243 debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5); 244 } 245 246 /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */ 247 @RemovableInRelease 248 @VisibleForTesting d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6)249 public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 250 Object arg4, Object arg5, Object arg6) { 251 debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6); 252 } 253 254 /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */ 255 @RemovableInRelease 256 @VisibleForTesting d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7)257 public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3, 258 Object arg4, Object arg5, Object arg6, Object arg7) { 259 debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7); 260 } 261 262 /** 263 * Sends an {@link android.util.Log#INFO} log message. 264 * 265 * @param tag Used to identify the source of a log message. Might be modified in the output 266 * (see {@link #normalizeTag(String)}) 267 * @param messageTemplate The message you would like logged. It is to be specified as a format 268 * string. 269 * @param args Arguments referenced by the format specifiers in the format string. If the last 270 * one is a {@link Throwable}, its trace will be printed. 271 */ 272 @VisibleForTesting i(String tag, String messageTemplate, Object... args)273 public static void i(String tag, String messageTemplate, Object... args) { 274 String message = formatLog(messageTemplate, args); 275 Throwable tr = getThrowableToLog(args); 276 if (tr != null) { 277 android.util.Log.i(normalizeTag(tag), message, tr); 278 } else { 279 android.util.Log.i(normalizeTag(tag), message); 280 } 281 } 282 283 /** 284 * Sends a {@link android.util.Log#WARN} log message. 285 * 286 * @param tag Used to identify the source of a log message. Might be modified in the output 287 * (see {@link #normalizeTag(String)}) 288 * @param messageTemplate The message you would like logged. It is to be specified as a format 289 * string. 290 * @param args Arguments referenced by the format specifiers in the format string. If the last 291 * one is a {@link Throwable}, its trace will be printed. 292 */ 293 @VisibleForTesting w(String tag, String messageTemplate, Object... args)294 public static void w(String tag, String messageTemplate, Object... args) { 295 String message = formatLog(messageTemplate, args); 296 Throwable tr = getThrowableToLog(args); 297 if (tr != null) { 298 android.util.Log.w(normalizeTag(tag), message, tr); 299 } else { 300 android.util.Log.w(normalizeTag(tag), message); 301 } 302 } 303 304 /** 305 * Sends an {@link android.util.Log#ERROR} log message. 306 * 307 * @param tag Used to identify the source of a log message. Might be modified in the output 308 * (see {@link #normalizeTag(String)}) 309 * @param messageTemplate The message you would like logged. It is to be specified as a format 310 * string. 311 * @param args Arguments referenced by the format specifiers in the format string. If the last 312 * one is a {@link Throwable}, its trace will be printed. 313 */ 314 @VisibleForTesting e(String tag, String messageTemplate, Object... args)315 public static void e(String tag, String messageTemplate, Object... args) { 316 String message = formatLog(messageTemplate, args); 317 Throwable tr = getThrowableToLog(args); 318 if (tr != null) { 319 android.util.Log.e(normalizeTag(tag), message, tr); 320 } else { 321 android.util.Log.e(normalizeTag(tag), message); 322 } 323 } 324 325 /** 326 * What a Terrible Failure: Used for conditions that should never happen, and logged at 327 * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might 328 * terminate the process. 329 * 330 * @see android.util.Log#wtf(String, String, Throwable) 331 * 332 * @param tag Used to identify the source of a log message. Might be modified in the output 333 * (see {@link #normalizeTag(String)}) 334 * @param messageTemplate The message you would like logged. It is to be specified as a format 335 * string. 336 * @param args Arguments referenced by the format specifiers in the format string. If the last 337 * one is a {@link Throwable}, its trace will be printed. 338 */ 339 @VisibleForTesting wtf(String tag, String messageTemplate, Object... args)340 public static void wtf(String tag, String messageTemplate, Object... args) { 341 String message = formatLog(messageTemplate, args); 342 Throwable tr = getThrowableToLog(args); 343 if (tr != null) { 344 android.util.Log.wtf(normalizeTag(tag), message, tr); 345 } else { 346 android.util.Log.wtf(normalizeTag(tag), message); 347 } 348 } 349 350 /** Handy function to get a loggable stack trace from a Throwable. */ getStackTraceString(Throwable tr)351 public static String getStackTraceString(Throwable tr) { 352 return android.util.Log.getStackTraceString(tr); 353 } 354 getThrowableToLog(Object[] args)355 private static Throwable getThrowableToLog(Object[] args) { 356 if (args == null || args.length == 0) return null; 357 358 Object lastArg = args[args.length - 1]; 359 360 if (!(lastArg instanceof Throwable)) return null; 361 return (Throwable) lastArg; 362 } 363 364 /** Returns a string form of the origin of the log call, to be used as secondary tag.*/ getCallOrigin()365 private static String getCallOrigin() { 366 StackTraceElement[] st = Thread.currentThread().getStackTrace(); 367 368 // The call stack should look like: 369 // n [a variable number of calls depending on the vm used] 370 // +0 getCallOrigin() 371 // +1 privateLogFunction: verbose or debug 372 // +2 formatLogWithStack() 373 // +3 logFunction: v or d 374 // +4 caller 375 376 int callerStackIndex; 377 String logClassName = Log.class.getName(); 378 for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) { 379 if (st[callerStackIndex].getClassName().equals(logClassName)) { 380 callerStackIndex += 4; 381 break; 382 } 383 } 384 385 return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber(); 386 } 387 } 388