Bagaimana Anda biasanya menandai entri log? (android)

96

Saya berasumsi sebagian besar dari Anda mengetahui android.util.Log Semua metode logging menerima 'String tag' sebagai argumen pertama.

Dan pertanyaan saya adalah Bagaimana Anda biasanya menandai log di aplikasi Anda? Saya telah melihat beberapa hardcode seperti ini:

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

Ini tidak terlihat bagus karena banyak alasan:

  • Anda dapat memberi tahu saya bahwa kode ini tidak memiliki hardcode, tetapi memang demikian.
  • Aplikasi saya dapat memiliki sejumlah kelas dalam paket berbeda dengan nama yang sama. Jadi akan sulit untuk membaca log.
  • Itu tidak fleksibel. Anda selalu menempatkan TAG bidang pribadi ke kelas Anda.

Apakah ada cara yang rapi untuk mendapatkan TAG untuk kelas?

andrii
sumber
2
Menggunakan TAG disarankan oleh Android javadoc , jadi menurut saya itu tidak lebih buruk daripada mendapatkan nama kelas saat runtime
Vladimir
saya lebih suka membuat kelas tertentu seperti GeneralConstants dan meletakkan TAG saya di atasnya dan saya dapat mencapai tag saya kelas mana pun yang saya inginkan seperti itu; GeneralConstans.MY_TAG
cagryInside
6
Saya pikir yang terbaik adalah memiliki TAG yang didefinisikan di kelas, hardcode nama kelas jelek tetapi satu-satunya cara yang dapat diandalkan untuk bekerja dengan proguard. Jika Anda tidak pernah menggunakan proguard maka MyActivity.class.getName () adalah solusi terbaik. Jika Anda khawatir tentang nama duplikat, cukup masukkan nama paket. Memiliki nama TAG di tempat yang berbeda akan menjadi mimpi buruk pemeliharaan.
Ralph Mueller

Jawaban:

179

Saya menggunakan TAG, tetapi saya menginisialisasinya seperti ini:

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

Dengan cara ini ketika saya memfaktor ulang kode saya, tag juga akan berubah sesuai.

gianpi
sumber
21
Saya mendefinisikan konstanta TAG dengan cara yang sama. Namun, saya bertanya-tanya, bagaimana alat obfuscation kode akan memengaruhi nama kelas saya dan akibatnya nilai konstanta ini?
Gumbit
1
selama ini saya paste secara manual "MyActivity.class.getName();". Saya selalu berpikir "TAG" hanyalah placeholder dalam contoh dari Google dll ... bukan Staticvariabel sebenarnya ! Ini adalah solusi yang jauh lebih baik terima kasih :)
wired00
4
Mengapa tidak menghapus statis dan menggunakannya this.getClass().getName()untuk membuatnya lebih umum?
theblang
11
Anda mungkin ingin mencoba this.getClass (). GetSimpleName () untuk menghindari batasan panjang pada TAG. IllegalArgumentException dilempar jika tag.length ()> 23.
Michael Levy
14
Seperti yang disebutkan oleh Ralph Mueller, teknik ini tidak berfungsi jika Anda menggunakan Proguard (seperti kebanyakan proyek Android) untuk mengaburkan nama kelas.
John Patterson
16

Saya biasanya membuat Appkelas yang berada dalam paket yang berbeda dan berisi metode statis yang berguna. Salah satu caranya adalah getTag()metode, dengan cara ini saya bisa mendapatkan TAG dimana-mana.
Appkelas terlihat seperti ini:

EDIT : Peningkatan per komentar massa (Terima kasih :))

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

}

Dan ketika saya ingin menggunakannya:

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

Keluaran dari getTagmetode ini adalah nama kelas pemanggil (dengan nama paket), dan nomor baris tempat pemanggilan getTag, untuk memudahkan debug.

Yaniv
sumber
6
Saya pasti tidak akan melakukan ini .. Pernyataan log Anda akan menghasilkan kinerja yang besar jika Anda melakukannya. Jika Anda melakukan ini, Anda pasti ingin meminta proguard menghapus pesan log untuk apa pun yang kurang dari peringatan pada build produksi.
Matt Wolfe
1
Matt, kamu benar sekali! Merupakan praktik yang baik untuk menghapus / menghapus log pada produksi - stackoverflow.com/a/2019563/2270166
Yaniv
2
Ini mungkin tidak lagi disarankan karena panjang tag sekarang dibatasi hingga 23 karakter
Claudio Redi
terima kasih telah menunjukkan cara getStackTrace()kerjanya. Tapi saya tidak akan menggunakannya karena mahal
BlueWizard
12

