Günlük girişlerini genellikle nasıl etiketlersiniz? (android)


96

Çoğunuzun android.util.Log'dan haberdar olduğunu varsayıyorum. Tüm günlükleme yöntemleri ilk argüman olarak 'String etiketini' kabul eder.

Ve sorum şu : Uygulamalarınızda günlüklerinizi genellikle nasıl etiketlersiniz? Bunun gibi bazı sabit kodlar gördüm:

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

Bu pek çok nedenden dolayı hoş görünmüyor:

  • Bana bu kodun sabit kodu olmadığını söyleyebilirsin, ama var.
  • Uygulamam, aynı ada sahip farklı paketlerde herhangi bir sayıda sınıfa sahip olabilir. Bu yüzden günlüğü okumak zor olurdu.
  • Esnek değil. Sınıfınıza her zaman özel bir alan ETİKETİ koydunuz.

Bir sınıf için ETİKET almanın düzgün bir yolu var mı?


2
TAG kullanımı Android javadoc tarafından önerildiği için çalışma zamanında sınıf adını almaktan daha kötü olduğunu düşünmüyorum
Vladimir

GeneralConstants gibi belirli bir sınıf oluşturmayı ve TAG'lerimi üzerine koymayı tercih ediyorum ve etiketlerime istediğim herhangi bir sınıfta ulaşabiliyorum; GeneralConstans.MY_TAG
cagryInside

6
Sınıfın adını kodlamak çirkin ama proguard ile çalışmanın tek güvenilir yolu olan TAG'ın sınıfta tanımlanması en iyisidir. Proguard'ı hiç kullanmazsanız, MyActivity.class.getName () en iyi çözümdür. Yinelenen adlardan endişe ediyorsanız, yalnızca paket adını ekleyin. TAG adlarının farklı bir yerde olması bakım kabusu haline gelecektir.
Ralph Mueller

Yanıtlar:


181

Bir ETİKET kullanıyorum, ancak şu şekilde başlatıyorum:

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

Bu şekilde, kodumu yeniden düzenlediğimde etiket de buna göre değişecektir.


21
TAG sabitini de aynı şekilde tanımlıyorum. Ancak merak ediyorum, kod gizleme araçları sınıf isimlerimi nasıl etkileyecek ve sonuç olarak bu sabitin değeri?
Olegs Briska

1
bunca zaman el ile yapıştırdım "MyActivity.class.getName();". Her zaman "ETİKET" in Google vb. Örneklerde sadece bir yer tutucu olduğunu düşünmüşümdür ... gerçek bir Staticdeğişken değil ! Bu çok daha iyi bir çözüm, teşekkürler :)
wired00

4
Neden statik olanı kaldırıp this.getClass().getName()onun yerine onu daha genel hale getirmiyorsunuz?
theblang

11
TAG üzerindeki uzunluk sınırlamalarını önlemek için this.getClass (). GetSimpleName () 'i denemek isteyebilirsiniz. Tag.length ()> 23 ise IllegalArgumentException atılır.
Michael Levy

14
Ralph Mueller'in bahsettiği gibi, sınıf adlarını gizlemek için Proguard kullanıyorsanız (çoğu Android projesinin yaptığı gibi) bu teknik çalışmaz.
John Patterson

16

Genellikle Appfarklı bir pakette oturan ve kullanışlı statik yöntemler içeren bir sınıf oluşturuyorum . Yöntemlerden biri getTag()yöntemdir, bu şekilde TAG'yi her yere alabilirim.
Appsınıf şuna benzer:

DÜZENLEME : Br mob yorumu başına geliştirildi (Teşekkürler :))

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

}

Ve onu kullanmak istediğimde:

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

getTagYöntemin çıktısı, getTagkolay hata ayıklama için çağıran sınıfın adı (paket adıyla birlikte) ve çağrının yapıldığı satır numarasıdır .


6
Bunu kesinlikle yapmam .. Bunu yaparsanız, günlük ifadeleriniz performans açısından büyük bir darbe alacak. Bunu yaparsanız, proguard'ın üretim yapılarında uyarıdan daha az bir şey için günlük mesajlarını kaldırmasını kesinlikle isteyeceksiniz.
Matt Wolfe

