Como você costuma marcar entradas de registro? (android)

96

Presumo que a maioria de vocês conheça android.util.Log Todos os métodos de registro aceitam 'String tag' como primeiro argumento.

E minha pergunta é como você geralmente marca seus logs em seus aplicativos? Eu vi alguns hardcode como este:

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

Isso não parece bom por vários motivos:

  • Você pode me dizer que este código não tem hardcode, mas tem.
  • Meu aplicativo pode ter qualquer número de classes em pacotes diferentes com o mesmo nome. Portanto, seria difícil ler o log.
  • Não é flexível. Você sempre colocou um campo TAG privado em sua classe.

Existe alguma maneira legal de obter um TAG para uma aula?

andrii
fonte
2
O uso de TAG é sugerido pelo javadoc do Android , então não acho que seja pior do que obter o nome da classe em tempo de execução
Vladimir
eu prefiro criar uma classe específica como GeneralConstants e colocar meus TAGs nela e posso alcançar minhas tags em qualquer classe que eu quiser; GeneralConstans.MY_TAG
cagryInside
6
Acho que é melhor ter o TAG definido na classe, codificar o nome da classe é feio, mas a única maneira confiável de trabalhar com o proguard. Se você nunca usa o proguard, MyActivity.class.getName () é a melhor solução. Se você está preocupado com nomes duplicados, apenas inclua o nome do pacote. Ter nomes de TAG em um lugar diferente se tornará um pesadelo de manutenção.
Ralph Mueller

Respostas:

179

Eu uso um TAG, mas inicializo-o assim:

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

Dessa forma, quando eu refatorar meu código, a tag também mudará de acordo.

Gianpi
fonte
21
Estou definindo a constante TAG da mesma maneira. No entanto, estou me perguntando como as ferramentas de ofuscação de código afetarão meus nomes de classe e, como resultado, o valor dessa constante?
Gumbit
1
todo esse tempo eu colei manualmente "MyActivity.class.getName();". Sempre pensei que "TAG" era apenas um marcador de posição em exemplos do Google, etc ... não uma Staticvariável real ! Esta é uma solução muito melhor, obrigado :)
wired00 01 de
4
Por que não remover a estática e usá this.getClass().getName()-la para torná-la mais genérica?
theblang
11
Você pode querer tentar this.getClass (). GetSimpleName () para evitar as limitações de comprimento em TAG. IllegalArgumentException será lançada se tag.length ()> 23.
Michael Levy
14
Conforme mencionado por Ralph Mueller, essa técnica não funciona se você usar o Proguard (como a maioria dos projetos Android fazem) para ofuscar os nomes das classes.
John Patterson
16

Eu geralmente crio uma Appclasse que fica em um pacote diferente e contém métodos estáticos úteis. Um dos métodos é um getTag()método, dessa forma posso obter o TAG em qualquer lugar.
Appclasse se parece com isto:

EDITAR : Melhorado por comentário do br mob (Obrigado :))

public class App {

    public static String getTag() {
        String tag = "";
        final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        for (int i = 0; i < ste.length; i++) {
            if (ste[i].getMethodName().equals("getTag")) {
                tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
            }
        }
        return tag;
    }

}

E quando eu quiser usar:

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

A saída do getTagmétodo é o nome da classe do chamador (com o nome do pacote) e o número da linha de onde o getTagé chamado, para facilitar a depuração.

Yaniv
fonte
6
Eu definitivamente não faria isso .. Suas instruções de log terão um grande impacto no desempenho se você fizer isso. Se você fizer isso, você definitivamente vai querer que o proguard remova as mensagens de log para qualquer coisa menos do que um aviso em compilações de produção.
Matt Wolfe
1
Matt, você está absolutamente certo! É uma boa prática remover / descascar os logs na produção - stackoverflow.com/a/2019563/2270166
Yaniv
2
Provavelmente, isso não é mais recomendado, pois o comprimento da tag agora está restrito a 23 caracteres
Claudio Redi
obrigado por me mostrar como getStackTrace()funciona. Mas eu não vou usá-lo porque é caro
BlueWizard
12

