Index: docs/android_logging.md |
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/docs/android_logging.md |
similarity index 22% |
rename from base/android/java/src/org/chromium/base/README_logging.md |
rename to docs/android_logging.md |
index ffaeb2e3499848bc241c7f8c9c4f74aa481a71d6..3068dc5409da074d9d53d34e8f9273b95c18b277 100644 |
--- a/base/android/java/src/org/chromium/base/README_logging.md |
+++ b/docs/android_logging.md |
@@ -1,26 +1,35 @@ |
-## Logging ## |
+# Logging # |
+ |
+[TOC] |
+ |
+ |
+## Overview |
Logging used to be done using Android's [android.util.Log] |
(http://developer.android.com/reference/android/util/Log.html). |
-A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as |
-belonging to logical groups going beyond single classes, and to make it easy to switch logging on |
-or off for individual groups. |
+A wrapper on that is now available: org.chromium.base.Log. It is designed to |
+write logs as belonging to logical groups going beyond single classes, and to |
+make it easy to switch logging on or off for individual groups. |
Usage: |
- private static final String TAG = "cr.YourModuleTag"; |
- ... |
- Log.i(TAG, "Logged INFO message."); |
- Log.d(TAG, "Some DEBUG info: %s", data); |
+```java |
+private static final String TAG = "cr.YourModuleTag"; |
+... |
+Log.i(TAG, "Logged INFO message."); |
+Log.d(TAG, "Some DEBUG info: %s", data); |
+``` |
Output: |
- I/cr.YourModuleTag: ( 999): Logged INFO message |
- D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data's toString output |
+``` |
+I/cr.YourModuleTag: ( 999): Logged INFO message |
+D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data.toString |
+``` |
-Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most |
-cases, the class name is not needed. |
+Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for |
+example. In most cases, the class name is not needed. |
### Verbose and Debug logs have special handling ### |
@@ -33,130 +42,162 @@ cases, the class name is not needed. |
### An exception trace is printed when the exception is the last parameter ### |
-As with `java.util.Log`, putting a throwable as last parameter will dump the corresponding stack |
-trace: |
+As with `java.util.Log`, putting a throwable as last parameter will dump the |
+corresponding stack trace: |
- Log.i(TAG, "An error happened: %s", e) |
+```java |
+Log.i(TAG, "An error happened: %s", e) |
+``` |
- I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message |
- I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message |
- I/cr.YourModuleTag: ( 999): at foo.bar.MyClass.test(MyClass.java:42) |
- I/cr.YourModuleTag: ( 999): ... |
+``` |
+I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message |
+I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message |
+I/cr.YourModuleTag: ( 999): at foo.bar.MyClass.test(MyClass.java:42) |
+I/cr.YourModuleTag: ( 999): ... |
+``` |
-Having the exception as last parameter doesn't prevent it from being used for string formatting. |
+Having the exception as last parameter doesn't prevent it from being used for |
+string formatting. |
-### Logging Best Practices |
+## Logging Best Practices |
-#### Rule #1: Never log PII (Personal Identification Information): |
+### Rule #1: Never log PII (Personal Identification Information): |
-This is a huge concern, because other applications can access the log and extract a lot of data |
-from your own by doing so. Even if JellyBean restricted this, people are going to run your |
-application on rooted devices and allow some apps to access it. Also anyone with USB access to the |
-device can use ADB to get the full logcat and get the same data right now. |
+This is a huge concern, because other applications can access the log and |
+extract a lot of data from your own by doing so. Even if JellyBean restricted |
+this, people are going to run your application on rooted devices and allow some |
+apps to access it. Also anyone with USB access to the device can use ADB to get |
+the full logcat and get the same data right now. |
-If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a |
-truncated hash of the PII instead. Truncation is required to make it harder for an attacker to |
-recover the full data through rainbow tables and similar methods. |
+If you really need to print something , print a series of Xs instead |
+(e.g. "XXXXXX"), or print a truncated hash of the PII instead. Truncation is |
+required to make it harder for an attacker to recover the full data through |
+rainbow tables and similar methods. |
Similarly, avoid dumping API keys, cookies, etc... |
-#### Rule #2: Do not build debug logs in production code: |
- |
-The log methods are removed in release builds using Proguard. Because log messages might not be |
-written, the cost of creating them should also be avoided. This can be done using three |
-complementary ways: |
- |
-- Use string formatting instead of concatenations |
- |
- // BAD |
- Log.d(TAG, "I " + preference + " writing logs."); |
- |
- // BETTER |
- Log.d(TAG, "I %s writing logs.", preference); |
- |
- Proguard removes the method call itself, but doesn't do anything about the arguments. The |
- method's arguments will still be computed and provided as input. The first call above will |
- always lead to the creation of a `StringBuilder` and a few concatenations, while the second just |
- passes the arguments and won't need that. |
- |
-- Guard expensive calls |
- |
- Sometimes the values to log aren't readily available and need to be computed specially. This |
- should be avoided when logging is disabled. |
- |
- static private final boolean DEBUG = false; // set to 'true' to enable debug |
- ... |
- if (DEBUG) { |
- Log.i(TAG, createThatExpensiveLogMessage(activity)) |
- } |
- |
- Because the variable is a `static final` that can be evaluated at compile time, the Java |
- compiler will optimize out all guarded calls from the generated `.class` file. Changing it |
- however requires editing each of the files for which debug should be enabled and recompiling. |
- |
-- Annotate debug functions with the `@RemovableInRelease` annotation. |
- |
- That annotation tells Proguard to assume that a given function has no side effects, and is |
- called only for its returned value. If this value is unused, the call will be removed. If the |
- function is not called at all, it will also be removed. Since Proguard is already used to |
- strip debug and verbose calls out of release builds, this annotation allows it to have a |
- deeper action by removing also function calls used to generate the log call's arguments. |
- |
- /* If that function is only used in Log.d calls, proguard should completely remove it from |
- * the release builds. */ |
- @RemovableInRelease |
- private static String getSomeDebugLogString(Thing[] things) { |
- StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:"); |
- for (Thing thing : things) { |
- sb.append('\n').append(thing.id).append(' ').append(report.foo); |
- } |
- return sb.toString(); |
- } |
- |
- public void bar() { |
- ... |
- Log.d(TAG, getSomeDebugLogString(things)); /* The line is removed in release builds. */ |
- } |
- |
- Again, this is useful only if the input to that function are variables already available in |
- the scope. The idea is to move computations, concatenations, etc. to a place where that can be |
- removed when not needed, without invading the main function's logic. It can then have a similar |
- effect as guarding with a static final property that would be enabled in Debug and disabled in |
- Release. |
- |
-#### Rule #3: Favor small log messages |
- |
-This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make |
-your log information as terse as possible. This reduces the risk of pushing interesting log data |
-out of the buffer when something really nasty happens. It's really better to have a single-line |
-log message, than several ones. I.e. don't use: |
- |
- Log.GROUP.d(TAG, "field1 = %s", value1); |
- Log.GROUP.d(TAG, "field2 = %s", value2); |
- Log.GROUP.d(TAG, "field3 = %s", value3); |
+### Rule #2: Do not build debug logs in production code: |
+ |
+The log methods are removed in release builds using Proguard. Because log |
+messages might not be written, the cost of creating them should also be avoided. |
+This can be done using three complementary ways: |
+ |
+#### Use string formatting instead of concatenations |
+ |
+```java |
+// BAD |
+Log.d(TAG, "I " + preference + " writing logs."); |
+ |
+// BETTER |
+Log.d(TAG, "I %s writing logs.", preference); |
+``` |
+ |
+Proguard removes the method call itself, but doesn't do anything about the |
+arguments. The method's arguments will still be computed and provided as |
+input. The first call above will always lead to the creation of a |
+`StringBuilder` and a few concatenations, while the second just passes the |
+arguments and won't need that. |
+ |
+#### Guard expensive calls |
+ |
+Sometimes the values to log aren't readily available and need to be computed |
+specially. This should be avoided when logging is disabled. |
+ |
+```java |
+static private final boolean DEBUG = false; // debug toggle. |
+... |
+if (DEBUG) { |
+ Log.i(TAG, createThatExpensiveLogMessage(activity)) |
+} |
+``` |
+ |
+Because the variable is a `static final` that can be evaluated at compile |
+time, the Java compiler will optimize out all guarded calls from the |
+generated `.class` file. Changing it however requires editing each of the |
+files for which debug should be enabled and recompiling. |
+ |
+#### Annotate debug functions with the `@RemovableInRelease` annotation. |
+ |
+That annotation tells Proguard to assume that a given function has no side |
+effects, and is called only for its returned value. If this value is unused, |
+the call will be removed. If the function is not called at all, it will also |
+be removed. Since Proguard is already used to strip debug and verbose calls |
+out of release builds, this annotation allows it to have a deeper action by |
+removing also function calls used to generate the log call's arguments. |
+ |
+```java |
+/* If that function is only used in Log.d calls, proguard should |
+ * completely remove it from the release builds. */ |
+@RemovableInRelease |
+private static String getSomeDebugLogString(Thing[] things) { |
+ StringBuilder sb = new StringBuilder( |
+ "Reporting " + thing.length + " things: "); |
+ for (Thing thing : things) { |
+ sb.append('\n').append(thing.id).append(' ').append(report.foo); |
+ } |
+ return sb.toString(); |
+} |
+ |
+public void bar() { |
+ ... |
+ Log.d(TAG, getSomeDebugLogString(things)); /* The line is removed in |
+ * release builds. */ |
+} |
+``` |
+ |
+Again, this is useful only if the input to that function are variables |
+already available in the scope. The idea is to move computations, |
+concatenations, etc. to a place where that can be removed when not needed, |
+without invading the main function's logic. It can then have a similar |
+effect as guarding with a static final property that would be enabled in |
+Debug and disabled in Release. |
+ |
+### Rule #3: Favor small log messages |
+ |
+This is still related to the global fixed-sized kernel buffer used to keep all |
+logs. Try to make your log information as terse as possible. This reduces the |
+risk of pushing interesting log data out of the buffer when something really |
+nasty happens. It's really better to have a single-line log message, than |
+several ones. I.e. don't use: |
+ |
+```java |
+Log.GROUP.d(TAG, "field1 = %s", value1); |
+Log.GROUP.d(TAG, "field2 = %s", value2); |
+Log.GROUP.d(TAG, "field3 = %s", value3); |
+``` |
Instead, write this as: |
- Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3); |
+```java |
+Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3); |
+``` |
-That doesn't seem to be much different if you count overall character counts, but each independent |
-log entry also implies a small, but non-trivial header, in the kernel log buffer. |
-And since every byte count, you can also try something even shorter, as in: |
+That doesn't seem to be much different if you count overall character counts, |
+but each independent log entry also implies a small, but non-trivial header, in |
+the kernel log buffer. And since every byte count, you can also try something |
+even shorter, as in: |
- Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3); |
+```java |
+Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3); |
+``` |
-### Filtering logs |
+## Filtering logs |
Logcat allows filtering by specifying tags and the associated level: |
- adb logcat [TAG_EXPR:LEVEL]... |
- adb logcat cr.YourModuleTag:D *:S |
+```shell |
+adb logcat [TAG_EXPR:LEVEL]... |
+adb logcat cr.YourModuleTag:D *:S |
+``` |
-This shows only logs having a level higher or equal to DEBUG for `cr.YourModuleTag`, and SILENT |
-(nothing is logged at this level or higher, so it silences the tags) for everything else. You can |
-persist a filter by setting an environment variable: |
+This shows only logs having a level higher or equal to DEBUG for |
+`cr.YourModuleTag`, and SILENT (nothing is logged at this level or higher, so it |
+silences the tags) for everything else. You can persist a filter by setting an |
+environment variable: |
- export ANDROID_LOG_TAGS="cr.YourModuleTag:D *:S" |
+```shell |
+export ANDROID_LOG_TAGS="cr.YourModuleTag:D *:S" |
+``` |
For more, see the [related page on developer.android.com] |
(http://developer.android.com/tools/debugging/debugging-log.html#filteringOutput) |