Understand logging

This article covers the process of logging, including log standards, level guidelines, classes, purposes, and multistack approximations.

Log standards

Logging in Android is complex due to the mix of standards used that are combined in logcat. The main standards used are detailed below:

Source Examples Stack level guidance
RFC 5424 (syslog standard) Linux kernel, many Unix apps Kernel, system daemons
android.util.Log Android framework + app logging Android framework and system app
java.util.logging.Level General logging in Java non-system app

Figure 1: Log level standards.

Though each of these standards have similar level construction, they vary in granularity. Approximate equivalents across the standards are as follows:

RFC 5424 Level RFC 5424 Severity RFC 5424 Description android.util.Log java.util.logging.Level
0 Emergency System is unusable Log.e / Log.wtf SEVERE
1 Alert Action must be taken immediately Log.e / Log.wtf SEVERE
2 Critical Critical conditions Log.e / Log.wtf SEVERE
3 Error Error conditions Log.e SEVERE
4 Warning Warning conditions Log.w WARNING
5 Notice Normal but significant Log.w WARNING
6 Info Information messaging Log.i INFO
7 Debug Debug-level messages Log.d CONFIG, FINE
- - Verbose messaging Log.v FINER / FINEST

Figure 2: syslog, Android, and Java logging levels.

Log level guidelines

There are existing guidelines given for each log standard. The chosen log level follows the appropriate standard being used, like using the syslog standard for kernel development.

Log level orders, from least-to-most, are shown in the three figures below:

ERROR These logs are always kept.
WARN These logs are always kept.
INFO These logs are always kept.
DEBUG These logs are compiled but stripped at runtime.
VERBOSE These logs are never compiled into an app except during development.

Figure 3: android.util.Log

CONFIG Message level for static configuration messages
FINE Message level providing tracing information
FINER Indicates a fairly detailed tracing message
FINEST Indicates a highly detailed tracing message
INFO Message level for informational messages
SEVERE Message level indicating a serious failure
WARNING Message level indicating a potential problem

Figure 4: java.util.Logging.Level.

0 Emergency System is unusable
1 Alert Action must be taken immediately
2 Critical Critical conditions
3 Error Error conditions
4 Warning Warning conditions
5 Notice Normal but significant condition
6 Informational Informational messages
7 Debug Debug-level messages

Figure 5: RFC 5424 - Section 6.2.1.

App logging

Selective logging is performed with TAG by android.util.Log class using Log#isLoggable, as shown below:

if (Log.isLoggable("FOO_TAG", Log.VERBOSE)) {
 Log.v("FOO_TAG", "Message for logging.");
}

Logs can be tuned at runtime to provide a select level of logging as shown below:

adb shell setprop log.tag.FOO_TAG VERBOSE

log.tag.* properties are reset on reboot. There are persistent variants that remain across reboots as well. See below:

adb shell setprop persist.log.tag.FOO_TAG VERBOSE

Log#isLoggable checks leave log traces in the app code. Boolean DEBUG flags bypass log traces using compiler optimizations that are set to false, as shown below:

private final static boolean DEBUG = false;

… If (DEBUG) { Log.v("FOO_TAG", "Extra debug logging."); }

Logging can be removed on a per-APK basis via ProGuard rulesets by R8 at compile time. The following example removes everything below INFO level logging for android.util.Log:

# This allows proguard to strip isLoggable() blocks containing only <=INFO log
# code from release builds.
-assumenosideeffects class android.util.Log {
  static *** i(...);
  static *** d(...);
  static *** v(...);
  static *** isLoggable(...);
}
-maximumremovedandroidloglevel 4

This is useful for handling multiple app build types (for example, development builds vs. release builds) where the underlying code is expected to be the same, but the allowed log levels are different. An explicit policy must be set and followed for apps (particularly system apps) to decide how build types and release expectations impact log output.

System logging in the Android Runtime (ART)

There are several available classes that are available for system apps and services:

Class Purpose
android.telephony.Rlog Radio logging
android.util.Log General app logging
android.util.EventLog System integrator diagnostic event logging
android.util.Slog Platform framework logging

Figure 6: Available system log classes and purposes.

Though android.util.Log and android.util.Slog use the same log level standards, Slog is an @hide class usable only by the platform. The EventLog levels are mapped to the entries in the event.logtags file in /system/etc/event-log-tags.

Native logging

Logging in C/C++ follows the syslog standard with syslog(2) corresponding to the Linux kernel syslog that controls the printk buffer, and syslog(3) corresponding to the general system logger. Android uses the liblog library for general system logging.

liblog provides wrappers for the sublogs groups using the following macro form:

[Sublog Buffer ID] LOG [Log Level ID]

RLOGD, for example, corresponds to [Radio log buffer ID] LOG [Debug Level]. The major liblog wrappers are as follows:

Wrapper class Example functions
log_main.h ALOGV, ALOGW
log_radio.h RLOGD, RLOGE
log_system.h SLOGI, SLOGW

Figure 7: liblog wrappers.

Android has higher level interfaces for logging that are favoured over direct liblog usage, as seen below:

Library Usage
async_safe Library only for logging from async-signal-safe environments
libbase Logging library that provides a C++ stream interface to logging, similar to Google-style (glog) logging. libbase is usable in both external projects and is available in apps using libbase_ndk.

Figure 8: Higher level log Libraries.

Multistack approximations

Due to differences in granularity and level intent, there are no clear or exact matchings of different logging standards. For example, the java.util.logging.Level and android.util.Log levels for error logs are not a 1:1 match:

java.util.Logging.Level android.util.Log
SEVERE Log.wtf
SEVERE Log.e

Figure 9: Error level in standard Java logging vs. Android logging.

In cases like this, use the individual standard to determine which level to apply.

During system development with multiple stack level components, follow Figure 1 to determine which standard to use per-component. For an approximate guide to tier messaging, follow Figure 2.

Security and privacy

Do not log Personally Identifiable Information (PII). This includes details such as:

  • Email addresses
  • Telephone numbers
  • Names

Similarly, certain details are considered sensitive even if not explicitly personally identifiable.

For example, though timezone info is not considered personally identifiable, it does give an indication of the approximate location of a user.

Log policy and acceptable details must be handled as part of security and privacy review before release.

Device logs

Access to all device logs, including using android.permission.READ_LOGS is restricted:

  • If an app in the background requests access to all device logs, the request is automatically denied unless the app:
    • Shares the system UID.
    • Uses a native system process (UID < APP_UID).
    • Uses DropBoxManager.
    • Accesses only the event log buffer.
    • Uses the EventLog API.
    • Uses instrumented tests.
  • If an app in the foreground with READ_LOGS requests access to device logs, the system prompts the user to approve or deny the access request.