1
Matt, kesinlikle haklısın! Üretimde günlükleri kaldırmak / çıkarmak iyi bir uygulamadır - stackoverflow.com/a/2019563/2270166
Yaniv

2
Etiket uzunluğu artık 23 karakterle sınırlı olduğundan bu muhtemelen artık önerilmez
Claudio Redi

Nasıl getStackTrace()çalıştığını bana gösterdiğin için teşekkürler . Ama pahalı olduğu için kullanmayacağım
BlueWizard

13

Go Android Studio -> tercih -> Canlı Şablonlar -> AndroidLog ardından seçmek Log.d (TAG, String) .

In Şablon metni değiştirmek

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

ile

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

Android menüsünün resmi

Daha sonra Değişkenleri düzenle'yi tıklayın ve className Name sütununun yanındaki İfade sütununa className () girin .Android menü 2'nin görüntüsü

Şimdi kısayolu logdyazdığınızda koyacak

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

Artık bir ETİKET tanımlamanıza gerek yok.


1
Bu, Android Studio'nun gerçekten harika bir kullanımı ve soruna ilginç bir yaklaşım, ancak aynı zamanda aslında TAG değişkeninin yerine dize giriyorsunuz, yani değiştirmek gerekirse biraz hantal olabilir, değil mi? Yine de işlevselliği göstermek için +1, teşekkürler!
Voy

3
Bu yolu seviyorum, ancak mevcut olanı değiştirmek yerine yeni bir günlük girişi oluşturmayı tercih ederim, sadece gelecekteki bir güncellemede veya başka bir şeyde değiştiğinde güvenli tarafta olmak için.
Alaa

9

Yaniv cevabını iyileştirmeyi seviyorum, eğer bu formatta günlüğünüz varsa (dosyaadı.java:XX) xx satır numarası, kısayolu bir hata olduğunda aynı şekilde bağlayabilirsiniz, bu şekilde doğrudan söz konusu satıra ulaşabilirim sadece logcat'e tıklayarak

Bunu genişletilmiş Uygulamamın içine koyuyorum, böylece diğer tüm dosyalarda kullanabiliyorum

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

Ekran görüntüsü:


Sevmek, "çalmak" ve cevabımı güncellemek :)
Yaniv

4
Etiket uzunluğu artık 23 karakterle sınırlı olduğundan bu muhtemelen artık önerilmez
Claudio Redi

3

AndroidStudio'nun logtvarsayılan olarak bir şablonu vardır ( logtbir kod kümesine genişletmek için yazabilir ve sekme tuşuna basabilirsiniz). TAG tanımını başka bir sınıftan kopyalayıp yapıştırmaktan ve bahsettiğiniz sınıfı değiştirmeyi unutmamak için bunu kullanmanızı öneririm. Şablon varsayılan olarak şu şekilde genişler:

private static final String TAG = "$CLASS_NAME$"

Yeniden düzenlemeden sonra eski sınıf adını kullanmaktan kaçınmak için bunu şu şekilde değiştirebilirsiniz:

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

"Değişkenleri düzenle" düğmesini işaretlemeyi ve CLASS_NAMEdeğişkenin className()İfade kullanmak için tanımlandığından ve "Tanımlandıysa atla" seçeneğinin işaretli olduğundan emin olun .


2

Olarak adlandırılan Statik değişkenler, yöntemler ve sınıflardan oluşan bir sınıf oluşturdum S.

Günlüğe kaydetme yöntemi aşağıdadır:

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

Gibi herhangi bir sınıfta denir da dolayısıyla, ben gereksiz yere uzun etiketi yapmaktan kaçınmaya dışarı çıkarmadan am Paket adını ekler.S.L(this, whaterver_object);getClass().getName()

