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; |
---|
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.