Masuk ke Android Studio -> preferensi -> Live Templates -> AndroidLog lalu pilih Log.d (TAG, String) .

Di teks Template ganti

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

dengan

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

Gambar menu Android

Kemudian klik Edit variabel dan masukkan className () di kolom Expression di sebelah kolom ClassName Name .gambar dari menu Android 2

Sekarang ketika Anda mengetik pintasan logditu akan dimasukkan

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

Anda tidak perlu lagi mendefinisikan TAG.

Nicolas Manzini
sumber
1
itu adalah penggunaan Android Studio yang sangat keren dan pendekatan yang menarik untuk masalah ini, meskipun pada saat yang sama Anda benar-benar memasukkan string sebagai ganti variabel TAG, artinya ini bisa sedikit rumit jika perlu mengubahnya, bukan? 1 untuk menunjukkan fungsionalitasnya, terima kasih!
Voy
3
Saya suka cara ini, namun saya lebih suka membuat entri log baru daripada memodifikasi yang sudah ada, hanya untuk berada di sisi yang aman jika diubah di pembaruan mendatang atau sesuatu.
Alaa
9

Saya ingin meningkatkan jawaban Yaniv jika Anda memiliki log dalam format ini (namafile.java:XX) nomor baris xx Anda dapat menautkan pintasan dengan cara yang sama terhubung ketika ada kesalahan, dengan cara ini saya bisa langsung ke baris yang dimaksud hanya dengan mengklik logcat

Saya meletakkan ini di dalam Aplikasi tambahan saya sehingga saya dapat menggunakan di setiap file lainnya

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

Tangkapan layar:

br mob
sumber
Menyukainya, "mencuri" dan memperbarui jawaban saya :)
Yaniv
4
Ini mungkin tidak lagi disarankan karena panjang tag sekarang dibatasi hingga 23 karakter
Claudio Redi
3

AndroidStudio memiliki logttemplate secara default (Anda dapat mengetik logtdan menekan tab agar template dapat diperluas menjadi kode yang sama). Saya sarankan menggunakan ini untuk menghindari menyalin menempel definisi TAG dari kelas lain dan lupa untuk mengubah kelas yang Anda rujuk. Template meluas secara default ke

private static final String TAG = "$CLASS_NAME$"

Untuk menghindari penggunaan nama kelas lama setelah pemfaktoran ulang, Anda dapat mengubahnya menjadi

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

Ingatlah untuk memeriksa tombol "Edit variabel" dan pastikan bahwa CLASS_NAMEvariabel ditentukan untuk menggunakan className()Ekspresi dan "Lewati jika ditentukan" dicentang.

Hemaolle
sumber
2

Saya telah membuat kelas variabel Statis, metode, dan kelas bernama S.

Berikut ini adalah metode logging:

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

Ini dipanggil di kelas mana pun karena S.L(this, whaterver_object);The getClass().getName()juga menambahkan nama paket, oleh karena itu, saya menghapusnya untuk menghindari pembuatan tag yang terlalu panjang.

