Jak zazwyczaj oznaczasz wpisy dziennika? (android)


96

Zakładam, że większość z Was wie o android.util.Log Wszystkie metody logowania akceptują „String tag” jako pierwszy argument.

Moje pytanie brzmi: Jak zwykle tagujesz swoje dzienniki w swoich aplikacjach? Widziałem taki kod:

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

To nie wygląda ładnie z wielu powodów:

  • Możesz mi powiedzieć, że ten kod nie ma twardego kodu, ale ma.
  • Moja aplikacja może mieć dowolną liczbę klas w różnych pakietach o tej samej nazwie. Trudno byłoby więc przeczytać dziennik.
  • To nie jest elastyczne. W swojej klasie zawsze umieszczałeś TAG pola prywatnego.

Czy jest jakiś fajny sposób na uzyskanie TAG-a na zajęcia?


2
Używanie TAG jest sugerowane przez Android javadoc , więc nie sądzę, że jest to gorsze niż uzyskanie nazwy klasy w czasie wykonywania
Vladimir,

wolę utworzyć określoną klasę, taką jak GeneralConstants i umieścić na niej moje TAG, a mogę dotrzeć do moich tagów w dowolnej klasie, jaką chcę; GeneralConstans.MY_TAG
cagryInside

6
Myślę, że najlepiej jest mieć zdefiniowany TAG w klasie, zakodowanie nazwy klasy jest brzydkie, ale jedyny niezawodny sposób pracy z proguardem. Jeśli nigdy nie używasz proguard, wówczas MyActivity.class.getName () jest najlepszym rozwiązaniem. Jeśli martwisz się o zduplikowane nazwy, po prostu podaj nazwę pakietu. Posiadanie nazw TAG w innym miejscu stanie się koszmarem konserwacji.
Ralph Mueller

Odpowiedzi:


181

Używam TAG-a, ale inicjalizuję go w ten sposób:

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

W ten sposób, gdy refaktoryzuję swój kod, tag również się odpowiednio zmieni.


21
W ten sam sposób definiuję stałą TAG. Zastanawiam się jednak, jak narzędzia zaciemniania kodu wpłyną na nazwy moich klas, a co za tym idzie, na wartość tej stałej?
Olegs Briska

1
przez cały ten czas wklejałem ręcznie "MyActivity.class.getName();". Zawsze myślałem, że „TAG” to tylko symbol zastępczy w przykładach z Google itp ... a nie rzeczywista Staticzmienna! To znacznie lepsze rozwiązanie dzięki :)
wired00

4
Dlaczego nie usunąć statycznego i użyć this.getClass().getName()zamiast tego, aby był bardziej ogólny?
theblang

11
Możesz spróbować this.getClass (). GetSimpleName (), aby uniknąć ograniczeń długości w TAG. IllegalArgumentException jest generowany, jeśli tag.length ()> 23.
Michael Levy

14
Jak wspomniał Ralph Mueller, ta technika nie działa, jeśli używasz Proguard (jak robi to większość projektów Androida) do zaciemniania nazw klas.
John Patterson

16

Zwykle tworzę Appklasę, która znajduje się w innym pakiecie i zawiera przydatne metody statyczne. Jedną z metod jest getTag()metoda, w ten sposób mogę uzyskać TAG wszędzie.
Appklasa wygląda następująco:

EDYCJA : Ulepszone za komentarz br mob (dzięki :))

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

}

A kiedy chcę go użyć:

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

Wyjście getTagmetody jest nazwa klasy rozmówcy (z nazwą pakietu), a numer linii, gdzie getTagnazywany jest od, do łatwego debuging.


6
Zdecydowanie bym tego nie zrobił. Jeśli to zrobisz, Twoje wyciągi z dziennika będą miały duży wpływ na wydajność. Jeśli to zrobisz, na pewno będziesz chciał, aby program Proguard usuwał komunikaty dziennika dla czegoś mniejszego niż ostrzeżenie o kompilacjach produkcyjnych.
Matt Wolfe

1
Matt, masz absolutną rację! Dobrą praktyką jest usuwanie / zdejmowanie dzienników podczas produkcji - stackoverflow.com/a/2019563/2270166
Yaniv

