Bagaimana cara menghapus semua panggilan debug logging sebelum membangun versi rilis aplikasi Android?

397

Menurut Google, saya harus " menonaktifkan panggilan ke metode Log dalam kode sumber " sebelum menerbitkan aplikasi Android saya ke Google Play. Ekstrak dari bagian 3 daftar periksa publikasi :

Pastikan Anda menonaktifkan logging dan menonaktifkan opsi debugging sebelum Anda membangun aplikasi Anda untuk rilis. Anda dapat menonaktifkan logging dengan menghapus panggilan ke metode Log dalam file sumber Anda.

Proyek open-source saya besar dan sulit melakukannya secara manual setiap kali saya merilis. Selain itu, menghapus baris Log berpotensi rumit, misalnya:

if(condition)
  Log.d(LOG_TAG, "Something");
data.load();
data.show();

Jika saya mengomentari baris Log, maka ketentuannya berlaku untuk baris berikutnya, dan kemungkinan dimuat () tidak dipanggil. Apakah situasi seperti itu cukup langka sehingga saya dapat memutuskan bahwa seharusnya tidak ada?

Jadi, apakah ada cara tingkat kode sumber yang lebih baik untuk melakukan itu? Atau mungkin beberapa sintaks ProGuard pintar untuk menghapus semua baris Log secara efisien tapi aman?

Nicolas Raoul
sumber
2
+1 karena saya tidak ingat ini ada dalam daftar periksa publikasi.
rds
51
Untuk mengomentari baris yang tidak diblokir, saya menggunakan "; //" daripada "//".
yingted
Jika Anda harus dapat membatalkan ini, Anda mungkin ingin menggunakannya sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g' .
yingted
2
Tautan yang ditambahkan Dimitar tidak berfungsi lagi. Saya menemukan ini sebagai gantinya source.android.com/source/code-style.html#log-sparingly .
JosephL
1
@ mboy: Mungkin untuk kinerja terutama saat ini, tetapi pada versi Android lama juga memiliki manfaat keamanan.
Nicolas Raoul

Jawaban:

488

Saya menemukan solusi yang jauh lebih mudah adalah dengan melupakan semua ifcek di semua tempat dan cukup gunakan ProGuard untuk menghapus panggilan metode Log.d()atau apa pun Log.v()ketika kita memanggil releasetarget Ant .

Dengan begitu, kami selalu memiliki info debug yang menjadi keluaran untuk build reguler dan tidak harus membuat perubahan kode untuk build rilis. ProGuard juga dapat melakukan beberapa lintasan melewati kode byte untuk menghapus pernyataan yang tidak diinginkan lainnya, blok kosong dan secara otomatis dapat inline metode pendek jika diperlukan.

Sebagai contoh, berikut ini adalah konfigurasi ProGuard yang sangat mendasar untuk Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
}

Jadi Anda akan menyimpannya di file, lalu panggil ProGuard dari Ant, dengan mengirimkan JAR yang baru dikompilasi dan platform Android JAR yang Anda gunakan.

Lihat juga contoh-contoh dalam manual ProGuard.


Pembaruan (4,5 tahun kemudian): Saat ini saya menggunakan Kayu untuk Android logging.

Tidak hanya itu sedikit lebih bagus daripada yang standar Log implementasi - tag log diatur secara otomatis, dan mudah untuk mencatat string dan pengecualian yang diformat - tetapi Anda juga dapat menentukan perilaku pencatatan yang berbeda saat runtime.

Dalam contoh ini, pernyataan logging hanya akan ditulis ke logcat di build debug aplikasi saya:

Kayu diatur dalam Application onCreate()metode saya :

if (BuildConfig.DEBUG) {
  Timber.plant(new Timber.DebugTree());
}

Kemudian di tempat lain dalam kode saya, saya bisa login dengan mudah:

Timber.d("Downloading URL: %s", url);
try {
  // ...
} catch (IOException ioe) {
  Timber.e(ioe, "Bad things happened!");
}

Lihat contoh aplikasi Kayu untuk contoh lebih lanjut, di mana semua laporan log dikirim ke logcat selama pengembangan dan, dalam produksi, tidak ada laporan debug dicatat, tetapi kesalahan dilaporkan secara diam-diam ke Crashlytics.

