Como remover todas as chamadas de log de depuração antes de criar a versão de lançamento de um aplicativo Android?

397

Segundo o Google, devo " desativar todas as chamadas para métodos de registro no código-fonte " antes de publicar meu aplicativo Android no Google Play. Trecho da seção 3 da lista de verificação da publicação :

Certifique-se de desativar o log e desativar a opção de depuração antes de criar seu aplicativo para liberação. Você pode desativar o log removendo chamadas para métodos de log em seus arquivos de origem.

Meu projeto de código aberto é grande e é difícil fazê-lo manualmente toda vez que eu for lançado. Além disso, a remoção de uma linha de log é potencialmente complicada, por exemplo:

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

Se eu comentar a linha de log, a condição se aplica à próxima linha e as chances são de que load () não seja chamado. Essas situações são raras o suficiente para que eu possa decidir que não deveria existir?

Então, existe uma maneira melhor de fazer isso no nível do código fonte? Ou talvez alguma sintaxe inteligente do ProGuard para remover com eficiência, mas com segurança, todas as linhas de log?

Nicolas Raoul
fonte
2
+1 porque não lembro que isso estava na lista de verificação da publicação.
rds 22/07
51
Para comentar uma linha não bloqueada, eu uso "; //" em vez de "//".
yingted
Se você precisar desfazer isso, provavelmente desejará usá-lo sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'.
yingted
2
O link que o Dimitar adicionou não funciona mais. Eu encontrei isso em vez source.android.com/source/code-style.html#log-sparingly .
JosephL
11
@ boy: Provavelmente para desempenho principalmente hoje em dia, mas nas versões antigas do Android também traz benefícios de segurança.
Nicolas Raoul

Respostas:

488

Eu encontrar uma solução muito mais fácil é esquecer todos os ifcheques em todo o lugar e usar apenas ProGuard para retirar qualquer Log.d()ou Log.v()chamadas de método quando chamamos o nosso Ant release-alvo.

Dessa forma, sempre temos as informações de depuração sendo exibidas para compilações regulares e não precisamos fazer alterações no código para compilações de versão. O ProGuard também pode fazer várias passagens pelo bytecode para remover outras instruções indesejadas, blocos vazios e pode alinhar automaticamente métodos curtos, quando apropriado.

Por exemplo, aqui está uma configuração muito básica do ProGuard para Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Assim, você salvaria isso em um arquivo e ligaria para o ProGuard do Ant, passando o JAR recém-compilado e o JAR da plataforma Android que você está usando.

Veja também os exemplos no manual do ProGuard.


Atualização (4,5 anos depois): Hoje em dia eu usei o Timber for Android logging.

Além de ser um pouco melhor que a Logimplementação padrão - a tag de log é definida automaticamente e é fácil registrar seqüências de caracteres e exceções formatadas -, você também pode especificar comportamentos de log diferentes em tempo de execução.

Neste exemplo, as instruções de log serão gravadas apenas no logcat nas compilações de depuração do meu aplicativo:

A madeira é configurada no meu Application onCreate()método:

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

Então, em qualquer outro lugar do meu código, eu posso registrar facilmente:

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

Consulte o aplicativo de exemplo Timber para obter um exemplo mais avançado, no qual todas as instruções de log são enviadas ao logcat durante o desenvolvimento e, na produção, nenhuma instrução de depuração é registrada, mas os erros são relatados silenciosamente ao Crashlytics.

Christopher Orr
fonte
59
E por que isso não está no arquivo de programa padrão?
rds 22/07
10
+ rds, pois tornará os números de linha dos traços de pilha de produção diferentes dos do código, à medida que as linhas são removidas.
Guy
5
Posso confirmar que retirar as chamadas de log mudará os números de linha nos traços de pilha. Isso nem sempre estará fora de sincronia (eu fiz vários testes rápidos, mas não consigo identificar exatamente qual é a causa, possivelmente se você concatenar uma sequência na chamada de log), mas às vezes haverá algumas faltas. Vale a pena o IMO problema pela capacidade de remover facilmente as chamadas de log.
Tony Chan
5
@Fraggle No proguard-android.txt nas ferramentas do ADT: "Observe que se você deseja ativar a otimização, não pode incluir apenas sinalizadores de otimização no seu próprio arquivo de configuração do projeto; em vez disso, será necessário apontar para" proguard-android-optimize. arquivo txt "em vez deste no seu arquivo # # project.properties.
quer
3
Como espinchi disse na resposta abaixo. "O único problema com essa abordagem é que, se você fizer o Log.d (" tag "," Processed: "+ new ItemCounter (blabla) +" items "), mesmo que essa mensagem de log não apareça na versão lançada, um StringBuilder é usado para criar a mensagem, o que pode ser caro para criar. "Isso também é verdade no caso da madeira?
Chitrang
117

