Comment supprimer tous les appels de journalisation de débogage avant de créer la version finale d'une application Android?

397

Selon Google, je dois " désactiver tous les appels aux méthodes Log dans le code source " avant de publier mon application Android sur Google Play. Extrait de la section 3 de la liste de contrôle de publication :

Assurez-vous de désactiver la journalisation et de désactiver l'option de débogage avant de créer votre application pour publication. Vous pouvez désactiver la journalisation en supprimant les appels aux méthodes Log dans vos fichiers source.

Mon projet open-source est volumineux et il est difficile de le faire manuellement chaque fois que je publie. De plus, la suppression d'une ligne de journal est potentiellement délicate, par exemple:

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

Si je commente la ligne Log, la condition s'applique à la ligne suivante et il est probable que load () n'est pas appelée. Ces situations sont-elles suffisamment rares pour que je puisse décider qu'elles ne devraient pas exister?

Alors, existe-t-il une meilleure façon au niveau du code source de le faire? Ou peut-être une syntaxe intelligente de ProGuard pour supprimer efficacement mais en toute sécurité toutes les lignes de journal?

Nicolas Raoul
la source
2
+1 parce que je ne me souvenais pas que c'était dans la liste de contrôle de publication.
rds
51
Pour commenter une ligne non bloquée, j'utilise "; //" au lieu de "//".
décédé le
Si vous devez pouvoir annuler cela, vous voudrez probablement l'utiliser à la sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'place.
décédé le
2
Le lien ajouté par Dimitar ne fonctionne plus. J'ai trouvé cela à la place source.android.com/source/code-style.html#log-sparingly .
JosephL
1
@mboy: Probablement pour les performances principalement de nos jours, mais sur les anciennes versions d'Android, il présente également des avantages en termes de sécurité.
Nicolas Raoul

Réponses:

488

Je trouve qu'une solution beaucoup plus simple est d'oublier toutes les ifvérifications partout et d'utiliser simplement ProGuard pour éliminer tous les appels Log.d()ou la Log.v()méthode lorsque nous appelons notre releasecible Ant .

De cette façon, nous avons toujours les informations de débogage générées pour les versions régulières et nous n'avons pas à apporter de modifications de code aux versions. ProGuard peut également effectuer plusieurs passes sur le bytecode pour supprimer d'autres instructions indésirables, des blocs vides et peut automatiquement incorporer des méthodes courtes le cas échéant.

Par exemple, voici une configuration ProGuard très basique pour Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Donc, vous enregistrez cela dans un fichier, puis appelez ProGuard de Ant, en passant votre JAR juste compilé et le JAR de la plateforme Android que vous utilisez.

Voir également les exemples dans le manuel ProGuard.


Mise à jour (4,5 ans plus tard): Aujourd'hui, j'utilisais Timber pour la journalisation Android.

Non seulement c'est un peu plus agréable que l' Logimplémentation par défaut - la balise log est définie automatiquement, et il est facile d'enregistrer des chaînes formatées et des exceptions - mais vous pouvez également spécifier différents comportements de journalisation lors de l'exécution.

Dans cet exemple, les instructions de journalisation seront uniquement écrites dans logcat dans les versions de débogage de mon application:

Le bois est installé dans ma Application onCreate()méthode:

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

Puis, n'importe où ailleurs dans mon code, je peux me connecter facilement:

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

Voir l' exemple d'application Timber pour un exemple plus avancé, où toutes les instructions de journal sont envoyées à logcat pendant le développement et, en production, aucune instruction de débogage n'est enregistrée, mais les erreurs sont silencieusement signalées à Crashlytics.