Keuntungan:

  1. Lebih pendek dari Log.d(TAG,
  2. Tidak perlu mengubah nilai int menjadi stringnya. Infact tidak perlu mengetiktoString
  3. Jangan lupa untuk menghapus Log.dkarena saya hanya perlu menghapus metode dan lokasi semua log ditandai merah.
  4. Tidak perlu menentukan TAG di bagian atas aktivitas karena ini mengambil nama kelas.
  5. TAG memiliki awalan CCC(string yang pendek dan mudah diketik) sehingga mudah untuk hanya mencantumkan log Anda di monitor android di Android Studio. Terkadang Anda menjalankan layanan atau kelas lain secara bersamaan. Jika Anda harus mencari berdasarkan nama aktivitas saja maka Anda tidak dapat melihat dengan tepat kapan respons layanan diperoleh dan kemudian tindakan dari aktivitas Anda telah terjadi. Awalan seperti CCC membantu karena memberi Anda log secara kronologis dengan aktivitas yang terjadi
suku
sumber
1
Solusi bagus! Aku menggunakannya! Tapi saya digantikan Context ctxoleh Object ctxdan ctx.getClass().getName().replace(ctx.getPackageName(), "")oleh ctx.getClass().getSimpleName(). Dengan begitu, saya bisa menelepon ke S.L(Object, Object)mana saja (termasuk di Fragments yang tidak diperpanjang Context, untuk seketika).
Antonio Vinicius Menezes Medei
1

Anda dapat menggunakan this.toString()untuk mendapatkan pengenal unik untuk kelas tertentu tempat Anda mencetak ke log.

kaspermoerch
sumber
Ini bisa menjadi mahal tergantung pada apa yang toString()dilakukannya.
tar
1

Dengan mengorbankan memperbarui string ini ketika saya memindahkan kode antar metode atau mengganti nama metode, saya suka melakukan hal berikut. Secara filosofis juga tampaknya lebih baik untuk menyimpan "lokasi" atau "konteks" dalam tag, bukan pesannya.

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

}

Manfaatnya di sini adalah Anda dapat memfilter satu metode meskipun isinya tidak statis, mis

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

Satu-satunya kelemahan adalah bahwa ketika saya mengganti nama f()menjadi g()saya perlu mengingat string itu. Selain itu, pemfaktoran ulang IDE otomatis tidak akan menangkapnya.

Untuk sementara saya adalah penggemar menggunakan nama kelas pendek, maksud saya LOG_TAG = MyClass.class.getSimpleName(). Saya menemukan mereka lebih sulit untuk difilter di log karena lebih sedikit yang harus dilakukan.

ter
sumber
1

Ini adalah pertanyaan yang sangat lama, tetapi meskipun jawaban yang diperbarui untuk Juli 2018 lebih disukai menggunakan Kayu. Untuk Mencatat logging yang benar, error dan peringatan dapat dikirim ke pustaka error pihak ketiga, seperti Firebase atau Crashlytics.

Di kelas yang mengimplementasikan Aplikasi Anda harus menambahkan ini:

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

Jangan lupakan ketergantungan Timber.

implementation 'com.jakewharton.timber:timber:4.7.1'
aleksandrbel
sumber
0

Untuk pengguna yang mengunjungi pertanyaan ini:

private val TAG:String = this.javaClass.simpleName;
Pamirzameen
sumber
0

mereka menggunakan Timber untuk aplikasi IOsched 2019 untuk menampilkan info 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"
    ... >

pemakaian

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

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

perhatikan bahwa ini membuat Log hanya tersedia selama status DEBUG dan memfasilitasi tugas Anda untuk menghapusnya secara manual untuk peluncuran di Google Play -

saat merilis aplikasi di play store, kita perlu menghapus semua pernyataan Log dari aplikasi, sehingga tidak ada data aplikasi seperti informasi pengguna, data aplikasi tersembunyi, auth-token tersedia untuk pengguna di logcat sebagai teks biasa

lihat artikel ini https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d

Dan Alboteanu
sumber
-2

Saya biasanya menggunakan nama metode sebagai tag tetapi dari Thread

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

Ini menghindari Pengecualian baru.

pengguna2705093
sumber
-9
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
Timbul
sumber
3
Mengapa Anda membuat yang baru RuntimeExceptionhanya untuk mendapatkan nama kelas saat ini? Sangat buruk.
asgs
Ini adalah cara saya memberi tag pada entri log saya, ini adalah satu-satunya solusi yang dapat saya refactor dengan benar ketika saya menyalin kelas dari proyek ke proyek lain, jadi mengapa tidak. Saya terbuka untuk saran jika Anda memiliki ide yang lebih baik dan lebih nyaman.
Bangkitlah
1
Jika Anda hanya menyalin file kelas Java dari satu lokasi ke lokasi lain, tanpa mengganti nama, solusi yang disediakan oleh @gianpi adalah yang diperlukan. Jika tidak, Anda dapat melakukannya this.getClass().getName()meskipun Anda harus menghapus cakupan statis dariTAG
asgs