Informazioni sul logging

Questo articolo descrive il processo di logging, inclusi standard, linee guida per i livelli, classi, scopi e approssimazioni multistack.

Standard dei log

L'accesso in Android è complesso a causa del mix di standard utilizzati che vengono combinati in logcat. Di seguito sono descritti gli standard principali utilizzati:

Source Esempi Indicazioni sul livello dello stack
RFC 5424 (syslog standard) Kernel Linux, molte app Unix Kernel, daemon di sistema
android.util.Log Framework Android + logging app Framework Android e app di sistema
java.util.logging.Level Logging generale in Java app non di sistema

Figura 1: standard del livello di log.

Sebbene ciascuno di questi standard abbia una struttura di livello simile, variano in granularità. Gli equivalenti approssimativi tra gli standard sono i seguenti:

Livello RFC 5424 Gravità RFC 5424 Descrizione RFC 5424 android.util.Log java.util.logging.Level
0 Emergenza Il sistema è inutilizzabile Log.e / Log.wtf SEVERE
1 Avviso Azione deve essere intrapresa immediatamente Log.e / Log.wtf SEVERE
2 Critico Condizioni critiche Log.e / Log.wtf SEVERE
3 Errore Condizioni di errore Log.e SEVERE
4 Avviso Condizioni di avviso Log.w WARNING
5 Avviso Normale ma significativo Log.w WARNING
6 Informazioni Messaggistica informativa Log.i INFO
7 Debug Messaggi a livello di debug Log.d CONFIG, FINE
- - Messaggistica dettagliata Log.v FINER/FINEST

Figura 2: livelli di logging di syslog, Android e Java.

Linee guida per i livelli di log

Esistono linee guida per ogni standard di log. Il livello di log scelto segue lo standard appropriato in uso, ad esempio lo standard syslog per lo sviluppo del kernel.

Gli ordini dei livelli di log, dal meno al più importante, sono mostrati nelle tre figure seguenti:

ERROR Questi log vengono sempre conservati.
WARN Questi log vengono sempre conservati.
INFO Questi log vengono sempre conservati.
DEBUG Questi log vengono compilati, ma vengono rimossi in fase di runtime.
VERBOSE Questi log non vengono mai compilati in un'app, tranne durante lo sviluppo.

Figura 3: android.util.Log

CONFIG Livello del messaggio per i messaggi di configurazione statica
FINE Livello del messaggio che fornisce informazioni di tracciamento
FINER Indica un messaggio di tracciamento abbastanza dettagliato
FINEST Indica un messaggio di tracciamento molto dettagliato
INFO Livello del messaggio per i messaggi informativi
SEVERE Livello del messaggio che indica un errore grave
WARNING Livello del messaggio che indica un potenziale problema

Figura 4: java.util.Logging.Level.

0 Emergenza Il sistema è inutilizzabile
1 Avviso Azione deve essere intrapresa immediatamente
2 Critico Condizioni critiche
3 Errore Condizioni di errore
4 Avviso Condizioni di avviso
5 Avviso Condizione normale ma significativa
6 Informative Messaggi informativi
7 Debug Messaggi a livello di debug

Figura 5: RFC 5424 - Sezione 6.2.1.

Logging app

Il logging selettivo viene eseguito con TAG dalla classe android.util.Log utilizzando Log#isLoggable, come mostrato di seguito:

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

I log possono essere ottimizzati in fase di runtime per fornire un livello di logging selezionato, come mostrato di seguito:

adb shell setprop log.tag.FOO_TAG VERBOSE

Le proprietà log.tag.* vengono reimpostate al riavvio. Esistono anche varianti persistenti che rimangono anche dopo i riavvii. Vedi di seguito:

adb shell setprop persist.log.tag.FOO_TAG VERBOSE

I controlli Log#isLoggable lasciano tracce di log nel codice dell'app. I flag booleani DEBUG ignorano le tracce dei log utilizzando le ottimizzazioni del compilatore impostate su false, come mostrato di seguito:

private final static boolean DEBUG = false;

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

La registrazione può essere rimossa in base al singolo APK tramite i set di regole ProGuard da R8 in fase di compilazione. L'esempio seguente rimuove tutti i log di livello inferiore a INFO per 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