2
Prawdopodobnie nie jest to już zalecane, ponieważ długość tagu jest teraz ograniczona do 23 znaków
Claudio Redi

dzięki za pokazanie mi, jak getStackTrace()działa. Ale nie
użyję

12

Przejdź do Android Studio -> preferencje -> Live Templates -> AndroidLog, a następnie wybierz Log.d (TAG, String) .

W szablonie zastąp tekst

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

z

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

Obraz menu Androida

Następnie kliknij Edytuj zmienne i wpisz className () w kolumnie Wyrażenie obok kolumny Nazwa klasy .obraz menu systemu Android 2

Teraz, kiedy wpiszesz skrót logd, zostanie on umieszczony

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

Nie musisz już definiować TAG-a.


1
to naprawdę fajne użycie Android Studio i ciekawe podejście do problemu, chociaż w tym samym czasie faktycznie wprowadzasz ciąg znaków zamiast zmiennej TAG, co oznacza, że ​​może to być trochę kłopotliwe, jeśli zajdzie taka potrzeba, prawda? +1 za pokazanie funkcjonalności, dzięki!
Voy

3
Podoba mi się ten sposób, jednak wolę utworzyć nowy wpis w dzienniku zamiast modyfikować istniejący, aby być po bezpiecznej stronie, gdyby zmienił się w przyszłej aktualizacji lub coś w tym stylu.
Alaa,

9

Lubię poprawić odpowiedź Yaniv, jeśli masz dziennik w tym formacie (nazwa_pliku.java:XX). Xx numer linii możesz połączyć skrót w ten sam sposób, gdy pojawia się błąd, w ten sposób mogę uzyskać bezpośredni dostęp do danej linii wystarczy kliknąć logcat

Umieściłem to w mojej rozszerzonej aplikacji, aby móc używać go w każdym innym pliku

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

Zrzut ekranu:


Uwielbiam to, „kradnę” i aktualizuję moją odpowiedź :)
Janów

4
Prawdopodobnie nie jest to już zalecane, ponieważ długość tagu jest teraz ograniczona do 23 znaków
Claudio Redi

3

AndroidStudio ma logtdomyślnie szablon (możesz wpisać logti nacisnąć klawisz Tab, aby rozwinąć go do pojedynczego fragmentu kodu). Zalecam użycie tego, aby uniknąć kopiowania wklejania definicji TAG z innej klasy i zapomnienia o zmianie klasy, do której się odnosisz. Szablon domyślnie rozwija się do

private static final String TAG = "$CLASS_NAME$"

Aby uniknąć używania starej nazwy klasy po refaktoryzacji, możesz ją zmienić na

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

Pamiętaj, aby zaznaczyć przycisk „Edytuj zmienne” i upewnić się, że CLASS_NAMEzmienna jest zdefiniowana do używania className()wyrażenia i ma zaznaczone pole „Pomiń, jeśli zdefiniowano”.


2

Stworzyłem klasę zmiennych statycznych, metod i klas o nazwie as S .

Poniżej przedstawiono metodę logowania:

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

Jest wywoływany w dowolnej klasie, ponieważ S.L(this, whaterver_object);The getClass().getName()dołącza również nazwę pakietu, dlatego usuwam go, aby uniknąć niepotrzebnego wydłużania tagu.