Todas as boas respostas, mas quando terminei meu desenvolvimento, não quis usar declarações if em todas as chamadas de log, nem usar ferramentas externas.

Portanto, a solução que estou usando é substituir a classe android.util.Log pela minha própria 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);
    }
}

A única coisa que eu tinha que fazer em todos os arquivos de origem era substituir a importação do android.util.Log pela minha própria classe.

Reiner
fonte
143
O único problema dessa abordagem é que, se você fizer Log.d ("tag", "Processed:" + new ItemCounter (blabla) + "items"), mesmo que essa mensagem de log não apareça na versão lançada, um StringBuilder é usado para criar a mensagem, que pode ser cara de criar.
espinchi
9
Esta solução tem um grande problema. espinchi mencionou apenas a ponta do iceberg. O problema é que, quando você chama Log.d("tag", someValue.toString());isso, é muito fácil esquecer de verificar algum Valor por não ser nulo, o que significa que ele pode gerar um NullPointerExceptionem produção. Ele sugere uma solução segura, mas o enganará. Nós nos um private static boolean DEBUGe depoisif(DEBUG)Log.d(TAG, msg);
Philipp
2
@espinchi Sua preocupação parece se aplicar a todas as bibliotecas de log como discutidas nesta resposta stackoverflow.com/a/15452492/433718 (Slf4j, backlog, ...). Não é sugerido usá-los?
OneWorld 20/06
11
A única maneira de minimizar as despesas gerais mencionadas no primeiro comentário de @espinchi é alterar os métodos de log para aceitar varargs em vez de String. A solução completa é descrita aqui . Aparentemente, isso tem outra desvantagem: toda chamada deve ser editada (não apenas uma linha de importação).
Stan
21
Apenas um FYI, se você estiver usando o Android Studio e o sistema de construção de gradle, poderá usar static final boolean LOG = BuildConfig.DEBUGe não precisar modificar esse arquivo.
Ashishduh
61

Sugiro ter um boolean estático em algum lugar indicando se deve ou não registrar:

classe MyDebug {
  LOG booleano final estático = true;
}

Então, onde você quiser fazer login no seu código, faça o seguinte:

if (MyDebug.LOG) {
  if (condição) Log.i (...);
}

Agora, quando você define MyDebug.LOG como false, o compilador retira todo o código dessas verificações (já que é uma final estática, ele sabe em tempo de compilação que o código não é usado.)

Para projetos maiores, você pode começar a ter booleanos em arquivos individuais para poder habilitar ou desabilitar facilmente o log, conforme necessário. Por exemplo, estas são as várias constantes de registro que temos no gerenciador de janelas:

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;

Com o código correspondente como:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
hackbod
fonte
11
Eu também votaria nessa abordagem. Ele também foi usado na amostra de cobrança oficial do Google no aplicativo.
LA_ 5/04/11
4
Não seria menos detalhado passar a condição como primeiro parâmetro?
Snicolas
11
Essa parece ser a melhor solução, embora exija código adicional em cada instrução de log: os números de linha são preservados (fraqueza da abordagem do ProGuard); nenhum código para criar a mensagem de log é executado ( fraqueza da abordagem da classe wrapper e, aparentemente, da abordagem da biblioteca de log também) . O uso dessa abordagem no Google no exemplo de cobrança de aplicativos de acordo com @LA_ também suporta meus pensamentos.
OneWorld 20/06
2
@Snicolas Como você pode passar a condição como primeiro parâmetro sem implementar um wrapper? Além disso, se você adicioná-lo como parâmetro, antes de inserir o método, todos os parâmetros precisam ser avaliados, ou seja, também a sequência de mensagens. A condição precisa ser testada antes de criar os parâmetros. A solução proposta é possivelmente a melhor, se não houver ferramenta externa.
Tipo-a1pha
2
Em termos de código binário, é o melhor. Mas codificar como esse exige muito esforço para uma saída simples do log de depuração. A legibilidade do código diminui significativamente. Ganhe alguns, perca alguns, eu acho ...
Richard Le Mesurier 12/12/13
30