Christopher Orr
sumber
59
Dan mengapa itu tidak ada di file proguard default?
rds
10
+ rds karena ini akan membuat nomor baris stacktraces produksi berbeda dari yang ada di kode Anda, karena baris dihapus.
Guy
5
Saya dapat mengkonfirmasi bahwa menghapus panggilan Log akan menggeser nomor baris dalam stacktraces. Itu tidak akan selalu tidak sinkron (saya melakukan beberapa tes cepat tetapi tidak bisa menunjukkan dengan tepat apa penyebabnya, mungkin jika Anda menggabungkan string dalam panggilan Log), tetapi kadang-kadang akan ada beberapa baris off. Sepadan dengan masalah IMO karena kemampuan untuk dengan mudah menghapus panggilan Log.
Tony Chan
5
@Fraggle Dari proguard-android.txt dalam alat ADT: "Perhatikan bahwa jika Anda ingin mengaktifkan pengoptimalan, Anda tidak bisa hanya menyertakan flag pengoptimalan dalam file konfigurasi proyek Anda sendiri; sebaliknya Anda perlu menunjuk ke" proguard-android-optimize. txt "bukan file ini dari" # project.properties file Anda.
Raanan
3
Seperti kata espinchi dalam jawaban di bawah ini. "Satu-satunya masalah dengan pendekatan ini adalah bahwa, jika Anda melakukan Log.d (" tag "," Diproses: "+ ItemCounter baru (blabla) +" item "), bahkan jika pesan log ini tidak muncul dalam versi yang Anda rilis, StringBuilder digunakan untuk membuat pesan, yang bisa jadi mahal untuk dibuat. "Apakah ini juga benar dalam kasus Timber?
Chitrang
117

Semua jawaban yang baik, tetapi ketika saya selesai dengan pengembangan saya, saya tidak ingin menggunakan apakah pernyataan di sekitar semua panggilan Log, juga tidak ingin menggunakan alat eksternal.

Jadi solusi yang saya gunakan adalah mengganti kelas android.util.Log dengan kelas Log saya sendiri:

public class Log {
    static final boolean LOG = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG) android.util.Log.w(tag, string);
    }
}

Satu-satunya hal yang harus saya lakukan di semua file sumber adalah mengganti impor android.util.Log dengan kelas saya sendiri.

Reiner
sumber
143
Satu-satunya masalah dengan pendekatan ini adalah bahwa, jika Anda melakukan Log.d ("tag", "Diproses:" + ItemCounter baru (blabla) + "item"), bahkan jika pesan log ini tidak muncul dalam versi yang Anda rilis, sebuah StringBuilder digunakan untuk membuat pesan, yang bisa jadi mahal untuk dibuat.
espinchi
9
Solusi ini memiliki masalah besar. espinchi hanya menyebutkan ujung gunung es. Masalahnya adalah bahwa ketika Anda menelepon Log.d("tag", someValue.toString());itu sangat mudah untuk lupa untuk memeriksa beberapa Nilai karena tidak nol apa artinya itu mungkin melempar NullPointerExceptionproduksi. Ini menyarankan solusi yang aman tetapi itu akan menipu Anda. Kami, kami private static boolean DEBUGdan kemudianif(DEBUG)Log.d(TAG, msg);
philipp
2
@espinchi Kekhawatiran Anda tampaknya berlaku untuk semua perpustakaan logging seperti yang dibahas dalam jawaban ini stackoverflow.com/a/15452492/433718 (Slf4j, backlog, ...). Apakah tidak disarankan untuk menggunakannya?
OneWorld
1
Satu-satunya cara untuk meminimalkan overhead yang disebutkan dalam komentar pertama oleh @espinchi adalah mengubah metode logging untuk menerima varargs alih-alih String. Solusi lengkap diuraikan di sini . Ini tampaknya memiliki kelemahan lain: setiap panggilan harus diedit (tidak hanya satu jalur impor).
Stan
21
Hanya FYI, jika Anda menggunakan Android Studio dan sistem gradle build, Anda dapat menggunakan static final boolean LOG = BuildConfig.DEBUGdan tidak harus memodifikasi file ini.
ashishduh
61