Christopher Orr
la source
59
Et pourquoi ce n'est pas dans le fichier proguard par défaut?
rds
10
+ rds car cela rendra les numéros de ligne de stacktraces de production différents de ceux de votre code, car les lignes sont supprimées.
Guy
5
Je peux confirmer que la suppression des appels du journal entraînera le décalage des numéros de ligne dans les stacktraces. Il ne sera pas toujours désynchronisé (j'ai fait plusieurs tests rapides mais je ne peux pas exactement en identifier la cause, peut-être si vous concaténez une chaîne dans l'appel Log), mais parfois ce sera à quelques lignes. Ça vaut le coup IMO pour la possibilité de supprimer facilement les appels du journal.
Tony Chan
5
@Fraggle De proguard-android.txt dans les outils ADT: "Notez que si vous souhaitez activer l'optimisation, vous ne pouvez pas simplement inclure des indicateurs d'optimisation dans votre propre fichier de configuration de projet; à la place, vous devrez pointer vers" proguard-android-optimiser. txt "au lieu de celui-ci de votre fichier" # project.properties.
Raanan
3
Comme l'a dit espinchi dans la réponse ci-dessous. "Le seul problème avec cette approche est que, si vous utilisez Log.d (" tag "," Processed: "+ new ItemCounter (blabla) +" items "), même si ce message de journal n'apparaît pas dans votre version finale, un StringBuilder est utilisé pour créer le message, ce qui pourrait coûter cher à créer. "Est-ce vrai aussi dans le cas de Timber?
Chitrang
117

Toutes les bonnes réponses, mais une fois mon développement terminé, je ne voulais pas utiliser les instructions if pour tous les appels Log, ni utiliser des outils externes.

La solution que j'utilise est donc de remplacer la classe android.util.Log par ma propre 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);
    }
}

La seule chose que je devais faire dans tous les fichiers source était de remplacer l'importation de android.util.Log par ma propre classe.

Reiner
la source
143
Le seul problème avec cette approche est que, si vous faites Log.d ("tag", "Processed:" + new ItemCounter (blabla) + "items"), même si ce message de journal n'apparaît pas dans votre version publiée, un StringBuilder est utilisé pour créer le message, ce qui pourrait coûter cher à créer.
espinchi
9
Cette solution a un gros problème. espinchi n'a mentionné que la pointe de l'iceberg. Le problème est que lorsque vous appelez Log.d("tag", someValue.toString());cela, il est très facile d'oublier de vérifier que someValue n'est pas nul, ce qui signifie qu'il pourrait lancer une NullPointerExceptionproduction. Il suggère une solution sécurisée mais vous trompera. Nous nous un private static boolean DEBUGet puisif(DEBUG)Log.d(TAG, msg);
philipp
2
@espinchi Votre préoccupation semble s'appliquer à toutes les bibliothèques de journalisation comme indiqué dans cette réponse stackoverflow.com/a/15452492/433718 (Slf4j, backlog, ...). N'est-il pas suggéré de les utiliser?
OneWorld
1
La seule façon de minimiser les frais généraux mentionnés dans le premier commentaire de @espinchi est de changer les méthodes de journalisation pour accepter les varargs au lieu de String. La solution complète est décrite ici . Cela a apparemment un autre inconvénient: chaque appel doit être modifié (pas seulement une ligne d'importation).
Stan
21
Juste un info, si vous utilisez Android Studio et le système de construction Gradle, vous pouvez utiliser static final boolean LOG = BuildConfig.DEBUGet ne jamais avoir à modifier ce fichier.
ashishduh
61

Je suggère d'avoir un booléen statique quelque part indiquant s'il faut ou non se connecter:

classe MyDebug {
  statique final booléen LOG = true;
}

Ensuite, où que vous souhaitiez vous connecter à votre code, procédez comme suit:

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

Maintenant, lorsque vous définissez MyDebug.LOG sur false, le compilateur supprimera tout le code à l'intérieur de ces vérifications (car il s'agit d'une finale statique, il sait au moment de la compilation que le code n'est pas utilisé.)

Pour les projets plus importants, vous souhaiterez peut-être commencer à avoir des booléens dans des fichiers individuels pour pouvoir facilement activer ou désactiver la journalisation là-bas selon les besoins. Par exemple, voici les différentes constantes de journalisation que nous avons dans le gestionnaire de fenêtres:

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;