Zalety:

  1. Krótszy niż Log.d(TAG,
  2. Nie ma potrzeby konwertowania wartości int na ich ciąg. W rzeczywistości nie ma potrzeby pisaniatoString
  3. Nie zapomnij usunąć Log.dNigdy , ponieważ muszę tylko usunąć metodę, a lokalizacje wszystkich dzienników zostaną zaznaczone na czerwono.
  4. Nie ma potrzeby definiowania TAG na górze działania, ponieważ przyjmuje nazwę klasy.
  5. TAG ma prefiks CCC(krótki, łatwy do wpisania ciąg), dzięki czemu łatwo jest wyświetlić listę tylko dzienników na monitorze Android w Android Studio. Czasami jednocześnie prowadzisz usługi lub inne zajęcia. Jeśli musisz wyszukiwać według samej nazwy działania, nie możesz dokładnie zobaczyć, kiedy otrzymano odpowiedź usługi, a następnie nastąpiło działanie z Twojego działania. Prefiks taki jak CCC pomaga, ponieważ zapewnia chronologicznie dzienniki czynności, w których miało miejsce

1
Świetne rozwiązanie! Używam tego! Ale zastąpiłem Context ctxprzez Object ctxi ctx.getClass().getName().replace(ctx.getPackageName(), "")przez ctx.getClass().getSimpleName(). W ten sposób mogę zadzwonić S.L(Object, Object)wszędzie (w tym do tych, Fragmentktóre nie rozszerzają Context, na przykład).
Antonio Vinicius Menezes Medei

1

Możesz użyć, this.toString()aby uzyskać unikalny identyfikator dla określonej klasy, w której drukujesz do dziennika.


Może to być kosztowne w zależności od tego, co toString()robi.
smoła

1

Kosztem aktualizowania tych ciągów, gdy przenoszę kod między metodami lub zmieniam nazwy metod, lubię robić następujące rzeczy. Z filozoficznego punktu widzenia wydaje się również, że lepiej jest umieścić w tagu słowo „lokalizacja” lub „kontekst”, a nie wiadomość.

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!");
    }

}

Zaletą jest to, że możesz odfiltrować pojedynczą metodę, nawet jeśli treść nie jest statyczna, np

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

Jedyną wadą jest to, że kiedy zmieniam nazwę f()na g(), muszę pamiętać o tym ciągu. Ponadto automatyczna refaktoryzacja IDE ich nie złapie.

To znaczy przez jakiś czas byłem fanem używania krótkiej nazwy klasy LOG_TAG = MyClass.class.getSimpleName(). Trudniej było je filtrować w dziennikach, ponieważ było mniej do zrobienia.


1

Jest to bardzo stare pytanie, ale nawet pomyśleć, że zaktualizowana odpowiedź na lipiec 2018 r., Lepiej jest użyć drewna. W celu zarejestrowania prawidłowego logowania błędy i ostrzeżenia mogą być wysyłane do bibliotek awarii innych firm, takich jak Firebase lub Crashlytics.

W klasie implementującej Application należy dodać:

@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);
            }
        }
    }
}

Nie zapomnij o zależności od drewna.

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

0

Dla użytkowników, którzy odwiedzili to pytanie:

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

0

używają Timber dla aplikacji IOsched 2019, aby wyświetlić informacje o debugowaniu:

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

stosowanie

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

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

pamiętaj, że dzięki temu dzienniki są dostępne tylko w stanie DEBUG i ułatwia zadanie ich ręcznego usuwania w celu uruchomienia w Google Play -

po wydaniu aplikacji w sklepie Play musimy usunąć wszystkie instrukcje Log z aplikacji, aby żadne dane aplikacji, takie jak informacje o użytkowniku, ukryte dane aplikacji, tokeny uwierzytelniania nie były dostępne dla użytkownika w logcat jako zwykły tekst

sprawdź ten artykuł https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d


-2

Zwykle używam nazwy metody jako tagu, ale z Thread

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

Pozwala to uniknąć nowego wyjątku.


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

3
Dlaczego miałbyś tworzyć nowe RuntimeExceptiontylko po to, aby uzyskać aktualną nazwę klasy? Bardzo źle.
asgs

W ten sposób TAGUJĘ swoje wpisy w dzienniku, jest to jedyne rozwiązanie, które mogę poprawnie refaktoryzować, kiedy kopiuję klasę z projektu do innego, więc dlaczego nie. Jestem otwarty na sugestie, jeśli masz lepsze i wygodniejsze pomysły.
Powstań

1
Jeśli po prostu kopiujesz pliki klas Java z jednej lokalizacji do drugiej, bez zmiany nazwy, potrzebne jest rozwiązanie dostarczone przez @gianpi. W przeciwnym razie możesz po prostu to zrobić, this.getClass().getName()chociaż musiałbyś usunąć statyczny zakresTAG
asgs Kwietnia
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.