• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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.build.annotations.AlwaysInline;
8 import org.chromium.build.annotations.CheckDiscard;
9 import org.chromium.build.annotations.DoNotInline;
10 
11 import java.util.Locale;
12 
13 /**
14  * Utility class for Logging.
15  *
16  * <p>
17  * Defines logging access points for each feature. They format and forward the logs to
18  * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify
19  * the origin of logs, and enable or disable logging in different parts of the code.
20  * </p>
21  * <p>
22  * Usage documentation: {@code //docs/android_logging.md}.
23  * </p>
24  */
25 public class Log {
26     /** Convenience property, same as {@link android.util.Log#ASSERT}. */
27     public static final int ASSERT = android.util.Log.ASSERT;
28 
29     /** Convenience property, same as {@link android.util.Log#DEBUG}. */
30     public static final int DEBUG = android.util.Log.DEBUG;
31 
32     /** Convenience property, same as {@link android.util.Log#ERROR}. */
33     public static final int ERROR = android.util.Log.ERROR;
34 
35     /** Convenience property, same as {@link android.util.Log#INFO}. */
36     public static final int INFO = android.util.Log.INFO;
37 
38     /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
39     public static final int VERBOSE = android.util.Log.VERBOSE;
40 
41     /** Convenience property, same as {@link android.util.Log#WARN}. */
42     public static final int WARN = android.util.Log.WARN;
43 
Log()44     private Log() {
45         // Static only access
46     }
47 
48     /** Returns a formatted log message, using the supplied format and arguments.*/
formatLog(String messageTemplate, Throwable tr, Object... params)49     private static String formatLog(String messageTemplate, Throwable tr, Object... params) {
50         if ((params != null) && ((tr == null && params.length > 0) || params.length > 1)) {
51             messageTemplate = String.format(Locale.US, messageTemplate, params);
52         }
53 
54         return messageTemplate;
55     }
56 
57     /**
58      * Returns a normalized tag that will be in the form: "cr_foo". This function is called by the
59      * various Log overrides. If using {@link #isLoggable(String, int)}, you might want to call it
60      * to get the tag that will actually be used.
61      */
62     @AlwaysInline
normalizeTag(String tag)63     public static String normalizeTag(String tag) {
64         // @AlwaysInline makes sense because this method is almost always called with a string
65         // literal as a parameter, so inlining causes the .concat() to happen at build-time.
66         return "cr_" + tag;
67     }
68 
69     /**
70      * Returns a formatted log message, using the supplied format and arguments.
71      * The message will be prepended with the filename and line number of the call.
72      */
formatLogWithStack( String messageTemplate, Throwable tr, Object... params)73     private static String formatLogWithStack(
74             String messageTemplate, Throwable tr, Object... params) {
75         return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, tr, params);
76     }
77 
isDebug()78     private static boolean isDebug() {
79         // Proguard sets value to false in release builds.
80         return true;
81     }
82 
83     /**
84      * In debug: Forwards to {@link android.util.Log#isLoggable(String, int)}, but always
85      * In release: Always returns false (via proguard rule).
86      */
isLoggable(String tag, int level)87     public static boolean isLoggable(String tag, int level) {
88         // Early return helps optimizer eliminate calls to isLoggable().
89         if (!isDebug() && level <= INFO) {
90             return false;
91         }
92         return android.util.Log.isLoggable(tag, level);
93     }
94 
95     /**
96      * Sends a {@link android.util.Log#VERBOSE} log message.
97      *
98      * @param tag Used to identify the source of a log message. Might be modified in the output
99      *            (see {@link #normalizeTag(String)})
100      * @param messageTemplate The message you would like logged. It is to be specified as a format
101      *                        string.
102      * @param args Arguments referenced by the format specifiers in the format string. If the last
103      *             one is a {@link Throwable}, its trace will be printed.
104      */
105     @CheckDiscard("crbug.com/1231625")
v(String tag, String messageTemplate, Object... args)106     public static void v(String tag, String messageTemplate, Object... args) {
107         if (!isDebug()) return;
108 
109         Throwable tr = getThrowableToLog(args);
110         String message = formatLogWithStack(messageTemplate, tr, args);
111         tag = normalizeTag(tag);
112         if (tr != null) {
113             android.util.Log.v(tag, message, tr);
114         } else {
115             android.util.Log.v(tag, message);
116         }
117     }
118 
119     /**
120      * Sends a {@link android.util.Log#DEBUG} log message.
121      *
122      * @param tag Used to identify the source of a log message. Might be modified in the output
123      *            (see {@link #normalizeTag(String)})
124      * @param messageTemplate The message you would like logged. It is to be specified as a format
125      *                        string.
126      * @param args Arguments referenced by the format specifiers in the format string. If the last
127      *             one is a {@link Throwable}, its trace will be printed.
128      */
129     @CheckDiscard("crbug.com/1231625")
d(String tag, String messageTemplate, Object... args)130     public static void d(String tag, String messageTemplate, Object... args) {
131         if (!isDebug()) return;
132 
133         Throwable tr = getThrowableToLog(args);
134         String message = formatLogWithStack(messageTemplate, tr, args);
135         tag = normalizeTag(tag);
136         if (tr != null) {
137             android.util.Log.d(tag, message, tr);
138         } else {
139             android.util.Log.d(tag, message);
140         }
141     }
142 
143     /**
144      * Sends an {@link android.util.Log#INFO} log message.
145      *
146      * @param tag Used to identify the source of a log message. Might be modified in the output
147      *            (see {@link #normalizeTag(String)})
148      * @param messageTemplate The message you would like logged. It is to be specified as a format
149      *                        string.
150      * @param args Arguments referenced by the format specifiers in the format string. If the last
151      *             one is a {@link Throwable}, its trace will be printed.
152      */
i(String tag, String messageTemplate, Object... args)153     public static void i(String tag, String messageTemplate, Object... args) {
154         Throwable tr = getThrowableToLog(args);
155         String message = formatLog(messageTemplate, tr, args);
156         tag = normalizeTag(tag);
157         if (tr != null) {
158             android.util.Log.i(tag, message, tr);
159         } else {
160             android.util.Log.i(tag, message);
161         }
162     }
163 
164     // Overloads to avoid varargs overhead.
165     @AlwaysInline
i(String tag, String message)166     public static void i(String tag, String message) {
167         android.util.Log.i(normalizeTag(tag), message);
168     }
169     @AlwaysInline
i(String tag, String message, Throwable t)170     public static void i(String tag, String message, Throwable t) {
171         android.util.Log.i(normalizeTag(tag), message, t);
172     }
173     @DoNotInline
i(String tag, String messageTemplate, Object o)174     public static void i(String tag, String messageTemplate, Object o) {
175         i(tag, messageTemplate, new Object[] {o});
176     }
177     @DoNotInline
i(String tag, String messageTemplate, Object o1, Object o2)178     public static void i(String tag, String messageTemplate, Object o1, Object o2) {
179         i(tag, messageTemplate, new Object[] {o1, o2});
180     }
181 
182     /**
183      * Sends a {@link android.util.Log#WARN} log message.
184      *
185      * @param tag Used to identify the source of a log message. Might be modified in the output
186      *            (see {@link #normalizeTag(String)})
187      * @param messageTemplate The message you would like logged. It is to be specified as a format
188      *                        string.
189      * @param args Arguments referenced by the format specifiers in the format string. If the last
190      *             one is a {@link Throwable}, its trace will be printed.
191      */
w(String tag, String messageTemplate, Object... args)192     public static void w(String tag, String messageTemplate, Object... args) {
193         Throwable tr = getThrowableToLog(args);
194         String message = formatLog(messageTemplate, tr, args);
195         tag = normalizeTag(tag);
196         if (tr != null) {
197             android.util.Log.w(tag, message, tr);
198         } else {
199             android.util.Log.w(tag, message);
200         }
201     }
202 
203     // Overloads to avoid varargs overhead.
204     @AlwaysInline
w(String tag, String message)205     public static void w(String tag, String message) {
206         android.util.Log.w(normalizeTag(tag), message);
207     }
208     @AlwaysInline
w(String tag, String message, Throwable t)209     public static void w(String tag, String message, Throwable t) {
210         android.util.Log.w(normalizeTag(tag), message, t);
211     }
212     @DoNotInline
w(String tag, String messageTemplate, Object o)213     public static void w(String tag, String messageTemplate, Object o) {
214         w(tag, messageTemplate, new Object[] {o});
215     }
216     @DoNotInline
w(String tag, String messageTemplate, Object o1, Object o2)217     public static void w(String tag, String messageTemplate, Object o1, Object o2) {
218         w(tag, messageTemplate, new Object[] {o1, o2});
219     }
220 
221     /**
222      * Sends an {@link android.util.Log#ERROR} log message.
223      *
224      * @param tag Used to identify the source of a log message. Might be modified in the output
225      *            (see {@link #normalizeTag(String)})
226      * @param messageTemplate The message you would like logged. It is to be specified as a format
227      *                        string.
228      * @param args Arguments referenced by the format specifiers in the format string. If the last
229      *             one is a {@link Throwable}, its trace will be printed.
230      */
e(String tag, String messageTemplate, Object... args)231     public static void e(String tag, String messageTemplate, Object... args) {
232         Throwable tr = getThrowableToLog(args);
233         String message = formatLog(messageTemplate, tr, args);
234         tag = normalizeTag(tag);
235         if (tr != null) {
236             android.util.Log.e(tag, message, tr);
237         } else {
238             android.util.Log.e(tag, message);
239         }
240     }
241 
242     // Overloads to avoid varargs overhead.
243     @AlwaysInline
e(String tag, String message)244     public static void e(String tag, String message) {
245         android.util.Log.e(normalizeTag(tag), message);
246     }
247     @AlwaysInline
e(String tag, String message, Throwable t)248     public static void e(String tag, String message, Throwable t) {
249         android.util.Log.e(normalizeTag(tag), message, t);
250     }
251     @DoNotInline
e(String tag, String messageTemplate, Object o)252     public static void e(String tag, String messageTemplate, Object o) {
253         e(tag, messageTemplate, new Object[] {o});
254     }
255     @DoNotInline
e(String tag, String messageTemplate, Object o1, Object o2)256     public static void e(String tag, String messageTemplate, Object o1, Object o2) {
257         e(tag, messageTemplate, new Object[] {o1, o2});
258     }
259 
260     /**
261      * What a Terrible Failure: Used for conditions that should never happen, and logged at
262      * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might
263      * terminate the process.
264      *
265      * @see android.util.Log#wtf(String, String, Throwable)
266      *
267      * @param tag Used to identify the source of a log message. Might be modified in the output
268      *            (see {@link #normalizeTag(String)})
269      * @param messageTemplate The message you would like logged. It is to be specified as a format
270      *                        string.
271      * @param args Arguments referenced by the format specifiers in the format string. If the last
272      *             one is a {@link Throwable}, its trace will be printed.
273      */
wtf(String tag, String messageTemplate, Object... args)274     public static void wtf(String tag, String messageTemplate, Object... args) {
275         Throwable tr = getThrowableToLog(args);
276         String message = formatLog(messageTemplate, tr, args);
277         tag = normalizeTag(tag);
278         if (tr != null) {
279             android.util.Log.wtf(tag, message, tr);
280         } else {
281             android.util.Log.wtf(tag, message);
282         }
283     }
284 
285     /** Handy function to get a loggable stack trace from a Throwable. */
getStackTraceString(Throwable tr)286     public static String getStackTraceString(Throwable tr) {
287         return android.util.Log.getStackTraceString(tr);
288     }
289 
getThrowableToLog(Object[] args)290     private static Throwable getThrowableToLog(Object[] args) {
291         if (args == null || args.length == 0) return null;
292 
293         Object lastArg = args[args.length - 1];
294 
295         if (!(lastArg instanceof Throwable)) return null;
296         return (Throwable) lastArg;
297     }
298 
299     /** Returns a string form of the origin of the log call, to be used as secondary tag.*/
300     @CheckDiscard("crbug.com/1231625")
getCallOrigin()301     private static String getCallOrigin() {
302         StackTraceElement[] st = Thread.currentThread().getStackTrace();
303 
304         // The call stack should look like:
305         //   n [a variable number of calls depending on the vm used]
306         //  +0 getCallOrigin()
307         //  +1 formatLogWithStack()
308         //  +2 privateLogFunction: verbose or debug
309         //  +3 caller
310 
311         int callerStackIndex;
312         String logClassName = Log.class.getName();
313         for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) {
314             if (st[callerStackIndex].getClassName().equals(logClassName)) {
315                 callerStackIndex += 3;
316                 break;
317             }
318         }
319 
320         return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber();
321     }
322 }
323