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 5package org.chromium.base; 6 7import org.chromium.base.annotations.RemovableInRelease; 8 9import 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 */ 23public 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 45 private Log() { 46 // Static only access 47 } 48 49 /** Returns a formatted log message, using the supplied format and arguments.*/ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 private static Throwable getThrowableToLog(Object[] args) { 351 if (args == null || args.length == 0) return null; 352 353 Object lastArg = args[args.length - 1]; 354 355 if (!(lastArg instanceof Throwable)) return null; 356 return (Throwable) lastArg; 357 } 358 359 /** Returns a string form of the origin of the log call, to be used as secondary tag.*/ 360 private static String getCallOrigin() { 361 StackTraceElement[] st = Thread.currentThread().getStackTrace(); 362 363 // The call stack should look like: 364 // n [a variable number of calls depending on the vm used] 365 // +0 getCallOrigin() 366 // +1 privateLogFunction: verbose or debug 367 // +2 formatLogWithStack() 368 // +3 logFunction: v or d 369 // +4 caller 370 371 int callerStackIndex; 372 String logClassName = Log.class.getName(); 373 for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) { 374 if (st[callerStackIndex].getClassName().equals(logClassName)) { 375 callerStackIndex += 4; 376 break; 377 } 378 } 379 380 return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber(); 381 } 382} 383