A solução Proguard de Christopher é a melhor, mas se por algum motivo você não gostar da Proguard, aqui está uma solução de baixa tecnologia:

Logs de comentários:

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

Descomentar logs:

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

Uma restrição é que suas instruções de registro não devem se estender por várias linhas.

(Execute essas linhas em um shell UNIX na raiz do seu projeto. Se estiver usando o Windows, obtenha uma camada UNIX ou use comandos equivalentes do Windows)

Nicolas Raoul
fonte
11
precisa de um "" depois do -i no Sed se estiver rodando no Mac (como por isso ) Obrigado.
Vishal
Eu sinto que este pode ser o que eu acabo usando algo que estou trabalhando, porque eu não tive muita sorte fazê-lo com Proguard em tudo
Joe Plante
E se você tiver um Log após uma ramificação sem colchetes, como sugeriu em sua primeira postagem?
Tipo-a1pha
@ type-a1pha: Se você adotar esta solução, precisará considerar os blocos de colchete como obrigatórios.
Nicolas Raoul
2
@NicolasRaoul As correções semi cólon esta questão ( //vs. ;//)
Alex Gittemeier
18

Gostaria de adicionar algumas precisões sobre o uso do Proguard com o Android Studio e o gradle, pois tive muitos problemas para remover as linhas de log do binário final.

Para fazer assumenosideeffectstrabalhos em Proguard, há um pré-requisito.

No seu arquivo gradle, você deve especificar o uso do proguard-android-optimize.txtarquivo como padrão.

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

Na verdade, no proguard-android.txtarquivo padrão , a otimização é desabilitada com os dois sinalizadores:

-dontoptimize
-dontpreverify

O proguard-android-optimize.txtarquivo não adiciona essas linhas, então agora assumenosideeffectspode funcionar.

Pessoalmente , uso o SLF4J , ainda mais quando desenvolvo algumas bibliotecas que são distribuídas para outras. A vantagem é que, por padrão, não há saída. E se o integrador quiser algumas saídas de log, ele poderá usar o Logback para Android e ativar os logs, para que os logs possam ser redirecionados para um arquivo ou para o LogCat.

Se eu realmente precisar remover os logs da biblioteca final, adiciono ao meu arquivo Proguard (depois de ativar o proguard-android-optimize.txtarquivo, é claro):

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}
Vincent Hiribarren
fonte
Isso não funciona com o novo Jack compiler-- stackoverflow.com/questions/37932114/...
fattire
Isso me ajudou; tanto proguard-android-optimize.txtcomo arquivo Proguard padrão e -assumenosideeffectsem arquivo Proguard costume eram necessários! Estou usando o shinker R8 (o padrão hoje em dia) e o log padrão do Android.
Jonik 28/04
10

Eu sugiro usar a Timber da Jake Wharton

https://github.com/JakeWharton/timber

ele resolve seu problema com a ativação / desativação e adiciona automaticamente a classe de tag

somente