Vá para Android Studio -> preferência -> Modelos ao vivo -> AndroidLog e selecione Log.d (TAG, String) .

No texto do modelo substituir

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

com

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

Imagem do menu Android

Em seguida, clique em Editar variáveis e insira className () na coluna Expressão ao lado da coluna Nome da classe .imagem do menu Android 2

Agora, quando você digitar o atalho, logdele colocará

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

Você não precisa mais definir um TAG.

Nicolas Manzini
fonte
1
esse é um uso muito legal do Android Studio e uma abordagem interessante para o problema, embora ao mesmo tempo você esteja inserindo string no lugar da variável TAG, o que significa que pode ser um pouco complicado se necessário alterá-la, certo? 1 por mostrar a funcionalidade, obrigado!
Viagem
3
Eu gosto dessa forma, mas prefiro criar uma nova entrada de log em vez de modificar a existente, apenas para estar seguro se ela for alterada em uma atualização futura ou algo assim.
Alaa de
9

Eu gosto de melhorar a resposta do Yaniv se você tiver o log neste formato (nome do arquivo.java:XX) x número da linha você pode vincular o atalho da mesma forma que fica vinculado quando há um erro, desta forma posso ir direto para a linha em questão apenas clicando no logcat

Eu coloquei isso dentro do meu aplicativo estendido para que possa usar em todos os outros arquivos

public static String getTag() {
    String tag = "";
    final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
    for (int i = 0; i < ste.length; i++) {
        if (ste[i].getMethodName().equals("getTag")) {
            tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
        }
    }
    return tag;
}

Captura de tela:

br mob
fonte
Amando, "roubando" e atualizando minha resposta :)
Yaniv
4
Isso provavelmente não é mais recomendado, pois o comprimento da tag agora é restrito a 23 caracteres
Claudio Redi
3

O AndroidStudio tem um logtmodelo por padrão (você pode digitar logte pressionar tab para expandi-lo para um conjunto de código). Eu recomendo usar isso para evitar copiar e colar a definição de TAG de outra classe e esquecer de alterar a classe à qual você está se referindo. O modelo se expande por padrão para

private static final String TAG = "$CLASS_NAME$"

Para evitar o uso do nome da classe antiga após a refatoração, você pode alterá-lo para

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

Lembre-se de marcar o botão "Editar variáveis" e certifique-se de que a CLASS_NAMEvariável está definida para usar a className()Expressão e que a opção "Ignorar se definida" está marcada.

Hemaolle
fonte
2

Eu criei uma classe de variáveis ​​estáticas, métodos e classes denominadas como S.

A seguir está o método de registro:

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

Ele é chamado em qualquer classe, pois S.L(this, whaterver_object);The getClass().getName()também acrescenta o nome do pacote, portanto, estou removendo-o para evitar tornar a tag desnecessariamente longa.

