Roll src/third_party/WebKit 0c3f21f:4f9ce20 (svn 202223:202224)
[chromium-blink-merge.git] / docs / android_logging.md
blob3068dc5409da074d9d53d34e8f9273b95c18b277
1 # Logging #
3 [TOC]
6 ## Overview
8 Logging used to be done using Android's [android.util.Log]
9 (http://developer.android.com/reference/android/util/Log.html).
11 A wrapper on that is now available: org.chromium.base.Log. It is designed to
12 write logs as belonging to logical groups going beyond single classes, and to
13 make it easy to switch logging on or off for individual groups.
15 Usage:
17 ```java
18 private static final String TAG = "cr.YourModuleTag";
19 ...
20 Log.i(TAG, "Logged INFO message.");
21 Log.d(TAG, "Some DEBUG info: %s", data);
22 ```
24 Output:
26 ```
27 I/cr.YourModuleTag: ( 999): Logged INFO message
28 D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data.toString
29 ```
31 Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for
32 example. In most cases, the class name is not needed.
34 ### Verbose and Debug logs have special handling ###
36 *   `Log.v` and `Log.d` Calls made using `org.chromium.base.Log` are stripped
37     out of production binaries using Proguard. There is no way to get those logs
38     in release builds.
40 *   The file name and line number will be prepended to the log message.
41     For higher priority logs, those are not added for performance concerns.
43 ### An exception trace is printed when the exception is the last parameter ###
45 As with `java.util.Log`, putting a throwable as last parameter will dump the
46 corresponding stack trace:
48 ```java
49 Log.i(TAG, "An error happened: %s", e)
50 ```
52 ```
53 I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
54 I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
55 I/cr.YourModuleTag: ( 999):     at foo.bar.MyClass.test(MyClass.java:42)
56 I/cr.YourModuleTag: ( 999):     ...
57 ```
59 Having the exception as last parameter doesn't prevent it from being used for
60 string formatting.
62 ## Logging Best Practices
64 ### Rule #1: Never log PII (Personal Identification Information):
66 This is a huge concern, because other applications can access the log and
67 extract a lot of data from your own by doing so. Even if JellyBean restricted
68 this, people are going to run your application on rooted devices and allow some
69 apps to access it. Also anyone with USB access to the device can use ADB to get
70 the full logcat and get the same data right now.
72 If you really need to print something , print a series of Xs instead
73 (e.g. "XXXXXX"), or print a truncated hash of the PII instead. Truncation is
74 required to make it harder for an attacker to recover the full data through
75 rainbow tables and similar methods.
77 Similarly, avoid dumping API keys, cookies, etc...
79 ### Rule #2: Do not build debug logs in production code:
81 The log methods are removed in release builds using Proguard. Because log
82 messages might not be written, the cost of creating them should also be avoided.
83 This can be done using three complementary ways:
85 #### Use string formatting instead of concatenations
87 ```java
88 // BAD
89 Log.d(TAG, "I " + preference + " writing logs.");
91 // BETTER
92 Log.d(TAG, "I %s writing logs.", preference);
93 ```
95 Proguard removes the method call itself, but doesn't do anything about the
96 arguments. The method's arguments will still be computed and provided as
97 input. The first call above will always lead to the creation of a
98 `StringBuilder` and a few concatenations, while the second just passes the
99 arguments and won't need that.
101 #### Guard expensive calls
103 Sometimes the values to log aren't readily available and need to be computed
104 specially. This should be avoided when logging is disabled.
106 ```java
107 static private final boolean DEBUG = false;  // debug toggle.
109 if (DEBUG) {
110   Log.i(TAG, createThatExpensiveLogMessage(activity))
114 Because the variable is a `static final` that can be evaluated at compile
115 time, the Java compiler will optimize out all guarded calls from the
116 generated `.class` file. Changing it however requires editing each of the
117 files for which debug should be enabled and recompiling.
119 #### Annotate debug functions with the `@RemovableInRelease` annotation.
121 That annotation tells Proguard to assume that a given function has no side
122 effects, and is called only for its returned value. If this value is unused,
123 the call will be removed. If the function is not called at all, it will also
124 be removed. Since Proguard is already used to strip debug and verbose calls
125 out of release builds, this annotation allows it to have a deeper action by
126 removing also function calls used to generate the log call's arguments.
128 ```java
129 /* If that function is only used in Log.d calls, proguard should
130  * completely remove it from the release builds. */
131 @RemovableInRelease
132 private static String getSomeDebugLogString(Thing[] things) {
133   StringBuilder sb = new StringBuilder(
134       "Reporting " + thing.length + " things: ");
135   for (Thing thing : things) {
136     sb.append('\n').append(thing.id).append(' ').append(report.foo);
137   }
138   return sb.toString();
141 public void bar() {
142   ...
143   Log.d(TAG, getSomeDebugLogString(things)); /* The line is removed in
144                                               *  release builds. */
148 Again, this is useful only if the input to that function are variables
149 already available in the scope. The idea is to move computations,
150 concatenations, etc. to a place where that can be removed when not needed,
151 without invading the main function's logic. It can then have a similar
152 effect as guarding with a static final property that would be enabled in
153 Debug and disabled in Release.
155 ### Rule #3: Favor small log messages
157 This is still related to the global fixed-sized kernel buffer used to keep all
158 logs. Try to make your log information as terse as possible. This reduces the
159 risk of pushing interesting log data out of the buffer when something really
160 nasty happens. It's really better to have a single-line log message, than
161 several ones. I.e. don't use:
163 ```java
164 Log.GROUP.d(TAG, "field1 = %s", value1);
165 Log.GROUP.d(TAG, "field2 = %s", value2);
166 Log.GROUP.d(TAG, "field3 = %s", value3);
169 Instead, write this as:
171 ```java
172 Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
175 That doesn't seem to be much different if you count overall character counts,
176 but each independent log entry also implies a small, but non-trivial header, in
177 the kernel log buffer. And since every byte count, you can also try something
178 even shorter, as in:
180 ```java
181 Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
184 ## Filtering logs
186 Logcat allows filtering by specifying tags and the associated level:
188 ```shell
189 adb logcat [TAG_EXPR:LEVEL]...
190 adb logcat cr.YourModuleTag:D *:S
193 This shows only logs having a level higher or equal to DEBUG for
194 `cr.YourModuleTag`, and SILENT (nothing is logged at this level or higher, so it
195 silences the tags) for everything else. You can persist a filter by setting an
196 environment variable:
198 ```shell
199 export ANDROID_LOG_TAGS="cr.YourModuleTag:D *:S"
202 For more, see the [related page on developer.android.com]
203 (http://developer.android.com/tools/debugging/debugging-log.html#filteringOutput)