Saya sarankan memiliki boolean statis di suatu tempat yang menunjukkan apakah akan masuk atau tidak:

class MyDebug {
  LOG boolean akhir statis = true;
}

Lalu di mana pun Anda ingin masuk kode Anda, lakukan saja ini:

if (MyDebug.LOG) {
  jika (kondisi) Log.i (...);
}

Sekarang ketika Anda mengatur MyDebug.LOG ke false, kompiler akan menghapus semua kode di dalam pemeriksaan tersebut (karena ini adalah final statis, ia tahu pada waktu kompilasi kode itu tidak digunakan.)

Untuk proyek yang lebih besar, Anda mungkin ingin mulai memiliki boolean dalam file individual untuk dapat dengan mudah mengaktifkan atau menonaktifkan pencatatan yang diperlukan. Misalnya, ini adalah berbagai konstanta logging yang kita miliki di window manager:

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

Dengan kode yang sesuai seperti:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
hackbod
sumber
1
Saya akan memilih pendekatan semacam itu juga. Ini juga digunakan dalam sampel penagihan dalam aplikasi resmi Google.
LA_
4
Bukankah kurang verbose untuk lulus kondisi sebagai parameter pertama?
Snicolas
1
Ini tampaknya menjadi solusi terbaik meskipun memerlukan kode tambahan pada setiap pernyataan log: Nomor baris dipertahankan (kelemahan pendekatan ProGuard), Tidak ada kode untuk membuat pesan log dieksekusi ( kelemahan pendekatan kelas wrapper dan tampaknya juga pendekatan perpustakaan logging) . Penggunaan pendekatan ini di Googles dalam sampel tagihan aplikasi menurut @LA_ juga mendukung pemikiran saya.
OneWorld
2
@ Snicolas Bagaimana Anda bisa melewati kondisi sebagai parameter pertama tanpa menerapkan pembungkus? Apalagi jika Anda menambahkannya sebagai parameter, maka sebelum memasukkan metode, semua parameter perlu dievaluasi yaitu, juga string pesan. Kondisi ini perlu diuji sebelum membangun parameter. Solusi yang diusulkan mungkin yang terbaik tanpa perangkat eksternal.
type-a1pha
2
Dari kode biner, ini yang terbaik. Tetapi pengkodean seperti ini hanya banyak upaya untuk keluaran log debug yang sederhana. Keterbacaan kode menurun secara signifikan. Menangkan sebagian, kehilangan sebagian, kurasa ...
Richard Le Mesurier
30

Solusi Christopher Proguard adalah yang terbaik, tetapi jika karena alasan apa pun Anda tidak menyukai Proguard, berikut adalah solusi yang sangat berteknologi rendah:

Log komentar:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'

Log tanda komentar:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'

Kendala adalah bahwa instruksi logging Anda tidak boleh menjangkau lebih dari beberapa baris.

(Jalankan baris ini dalam shell UNIX di root proyek Anda. Jika menggunakan Windows, dapatkan layer UNIX atau gunakan perintah Windows yang setara)