Avec le code correspondant comme:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
hackbod
la source
1
Je voterais également pour une telle approche. Il est également utilisé dans l'exemple de facturation officiel de Google.
LA_
4
Ne serait-il pas moins bavard de passer la condition comme premier paramètre?
Snicolas
1
Cela semble être la meilleure solution bien qu'elle nécessite du code supplémentaire sur chaque instruction de journal: les numéros de ligne sont préservés (faiblesse de l'approche ProGuard), aucun code pour créer le message de journal n'est exécuté ( faiblesse de l'approche de la classe wrapper et apparemment de l'approche de la bibliothèque de journalisation également) . L'utilisation de cette approche dans Googles dans l'exemple de facturation d'application selon @LA_ soutient également mes pensées.
OneWorld
2
@Snicolas Comment pouvez-vous passer la condition comme premier paramètre sans implémenter un wrapper? De plus, si vous l'ajoutez en tant que paramètre, puis avant d'entrer dans la méthode, tous les paramètres doivent être évalués, c'est-à-dire également la chaîne de message. La condition doit être testée avant de construire les paramètres. La solution proposée est peut-être la meilleure étant donné aucun outil externe.
type-a1pha
2
En ce qui concerne le code binaire, c'est le meilleur. Mais coder comme ça demande beaucoup d'efforts pour une sortie de journal de débogage simple. La lisibilité du code diminue considérablement. Gagnez, perdez, je suppose ...
Richard Le Mesurier
30

La solution Proguard de Christopher est la meilleure, mais si pour une raison quelconque vous n'aimez pas Proguard, voici une solution très low-tech:

Journaux de commentaires:

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

Décommenter les journaux:

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

Une contrainte est que vos instructions de journalisation ne doivent pas s'étendre sur plusieurs lignes.

(Exécutez ces lignes dans un shell UNIX à la racine de votre projet. Si vous utilisez Windows, obtenez une couche UNIX ou utilisez des commandes Windows équivalentes)

Nicolas Raoul
la source
1
besoin d'un "" après le -i dans Sed si vous utilisez Mac (comme ceci ) Merci.
Vishal
Je pense que c'est peut-être ce que j'utilise pour quelque chose sur lequel je travaille parce que je n'ai pas eu beaucoup de chance de le faire avec Proguard
Joe Plante
Et si vous avez un journal après une branche while non entre crochets, comme vous l'avez suggéré dans votre premier post?
type-a1pha
@ type-a1pha: Si vous adoptez cette solution, vous devez alors considérer les blocs de crochets comme obligatoires.
Nicolas Raoul
2
@NicolasRaoul Le point-virgule corrige ce problème ( //vs. ;//)
Alex Gittemeier
18

Je voudrais ajouter quelques précisions sur l'utilisation de Proguard avec Android Studio et Gradle, car j'ai eu beaucoup de problèmes pour supprimer les lignes de journal du binaire final.

Afin de faire assumenosideeffectsdans Proguard fonctionne, il y a une condition préalable.

Dans votre fichier de notes, vous devez spécifier l'utilisation du proguard-android-optimize.txtfichier par défaut.

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

En fait, dans le proguard-android.txtfichier par défaut , l'optimisation est désactivée avec les deux drapeaux:

-dontoptimize
-dontpreverify

Le proguard-android-optimize.txtfichier n'ajoute pas ces lignes, il assumenosideeffectspeut donc maintenant fonctionner.

Ensuite, personnellement, j'utilise SLF4J , d'autant plus quand je développe des bibliothèques qui sont distribuées à d'autres. L'avantage est que par défaut il n'y a pas de sortie. Et si l'intégrateur veut des sorties de journal, il peut utiliser Logback pour Android et activer les journaux, afin que les journaux puissent être redirigés vers un fichier ou vers LogCat.

Si j'ai vraiment besoin de supprimer les journaux de la bibliothèque finale, j'ajoute ensuite à mon fichier Proguard (après avoir proguard-android-optimize.txtbien sûr activé le fichier):

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}
Vincent Hiribarren
la source
Cela ne fonctionne pas avec le nouveau compilateur Jack
fattire
Cela m'a aidé; à la fois proguard-android-optimize.txtcomme fichier Proguard par défaut et -assumenosideeffectsdans un fichier Proguard personnalisé étaient nécessaires! J'utilise R8 shinker (la valeur par défaut de nos jours) et la journalisation Android par défaut.
Jonik
10

