Come taggate solitamente le voci di registro? (Android)


96

Presumo che la maggior parte di voi sia a conoscenza di android.util.Log Tutti i metodi di registrazione accettano "String tag" come primo argomento.

E la mia domanda è: come taggate di solito i log nelle vostre applicazioni? Ho visto alcuni hardcode come questo:

public class MyActivity extends Activity {
    private static final String TAG = "MyActivity";
    //...
    public void method () {
        //...
        Log.d(TAG, "Some logging");
    }
}

Questo non sembra carino per molti motivi:

  • Puoi dirmi che questo codice non ha un hardcode, ma ce l'ha.
  • La mia applicazione potrebbe avere un numero qualsiasi di classi in diversi pacchetti con lo stesso nome. Quindi sarebbe difficile leggere il registro.
  • Non è flessibile. Hai sempre inserito un TAG di campo privato nella tua classe.

C'è un modo semplice per ottenere un TAG per un corso?


2
L'uso di TAG è suggerito da Android javadoc , quindi non penso sia peggio che ottenere il nome della classe in fase di esecuzione
Vladimir

preferisco creare una classe specifica come GeneralConstants e mettere i miei TAG su di essa e posso raggiungere i miei tag qualsiasi classe desidero in questo modo; GeneralConstans.MY_TAG
cagryInside

6
Penso che sia meglio avere il TAG definito nella classe, l'hardcoding del nome della classe è brutto ma l'unico modo affidabile per lavorare con proguard. Se non usi mai proguard, MyActivity.class.getName () è la soluzione migliore. Se sei preoccupato per i nomi duplicati, includi semplicemente il nome del pacchetto. Avere nomi TAG in un posto diverso diventerà un incubo di manutenzione.
Ralph Mueller

Risposte:


179

Uso un TAG, ma lo inizializzo in questo modo:

private static final String TAG = MyActivity.class.getName();

In questo modo, quando eseguo il refactoring del codice, anche il tag cambierà di conseguenza.


21
Definisco la costante TAG allo stesso modo. Tuttavia, mi chiedo, in che modo gli strumenti di offuscamento del codice influenzeranno i nomi delle mie classi e, di conseguenza, il valore di questa costante?
Gumbit

1
per tutto questo tempo ho incollato manualmente "MyActivity.class.getName();". Ho sempre pensato che "TAG" fosse solo un segnaposto negli esempi di Google ecc ... non una Staticvariabile reale ! Questa è una soluzione molto migliore grazie :)
wired00

4
Perché non rimuovere lo statico e utilizzarlo this.getClass().getName()invece per renderlo più generico?
theblang

11
Puoi provare this.getClass (). GetSimpleName () per evitare i limiti di lunghezza su TAG. IllegalArgumentException viene generata se tag.length ()> 23.
Michael Levy

14
Come menzionato da Ralph Mueller, questa tecnica non funziona se usi Proguard (come fanno la maggior parte dei progetti Android) per offuscare i nomi delle classi.
John Patterson

16

Di solito creo una Appclasse che si trova in un pacchetto diverso e contiene metodi statici utili. Uno dei metodi è un getTag()metodo, in questo modo posso ottenere il TAG ovunque.
Appla classe ha questo aspetto:

EDIT : Migliorato per commento mob (grazie :))

public class App {

    public static String getTag() {
        String tag = "";
        final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        for (int i = 0; i < ste.length; i++) {
            if (ste[i].getMethodName().equals("getTag")) {
                tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
            }
        }
        return tag;
    }

}

E quando voglio usarlo:

Log.i(App.getTag(), "Your message here");

L'output del getTagmetodo è il nome della classe chiamante (con il nome del pacchetto) e il numero di riga da cui getTagviene chiamato, per un facile debug.


6
Sicuramente non lo farei ... Se lo fai, le tue dichiarazioni di registro subiranno un grande successo. Se lo fai, vorrai sicuramente che proguard rimuova i messaggi di registro per qualcosa di meno che un avviso sulle build di produzione.
Matt Wolfe

1
Matt, hai assolutamente ragione! È buona norma rimuovere / rimuovere i registri durante la produzione: stackoverflow.com/a/2019563/2270166
Yaniv

2
Questo probabilmente non è più consigliato poiché la lunghezza del tag è ora limitata a 23 caratteri
Claudio Redi

grazie per avermi mostrato come getStackTrace()funziona. Ma non lo userò perché è costoso
BlueWizard

12

Vai su Android Studio -> preferenze -> Live Templates -> AndroidLog quindi seleziona Log.d (TAG, String) .