Nicolas Raoul
sumber
1
perlu "" setelah -i di Sed jika berjalan di Mac (sesuai ini ) Terima kasih.
Vishal
Saya merasa ini mungkin yang akhirnya saya gunakan untuk sesuatu yang saya kerjakan karena saya tidak beruntung sama sekali dengan Proguard
Joe Plante
Dan bagaimana jika Anda memiliki Log setelah cabang sementara non-kurung, seperti yang Anda sarankan di posting pertama Anda?
type-a1pha
@ type-a1pha: Jika Anda mengadopsi solusi ini, maka Anda harus mempertimbangkan blok braket sebagai wajib.
Nicolas Raoul
2
@NicolasRaoul Setengah usus besar memperbaiki masalah ini ( //vs. ;//)
Alex Gittemeier
18

Saya ingin menambahkan beberapa prasyarat tentang penggunaan Proguard dengan Android Studio dan gradle, karena saya punya banyak masalah untuk menghapus baris log dari biner terakhir.

Untuk membuat assumenosideeffectskarya Proguard, ada prasyarat.

Di file gradle Anda, Anda harus menentukan penggunaan proguard-android-optimize.txtfile sebagai default.

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

Sebenarnya, dalam proguard-android.txtfile default , optimisasi dinonaktifkan dengan dua flag:

-dontoptimize
-dontpreverify

The proguard-android-optimize.txtfile tidak menambahkan garis, jadi sekarang assumenosideeffectsbisa bekerja.

Kemudian, secara pribadi, saya menggunakan SLF4J , ketika saya mengembangkan beberapa perpustakaan yang didistribusikan kepada orang lain. Keuntungannya adalah secara default tidak ada output. Dan jika integrator menginginkan beberapa output log, ia dapat menggunakan Logback untuk Android dan mengaktifkan log, sehingga log dapat dialihkan ke file atau ke LogCat.

Jika saya benar-benar perlu menghapus log dari perpustakaan terakhir, saya kemudian menambahkan ke file Proguard saya (setelah mengaktifkan proguard-android-optimize.txtfile tentu saja):

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}
Vincent Hiribarren
sumber
Ini tidak berfungsi dengan kompiler Jack baru
fattire
Ini membantu saya; keduanya proguard-android-optimize.txtsebagai file Proguard default dan -assumenosideeffectsdalam file Proguard kustom diperlukan! Saya menggunakan shinker R8 (default saat ini) dan default Android logging.
Jonik
10

Saya sangat menyarankan menggunakan Kayu dari Jake Wharton

https://github.com/JakeWharton/timber

itu memecahkan masalah Anda dengan mengaktifkan / menonaktifkan ditambah menambahkan kelas tag secara otomatis

hanya

public class MyApp extends Application {