Ciò è utile per gestire più tipi di build di app (ad esempio, build di sviluppo e build di rilascio) in cui il codice sottostante dovrebbe essere lo stesso, ma i livelli di log consentiti sono diversi. Per decidere in che modo i tipi di build e le aspettative di rilascio influiscono sull'output dei log, è necessario impostare e seguire una policy esplicita per le app (in particolare le app di sistema).

Registrazione di sistema in Android Runtime (ART)

Sono disponibili diverse classi per app e servizi di sistema:

Corso Finalità
android.telephony.Rlog Registrazione della radio
android.util.Log Logging generale delle app
android.util.EventLog Registrazione eventi di diagnostica dell'integratore di sistemi
android.util.Slog Logging del framework della piattaforma

Figura 6: classi e scopi dei log di sistema disponibili.

Sebbene android.util.Log e android.util.Slog utilizzino gli stessi standard per il livello di log, Slog è una classe @hide utilizzabile solo dalla piattaforma. I livelli EventLog sono mappati alle voci del file event.logtags in /system/etc/event-log-tags.

Logging nativo

L'accesso in C/C++ segue lo standard syslog con syslog(2) corrispondente a syslog del kernel Linux che controlla il buffer printk e syslog(3) corrispondente al logger di sistema generale. Android utilizza la libreria liblog per la registrazione generale del sistema.

liblog fornisce wrapper per i gruppi di log secondari utilizzando la seguente macro modulo:

[Sublog Buffer ID] LOG [Log Level ID]

RLOGD, ad esempio, corrisponde a [Radio log buffer ID] LOG [Debug Level]. I principali wrapper liblog sono i seguenti:

Classe wrapper Funzioni di esempio
log_main.h ALOGV, ALOGW
log_radio.h RLOGD, RLOGE
log_system.h SLOGI, SLOGW

Figura 7: wrapper liblog.

Android dispone di interfacce di livello superiore per la registrazione che sono preferite rispetto all'utilizzo diretto di liblog, come mostrato di seguito:

Raccolta Utilizzo
async_safe Libreria solo per la registrazione da ambienti asincroni sicuri per i segnali
libbase Libreria di logging che fornisce un'interfaccia di flusso C++ per il logging, simile al logging in stile Google (glog). libbase è utilizzabile sia in progetti esterni ed è disponibile nelle app che utilizzano libbase_ndk.

Figura 8: librerie di log di livello superiore.

Approssimazioni multistack

A causa delle differenze di granularità e livello di intent, non esistono corrispondenze chiare o esatte tra i diversi standard di logging. Ad esempio, i livelli java.util.logging.Level e android.util.Log per i log degli errori non corrispondono in modo univoco:

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

Figura 9: livello di errore nella registrazione Java standard rispetto alla registrazione Android.

In casi come questo, utilizza lo standard individuale per determinare il livello da applicare.

Durante lo sviluppo del sistema con più componenti a livello di stack, segui la Figura 1 per determinare quale standard utilizzare per componente. Per una guida approssimativa ai messaggi dei livelli, segui la Figura 2.

Sicurezza e privacy

Non registrare informazioni che consentono l'identificazione personale (PII). Sono inclusi dettagli quali:

  • Indirizzi email
  • Numeri di telefono
  • Nomi.

Allo stesso modo, alcuni dettagli sono considerati sensibili anche se non consentono esplicitamente l'identificazione personale.

Ad esempio, sebbene le informazioni sul fuso orario non siano considerate informazioni che consentono l'identificazione personale, forniscono un'indicazione della posizione approssimativa di un utente.

Le norme sui log e i dettagli accettabili devono essere gestiti nell'ambito della revisione della sicurezza e della privacy prima del rilascio.

Log del dispositivo.

L'accesso a tutti i log del dispositivo, incluso l'utilizzo di android.permission.READ_LOGS è limitato:

  • Se un'app in background richiede l'accesso a tutti i log del dispositivo, la richiesta viene rifiutata automaticamente, a meno che l'app:
    • Condivide l'UID di sistema.
    • Utilizza un processo di sistema nativo (UID < APP_UID).
    • Usa DropBoxManager.
    • Accede solo al buffer del log eventi.
    • Utilizza l'API EventLog.
    • Utilizza test strumentati.
  • Se un'app in primo piano con READ_LOGS richiede l'accesso ai log del dispositivo, il sistema chiede all'utente di approvare o rifiutare la richiesta di accesso.