Vantagens:

  1. Menor que Log.d(TAG,
  2. Não há necessidade de converter valores inteiros em sua string. De fato, não há necessidade de digitartoString
  3. Não vou esquecer de deletar Log.djá que eu só tenho que deletar o método e os locais de todos os logs ficam marcados em vermelho.
  4. Não há necessidade de definir TAG no início da atividade, pois leva o nome da classe.
  5. O TAG tem um prefixo de CCC(uma string curta e fácil de digitar) para que seja fácil listar apenas seus logs no monitor do Android no Android Studio. Às vezes, você está executando serviços ou outras classes simultaneamente. Se você tiver que pesquisar apenas pelo nome da atividade, não poderá ver exatamente quando uma resposta de serviço foi obtida e uma ação de sua atividade ocorreu. Um prefixo como CCC ajuda, pois fornece registros cronologicamente com a atividade em que ocorreu
Suku
fonte
1
Ótima solução! Eu uso-o! Mas eu substituí Context ctxpor Object ctxe ctx.getClass().getName().replace(ctx.getPackageName(), "")por ctx.getClass().getSimpleName(). Dessa forma, posso ligar para S.L(Object, Object)qualquer lugar (inclusive em Fragments que não se estendem Context, por exemplo).
Antonio Vinicius Menezes Medei
1

Você pode usar this.toString()para obter um identificador único para a classe específica na qual imprime no log.

Kaspermoerch
fonte
Isso pode ficar caro dependendo do que toString()fizer.
alcatrão de
1

À custa de atualizar essas strings quando movo o código entre métodos ou renomeio métodos, gosto de fazer o seguinte. Filosoficamente, também parece ser melhor manter "localização" ou "contexto" na tag, não na mensagem.

public class MyClass {

    // note this is ALWAYS private...subclasses should define their own
    private static final LOG_TAG = MyClass.class.getName();

    public void f() {
        Log.i(LOG_TAG + ".f", "Merry Christmas!");
    }

}

A vantagem aqui é que você pode filtrar um único método, mesmo se o conteúdo não for estático, por exemplo

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

A única desvantagem é que, quando mudo o nome f()para g(), preciso manter essa string em mente. Além disso, a refatoração automática de IDE não os pegará.

Por um tempo, fui fã de usar o nome curto da classe, quero dizer LOG_TAG = MyClass.class.getSimpleName(). Achei mais difícil filtrá-los nos logs porque havia menos para continuar.

alcatrão
fonte
1

É uma pergunta muito antiga, mas mesmo com uma resposta atualizada para julho de 2018 é mais preferível usar Madeira. Para registrar o registro correto, erros e avisos podem ser enviados a bibliotecas de falhas de terceiros, como Firebase ou Crashlytics.

Na classe que implementa o aplicativo, você deve adicionar o seguinte:

@Override
public void onCreate() {
    super.onCreate();
    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    } else {
        Timber.plant(new CrashReportingTree());
    }
}

/** A tree which logs important information for crash reporting. */
private static class CrashReportingTree extends Timber.Tree {
    @Override protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE || priority == Log.DEBUG) {
            return;
        }

        FakeCrashLibrary.log(priority, tag, message);

        if (t != null) {
            if (priority == Log.ERROR) {
                FakeCrashLibrary.logError(t);
            } else if (priority == Log.WARN) {
                FakeCrashLibrary.logWarning(t);
            }
        }
    }
}

Não se esqueça da dependência de madeira.

implementation 'com.jakewharton.timber:timber:4.7.1'
Aleksandrbel
fonte
0

Para os usuários que visitam esta questão:

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

eles usam o Timber para o aplicativo IOsched 2019 para mostrar informações de depuração:

implementation 'com.jakewharton.timber:timber:4.7.1'

class ApplicationController: Application() {

override fun onCreate() {  
    super.onCreate()
    if(BuildConfig.DEBUG){
        Timber.plant(Timber.DebugTree())
    }
}   
// enables logs for every activity and service of the application
// needs to be registered in manifest like:  
 <application
    android:label="@string/app_name"
    android:name=".ApplicationController"
    ... >

uso

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

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

observe que isso torna os Logs disponíveis apenas durante o estado DEBUG e facilita a tarefa de removê-los manualmente para o lançamento no Google Play -

ao lançar o aplicativo na Play Store, precisamos remover todas as instruções Log do aplicativo, de modo que nenhum dos dados do aplicativo, como informações do usuário, dados ocultos do aplicativo, tokens de autenticação, estejam disponíveis para o usuário no logcat como texto simples

confira este artigo https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d

Dan Alboteanu
fonte
-2

Eu normalmente uso o nome do método como a tag, mas do Thread

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

Isso evita a nova exceção.

user2705093
fonte
-9
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
Surgir
fonte
3
Por que você criaria um novo RuntimeExceptionapenas para obter o nome da classe atual? Muito mal.
asgs de
É assim que marque minhas entradas de log, é a única solução que posso refatorar corretamente quando copio uma classe de um projeto para outro, então por que não? Estou aberto a sugestões se você tiver ideias melhores e mais confortáveis.
Surge em
1
Se você está apenas copiando arquivos de classe Java de um local para outro, sem renomear, a solução fornecida por @gianpi é o que é necessário. Caso contrário, você poderia apenas fazer, this.getClass().getName()embora fosse necessário remover o escopo estático doTAG
asgs