  public void onCreate() {
    super.onCreate();
    //Timber
    if (BuildConfig.DEBUG) {
      Timber.plant(new DebugTree());
    }
    ...

log hanya akan digunakan di versi debug Anda, dan kemudian gunakan

Timber.d("lol");

atau

Timber.i("lol says %s","lol");

untuk mencetak

"Kelas Anda / msg" tanpa menentukan tag

AndroidGecko
sumber
2
Kayu sangat bagus, tetapi jika Anda sudah memiliki proyek yang ada - Anda dapat mencoba github.com/zserge/log . Ini adalah pengganti drop-in untuk android.util.Log dan memiliki sebagian besar fitur yang dimiliki Timber dan bahkan lebih.
zserge
zserge, solusi log Anda terlihat bagus. Banyak fitur. Sudahkah Anda mempertimbangkan untuk menambahkan aturan Lint seperti yang dimiliki Timber?
jk7
8

Saya telah menggunakan kelas LogUtils seperti pada aplikasi contoh Google IO. Saya memodifikasi ini untuk menggunakan aplikasi DEBUG konstan tertentu, bukan BuildConfig.DEBUG karena BuildConfig.DEBUG tidak dapat diandalkan . Kemudian di Kelas saya, saya memiliki yang berikut ini.

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}
JosephL
sumber
+1 untuk laporan bug tentang Build.DEBUGyang biasa saya gunakan. Saya juga menyerah dengan berbagai solusi "benar" dan menggunakan solusi gaya yang mirip dengan Anda.
Richard Le Mesurier
7

Saya akan mempertimbangkan menggunakan fasilitas logging roboguice alih-alih android.util.Log bawaan

Fasilitas mereka secara otomatis menonaktifkan debug dan verbose log untuk rilis rilis. Plus, Anda mendapatkan beberapa fitur bagus secara gratis (misalnya perilaku logging yang dapat disesuaikan, data tambahan untuk setiap log, dan lainnya)

Menggunakan proguard bisa sangat merepotkan dan saya tidak akan mengalami kesulitan mengkonfigurasi dan membuatnya berfungsi dengan aplikasi Anda kecuali Anda memiliki alasan yang bagus untuk itu (menonaktifkan log bukan yang baik)

Zvi
sumber
Sebuah pendekatan yang sangat bagus ketika Anda tidak dapat menggunakan Kebingungan .... terutama karena roboguice pecah karena proguard LOL
Snicolas
1
Tautan yang diperbarui untuk fasilitas logging robojuice
RenniePet
7

Saya memposting solusi ini yang berlaku khusus untuk pengguna Android Studio. Saya juga baru-baru ini menemukan Timber dan berhasil mengimpornya ke aplikasi saya dengan melakukan hal berikut:

Masukkan versi terbaru perpustakaan ke build.gradle Anda:

compile 'com.jakewharton.timber:timber:4.1.1'

Kemudian di Android Studios, buka Edit -> Find -> Replace in Path ...

Ketik Log.e(TAG,atau bagaimanapun Anda telah menetapkan pesan Log ke dalam "Text to find"kotak teks. Maka Anda tinggal menggantinya denganTimber.e(

masukkan deskripsi gambar di sini

Klik Temukan dan ganti semua.

Android Studios sekarang akan memeriksa semua file Anda di proyek Anda dan mengganti semua Log dengan Timbers.

Satu-satunya masalah yang saya miliki dengan metode ini adalah gradle muncul dengan sejuta pesan kesalahan setelah itu karena tidak dapat menemukan "Kayu" dalam impor untuk setiap file java Anda. Cukup klik pada kesalahan dan Android Studios akan secara otomatis mengimpor "Kayu" ke java Anda. Setelah Anda selesai melakukannya untuk semua file kesalahan, gradle akan dikompilasi lagi.

Anda juga perlu memasukkan kode ini ke onCreatemetode Applicationkelas Anda :

    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    }

Ini akan menghasilkan pendataan aplikasi hanya ketika Anda berada dalam mode pengembangan tidak dalam produksi. Anda juga dapat memiliki BuildConfig.RELEASEuntuk masuk dalam mode rilis.

Simon
sumber
3
Coba lakukan hal yang sama untuk impor Anda, dan pastikan kotak Ekspresi Reguler dicentang Teks untuk menemukan: import android\.util\.Log\;Ganti dengan:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson
atau Anda dapat menggunakan pencarian terstruktur dan ganti seperti yang ditunjukkan Chike Mgbemena di posnya
Maksim Turaev
@MaksimTuraev Tautan Anda tidak lagi relevan. Sekarang ini adalah blog tentang gaya rambut.
Vadim Kotov
Sepertinya pos dihapus = (tidak dapat menemukannya di mana pun.
Maksim Turaev
@MaksimTuraev di sini adalah salinan dari mesin Wayback, tetapi gambarnya rusak - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Vadim Kotov
6

Per android.util.Log menyediakan cara untuk mengaktifkan / menonaktifkan log:

public static native boolean isLoggable(String tag, int level);

Default metode ini adalahLoggable (...) mengembalikan false, hanya setelah Anda setprop di perangkat suka ini:

adb shell setprop log.tag.MyAppTag DEBUG

Ini berarti setiap log di atas level DEBUG dapat dicetak. Referensi dokumen android:

Cek untuk melihat apakah log untuk tag yang ditentukan dapat loggable pada tingkat yang ditentukan. Level default setiap tag diatur ke INFO. Ini berarti bahwa setiap level di atas dan termasuk INFO akan dicatat. Sebelum Anda melakukan panggilan ke metode logging, Anda harus memeriksa untuk melihat apakah tag Anda harus dicatat. Anda dapat mengubah level default dengan menyetel properti sistem: 'setprop log.tag. 'Di mana level adalah VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, atau SUPPRESS. SUPPRESS akan mematikan semua logging untuk tag Anda. Anda juga dapat membuat file local.prop dengan yang berikut ini di dalamnya: 'log.tag. =' Dan tempatkan di /data/local.prop.

Jadi kita bisa menggunakan util log kustom:

public final class Dlog 
{
    public static void v(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.VERBOSE))
            Log.v(tag, msg);
    }

    public static void d(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.DEBUG))
            Log.d(tag, msg);
    }

    public static void i(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.INFO))
            Log.i(tag, msg);
    }

    public static void w(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.WARN))
            Log.w(tag, msg);
    }

    public static void e(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.ERROR))
            Log.e(tag, msg);
    }
}
Richard
sumber
6

