Come rimuovere tutte le chiamate di registrazione di debug prima di creare la versione di rilascio di un'app Android?


397

Secondo Google, devo " disattivare tutte le chiamate ai metodi Log nel codice sorgente " prima di pubblicare la mia app Android su Google Play. Estratto dalla sezione 3 dell'elenco di controllo della pubblicazione :

Assicurarsi di disattivare la registrazione e disabilitare l'opzione di debug prima di compilare l'applicazione per il rilascio. È possibile disattivare la registrazione rimuovendo le chiamate ai metodi Log nei file di origine.

Il mio progetto open source è ampio ed è una seccatura farlo manualmente ogni volta che lancio. Inoltre, rimuovere una linea di registro è potenzialmente complicato, ad esempio:

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

Se commento la riga Log, la condizione si applica alla riga successiva e le probabilità che load () non venga chiamata. Tali situazioni sono abbastanza rare da poter decidere che non dovrebbe esistere?

Quindi, esiste un modo migliore a livello di codice sorgente per farlo? O forse una sintassi intelligente di ProGuard per rimuovere in modo efficiente ma sicuro tutte le linee di registro?


2
+1 perché non ricordavo che fosse nell'elenco di controllo della pubblicazione.
martedì

51
Per commentare una riga non bloccata, uso "; //" anziché "//".
gridò il

Se devi essere in grado di annullare questo, probabilmente vorrai usare sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'invece.
gridò il

2
Il collegamento che Dimitar ha aggiunto non funziona più. Ho trovato questo invece source.android.com/source/code-style.html#log-sparingly .
JosephL

1
@mboy: probabilmente per le prestazioni soprattutto al giorno d'oggi, ma sulle vecchie versioni di Android ha anche vantaggi di sicurezza.
Nicolas Raoul,

Risposte:


488

Trovo che una soluzione molto più semplice sia dimenticare tutti i ifcontrolli dappertutto e usare ProGuard per eliminare qualsiasi chiamata Log.d()o Log.v()metodo quando chiamiamo il nostro releasetarget Ant .

In questo modo, abbiamo sempre l'output delle informazioni di debug per build regolari e non è necessario apportare modifiche al codice per le build di rilascio. ProGuard può anche eseguire più passaggi sul bytecode per rimuovere altre istruzioni indesiderate, blocchi vuoti e può incorporare automaticamente metodi brevi ove appropriato.

Ad esempio, ecco una configurazione ProGuard molto semplice per Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Quindi lo salveresti su un file, quindi chiamerai ProGuard da Ant, passando il tuo JAR appena compilato e il JAR della piattaforma Android che stai utilizzando.

Vedi anche gli esempi nel manuale ProGuard.


Aggiornamento (4,5 anni dopo): oggi ho usato Timber per la registrazione Android.

Non solo è un po 'più bello dell'implementazione predefinita Log- il tag di registro viene impostato automaticamente ed è facile registrare stringhe ed eccezioni formattate - ma è anche possibile specificare comportamenti di registrazione diversi in fase di esecuzione.

In questo esempio, le istruzioni di registrazione verranno scritte su logcat solo nelle build di debug della mia app:

Il legname è impostato nel mio Application onCreate()metodo:

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

Quindi in qualsiasi altra parte del mio codice posso accedere facilmente:

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

Vedi l' app di esempio Timber per un esempio più avanzato, in cui tutte le istruzioni di registro vengono inviate a logcat durante lo sviluppo e, in produzione, non vengono registrate istruzioni di debug, ma gli errori vengono silenziosamente segnalati a Crashlytics.


59
E perché non è quello nel file proguard predefinito?
martedì

10
+ rds poiché renderà i numeri di riga di stack stack di produzione diversi da quelli nel codice, man mano che le righe vengono rimosse.
Guy,

5
Posso confermare che l'eliminazione delle chiamate di registro sposta i numeri di riga in stacktraces. Non sarà sempre fuori sincrono (ho fatto diversi test rapidi ma non riesco esattamente a individuare quale sia la causa, possibilmente se concateni una stringa nella chiamata Log), ma a volte rimarranno alcune righe. Vale la pena l'IMO per la possibilità di rimuovere facilmente le chiamate del registro.
Tony Chan,

5
@Fraggle Da proguard-android.txt negli strumenti ADT: "Nota che se vuoi abilitare l'ottimizzazione, non puoi semplicemente includere flag di ottimizzazione nel tuo file di configurazione del progetto, ma dovrai puntare a" proguard-android-optimise. txt "anziché questo dal tuo" # project.properties file.
Raanan,

