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