Nel modello testo sostituire

android.util.Log.d(TAG, "$METHOD_NAME$: $content$");

con

android.util.Log.d("$className$", "$METHOD_NAME$: $content$");

Immagine del menu Android

Quindi fare clic su Modifica variabili e immettere className () nella colonna Expression accanto alla colonna className Name .immagine del menu Android 2

Ora quando digiti la scorciatoia logdche metterà

Log.d("CurrentClassName", "currentMethodName: ");

Non è più necessario definire un TAG.


1
è un utilizzo davvero interessante di Android Studio e un approccio interessante al problema, anche se allo stesso tempo stai effettivamente inserendo una stringa al posto della variabile TAG, il che significa che potrebbe essere un po 'macchinoso se necessario cambiarlo, giusto? +1 per aver mostrato la funzionalità però, grazie!
Voy

3
Mi piace in questo modo, tuttavia preferirei creare una nuova voce di registro invece di modificare quella esistente, solo per essere al sicuro se dovesse cambiare in un aggiornamento futuro o qualcosa del genere.
Alaa

9

Mi piace migliorare la risposta di Yaniv se hai il registro in questo formato (nomefile.java:XX) numero di riga xx puoi collegare il collegamento nello stesso modo in cui viene collegato quando c'è un errore, in questo modo posso andare direttamente alla riga in questione semplicemente facendo clic sul logcat

Lo metto nella mia applicazione estesa in modo da poterlo utilizzare in ogni altro file

public static String getTag() {
    String tag = "";
    final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
    for (int i = 0; i < ste.length; i++) {
        if (ste[i].getMethodName().equals("getTag")) {
            tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
        }
    }
    return tag;
}

Immagine dello schermo:


Amarlo, "rubarlo" e aggiornare la mia risposta :)
Yaniv

4
Questo probabilmente non è più consigliato poiché la lunghezza del tag è ora limitata a 23 caratteri
Claudio Redi

3

AndroidStudio ha un logtmodello di default (puoi digitare logte premere tab per farlo espandere in un sinppet di codice). Consiglio di usarlo per evitare di copiare e incollare la definizione del TAG da un'altra classe e dimenticare di cambiare la classe a cui ti riferisci. Il modello si espande per impostazione predefinita in

private static final String TAG = "$CLASS_NAME$"

Per evitare di usare il vecchio nome della classe dopo il refactoring, puoi cambiarlo in

private static final String TAG = $CLASS_NAME$.class.getSimpleName();

Ricordarsi di selezionare il pulsante "Modifica variabili" e assicurarsi che la CLASS_NAMEvariabile sia definita per utilizzare l' className()espressione e abbia "Salta se definita" selezionata.


2

Ho creato una classe di variabili statiche, metodi e classi denominate come S.

Il seguente è il metodo di registrazione:

public static void L(Context ctx, Object s) {
    Log.d("CCC " + ctx.getClass().getName().replace(ctx.getPackageName(), ""), s.toString());
}

Viene chiamato in qualsiasi classe in quanto S.L(this, whaterver_object);The getClass().getName()aggiunge anche il nome del pacchetto, quindi lo rimuovo per evitare di rendere il tag inutilmente lungo.

