Autore Topic: [Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO)  (Letto 17774 volte)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
+14
Disclaimer
Questo post fonda ufficialmente il Gruppo AndDev.it LOGTFO (Logcat or GTFO) di cui allego alla fine del post il manifesto (che ho copiato da Ricky`).
Invito tutti gli utenti del forum a leggere questo post.
La comprensione di questo post richiede almeno un'ora del tuo tempo una tantum ma che ti farà risparmiare giorni interi nello sviluppo del software, tempo a tutte le altre persone che frequentano questo forum e tanti post inutili o incompleti.
Appena un membro del Gruppo AndDev.it LOGTFO legge un post con problematiche risolvibili in questo post (come ad esempio: post senza logcat, domande tipo "cosa è/dove si trova il logcat", ecc..." ha il seguente compito da seguire:
  • Se qualcun'altro non lo ha già fatto, rispondere con soltanto il link a questo post (guarda il formato dei Link TFO proposti nell'apposito paragrafo);
  • Ignorare tutte le richieste di aiuto dell'autore fino a quando non renderà conforme il suo topic a questo post.
Per fare parte del Gruppo AndDev.it LOGTFO ti basta leggere, comprendere e rispettare questo post.

Cosa è ed a cosa serve il Logcat
Il termine Log indica la registrazione cronologica delle operazioni man mano che vengono eseguite (Wikipedia).
Il termine Cat indica un comando dei sistemi operativi Unix e Unix-like che che legge i file che gli sono specificati come parametri (o lo standard input) e produce sullo standard output la concatenazione del loro contenuto (Wikipedia).

I due termini uniti formano Logcat, che indica quindi il tracciamento cronologico delle operazioni con la relativa visualizzazione sullo standard output del sistema.

Facciamo un esempio banale di Logcat nel mondo reale:
Vostra madre vi chiama e vi dice "Figlio mio, questa sera abbiamo degli invitati a cena ed avrei voglia di fare la pasta al forno che a te piace tanto! Potresti passare dal market e comprare gli anelletti di pasta, la passata di pomodoro e la mozzarella. Grazie 1000!";
Perfetto, tu prendi un foglio di carta e scrivi:
Citazione
Spesa
Anelletti
Passata pomodoro
Mozzarella
Ovvero, da tutte le informazioni che ti ha dato tua madre (invitati a cena, il fatto che lei sappia che a te piace la pasta al forno, ecc...), tu stai salvando soltanto alcune informazioni che per te sono importanti (Anelletti, Passata pomodoro, Mozzarella) e li stai raggruppando logicamente sotto un nome (Spesa).
Appena arrivi al market ti basta controllare la tua lista per sapere cosa acquistare!
Complimenti, hai fatto un ottimo logcat: tutte le informazioni importanti sono state scritte in ordine cronologico sul tuo pezzo di carta e raggruppate sotto il nome Spesa!

Un altro esempio più vicino al mondo smartphone è il registro delle chiamate! Tutte le chiamate sono loggate in ordine cronologico e visualizzate sullo schermo raggruppate secondo il tipo di chiamata (tutte, in uscita, in entrata).
Ti basta consultare il registro delle chiamate per sapere chi ti ha chiamato (o chi hai chiamato) e a che ora.

In generale, quindi, il logcat non è altro che un insieme di informazioni che ci aiutano a ricordare o tracciare eventi nel passato.

Ad ogni informazione può essere associato un livello (o meglio filtro), in modo da organizzare in modo gerarchico le informazioni. In particolare i livelli sono i seguenti:
  • V — Verbose (lowest priority)
  • D — Debug
  • I — Info
  • W — Warning
  • E — Error
  • F — Fatal
  • S — Silent (highest priority, on which nothing is ever printed)

Quando effettuo il log di una informazione devo quindi anche associare il livello di log dell'informazione stessa. E' molto importante assegnare il giusto livello all'informazione per rendere il logcat finale il più leggibile possibile. Nei prossimi paragrafi spiegherò meglio come usare questi livelli durante il log.
N.B.: sul Framework Android non è possibile loggare a livello Fatal. Questo livello è infatti riservato al sistema.

Visualizzare e scrivere il Logcat
Per visualizzare il logcat prima di tutto dovete avere un dispositivo connesso o un emulatore funzionante, dopodiché avete due possibilità:
1. Da terminale del tuo sistema operativo (controlla il path di installazione dell'sdk):
Codice: [Seleziona]
cd C:\android-sdk-windows\platform-tools
adb logcat
2. Direttamente da eclipse:
Codice: [Seleziona]
Menu Windows -> Show View -> Other... -> Android -> LogCat
Quello che vedrete è il LogCat del dispositivo collegato via usb o dell'emulatore.

Per rendere più semplice la spiegazione ho creato un piccolo progetto Android che genera dei log. Scaricate il progetto Tutorial Logcat allegato al post, caricatelo su Eclipse e fatelo partire (per icona del progetto bisogna ringraziare bradipao).

Per scrivere sul logcat, inserite una frase nell'area di testo, premete il tasto "Log" e decidete il livello di logging.
Ad esempio io ho loggato queste frasi:
  • Ciao a tutti (livello info)
  • io sono MarcoDuff (livello verbose)
  • questo è il tutorial del LogCat (livello debug)

Guardando il LogCat sul terminale o su eclipse mi ritrovo (potrebbero anche esserci altri messaggi di altre applicazioni nel mezzo, per il momento ignorateli):
Codice: [Seleziona]
I/TutorialLogcat(  713): Ciao a tutti
V/TutorialLogcat(  713): io sono MarcoDuff
D/TutorialLogcat(  713): questo è il tutorial del LogCat

La prima lettera della riga del debug indica il livello (I per info, V per verbose e D per debug), poi abbiamo il TAG associato (quello che negli esempi di sopra era la "Spesa" o le chiamate "In ingresso" o "in uscita", un numero che possiamo ignorare (indica il thread) ed il messaggio loggato.
Molto importante è anche notare che il log viene scritto in modo cronologico, ovvero seguendo esattamente l'ordine con cui sono state inviate le richieste di log.

Vediamo adesso quale codice serve per creare un log. Niente di più semplice! Basta usare la classe Log ed i suoi metodi statici v, d, i, w, e (al solito, il nome del metodo indica il livello di debug: v per verbose, d per debug, ecc...).
Tutti i metodi di debug accettano due parametri: il Tag e il messaggio da loggare.
Per intenderci, il logcat di sopra è stato fatto richiamando questi metodi:
Codice (Java): [Seleziona]
Log.i("TutorialLogcat","Ciao a tutti");
Log.v("TutorialLogcat","io sono MarcoDuff");
Log.d("TutorialLogcat","questo è il tutorial del LogCat");

Tutti i metodi hanno due overload, uno che al posto del messaggio accetta un Throwable ed un'altro che in aggiunta ha un Throwable. Come facilmente intuibile, questi metodi sono molto utili in caso di eccezioni (il codice del progetto contiene anche un esempio su come gestire e loggare in modo corretto un errore, guardate il metodo onNumberFormatExceptionClick)!

Filtrare il Logcat
Molto spesso siamo interessati soltanto ad alcune porzioni di logcat, quindi è molto importante capire come filtrare i messaggi in esso contenuto. Gli esempi si riferiscono all'uso del logcat da terminale, per eclipse i comandi sono simili.
Alla stringa di comando adb logcat possiamo concatenare vari filtri. In particolare l'espressione dei filtri è la seguente:
Codice: [Seleziona]
<TAG>:<LIVELLO>esiste un TAG particolare che è * ed indica tutto. Facciamo degli esempi di comandi:

Comando per vedere i log solo a partire dal livello Error per tutti i tag possibili:
Codice: [Seleziona]
adb logcat *:e
Comando per vedere i log solo a partire dal livello Debug per il tag TutorialLogcat e a partire dal livello Warnig per tutti gli altri:
Codice: [Seleziona]
adb logcat TutorialLogcat:d *:w
Comando per vedere i log solo a partire dal livello Verbose per il tag TutorialLogcat e niente da altri tag:
Codice: [Seleziona]
adb logcat TutorialLogcat:v *:s
Faccio partire adesso quattro comandi sul nostro caso esempio:

Caso 1
Codice: [Seleziona]
C:\>adb logcat TutorialLogcat:v *:s
I/TutorialLogcat(  713): Ciao a tutti
V/TutorialLogcat(  713): io sono MarcoDuff
D/TutorialLogcat(  713): questo è il tutorial del LogCat

Caso 2
Codice: [Seleziona]
C:\>adb logcat TutorialLogcat:d *:s
I/TutorialLogcat(  713): Ciao a tutti
D/TutorialLogcat(  713): questo è il tutorial del LogCat

Caso 3
Codice: [Seleziona]
C:\>adb logcat TutorialLogcat:i *:s
I/TutorialLogcat(  713): Ciao a tutti

Caso 4
Codice: [Seleziona]
C:\>adb logcat TutorialLogcat:w *:s
Bisogna notare che quando si indica un livello, quello indica il livello di partenza di visualizzazione. Se indico il livello D (Caso 2) verranno visualizzati tutte le informazioni associate al livello D e tutte le altre con un una priorità più alta (I, W, E, F). Ecco perché nel caso 2 oltre ad essere visualizzata la frase "questo è il tutorial del LogCat" (livello D) viene visualizzata anche la frase "Ciao a tutti) (livello I) e non viene visualizzata la scritta "io sono MarcoDuff" (livello V).

Capire gli errori dal Logcat
Lo scopo principe del LogCat è proprio questo: capire cosa ha fatto andare in crash la nostra applicazione.
Premiamo il tasto "Genera NullPointerException" sull'applicazione e... Yikes! (cit. Monkey Island) la nostra cara applicazione va in Force Close. Cosa avrà causato il crash???

Guardando tutti gli errori del logcat tramite comando
Codice: [Seleziona]
C:\>adb logcat *:wnotiamo alla fine:

Codice: [Seleziona]
E/AndroidRuntime( 1895): FATAL EXCEPTION: main
E/AndroidRuntime( 1895): java.lang.IllegalStateException: Could not execute method of the activity
E/AndroidRuntime( 1895):        at android.view.View$1.onClick(View.java:2072)
E/AndroidRuntime( 1895):        at android.view.View.performClick(View.java:2408)
E/AndroidRuntime( 1895):        at android.view.View$PerformClick.run(View.java:8816)
E/AndroidRuntime( 1895):        at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime( 1895):        at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime( 1895):        at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 1895):        at android.app.ActivityThread.main(ActivityThread.java:4627)
E/AndroidRuntime( 1895):        at java.lang.reflect.Method.invokeNative(NativeMethod)
E/AndroidRuntime( 1895):        at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 1895):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime( 1895):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
E/AndroidRuntime( 1895):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 1895): Caused by: java.lang.reflect.InvocationTargetException
E/AndroidRuntime( 1895):        at com.marcoduff.tutorial.logcat.HomeActivity.onNullPointerExceptionClick(HomeActivity.java:59)
E/AndroidRuntime( 1895):        at java.lang.reflect.Method.invokeNative(NativeMethod)
E/AndroidRuntime( 1895):        at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 1895):        at android.view.View$1.onClick(View.java:2067)
E/AndroidRuntime( 1895):        ... 11 more
E/AndroidRuntime( 1895): Caused by: java.lang.NullPointerException
E/AndroidRuntime( 1895):        ... 15 more

Leggendo lo stacktrace ci rendiamo conto che...
il problema è un java.lang.NullPointerException (lo capiamo dalla riga E/AndroidRuntime( 1895): Caused by: java.lang.NullPointerException)
il problema è avvenuto alla riga 59 del file HomeActivity.java mentre veniva eseguito il metodo onNullPointerExceptionClick (lo capiamo dalla riga E/AndroidRuntime( 1895):        at com.marcoduff.tutorial.logcat.HomeActivity.onNullPointerExceptionClick(HomeActivity.java:59))

Che nel mio codice equivale al comando nullObject.toString();:
Codice (Java): [Seleziona]
        public void onNullPointerExceptionClick(View view) {
                Object nullObject = null;
                nullObject.toString();
        }
Magico vero?

Adesso non avete più scuse: dovete conoscere il LogCat!

That's all!

Formato dei Link TFO proposti
LogCat, o lo conosci o ti uccido!
Hasta el LogCat siempre!
Io faccio parte del Gruppo AndDev.it LOGTFO, tu no? Allora GTFO!

Manifesto

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO)
« Risposta #1 il: 17 Maggio 2011, 11:59:10 CEST »
0
Si merita un +1 e un UP
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline Deleted

  • Nuovo arrivato
  • *
  • Post: 9
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    GN
  • Play Store ID:
    AndroidHD
  • Sistema operativo:
    W7
Re:[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO)
« Risposta #2 il: 22 Febbraio 2012, 13:02:37 CET »
0
Cosa fare se l'applicazione funziona correttamente, ma il logcat presenta una sfilza di errori di tipo E?

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO)
« Risposta #3 il: 22 Febbraio 2012, 13:40:07 CET »
0
Cosa fare se l'applicazione funziona correttamente, ma il logcat presenta una sfilza di errori di tipo E?

Scorri uno ad uno la sfilza di errori di tipo E, sino a che non trovi quello che riporta tra parentesi il nome di un tuo file java più il numero di riga alla quale si è verificato l'errore. Ovviamente è importante anche la riga E che contiene la tipologia dell'eccezione, tipicamente la prima di ciascuna sequenza.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store