Je suggère fortement d'utiliser Timber de Jake Wharton

https://github.com/JakeWharton/timber

il résout votre problème d'activation / désactivation et ajoute automatiquement la classe de balises

juste

public class MyApp extends Application {

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

les journaux ne seront utilisés que dans votre ver de débogage, puis utiliser

Timber.d("lol");

ou

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

imprimer

"Votre classe / msg" sans spécifier la balise

AndroidGecko
la source
2
Le bois est très agréable, mais si vous avez déjà un projet existant - vous pouvez essayer github.com/zserge/log . C'est un remplacement direct pour android.util.Log et possède la plupart des fonctionnalités de Timber et bien plus encore.
zserge
zserge, votre solution de journal semble bonne. Beaucoup de fonctionnalités. Avez-vous envisagé d'ajouter des règles Lint comme Timber?
jk7
8

J'ai utilisé une classe LogUtils comme dans l'exemple d'application Google IO. J'ai modifié cela pour utiliser une constante DEBUG spécifique à l'application au lieu de BuildConfig.DEBUG car BuildConfig.DEBUG n'est pas fiable . Ensuite, dans mes cours, j'ai ce qui suit.

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
la source
+1 pour le rapport de bogue Build.DEBUGque j'utilisais. J'ai également abandonné les différentes solutions de contournement «correctes» et j'utilise une solution de style similaire pour vous.
Richard Le Mesurier
7

J'envisagerais d'utiliser la fonction de journalisation de roboguice au lieu du android.util.Log intégré

Leur fonction désactive automatiquement les journaux de débogage et détaillés pour les versions. De plus, vous obtenez gratuitement quelques fonctionnalités intéressantes (par exemple, un comportement de journalisation personnalisable, des données supplémentaires pour chaque journal et plus)

L'utilisation de proguard pourrait être assez compliquée et je ne passerais pas la peine de la configurer et de la faire fonctionner avec votre application à moins d'avoir une bonne raison à cela (la désactivation des journaux n'est pas une bonne)

Zvi
la source
Une très bonne approche lorsque vous ne pouvez pas utiliser l'obscurcissement ... en particulier à cause de la rupture du robot à cause de proguard LOL
Snicolas
1
Lien mis à jour pour l'installation de journalisation de robojuice
RenniePet
7

Je publie cette solution qui s'applique spécifiquement aux utilisateurs d'Android Studio. J'ai également récemment découvert Timber et l'ai importé avec succès dans mon application en procédant comme suit:

Mettez la dernière version de la bibliothèque dans votre build.gradle:

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

Ensuite, dans Android Studios, allez dans Edition -> Rechercher -> Remplacer dans le chemin ...

Tapez Log.e(TAG,ou comme vous avez défini vos messages de journal dans la "Text to find"zone de texte. Ensuite, il vous suffit de le remplacer parTimber.e(

entrez la description de l'image ici

Cliquez sur Rechercher, puis remplacez tout.

Les studios Android vont maintenant parcourir tous vos fichiers dans votre projet et remplacer tous les journaux par des bois.

Le seul problème que j'ai eu avec cette méthode est que gradle apparaît avec un million de messages d'erreur par la suite car il ne peut pas trouver "Timber" dans les importations pour chacun de vos fichiers java. Cliquez simplement sur les erreurs et Android Studios importera automatiquement "Timber" dans votre java. Une fois que vous l'avez fait pour tous vos fichiers d'erreurs, gradle se compilera à nouveau.

Vous devez également mettre ce morceau de code dans la onCreateméthode de votre Applicationclasse:

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

Cela entraînera la journalisation de l'application uniquement lorsque vous êtes en mode développement et non en production. Vous pouvez également avoir BuildConfig.RELEASEpour vous connecter en mode de libération.

Simon
la source
3
Essayez de faire la même chose pour vos importations et assurez-vous que la case Expression régulière est cochée Texte pour trouver: import android\.util\.Log\;Remplacez par:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson
ou vous pouvez utiliser la recherche structurelle et remplacer comme Chike Mgbemena le montre dans son post
Maksim Turaev
@MaksimTuraev Votre lien n'est plus pertinent. Maintenant, c'est un blog sur les coiffures.
Vadim Kotov
On dirait que le message est supprimé = (ne le trouve nulle part.
Maksim Turaev
@MaksimTuraev ici est une copie de la machine Wayback, mais les images sont cassées - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Vadim Kotov
6

Per android.util.Log fournit un moyen d'activer / désactiver le journal:

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

Par défaut, la méthode isLoggable (...) retourne false, seulement après que vous définissez prop dans le périphérique comme ceci:

adb shell setprop log.tag.MyAppTag DEBUG

Cela signifie que tout journal au-dessus du niveau DEBUG peut être imprimé. Référence android doc:

Vérifie si un journal pour la balise spécifiée est enregistrable ou non au niveau spécifié. Le niveau par défaut de toute balise est défini sur INFO. Cela signifie que tout niveau supérieur et y compris INFO sera enregistré. Avant d'appeler une méthode de journalisation, vous devez vérifier si votre balise doit être journalisée. Vous pouvez modifier le niveau par défaut en définissant une propriété système: 'setprop log.tag. 'Où le niveau est VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT ou SUPPRESS. SUPPRESS désactivera toute journalisation de votre balise. Vous pouvez également créer un fichier local.prop contenant les éléments suivants: 'log.tag. =' Et le placer dans /data/local.prop.

Nous pourrions donc utiliser un journal personnalisé:

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
la source
6

Si vous pouvez exécuter un remplacement global (une fois), et après cela conserver une convention de codage, vous pouvez suivre le modèle souvent utilisé dans le cadre Android .

Au lieu d'écrire

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

avoir comme

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

Proguard peut maintenant supprimer StringBuilder et toutes les chaînes et méthodes qu'il utilise en cours de route, de la version optimisée DEX. Utilisez proguard-android-optimize.txtet vous n'avez pas à vous soucier de android.util.Log dans votre proguard-rules.pro:

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

Avec le plugin Android Studio Gradle, est assez fiable, vous n'avez donc pas besoin de constantes supplémentaires pour contrôler le stripage.BuildConfig.DEBUG

Alex Cohn
la source
4

Ajoutez ce qui suit à votre fichier proguard-rules.txt

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

entrez la description de l'image ici

C'est ce que je faisais sur mes projets Android ..

Dans Android Studio, nous pouvons effectuer une opération similaire en appuyant sur Ctrl + Maj + F pour rechercher dans l'ensemble du projet (Commande + Maj + F dans MacOs) et Ctrl + Maj + R pour remplacer ((Commande + Maj + R dans MacOs))

Lins Louis
la source
Cela semble ouvrir le travail avec les projets d'éclipse. L'option de recherche n'est même pas disponible sur les studios Android.
Simon
2
dans Android Studio, vous pouvez effectuer une recherche similaire avec le raccourci Ctrl + Maj + F
Lins Louis
L'exemple de code dans la question explique pourquoi ce n'est pas fiable.
Nicolas Raoul
Cela pourrait entraîner des problèmes lors de la suppression de toute commande contenue dans le journal. Par exemple chocolateLog.recipie ();
Andrew S
Impossible de trouver cette option pour Android Studio 2.1. En outre, je peux utiliser cette astuce sur 1 fichier à la fois par recherche / remplacement normal.
VVB
3

J'ai une solution très simple. J'utilise IntelliJ pour le développement, donc les détails varient, mais l'idée devrait s'appliquer à tous les IDE.

Je choisis à la racine de mon arbre source, clique avec le bouton droit et sélectionne pour faire "remplacer". Je choisis alors de remplacer tous les "Log". avec "// Log.". Cela supprime toutes les instructions de journal. Pour les remettre plus tard, je répète le même remplacement, mais cette fois comme remplacer tous "// Log". avec "Journal".

Fonctionne très bien pour moi. N'oubliez pas de définir le remplacement comme sensible à la casse pour éviter les accidents tels que «Dialogue». Pour une assurance supplémentaire, vous pouvez également effectuer la première étape avec «Journal». comme chaîne à rechercher.

Brillant.

kg_sYy
la source
2
Veuillez lire le paragraphe «Si je commente la ligne du journal» dans ma question.
Nicolas Raoul
OK, oui je devrais relire plus souvent après avoir parcouru les réponses :). Si vous avez de tels cas, vous voudrez peut-être une solution différente telle que suggérée avant, comme mettre tous vos journaux derrière une autre interface. Ma suggestion fonctionne peut-être mieux pour les petites équipes et les projets, où les gens souhaitent éviter les frais supplémentaires de bibliothèques de journalisation, vous connaissez bien les gens et le code, etc.
kg_sYy
1
Le remplacement de Log.d par; // Log.d prend également en charge ce scénario "If".
Jasper
3

Comme le commentaire de zserge l'a suggéré,

Le bois est très agréable, mais si vous avez déjà un projet existant - vous pouvez essayer github.com/zserge/log. C'est un remplacement direct pour android.util.Log et possède la plupart des fonctionnalités de Timber et bien plus encore.

sa bibliothèque de journaux fournit un commutateur d'activation / désactivation simple d'impression de journaux comme ci-dessous.

De plus, il suffit de changer de importligne et rien n'a besoin de changer pour l' Log.d(...);instruction.

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
la source
Devez-vous mettre cette ligne de code dans chaque activité / fragment, ou juste au même endroit?
Noah Ternullo
@NoahTernullo // dans le fichier d'application dérivé. DefaultApplication.java
Youngjae
1

J'ai amélioré la solution ci-dessus en prenant en charge différents niveaux de journal et en modifiant automatiquement les niveaux de journal selon que le code est exécuté sur un appareil en direct ou sur l'émulateur.

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
la source
1
Même problème que la solution précédente. Si le paramètre de chaîne est généré à l'aide d'appels coûteux, il gaspille toujours des ressources. La vérification de l'appel doit être effectuée avant de générer les paramètres passés.
type-a1pha
1

ProGuard le fera pour vous sur votre version de version et maintenant les bonnes nouvelles d'Android.com:

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

L'outil ProGuard réduit, optimise et obscurcit votre code en supprimant le code inutilisé et en renommant les classes, les champs et les méthodes avec des noms sémantiquement obscurs. Le résultat est un fichier .apk de plus petite taille qui est plus difficile à rétroconcevoir. Étant donné que ProGuard rend votre application plus difficile à rétroconcevoir, il est important que vous l'utilisiez lorsque votre application utilise des fonctionnalités sensibles à la sécurité, comme lorsque vous octroyez une licence à vos applications.

ProGuard est intégré au système de construction Android, vous n'avez donc pas à l'invoquer manuellement. ProGuard ne s'exécute que lorsque vous générez votre application en mode édition, vous n'avez donc pas à gérer le code obscurci lorsque vous générez votre application en mode débogage. L'exécution de ProGuard est entièrement facultative, mais fortement recommandée.

Ce document décrit comment activer et configurer ProGuard ainsi qu'utiliser l'outil de retrace pour décoder les traces de pile obscurcies

Max Gold
la source
2
Cependant, il ne semble pas supprimer la journalisation du débogage. La réponse de Christopher sonne donc mieux.
Nicolas Raoul
0

J'aime utiliser Log.d (TAG, une chaîne, souvent un String.format ()).

TAG est toujours le nom de la classe

Transform Log.d (TAG, -> Logd (dans le texte de votre classe

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

De cette façon, lorsque vous êtes prêt à créer une version finale, définissez MainClass.debug sur false!

user462990
la source
1
le problème avec ceci et d'autres solutions en dehors de proguard ou de les commenter est que vous laissez dans le code, provoquant éventuellement une grande quantité de constructions de chaînes. dans une application moyenne, ce n'est pas un problème, mais si vous essayez de l'optimiser, cela devient un problème.
Lassi Kinnunen
0

Les journaux peuvent être supprimés à l'aide de bash sous linux et sed:

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

Fonctionne pour les journaux multilignes. Dans cette solution, vous pouvez être sûr que les journaux ne sont pas présents dans le code de production.

sylwano
la source
0

Je sais que c'est une vieille question, mais pourquoi n'avez-vous pas remplacé tous vos appels de journal par quelque chose comme Boolean logCallWasHere = true; // --- reste de votre log ici

C'est pourquoi vous saurez quand vous voulez les remettre, et ils n'affecteront pas votre appel de déclaration if :)

masood elsad
la source
Intéressant, espérons que ces lignes sont ensuite ignorées par le compilateur / optimiseur. Le nom de la variable doit cependant être unique, car certaines méthodes ont plusieurs appels de journal et vous ne pouvez pas déclarer deux fois la même variable.
Nicolas Raoul
Vous pouvez déclarer la variable en haut sur l'activité et supprimer la déclaration booléenne de cette ligne;)
masood elsad
0

Pourquoi ne pas simplement faire

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

? Aucune bibliothèque supplémentaire n'est nécessaire, aucune règle de proguard qui a tendance à bousiller le projet et le compilateur java laissera simplement de côté le bytecode pour cet appel lorsque vous effectuez la construction de la version.

Primož Kralj
la source
Un inconvénient est qu'il est plus verbeux que la simple écriture Log.d("tag","msg");, et il est également facile d'oublier d'écrire la if(BuildConfig.DEBUG)partie.
Nicolas Raoul
1
Un autre problème est que les chaînes restent dans la version compressée.
straya
0

Voici ma solution si vous ne voulez pas jouer avec des bibliothèques supplémentaires ou modifier votre code manuellement. J'ai créé ce bloc-notes Jupyter pour parcourir tous les fichiers java et commenter tous les messages du journal. Pas parfait mais ça a fait le boulot pour moi.

Naci
la source
0

mon chemin:

1) activer le mode de sélection de colonne (alt + shift + insert)

2) sélectionnez sur un Log.d (TAG, "texte"); la partie «Journal».

3) puis faites shift + ctrl + alt + j

4) cliquez sur la flèche gauche

5) faire shift + end

6) appuyez sur supprimer.

cela supprime tous les appels LOG à la fois dans un fichier java.

Ronny Bigler
la source
0

Vous pouvez essayer d'utiliser cette méthode conventionnelle simple:

Ctrl+ Shift+R

remplacer

Log.e(

Avec

// Log.e(
Fathur Rohim
la source
Cela ne fonctionnerait pas bien avec l'exemple de code donné dans la question.
Nicolas Raoul
0

Facile avec kotlin, déclarez simplement quelques fonctions de haut niveau

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
la source
-1

la manière la plus simple;

utilisation DebugLog

Tous les journaux sont désactivés par DebugLog lorsque l'application est publiée.

https://github.com/MustafaFerhan/DebugLog

Mustafa Ferhan
la source
C'est absolument faux. Cela n'entraîne que la non-journalisation des journaux, il ne les supprime pas du code, ils sont donc toujours là pour aider les gens à rétroconcevoir votre code, et cela a toujours le coût de formater les chaînes de tous ces journaux.
Glenn Maynard