3
Come espinchi ha detto nella risposta di seguito. "L'unico problema con questo approccio è che, se si esegue Log.d (" tag "," Elaborato: "+ nuovo ItemCounter (blabla) +" items "), anche se questo messaggio di registro non viene visualizzato nella versione rilasciata, uno StringBuilder viene utilizzato per creare il messaggio, che potrebbe essere costoso da creare. "È vero anche nel caso di Timber?
Chitrang,

117

Tutte buone risposte, ma quando ho terminato il mio sviluppo non volevo usare le istruzioni if ​​intorno a tutte le chiamate di Log, né volevo usare strumenti esterni.

Quindi la soluzione che sto usando è quella di sostituire la classe android.util.Log con la mia classe Log:

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

L'unica cosa che dovevo fare in tutti i file sorgente era sostituire l'importazione di android.util.Log con la mia classe.


143
L'unico problema con questo approccio è che, se si esegue Log.d ("tag", "Elaborato:" + nuovo ItemCounter (blabla) + "items"), anche se questo messaggio di registro non viene visualizzato nella versione rilasciata, un StringBuilder viene utilizzato per creare il messaggio, che potrebbe essere costoso da creare.
espinchi,

9
Questa soluzione ha un grosso problema. espinchi ha menzionato solo la punta dell'iceberg. Il problema è che quando chiami Log.d("tag", someValue.toString());che è molto facile dimenticare di controllare someValue per non essere nullo, ciò significa che potrebbe lanciare una NullPointerExceptionproduzione. Suggerisce una soluzione sicura ma ti ingannerà. Siamo noi un private static boolean DEBUGe quindiif(DEBUG)Log.d(TAG, msg);
philipp

2
@espinchi La vostra preoccupazione sembra applicarsi a tutte le biblioteche di registrazione come discusso in questa risposta stackoverflow.com/a/15452492/433718 (SLF4J, portafoglio ordini, ...). Non è consigliato usarli?
OneWorld,

1
L'unico modo per ridurre al minimo le spese generali menzionate nel primo commento di @espinchi è modificare i metodi di registrazione per accettare varargs anziché String. La soluzione completa è descritta qui . Ciò sembra avere un altro svantaggio: ogni chiamata dovrebbe essere modificata (non solo una riga di importazione).
Stan,

21
Solo un FYI, se stai usando Android Studio e il sistema di compilazione gradle, puoi usare static final boolean LOG = BuildConfig.DEBUGe non dover mai modificare questo file.
ashishduh,

61

Suggerisco di avere un booleano statico da qualche parte che indica se accedere o meno:

class MyDebug {
  LOG booleano finale statico = true;
}

Quindi, ovunque tu voglia accedere al tuo codice, basta fare questo:

if (MyDebug.LOG) {
  if (condition) Log.i (...);
}

Ora, quando imposti MyDebug.LOG su false, il compilatore eliminerà tutto il codice all'interno di tali controlli (dato che si tratta di un finale statico, sa al momento della compilazione che il codice non viene utilizzato).

Per progetti più grandi, potresti voler iniziare con booleani nei singoli file per poter abilitare o disabilitare facilmente la registrazione lì, se necessario. Ad esempio, queste sono le varie costanti di registrazione che abbiamo nel gestore delle finestre:

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;

Con il codice corrispondente come:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");

1
Vorrei votare anche per tale approccio. Utilizzato anche nell'esempio di fatturazione in-app ufficiale di Google.
LA_

4
Non sarebbe meno prolisso passare la condizione come primo parametro?
Snicolas,