Jika Anda dapat menjalankan penggantian global (sekali), dan setelah itu mempertahankan beberapa konvensi pengkodean, Anda dapat mengikuti pola yang sering digunakan dalam kerangka kerja Android .

Alih-alih menulis

Log.d(TAG, string1 + string2 + arg3.toString());

memilikinya sebagai

if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

Sekarang proguard dapat menghapus StringBuilder dan semua string dan metode yang digunakannya, dari rilis DEX yang dioptimalkan. Gunakan proguard-android-optimize.txtdan Anda tidak perlu khawatir tentang android.util.Log di proguard-rules.pro:

android {
  
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
}

Dengan plugin Android Studio gradle, cukup dapat diandalkan, sehingga Anda tidak perlu konstanta tambahan untuk mengontrol stripping.BuildConfig.DEBUG

Alex Cohn
sumber
4

Tambahkan berikut ini ke file proguard-rules.txt Anda

-assumenosideeffects class android.util.Log {
  public static *** d(...);
  public static *** w(...);
  public static *** v(...);
  public static *** i(...);
}
eranga
sumber
4

masukkan deskripsi gambar di sini

Ini adalah apa yang saya lakukan pada proyek android saya ..

Di Android Studio kita dapat melakukan operasi serupa dengan, Ctrl + Shift + F untuk mencari dari seluruh proyek (Command + Shift + F di MacOs) dan Ctrl + Shift + R untuk Ganti ((Command + Shift + R di MacOs))

Lins Louis
sumber
Ini tampaknya membuka pekerjaan dengan proyek gerhana. Opsi pencarian bahkan tidak tersedia di studio android.
Simon
2
di Android Studio Anda dapat melakukan pencarian serupa dengan Ctrl + Shift + F shortcut
Lins Louis
Kode contoh dalam pertanyaan menjelaskan mengapa ini tidak dapat diandalkan.
Nicolas Raoul
Itu bisa menyebabkan masalah menghapus perintah apa pun yang berisi di Log. Misalnya chocolateLog.recipie ();
Andrew S
Tidak dapat menemukan opsi ini untuk Android Studio 2.1. Juga, saya bisa menggunakan trik ini pada 1 file sekaligus dengan pencarian / penggantian normal.
VVB
3

Saya punya solusi yang sangat sederhana. Saya menggunakan IntelliJ untuk pengembangan, jadi detailnya berbeda-beda, tetapi idenya harus berlaku di semua IDE.

Saya memilih untuk me-root pohon sumber saya, klik kanan dan pilih untuk melakukan "ganti". Saya kemudian memilih untuk mengganti semua "Log." dengan "// Log.". Ini menghapus semua pernyataan log. Untuk mengembalikannya nanti saya ulangi penggantian yang sama tetapi kali ini ganti semua "// Log." dengan "Log.".

Bekerja sangat bagus untuk saya. Hanya ingat untuk mengatur penggantian sebagai case sensitif untuk menghindari kecelakaan seperti "Dialog." Untuk jaminan tambahan, Anda juga dapat melakukan langkah pertama dengan "Log." sebagai string untuk mencari.

Cemerlang.

kg_sYy
sumber
2
Harap baca paragraf "Jika saya mengomentari baris Log" dalam pertanyaan saya.
Nicolas Raoul
OK, ya saya harus membaca kembali lebih sering setelah menelusuri jawabannya :). Jika Anda memiliki kasus seperti itu, Anda mungkin menginginkan solusi yang berbeda seperti yang disarankan sebelumnya seperti meletakkan semua log di belakang antarmuka lain. Saran saya mungkin bekerja lebih baik untuk tim dan proyek yang lebih kecil, di mana orang ingin menghindari overhead dari
lib
1
Mengganti Log.d dengan; // Log.d menangani skenario "Jika" itu juga.
Jasper
3

Seperti yang disarankan komentar zserge ,

Kayu sangat bagus, tetapi jika Anda sudah memiliki proyek yang ada - Anda dapat mencoba github.com/zserge/log. Ini adalah pengganti drop-in untuk android.util.Log dan memiliki sebagian besar fitur yang dimiliki Timber dan bahkan lebih.