public class MyApp extends Application {

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

logs serão usados ​​apenas na sua versão de depuração e, em seguida, use

Timber.d("lol");

ou

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

imprimir

"Sua classe / msg" sem digitar a tag

AndroidGecko
fonte
2
A madeira é muito boa, mas se você já possui um projeto - tente github.com/zserge/log . É um substituto para o android.util.Log e possui a maioria dos recursos que a Timber possui e muito mais.
precisa saber é o seguinte
zserge, sua solução de log parece boa. Muitos recursos. Você já pensou em adicionar regras Lint como a Timber?
Jk7 3/03
8

Eu usei uma classe LogUtils como no aplicativo de exemplo do Google IO. Modifiquei isso para usar uma constante DEBUG específica do aplicativo em vez de BuildConfig.DEBUG porque o BuildConfig.DEBUG não é confiável . Então, nas minhas aulas, tenho o seguinte.

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
fonte
+1 para relatar erros Build.DEBUGque eu costumava usar. Também desisti das várias soluções "corretas" e usei uma solução de estilo semelhante a você.
Richard Le Mesurier
7

Eu consideraria usar o recurso de log do roboguice em vez do android.util.Log interno

Suas instalações desabilitam automaticamente logs detalhados e de depuração para compilações de versão. Além disso, você obtém alguns recursos bacanas de graça (por exemplo, comportamento de log personalizável, dados adicionais para cada log e muito mais)

Usar o proguard pode ser um aborrecimento e eu não enfrentaria problemas para configurar e fazê-lo funcionar com seu aplicativo, a menos que você tenha uma boa razão para isso (desativar os logs não é bom)

Zvi
fonte
A very nice abordagem quando você não pode usar Obfuscation .... particularmente por causa da quebra roboguice por causa de LOL proguard
Snicolas
11
Atualizado ligação para facilidade de registro de robojuice: github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet
7

Estou publicando esta solução que se aplica especificamente aos usuários do Android Studio. Também descobri recentemente o Timber e o importei com sucesso no meu aplicativo, fazendo o seguinte:

Coloque a versão mais recente da biblioteca em seu build.gradle:

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

Em Android Studios, vá para Editar -> Localizar -> Substituir no caminho ...

Digite Log.e(TAG,ou, no entanto, você definiu suas mensagens de log na "Text to find"caixa de texto. Então você apenas substitui-o porTimber.e(

insira a descrição da imagem aqui

Clique em Localizar e substitua tudo.

Agora, o Android Studios examinará todos os seus arquivos no seu projeto e substituirá todos os registros por madeiras.

O único problema que tive com esse método é que o gradle aparece com um milhão de mensagens de erro depois, porque não consegue encontrar "Madeira" nas importações de cada um dos seus arquivos java. Basta clicar nos erros e o Android Studios importará automaticamente "Timber" para o seu java. Depois de ter feito isso para todos os seus arquivos de erros, o gradle será compilado novamente.

Você também precisa colocar este pedaço de código no seu onCreatemétodo da sua Applicationclasse:

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

Isso resultará no log do aplicativo apenas quando você estiver no modo de desenvolvimento e não na produção. Você também pode ter BuildConfig.RELEASEpara efetuar login no modo de liberação.

Simon
fonte
3
Tente fazer a mesma coisa para as suas importações e tornar o texto se a caixa Expressão regular está marcada para encontrar: import android\.util\.Log\;Substituir por:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson
ou você pode usar a pesquisa estrutural e substituir como mostra Chike Mgbemena em seu post #
Maksim Turaev
@MaksimTuraev Seu link não é mais relevante. Agora é um blog sobre penteados.
Vadim Kotov
Looks Like Post é removido = (não pode encontrá-lo em qualquer lugar.
Maksim Turaev
@MaksimTuraev está aqui uma cópia da máquina Wayback, mas as imagens estão quebradas - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Vadim Kotov
6

Por android.util.Log fornece uma maneira de ativar / desativar o log:

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

Por padrão, o método isLoggable (...) retorna false, somente depois que você setprop no dispositivo gosta desta:

adb shell setprop log.tag.MyAppTag DEBUG

Isso significa que qualquer registro acima do nível de DEBUG pode ser impresso. Referência android doc:

Verifica se um log para a tag especificada é ou não registrável no nível especificado. O nível padrão de qualquer tag é definido como INFO. Isso significa que qualquer nível acima e incluindo INFO será registrado. Antes de fazer chamadas para um método de registro, verifique se a sua etiqueta deve ser registrada. Você pode alterar o nível padrão configurando uma propriedade do sistema: 'setprop log.tag. 'Onde o nível é VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT ou SUPPRESS. SUPPRESS desativará todos os registros da sua tag. Você também pode criar um arquivo local.prop que contenha o seguinte: 'log.tag. =' E coloque-o em /data/local.prop.

Assim, poderíamos usar o utilitário de log personalizado:

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
fonte
6

Se você pode executar uma substituição global (uma vez) e depois preservar alguma convenção de codificação, pode seguir o padrão frequentemente usado na estrutura do Android .

Em vez de escrever

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

tê-lo como

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

Agora, o proguard pode remover o StringBuilder e todas as strings e métodos que ele usa no caminho, da versão otimizada do DEX. Use proguard-android-optimize.txte você não precisa se preocupar com android.util.Log em seu proguard-rules.pro:

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

Com o plug-in gradle do Android Studio, é bastante confiável, portanto você não precisa de constantes extras para controlar a remoção.BuildConfig.DEBUG

Alex Cohn
fonte
4

Adicione o seguinte ao seu arquivo proguard-rules.txt

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

insira a descrição da imagem aqui

Isto é o que eu costumava fazer nos meus projetos android ..

No Android Studio, podemos fazer operações semelhantes, Ctrl + Shift + F para localizar todo o projeto (Command + Shift + F nos MacOs) e Ctrl + Shift + R para substituir ((Command + Shift + R nos MacOs))

Lins Louis
fonte
Isso parece abrir trabalho com projetos eclipse. A opção de pesquisa nem sequer está disponível nos estúdios Android.
Simon
2
no Android Studio, você pode fazer pesquisas semelhantes com o atalho Ctrl + Shift + F
Louis Louis
O código de exemplo na pergunta explica por que isso não é confiável.
Nicolas Raoul
Isso pode causar problemas ao remover qualquer comando que contenha no log. Por exemplo chocolateLog.recipie ();
Andrew S
Não foi possível encontrar esta opção para o Android Studio 2.1. Além disso, eu posso usar esse truque em um arquivo por vez, procurando / substituindo normalmente.
VVB 19/09/16
3

Eu tenho uma solução muito simples. Como uso o IntelliJ para desenvolvimento, os detalhes variam, mas a ideia deve se aplicar a todos os IDEs.

Eu escolho a raiz da minha árvore de origem, clique com o botão direito do mouse e selecione "substituir". Eu, então, optar por substituir todos os "Log". com "// Log". Isso remove todas as instruções de log. Para colocá-los de volta mais tarde, repito a mesma substituição, mas desta vez como substitua todos os "// Log". com "Log".

Funciona muito bem para mim. Lembre-se de definir a substituição como sensível a maiúsculas e minúsculas para evitar acidentes como "Diálogo". Para maior segurança, você também pode executar o primeiro passo com "Log". como a sequência a ser pesquisada.

Brilhante.

kg_sYy
fonte
2
Por favor, leia o parágrafo "Se eu comentar a linha de log" na minha pergunta.
Nicolas Raoul
OK, sim, devo reler com mais frequência depois de navegar nas respostas :). Se você tiver esses casos, convém uma solução diferente, como sugerido anteriormente, como colocar todos os seus logs atrás de outra interface. Minha sugestão talvez funcione melhor para as equipes e projetos menores, onde as pessoas desejam evitar sobrecarga de libs madeireiras extras, você conhece as pessoas e código bem, etc.
kg_sYy
11
Substituir Log.d por; // Log.d também cuida do cenário "Se".
Jasper
3

Como o comentário de zserge sugeriu,

A madeira é muito boa, mas se você já possui um projeto - tente github.com/zserge/log. É um substituto para o android.util.Log e possui a maioria dos recursos que a Timber possui e muito mais.

sua biblioteca de logs fornece a opção simples de ativar / desativar a impressão de logs, conforme abaixo.

Além disso, ele exige apenas alteração de importlinha e nada precisa ser alterado para Log.d(...);declaração.

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
fonte
Você precisa colocar essa linha de código em cada Atividade / Fragmento, ou apenas em um só lugar?
Noah Ternullo
@NoahTernullo // no arquivo de aplicativo derivado. DefaultApplication.java
Youngjae
1

Aprimorei a solução acima, fornecendo suporte para diferentes níveis de log e alterando-os automaticamente, dependendo se o código está sendo executado em um dispositivo ativo ou no emulador.

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
fonte
11
Mesmo problema que a solução anterior. Se o parâmetro string for criado usando chamadas caras, ele ainda desperdiçará recursos. A verificação da chamada precisa ser feita antes da criação dos parâmetros passados.
tipo-a1pha
1

O ProGuard fará isso por você na versão de lançamento e agora as boas notícias do android.com:

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

A ferramenta ProGuard reduz, otimiza e ofusca seu código removendo código não utilizado e renomeando classes, campos e métodos com nomes semanticamente obscuros. O resultado é um arquivo .apk de tamanho menor, mais difícil de fazer a engenharia reversa. Como o ProGuard dificulta a engenharia reversa de seu aplicativo, é importante usá-lo quando ele utiliza recursos sensíveis à segurança, como quando você está licenciando seus aplicativos.

O ProGuard está integrado ao sistema de compilação Android, para que você não precise invocá-lo manualmente. O ProGuard é executado apenas quando você cria seu aplicativo no modo de liberação, portanto, não é necessário lidar com o código ofuscado ao criar seu aplicativo no modo de depuração. A execução do ProGuard é totalmente opcional, mas altamente recomendada.

Este documento descreve como ativar e configurar o ProGuard, além de usar a ferramenta de retraçar para decodificar rastreamentos ofuscados da pilha

Max Gold
fonte
2
Porém, não parece remover o log de depuração por padrão. Então a resposta de Christopher parece melhor.
Nicolas Raoul
0

Eu gosto de usar Log.d (TAG, alguma string, geralmente uma String.format ()).

TAG é sempre o nome da classe

Transforme Log.d (TAG, -> Logd (no texto da sua classe

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

Dessa forma, quando você estiver pronto para criar uma versão, defina MainClass.debug como false!

user462990
fonte
11
o problema com esta e outras soluções, além do proguard ou comentá-las, é que você está deixando o código, causando possivelmente uma grande quantidade de compilações de strings. em um aplicativo comum, não é um problema, mas se você está tentando otimizar, isso se torna um problema.
Lassi Kinnunen
0

Os logs podem ser removidos usando o bash no linux e sed:

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

Funciona para logs de várias linhas. Nesta solução, você pode ter certeza de que os logs não estão presentes no código de produção.

Sylwano
fonte
0

Sei que essa é uma pergunta antiga, mas por que você não substituiu todas as suas chamadas de log por algo como Boolean logCallWasHere = true; // --- resto do seu registro aqui

É por isso que você saberá quando deseja colocá-los de volta e eles não afetarão sua chamada if :)

masood elsad
fonte
Interessante, espero que essas linhas sejam ignoradas pelo compilador / otimizador. O nome da variável precisaria ser exclusivo, porém, porque alguns métodos têm várias chamadas de log e você não pode declarar a mesma variável duas vezes.
Nicolas Raoul
Você pode declarar a variável no topo da atividade e remover a declaração boolean desta linha;)
masood Elsad
0

Por que não fazer

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

? Nenhuma biblioteca adicional é necessária, nenhuma regra de programa que tende a estragar o projeto e o compilador java deixará de fora o bytecode para esta chamada quando você criar a versão build.

Primož Kralj
fonte
Um inconveniente é que é mais detalhado do que apenas escrever Log.d("tag","msg");e também é fácil esquecer de escrever a if(BuildConfig.DEBUG)parte.
Nicolas Raoul
11
Outro problema é que as seqüências permanecem no release compactado.
Stray # 10/19
0

Aqui está minha solução, se você não quiser mexer com bibliotecas adicionais ou editar seu código manualmente. Criei este bloco de anotações Jupyter para revisar todos os arquivos java e comentar todas as mensagens de log. Não é perfeito, mas o trabalho foi feito para mim.

Naci
fonte
0

o meu caminho:

1) ative o modo de seleção de coluna (alt + shift + insert)

2) selecione em um Log.d (TAG, "texto"); a parte 'Log'.

3), em seguida, shift + ctrl + alt + j

4) clique na seta esquerda

5) faça shift + end

6) clique em excluir.

isso remove todas as chamadas de LOG de uma vez em um arquivo java.

Ronny Bigler
fonte
0

Você pode tentar usar este método convencional simples:

Ctrl+ Shift+R

substituir

Log.e(

Com

// Log.e(
Fathur Rohim
fonte
Isso não funcionaria bem com o código de exemplo fornecido na pergunta.
Nicolas Raoul
0

Fácil com o kotlin, basta declarar algumas funções de nível superior

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
fonte
-1

a maneira mais simples;

usar DebugLog

Todos os logs são desativados pelo DebugLog quando o aplicativo é lançado.

https://github.com/MustafaFerhan/DebugLog

Mustafa Ferhan
fonte
Isto está absolutamente errado. Isso apenas faz com que os logs não sejam registrados, não os remove do código; portanto, eles ainda estão lá para ajudar as pessoas a fazer engenharia reversa do seu código, e ainda tem o custo de formatar as seqüências de caracteres de todos esses logs.
Glenn Maynard