1
Questa sembra essere la soluzione migliore sebbene richieda codice aggiuntivo su ogni istruzione di registro: i numeri di riga vengono conservati (debolezza dell'approccio ProGuard), non viene eseguito alcun codice per creare il messaggio di registro ( debolezza dell'approccio della classe wrapper e apparentemente anche dell'approccio della libreria di registrazione) . L'uso di questo approccio su Google nell'esempio di fatturazione delle app secondo @LA_ supporta anche i miei pensieri.
OneWorld,

2
@Snicolas Come si può passare la condizione come primo parametro senza implementare un wrapper? Inoltre, se lo aggiungi come parametro, prima di inserire il metodo, tutti i parametri devono essere valutati, vale a dire anche la stringa di messaggio. La condizione deve essere testata prima di creare i parametri. La soluzione proposta è probabilmente la migliore senza uno strumento esterno.
type-a1pha,

2
Per quanto riguarda il codice binario, questo è il migliore. Ma codificare in questo modo è solo uno sforzo per un semplice output del log di debug. La leggibilità del codice diminuisce in modo significativo. Vincine un po ', perdine un po', immagino ...
Richard Le Mesurier il

30

La soluzione Proguard di Christopher è la migliore, ma se per qualsiasi motivo non ti piace Proguard, ecco una soluzione molto low-tech:

Log dei commenti:

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

Registri di non commento:

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

Un vincolo è che le istruzioni di registrazione non devono estendersi su più righe.

(Eseguire queste righe in una shell UNIX alla radice del progetto. Se si utilizza Windows, ottenere un livello UNIX o utilizzare comandi Windows equivalenti)


1
bisogno di un "" dopo il -i in Sed se in esecuzione su Mac (come da questo ) Grazie.
Vishal,

Sento che questo potrebbe essere quello che finirò per qualcosa a cui sto lavorando perché non ho avuto molta fortuna a farlo con Proguard
Joe Plante,

E se avessi un registro dopo un ramo while non tra parentesi, come hai suggerito nel tuo primo post?
type-a1pha,

@ type-a1pha: se adotti questa soluzione, devi considerare i blocchi parentesi obbligatori.
Nicolas Raoul,

2
@NicolasRaoul Il punto e virgola risolve questo problema ( //vs. ;//)
Alex Gittemeier

18

Vorrei aggiungere alcune precisazioni sull'uso di Proguard con Android Studio e Gradle, poiché ho avuto molti problemi a rimuovere le linee di registro dal file binario finale.

Per far assumenosideeffectsfunzionare Proguard, c'è un prerequisito.

Nel tuo file gradle, devi specificare l'uso del proguard-android-optimize.txtfile predefinito.

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

In realtà, nel proguard-android.txtfile predefinito , l'ottimizzazione è disabilitata con i due flag:

-dontoptimize
-dontpreverify

Il proguard-android-optimize.txtfile non aggiunge quelle righe, quindi ora assumenosideeffectspuò funzionare.

Quindi, personalmente, uso SLF4J , tanto più quando sviluppo alcune librerie che sono distribuite ad altri. Il vantaggio è che per impostazione predefinita non c'è output. E se l'integratore desidera alcuni output di log, può utilizzare Logback per Android e attivare i log, in modo che i log possano essere reindirizzati a un file o a LogCat.

Se ho davvero bisogno di eliminare i log dalla libreria finale, aggiungo quindi al mio file Proguard (dopo aver abilitato il proguard-android-optimize.txtfile ovviamente):

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}

Questo non funziona con il nuovo Jack compiler-- stackoverflow.com/questions/37932114/...
fattire

Questo mi ha aiutato; erano necessari sia proguard-android-optimize.txtil file Proguard predefinito sia il file -assumenosideeffectsProguard personalizzato! Sto usando R8 shinker (il predefinito al giorno d'oggi) e la registrazione Android predefinita.
Jonik,

10

Consiglio vivamente di usare Timber di Jake Wharton

https://github.com/JakeWharton/timber

risolve il problema con l'attivazione / disattivazione e aggiunge automaticamente la classe di tag

appena

public class MyApp extends Application {

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

i log verranno utilizzati solo nella tua versione di debug, quindi verranno utilizzati

Timber.d("lol");

o

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

per stampare

"La tua classe / msg" senza specificare il tag


2
Il legname è molto bello, ma se hai già un progetto esistente, puoi provare github.com/zserge/log . È un sostituto drop-in per android.util.Log e ha la maggior parte delle funzionalità di Timber e anche di più.
zserge,

zserge, la tua soluzione di log sembra buona. Molte funzioni. Hai mai pensato di aggiungere regole Lint come ha fatto Timber?
jk7

8

Ho usato una classe LogUtils come nell'applicazione esempio di Google IO. Ho modificato questo per utilizzare una costante DEBUG specifica dell'applicazione anziché BuildConfig.DEBUG perché BuildConfig.DEBUG non è affidabile . Quindi nelle mie lezioni ho quanto segue.

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

+1 per la segnalazione di bug Build.DEBUGche utilizzavo. Ho anche rinunciato alle varie soluzioni "corrette" e utilizzo una soluzione di stile simile a te.
Richard Le Mesurier,

7

Vorrei prendere in considerazione l'utilizzo della funzione di registrazione di roboguice invece di android.util.Log integrato

La loro funzione disabilita automaticamente i log di debug e dettagliati per le build di rilascio. Inoltre, ottieni alcune eleganti funzionalità gratuitamente (ad es. Comportamento di registrazione personalizzabile, dati aggiuntivi per ogni registro e altro)

L'utilizzo di proguard potrebbe essere una seccatura e non avrei problemi a configurarlo e farlo funzionare con la tua applicazione a meno che tu non abbia una buona ragione per farlo (disabilitare i log non è buono)


Un approccio molto carino quando non puoi usare Obfuscation .... in particolare a causa della rottura della roboguice a causa della proguardia LOL
Snicolas,

1
Link aggiornato per la funzione di registrazione di robojuice: github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet

7

Sto pubblicando questa soluzione che si applica specificamente agli utenti di Android Studio. Recentemente ho anche scoperto Timber e l'ho importato correttamente nella mia app procedendo come segue:

Inserisci l'ultima versione della libreria nel tuo build.gradle:

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

Quindi in Android Studios, vai su Modifica -> Trova -> Sostituisci nel percorso ...

Digita Log.e(TAG,o comunque hai definito i tuoi messaggi di Log nella "Text to find"casella di testo. Quindi lo sostituisci conTimber.e(

inserisci qui la descrizione dell'immagine

Fai clic su Trova, quindi sostituisci tutto.

Android Studios ora esaminerà tutti i tuoi file nel tuo progetto e sostituirà tutti i registri con i legni.

L'unico problema che ho avuto con questo metodo è che Gradle si presenta con milioni di messaggi di errore in seguito perché non riesce a trovare "Timber" nelle importazioni per ciascuno dei tuoi file java. Basta fare clic sugli errori e Android Studios importerà automaticamente "Timber" nel tuo java. Una volta che lo hai fatto per tutti i tuoi file di errori, Gradle verrà nuovamente compilato.

Devi anche inserire questo pezzo di codice nel tuo onCreatemetodo della tua Applicationclasse:

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

Ciò comporterà la registrazione dell'app solo quando ci si trova in modalità di sviluppo e non in produzione. Puoi anche avere BuildConfig.RELEASEper la registrazione in modalità di rilascio.


3
Prova a fare la stessa cosa per le tue importazioni e assicurati che la casella Espressione regolare sia selezionata Testo da trovare: import android\.util\.Log\;Sostituisci con:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson,

oppure puoi usare la ricerca strutturale e sostituire come mostra Chike Mgbemena nel suo post
Maksim Turaev,

@MaksimTuraev Il tuo link non è più pertinente. Ora è un blog sulle acconciature.
Vadim Kotov,

Sembra che il post sia rimosso = (non riesco a trovarlo da nessuna parte.
Maksim Turaev

@MaksimTuraev qui è una copia dalla macchina Wayback, ma le immagini sono rotte - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Vadim Kotov

6

Per android.util.Log fornisce un modo per abilitare / disabilitare il registro:

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

Per impostazione predefinita, il metodo isLoggable (...) restituisce false, solo dopo che setprop nel dispositivo piace questo:

adb shell setprop log.tag.MyAppTag DEBUG

Significa che qualsiasi registro al di sopra del livello DEBUG può essere stampato. Documento Android di riferimento:

Verifica se un registro per il tag specificato è registrabile al livello specificato. Il livello predefinito di qualsiasi tag è impostato su INFO. Ciò significa che verrà registrato qualsiasi livello superiore e incluso INFO. Prima di effettuare qualsiasi chiamata a un metodo di registrazione, è necessario verificare se il tag deve essere registrato. È possibile modificare il livello predefinito impostando una proprietà di sistema: 'setprop log.tag. 'Dove livello è VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT o SUPPRESS. SUPPRESS disattiverà tutte le registrazioni per il tuo tag. Puoi anche creare un file local.prop che includa quanto segue: 'log.tag. =' E posizionarlo in /data/local.prop.

Quindi potremmo usare log util personalizzato:

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

6

Se è possibile eseguire una sostituzione globale (una volta) e successivamente conservare alcune convenzioni di codifica, è possibile seguire il modello spesso utilizzato nel framework Android .

Invece di scrivere

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

fallo come

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

Ora proguard può rimuovere StringBuilder e tutte le stringhe e i metodi che utilizza lungo la strada, dalla versione ottimizzata DEX. Usa proguard-android-optimize.txte non devi preoccuparti di android.util.Log nel tuo proguard-rules.pro:

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

Con il plug-in Android Studio Gradle, è abbastanza affidabile, quindi non hai bisogno di costanti extra per controllare lo stripping.BuildConfig.DEBUG


4

Aggiungi seguito al tuo file proguard-rules.txt

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

4

inserisci qui la descrizione dell'immagine

Questo è quello che facevo nei miei progetti Android ..

In Android Studio possiamo eseguire operazioni simili tramite, Ctrl + Maiusc + F per trovare da tutto il progetto (Comando + Maiusc + F in MacO) e Ctrl + Maiusc + R per Sostituire ((Comando + Maiusc + R in MacO))


Questo sembra aprire il lavoro con i progetti di eclissi. L'opzione di ricerca non è nemmeno disponibile su Android Studios.
Simon

2
in Android Studio puoi fare una ricerca simile con Ctrl + Shift + F scorciatoia
Lins Louis

Il codice di esempio nella domanda spiega perché questo non è affidabile.
Nicolas Raoul,

Potrebbe causare problemi durante la rimozione di qualsiasi comando che contiene nel registro. Ad esempio chocolateLog.recipie ();
Andrew S,

Impossibile trovare questa opzione per Android Studio 2.1. Inoltre, posso usare questo trucco su 1 file alla volta tramite la normale ricerca / sostituzione.
VVB,

3

Ho una soluzione molto semplice. Uso IntelliJ per lo sviluppo, quindi i dettagli variano ma l'idea dovrebbe applicarsi a tutti gli IDE.

Scelgo la radice del mio albero dei sorgenti, faccio clic con il tasto destro e seleziono per fare "sostituisci". Ho quindi scelto di sostituire tutto "Registro". con "// Log.". Ciò rimuove tutte le istruzioni del registro. Per rimetterli più tardi, ripeto la stessa sostituzione, ma questa volta sostituisco tutto "// Registro". con "Log".

Funziona alla grande per me. Ricorda solo di impostare la sostituzione come maiuscole / minuscole per evitare incidenti come "Finestra di dialogo". Per maggiore sicurezza, puoi anche fare il primo passo con "Log". come stringa da cercare.

Brillante.


2
Si prega di leggere il paragrafo "Se commento la riga del registro" nella mia domanda.
Nicolas Raoul,

OK, sì, dovrei rileggere più spesso dopo aver cercato le risposte :). Se si verificano casi del genere, è possibile che si desideri una soluzione diversa come quella suggerita prima di mettere tutti i registri dietro un'altra interfaccia. Il mio suggerimento forse funziona meglio per team e progetti più piccoli, in cui le persone desiderano evitare il sovraccarico di librerie di registrazione extra, conosci bene le persone e il codice, ecc.
kg_sYy

1
Sostituendo Log.d con; // Log.d si occupa anche di quello scenario "If".
Jasper,

3

Come suggerito dal commento di zserge ,

Il legname è molto bello, ma se hai già un progetto esistente, puoi provare github.com/zserge/log. È un sostituto drop-in per android.util.Log e ha la maggior parte delle funzionalità di Timber e anche di più.

la sua libreria di log fornisce un semplice interruttore di abilitazione / disabilitazione della stampa dei log come di seguito.

Inoltre, richiede solo di cambiare le importrighe e nulla deve cambiare per l' Log.d(...);affermazione.

if (!BuildConfig.DEBUG)
    Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT

Devi inserire quella riga di codice in ogni attività / frammento o solo in un posto?
Noah Ternullo,

@NoahTernullo // nel file dell'applicazione derivata. DefaultApplication.java
Youngjae

1

Ho migliorato la soluzione sopra fornendo supporto per diversi livelli di registro e modificando automaticamente i livelli di registro a seconda che il codice venga eseguito su un dispositivo live o sull'emulatore.

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


}

1
Stesso problema della soluzione precedente. Se il parametro string viene creato utilizzando chiamate costose, spreca comunque risorse. Il controllo per la chiamata deve essere eseguito prima di creare i parametri passati.
type-a1pha,

1

ProGuard lo farà per te sulla tua build di rilascio e ora le buone notizie da android.com:

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

Lo strumento ProGuard riduce, ottimizza e offusca il codice rimuovendo il codice inutilizzato e rinominando classi, campi e metodi con nomi semanticamente oscuri. Il risultato è un file .apk di dimensioni inferiori che è più difficile da decodificare. Poiché ProGuard rende l'applicazione più difficile da decodificare, è importante utilizzarla quando l'applicazione utilizza funzionalità sensibili alla sicurezza, ad esempio quando si concedono in licenza le applicazioni.

ProGuard è integrato nel sistema di generazione Android, quindi non è necessario invocarlo manualmente. ProGuard viene eseguito solo quando si crea l'applicazione in modalità di rilascio, quindi non è necessario gestire il codice offuscato quando si crea l'applicazione in modalità di debug. Avere ProGuard in esecuzione è completamente opzionale, ma altamente raccomandato.

Questo documento descrive come abilitare e configurare ProGuard e come utilizzare lo strumento retrace per decodificare le tracce dello stack offuscate


2
Tuttavia, non sembra rimuovere la registrazione di debug per impostazione predefinita. Quindi la risposta di Christopher suona meglio.
Nicolas Raoul,

0

Mi piace usare Log.d (TAG, alcune stringhe, spesso String.format ()).

TAG è sempre il nome della classe

Transform Log.d (TAG, -> Logd (nel testo della tua classe

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

In questo modo quando sei pronto per creare una versione di rilascio, imposta MainClass.debug su false!


1
il problema con questa e altre soluzioni a parte proguard o commentarle è che stai lasciando nel codice, causando probabilmente una grande quantità di build di stringhe. in un'app media non è un problema, ma se stai cercando di ottimizzare diventa un problema.
Lassi Kinnunen,

0

I log possono essere rimossi usando bash in linux e sed:

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

Funziona per registri multilinea. In questa soluzione si può essere certi che i registri non sono presenti nel codice di produzione.


0

So che questa è una vecchia domanda, ma perché non hai sostituito tutte le tue chiamate di registro con qualcosa come booleano logCallWasHere = true; // --- resto del registro qui

Questo è il motivo per cui saprai quando vuoi rimetterli indietro e non influenzeranno la tua chiamata if statement :)


Interessante, si spera che tali righe vengano quindi ignorate dal compilatore / ottimizzatore. Il nome della variabile dovrebbe essere univoco, tuttavia, poiché alcuni metodi hanno diverse chiamate di registro e non è possibile dichiarare la stessa variabile due volte.
Nicolas Raoul,

Puoi dichiarare la variabile in cima all'attività e rimuovere la dichiarazione booleana da questa riga;)
masood elsad

0

Perché non farlo

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

? Non sono necessarie librerie aggiuntive, nessuna regola proguard che tende a rovinare il progetto e il compilatore java tralascerà il bytecode per questa chiamata quando si effettua il build di rilascio.


Un inconveniente è che è più dettagliato della semplice scrittura Log.d("tag","msg");, ed è anche facile dimenticare di scrivere la if(BuildConfig.DEBUG)parte.
Nicolas Raoul,

1
Un altro problema con questo è che le stringhe rimangono nel rilascio compresso.
straya,

0

Ecco la mia soluzione se non vuoi pasticciare con librerie aggiuntive o modificare il tuo codice manualmente. Ho creato questo taccuino Jupyter per esaminare tutti i file Java e commentare tutti i messaggi di registro. Non perfetto ma ha fatto il lavoro per me.


0

a modo mio:

1) abilita la modalità di selezione delle colonne (alt + maiusc + insert)

2) selezionare su un Log.d (TAG, "testo"); la parte "Registro".

3) quindi sposta + ctrl + alt + j

4) fare clic sulla freccia sinistra

5) sposta + fine

6) premi cancella.

questo rimuove tutte le chiamate LOG contemporaneamente in un file java.


0

Puoi provare a usare questo semplice metodo convenzionale:

Ctrl+Shift +R

sostituire

Log.e(

Con

// Log.e(

Ciò non funzionerebbe bene con il codice di esempio fornito nella domanda.
Nicolas Raoul,

0

Facile con kotlin, basta dichiarare alcune funzioni di alto livello

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

-1

il modo più semplice;

uso DebugLog

Tutti i log sono disabilitati da DebugLog quando l'app viene rilasciata.

https://github.com/MustafaFerhan/DebugLog


Questo è assolutamente sbagliato. Questo fa sì che i registri non vengano registrati, non li rimuove dal codice, quindi sono ancora lì per aiutare le persone a decodificare il codice e ha ancora il costo di formattare le stringhe di tutti quei registri.
Glenn Maynard,
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.