perpustakaan log-nya menyediakan sakelar aktifkan / nonaktifkan pencetakan log sederhana seperti di bawah ini.

Selain itu, hanya perlu mengubah importbaris, dan tidak perlu mengubah Log.d(...);pernyataan.

if (!BuildConfig.DEBUG)
    Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT
Youngjae
sumber
Apakah Anda harus meletakkan baris kode di setiap Kegiatan / Fragmen, atau hanya di satu tempat?
Noah Ternullo
@NoahTernullo // dalam file Aplikasi yang diturunkan. DefaultApplication.java
Youngjae
1

Saya telah meningkatkan solusi di atas dengan memberikan dukungan untuk level log yang berbeda dan dengan mengubah level log secara otomatis tergantung pada apakah kode tersebut dijalankan pada perangkat langsung atau pada emulator.

public class Log {

final static int WARN = 1;
final static int INFO = 2;
final static int DEBUG = 3;
final static int VERB = 4;

static int LOG_LEVEL;

static
{
    if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) {
        LOG_LEVEL = VERB;
    } else {
        LOG_LEVEL = INFO;
    }

}


/**
 *Error
 */
public static void e(String tag, String string)
{
        android.util.Log.e(tag, string);
}

/**
 * Warn
 */
public static void w(String tag, String string)
{
        android.util.Log.w(tag, string);
}

/**
 * Info
 */
public static void i(String tag, String string)
{
    if(LOG_LEVEL >= INFO)
    {
        android.util.Log.i(tag, string);
    }
}

/**
 * Debug
 */
public static void d(String tag, String string)
{
    if(LOG_LEVEL >= DEBUG)
    {
        android.util.Log.d(tag, string);
    }
}

/**
 * Verbose
 */
public static void v(String tag, String string)
{
    if(LOG_LEVEL >= VERB)
    {
        android.util.Log.v(tag, string);
    }
}


}
danwms
sumber
1
Masalah yang sama dengan solusi sebelumnya. Jika parameter string dibuat menggunakan panggilan mahal, ia masih membuang sumber daya. Pemeriksaan untuk panggilan perlu dilakukan sebelum membangun parameter yang disahkan.
type-a1pha
1

ProGuard akan melakukannya untuk Anda pada rilis rilis Anda dan sekarang kabar baik dari android.com:

http://developer.android.com/tools/help/proguard.html

Alat ProGuard menyusut, mengoptimalkan, dan mengaburkan kode Anda dengan menghapus kode yang tidak digunakan dan mengganti nama kelas, bidang, dan metode dengan nama yang secara semantik tidak jelas. Hasilnya adalah file .apk berukuran lebih kecil yang lebih sulit untuk dibalik. Karena ProGuard membuat aplikasi Anda lebih sulit untuk direkayasa ulang, penting bagi Anda untuk menggunakannya saat aplikasi Anda menggunakan fitur yang sensitif terhadap keamanan seperti ketika Anda Melisensikan Aplikasi Anda.

ProGuard terintegrasi ke dalam sistem build Android, jadi Anda tidak perlu memintanya secara manual. ProGuard hanya berjalan ketika Anda membangun aplikasi dalam mode rilis, jadi Anda tidak harus berurusan dengan kode yang dikaburkan ketika Anda membangun aplikasi dalam mode debug. Menjalankan ProGuard sepenuhnya opsional, tetapi sangat disarankan.

Dokumen ini menjelaskan cara mengaktifkan dan mengkonfigurasi ProGuard serta menggunakan alat retrace untuk memecahkan kode jejak tumpukan yang dikaburkan

Max Gold
sumber
2
Tampaknya tidak menghapus logging debug secara default. Jadi jawaban Christopher terdengar lebih baik.
Nicolas Raoul
0

Saya suka menggunakan Log.d (TAG, beberapa string, seringkali sebuah String.format ()).

TAG selalu merupakan nama kelas

