Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: docs/android_logging.md

Issue 1324943003: Move the android logging doc to //docs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/android/java/src/org/chromium/base/README_logging.md ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Logging #
Bernhard Bauer 2015/09/02 10:40:15 I wonder why this doesn't show up as a move...
dgn 2015/09/02 10:57:50 I did a bunch of changes to make it 80 char lines,
dgn 2015/09/02 11:03:10 shows as move with `git cl upload --similarity 10`
2
3 [TOC]
4
5
6 ## Overview
7
8 Logging used to be done using Android's [android.util.Log]
9 (http://developer.android.com/reference/android/util/Log.html).
10
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.
14
15 Usage:
16
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 ```
23
24 Output:
25
26 ```
27 I/cr.YourModuleTag: ( 999): Logged INFO message
28 D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data.toString
29 ```
30
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.
33
34 ### Verbose and Debug logs have special handling ###
35
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.
39
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.
42
43 ### An exception trace is printed when the exception is the last parameter ###
44
45 As with `java.util.Log`, putting a throwable as last parameter will dump the
46 corresponding stack trace:
47
48 ```java
49 Log.i(TAG, "An error happened: %s", e)
50 ```
51
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 ```
58
59 Having the exception as last parameter doesn't prevent it from being used for
60 string formatting.
61
62 ## Logging Best Practices
63
64 ### Rule #1: Never log PII (Personal Identification Information):
65
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.
71
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.
76
77 Similarly, avoid dumping API keys, cookies, etc...
78
79 ### Rule #2: Do not build debug logs in production code:
80
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:
84
85 #### Use string formatting instead of concatenations
86
87 ```java
88 // BAD
89 Log.d(TAG, "I " + preference + " writing logs.");
90
91 // BETTER
92 Log.d(TAG, "I %s writing logs.", preference);
93 ```
94
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.
100
101 #### Guard expensive calls
102
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.
105
106 ```java
107 static private final boolean DEBUG = false; // debug toggle.
108 ...
109 if (DEBUG) {
110 Log.i(TAG, createThatExpensiveLogMessage(activity))
111 }
112 ```
113
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.
118
119 #### Annotate debug functions with the `@RemovableInRelease` annotation.
120
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.
127
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();
139 }
140
141 public void bar() {
142 ...
143 Log.d(TAG, getSomeDebugLogString(things)); /* The line is removed in
144 * release builds. */
145 }
146 ```
147
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.
154
155 ### Rule #3: Favor small log messages
156
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:
162
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);
167 ```
168
169 Instead, write this as:
170
171 ```java
172 Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
173 ```
174
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:
179
180 ```java
181 Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
182 ```
183
184 ## Filtering logs
185
186 Logcat allows filtering by specifying tags and the associated level:
187
188 ```shell
189 adb logcat [TAG_EXPR:LEVEL]...
190 adb logcat cr.YourModuleTag:D *:S
191 ```
192
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:
197
198 ```shell
199 export ANDROID_LOG_TAGS="cr.YourModuleTag:D *:S"
200 ```
201
202 For more, see the [related page on developer.android.com]
203 (http://developer.android.com/tools/debugging/debugging-log.html#filteringOutput )
OLDNEW
« no previous file with comments | « base/android/java/src/org/chromium/base/README_logging.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698