Avantajlar:

  1. Daha kısa Log.d(TAG,
  2. İnt değerlerini dizelerine dönüştürmeye gerek yok. Yazmaya gerek yoktoString
  3. Log.dSadece yöntemi silmem gerektiğinden ve tüm günlüklerin konumları kırmızı ile işaretlendiğinden , silmeyi unutmayacağım .
  4. Sınıfın adını aldığı için etkinliğin üst kısmında ETİKETİ tanımlamaya gerek yoktur.
  5. TAG, CCCAndroid Studio'daki android monitörde yalnızca günlüklerinizi listelemek kolay olacak şekilde (kısa, yazması kolay bir dize) önekine sahiptir . Bazen hizmetleri veya diğer sınıfları aynı anda yürütüyorsunuz. Yalnızca etkinlik adına göre arama yapmanız gerekiyorsa, tam olarak ne zaman bir hizmet yanıtının alındığını ve ardından etkinliğinizden bir eylemin gerçekleştiğini göremezsiniz. CCC gibi bir önek, size gerçekleştiği etkinlikle birlikte günlükleri kronolojik olarak verdiği için yardımcı olur.

1
Harika çözüm! Ben kullanıyorum! Ama yerini Context ctxtarafından Object ctxve ctx.getClass().getName().replace(ctx.getPackageName(), "")tarafından ctx.getClass().getSimpleName(). Bu şekilde S.L(Object, Object)her yeri arayabilirim ( Fragmentuzatılmayanlar dahil Context, anında).
Antonio Vinicius Menezes Medei

1

Sen kullanabilirsiniz this.toString()sen günlüğüne yazdırmak hangi belirli sınıf için benzersiz tanıtıcısını alır.


Bu, ne yaptığına bağlı olarak pahalı olabilir toString().
katran

1

Kodu yöntemler arasında taşıdığımda veya yöntemleri yeniden adlandırdığımda bu dizeleri güncelleme pahasına, aşağıdakileri yapmayı seviyorum. Felsefi olarak, mesajda değil, etikette "konum" veya "bağlam" tutmak daha iyi görünmektedir.

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

}

Buradaki avantaj, içerik statik olmasa bile tek bir yöntemi filtreleyebilmenizdir.

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

Tek dezavantajı, adını f()değiştirdiğimde g()bu dizeyi aklımda tutmam gerektiğidir. Ayrıca, otomatik IDE yeniden düzenleme bunları yakalayamaz.

Bir süredir kısa sınıf adını kullanma hayranıydım, yani LOG_TAG = MyClass.class.getSimpleName(). Onları günlüklerde filtrelemeyi daha zor buldum çünkü devam edecek daha az şey vardı.


1

Bu çok eski bir soru, ancak Temmuz 2018 için güncellenmiş bir cevap düşünülse bile, Kereste kullanılması daha çok tercih edilir. Doğru günlük kaydını günlüğe kaydetmek için, hatalar ve uyarılar Firebase veya Crashlytics gibi üçüncü taraf kilitlenme kitaplıklarına gönderilebilir.

Uygulamayı uygulayan sınıfta şunu eklemelisiniz:

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

Kereste bağımlılığını unutmayınız.

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

0

Bu soruyu ziyaret eden kullanıcılar için:

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

0

IOsched uygulaması 2019 için Timber'ı hata ayıklama bilgilerini göstermek için kullanıyorlar:

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

kullanım

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

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

bunun Günlükleri yalnızca HATA AYIKLAMA durumunda kullanılabilir hale getirdiğini ve Google Play'de başlatmak için bunları manuel olarak kaldırma görevini kolaylaştırdığını unutmayın -

Uygulamayı oyun mağazasında yayınlarken, tüm Log ifadesini uygulamadan kaldırmamız gerekir, böylece kullanıcı bilgileri, gizli uygulama verileri, yetkilendirme belirteçleri gibi uygulama verilerinin hiçbiri logcat'te düz metin olarak kullanıcıya sunulmaz.

bu makaleye göz atın https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d


-2

Genellikle yöntem adını etiket olarak kullanıyorum ama Thread'den

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

Bu, yeni İstisnayı önler.


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

3
RuntimeExceptionSadece mevcut sınıf adını almak için neden yeni bir tane oluşturuyorsunuz ? Çok kötü.
2013

Günlük girişlerimi bu şekilde ETİKETLİYORUM, bir sınıfı bir projeden diğerine kopyaladığımda düzgün şekilde yeniden düzenleyebileceğim tek çözüm bu, öyleyse neden olmasın. Daha iyi ve daha rahat fikirleriniz varsa, önerilere açığım.
Kalk

1
Java sınıfı dosyalarını yeniden adlandırmadan bir konumdan diğerine kopyalıyorsanız, @gianpi tarafından sağlanan çözüm gerekli olan şeydir. Aksi takdirde, this.getClass().getName()statik kapsamını kaldırmak zorunda olsanız bile yapabilirsiniz .TAG
asgs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.