Transform Log.d (TAG, -> Logd (dalam teks kelas Anda

private void Logd(String str){
    if (MainClass.debug) Log.d(className, str);
}

Dengan cara ini ketika Anda siap untuk membuat versi rilis, atur MainClass.debug ke false!

pengguna462990
sumber
1
masalah dengan ini dan solusi lain selain dari proguard atau mengomentari mereka adalah bahwa Anda meninggalkan kode, menyebabkan kemungkinan sejumlah besar string dibangun. dalam aplikasi rata-rata bukan masalah, tetapi jika Anda mencoba mengoptimalkannya menjadi masalah.
Lassi Kinnunen
0

Log dapat dihapus menggunakan bash di linux dan sed:

find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'

Bekerja untuk log multiline. Dalam solusi ini Anda dapat yakin, bahwa log tidak ada dalam kode produksi.

sylwano
sumber
0

Saya tahu ini adalah pertanyaan lama, tetapi mengapa Anda tidak mengganti semua panggilan log Anda dengan sesuatu seperti Boolean logCallWasHere = true; // --- sisa log Anda di sini

Ini sebabnya Anda akan tahu kapan Anda ingin mengembalikannya, dan mereka tidak akan memengaruhi panggilan pernyataan if Anda :)

masood elsad
sumber
Menarik, semoga baris tersebut kemudian diabaikan oleh kompiler / pengoptimal. Nama variabel harus unik, karena beberapa metode memiliki beberapa panggilan log, dan Anda tidak dapat mendeklarasikan variabel yang sama dua kali.
Nicolas Raoul
Anda dapat mendeklarasikan variabel di atas aktivitas dan menghapus deklarasi boolean dari baris ini;)
masood elsad
0

Kenapa tidak lakukan saja

if(BuildConfig.DEBUG)
  Log.d("tag","msg");

? Tidak diperlukan pustaka tambahan, tidak ada aturan proguard yang cenderung mengacaukan proyek dan kompiler java hanya akan meninggalkan bytecode untuk panggilan ini ketika Anda membuat rilis build.

Primož Kralj
sumber
Yang tidak nyaman adalah bahwa itu lebih bertele-tele dari sekedar menulis Log.d("tag","msg");, dan juga mudah untuk lupa menulis if(BuildConfig.DEBUG)bagian itu.
Nicolas Raoul
1
Masalah lain dengan ini adalah string tetap dalam rilis yang dikemas.
straya
0

Ini solusi saya jika Anda tidak ingin mengacaukan dengan perpustakaan tambahan atau mengedit kode Anda secara manual. Saya membuat notebook Jupyter ini untuk membahas semua file java dan mengomentari semua pesan Log. Tidak sempurna tetapi itu menyelesaikan pekerjaan untuk saya.

Naci
sumber
0

jalanku:

1) aktifkan Mode Pemilihan Kolom (alt + shift + insert)

2) pilih satu Log.d (TAG, "text"); bagian 'Log.'

3) kemudian lakukan shift + ctrl + alt + j

4) klik panah kiri

5) lakukan shift + end

6) tekan delete.

ini menghapus semua panggilan LOG sekaligus dalam file java.

Ronny Bigler
sumber
0

Anda dapat mencoba menggunakan metode konvensional sederhana ini:

Ctrl+ Shift+R

menggantikan

Log.e(

Dengan

// Log.e(
Fathur Rohim
sumber
Itu tidak akan bekerja dengan baik dengan kode contoh yang diberikan dalam pertanyaan.
Nicolas Raoul
0

Mudah dengan kotlin, cukup mendeklarasikan beberapa fungsi tingkat atas

val isDebug: Boolean
    get() = BuildConfig.DEBUG

fun logE(tag: String, message: String) {
    if (isDebug) Log.e(tag, message)
}

fun logD(tag: String, message: String) {
    if (isDebug) Log.d(tag, message)
}
Zakhar Rodionov
sumber
-1

cara paling sederhana;

menggunakan DebugLog

Semua log dinonaktifkan oleh DebugLog ketika aplikasi dirilis.

https://github.com/MustafaFerhan/DebugLog

Mustafa Ferhan
sumber
Ini benar-benar salah. Ini hanya menyebabkan log tidak dicatat, itu tidak menghapusnya dari kode, jadi mereka masih ada untuk membantu orang merekayasa balik kode Anda, dan masih ada biaya untuk memformat string dari semua log tersebut.
Glenn Maynard