Vantaggi:

  1. Più corto di Log.d(TAG,
  2. Non è necessario convertire i valori int nella loro stringa. Infatti non c'è bisogno di digitaretoString
  3. Non dimenticherò Log.dmai di eliminare perché devo solo eliminare il metodo e le posizioni di tutti i registri vengono contrassegnate in rosso.
  4. Non c'è bisogno di definire TAG all'inizio dell'attività in quanto prende il nome della classe.
  5. Il TAG ha il prefisso CCC(una stringa breve e facile da digitare) in modo che sia facile elencare solo i tuoi registri nel monitor Android in Android Studio. A volte si eseguono servizi o altre classi contemporaneamente. Se devi cercare solo per nome dell'attività, non puoi vedere esattamente quando è stata ottenuta una risposta del servizio e quindi si è verificata un'azione dalla tua attività. Un prefisso come CCC aiuta in quanto ti fornisce registri cronologicamente con l'attività in cui si è verificato

1
Ottima soluzione! Lo uso! Ma ho sostituito Context ctxda Object ctxe ctx.getClass().getName().replace(ctx.getPackageName(), "")per ctx.getClass().getSimpleName(). In questo modo, posso chiamare S.L(Object, Object)ovunque (anche in Fragments che non si estendono Context, per istante).
Antonio Vinicius Menezes Medei il

1

È possibile utilizzare this.toString()per ottenere un identificativo univoco per la classe specifica in cui si stampa nel registro.


Questo potrebbe diventare costoso a seconda di cosa toString()fa.
tar

1

A scapito dell'aggiornamento di queste stringhe quando sposto codice tra metodi o rinomino metodi, mi piace fare quanto segue. Filosoficamente sembra anche meglio mantenere "posizione" o "contesto" nel tag, non nel messaggio.

public class MyClass {

    // note this is ALWAYS private...subclasses should define their own
    private static final LOG_TAG = MyClass.class.getName();

    public void f() {
        Log.i(LOG_TAG + ".f", "Merry Christmas!");
    }

}

Il vantaggio qui è che puoi filtrare un singolo metodo anche se il contenuto non è statico, ad es

Log.i(LOG_TAG + ".f", String.valueOf(new Random().nextInt()));

L'unico inconveniente è che quando rinomino f()in g()devo tenere a mente quella stringa. Inoltre, il refactoring IDE automatico non li cattura.

Per un po 'sono stato un fan dell'uso del nome breve della classe, voglio dire LOG_TAG = MyClass.class.getSimpleName(). Li ho trovati più difficili da filtrare nei log perché c'erano meno cose su cui lavorare.


1

È una domanda molto vecchia, ma anche se una risposta aggiornata per luglio 2018 è più preferibile utilizzare Timber. Per registrare la registrazione corretta, è possibile inviare errori e avvisi a librerie di crash di terze parti, come Firebase o Crashlytics.

Nella classe che implementa Application dovresti aggiungere questo:

@Override
public void onCreate() {
    super.onCreate();
    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    } else {
        Timber.plant(new CrashReportingTree());
    }
}

/** A tree which logs important information for crash reporting. */
private static class CrashReportingTree extends Timber.Tree {
    @Override protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE || priority == Log.DEBUG) {
            return;
        }

        FakeCrashLibrary.log(priority, tag, message);

        if (t != null) {
            if (priority == Log.ERROR) {
                FakeCrashLibrary.logError(t);
            } else if (priority == Log.WARN) {
                FakeCrashLibrary.logWarning(t);
            }
        }
    }
}

Non dimenticare la dipendenza dal legno.

implementation 'com.jakewharton.timber:timber:4.7.1'

0

Per quegli utenti che visitano questa domanda:

private val TAG:String = this.javaClass.simpleName;

0

usano Timber per l'app IOsched 2019 per mostrare le informazioni di debug:

implementation 'com.jakewharton.timber:timber:4.7.1'

class ApplicationController: Application() {

override fun onCreate() {  
    super.onCreate()
    if(BuildConfig.DEBUG){
        Timber.plant(Timber.DebugTree())
    }
}   
// enables logs for every activity and service of the application
// needs to be registered in manifest like:  
 <application
    android:label="@string/app_name"
    android:name=".ApplicationController"
    ... >

utilizzo

  Timber.e("Error Message") 
  // will print ->  D/MainActivity: Error Message

  Timber.d("Debug Message");
  Timber.tag("new tag").e("error message");

nota che questo rende i log disponibili solo durante lo stato DEBUG e ti facilita il compito di rimuoverli manualmente per il lancio su Google Play -

quando si rilascia l'app sul Play Store, è necessario rimuovere tutte le istruzioni Log dall'app, in modo che nessuno dei dati dell'applicazione come le informazioni sull'utente, i dati nascosti dell'applicazione, i token di autenticazione siano disponibili per l'utente in logcat come testo normale

consulta questo articolo https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d


-2

Di solito uso il nome del metodo come tag ma da Thread

String TAG = Thread.currentThread().getStackTrace()[1].getMethodName();

Ciò evita la nuova eccezione.


-9
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();

3
Perché dovresti crearne una nuova RuntimeExceptionsolo per ottenere il nome della classe corrente? Molto brutto.
asgs

Questo è il modo in cui taggo le mie voci di log, è l'unica soluzione che posso refactoring correttamente quando copio una classe da un progetto a un altro, quindi perché no. Sono aperto a suggerimenti se hai idee migliori e più comode.
Alzati il

1
Se stai semplicemente copiando file di classe Java da una posizione a un'altra, senza dover rinominare, la soluzione fornita da @gianpi è ciò che serve. Altrimenti, potresti semplicemente farlo this.getClass().getName()anche se dovresti rimuovere l'ambito statico diTAG
asgs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.