¿Cómo suele etiquetar las entradas del registro? (androide)

96

Supongo que la mayoría de ustedes conocen android.util.Log Todos los métodos de registro aceptan 'Etiqueta de cadena' como primer argumento.

Y mi pregunta es ¿Cómo suele etiquetar sus registros en sus aplicaciones? He visto un código duro como este:

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

Esto no se ve bien por muchas razones:

  • Puede decirme que este código no tiene hardcode, pero lo tiene.
  • Mi aplicación podría tener cualquier cantidad de clases en diferentes paquetes con el mismo nombre. Por lo que sería difícil leer el registro.
  • No es flexible. Siempre ha puesto un TAG de campo privado en su clase.

¿Existe alguna forma sencilla de obtener un TAG para una clase?

andrii
fuente
2
El uso de TAG es sugerido por Android javadoc , así que no creo que sea peor que llegar a nombre de la clase en tiempo de ejecución
Vladimir
prefiero crear una clase específica como GeneralConstants y poner mis TAG en ella y puedo alcanzar mis etiquetas en cualquier clase que quiera así; GeneralConstans.MY_TAG
cagryInside
6
Creo que es mejor tener el TAG definido en la clase, codificar el nombre de la clase es feo, pero es la única forma confiable de trabajar con proguard. Si nunca usa proguard, entonces MyActivity.class.getName () es la mejor solución. Si le preocupan los nombres duplicados, solo incluya el nombre del paquete. Tener nombres de TAG en un lugar diferente se convertirá en una pesadilla de mantenimiento.
Ralph Mueller

Respuestas:

179

Yo uso un TAG, pero lo inicializo así:

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

De esta manera, cuando refactorice mi código, la etiqueta también cambiará en consecuencia.

gianpi
fuente
21
Estoy definiendo la constante TAG de la misma manera. Sin embargo, me pregunto, ¿cómo afectarán las herramientas de ofuscación de código a los nombres de mis clases y, como resultado, al valor de esta constante?
Gumbit
1
todo este tiempo he pegado manualmente "MyActivity.class.getName();". Siempre he pensado que "TAG" era solo un marcador de posición en ejemplos de Google, etc. ¡no una Staticvariable real ! Esta es una solución mucho mejor gracias :)
wired00
4
¿Por qué no eliminar la estática y utilizarla this.getClass().getName()en su lugar para hacerla más genérica?
theblang
11
Es posible que desee probar this.getClass (). GetSimpleName () para evitar las limitaciones de longitud en TAG. Se lanza IllegalArgumentException si tag.length ()> 23.
Michael Levy
14
Como mencionó Ralph Mueller, esta técnica no funciona si usa Proguard (como lo hacen la mayoría de los proyectos de Android) para ofuscar los nombres de las clases.
John Patterson
16

Normalmente creo una Appclase que se encuentra en un paquete diferente y contiene métodos estáticos útiles. Uno de los métodos es un getTag()método, de esta manera puedo obtener el TAG en todas partes.
Appla clase se ve así:

EDITAR : Mejorado por comentario br mob (Gracias :))

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

}

Y cuando quiero usarlo:

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

La salida del getTagmétodo es el nombre de la clase que llama (con el nombre del paquete) y el número de línea desde donde getTagse llama, para facilitar la depuración.

Yaniv
fuente
6
Definitivamente no haría esto ... Sus declaraciones de registro van a sufrir un gran impacto en el rendimiento si lo hace. Si hace esto, definitivamente querrá que proguard elimine los mensajes de registro para algo menos que una advertencia en las compilaciones de producción.
Matt Wolfe
1
Matt, ¡tienes toda la razón! Es una buena práctica eliminar / eliminar registros en producción - stackoverflow.com/a/2019563/2270166
Yaniv
2
Esto probablemente ya no se recomienda ya que la longitud de la etiqueta ahora está restringida a 23 caracteres
Claudio Redi
gracias por mostrarme cómo getStackTrace()funciona. Pero no lo
usaré
12

Vaya a Android Studio -> preferencia -> Plantillas en vivo -> AndroidLog y luego seleccione Log.d (TAG, String) .

En texto de plantilla, reemplazar

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

con

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

Imagen del menú de Android

Luego haga clic en Editar variables e ingrese className () en la columna Expresión junto a la columna className Name .imagen del menú de Android 2

Ahora, cuando escriba el atajo logd, pondrá

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

Ya no es necesario definir un TAG.

Nicolas Manzini
fuente
1
ese es un uso realmente genial de Android Studio y un enfoque interesante para el problema, aunque al mismo tiempo estás ingresando una cadena en lugar de la variable TAG, lo que significa que podría ser un poco engorroso si es necesario cambiarlo, ¿verdad? +1 por mostrar la funcionalidad, ¡gracias!
Voy
3
Me gusta de esta manera, sin embargo, prefiero crear una nueva entrada de registro en lugar de modificar la existente, solo para estar seguro si cambia en una actualización futura o algo así.
Alaa
9

Me gusta mejorar la respuesta de Yaniv si tiene el registro en este formato (nombre de archivo.java:XX) xx número de línea, puede vincular el acceso directo de la misma manera que se vincula cuando hay un error, de esta manera puedo ir directamente a la línea en cuestión con solo hacer clic en el logcat

Pongo esto dentro de mi aplicación extendida para poder usarlo en todos los demás archivos

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 pantalla:

br mob
fuente
Me encanta, "robar" y actualizar mi respuesta :)
Yaniv
4
Esto probablemente ya no se recomienda ya que la longitud de la etiqueta ahora está restringida a 23 caracteres
Claudio Redi
3

AndroidStudio tiene una logtplantilla por defecto (puede escribir logty presionar tabulador para que se expanda a un solo código). Recomiendo usar esto para evitar copiar y pegar la definición de TAG de otra clase y olvidar cambiar la clase a la que se refiere. La plantilla se expande de forma predeterminada a

private static final String TAG = "$CLASS_NAME$"

Para evitar usar el nombre de la clase anterior después de la refactorización, puede cambiarlo a

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

Recuerde marcar el botón "Editar variables" y asegurarse de que la CLASS_NAMEvariable esté definida para usar la className()expresión y tenga marcada la opción "Omitir si está definida".

Hemaolle
fuente
2

He creado una clase de variables, métodos y clases estáticas con el nombre S.

El siguiente es el método de registro:

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

Se llama de ninguna clase como S.L(this, whaterver_object);El getClass().getName()también añade el nombre del paquete, por lo tanto, yo estoy quitando a cabo para evitar que la etiqueta innecesariamente largo.

Ventajas:

  1. Más corto que Log.d(TAG,
  2. No es necesario convertir valores int a su cadena. De hecho, no es necesario escribirtoString
  3. No me olvidaré de eliminarlo, Log.dya que solo tengo que eliminar el método y las ubicaciones de todos los registros se marcan en rojo.
  4. No es necesario definir TAG en la parte superior de la actividad, ya que toma el nombre de la clase.
  5. La ETIQUETA tiene un prefijo de CCC(una cadena corta y fácil de escribir) para que sea fácil enumerar solo sus registros en el monitor de Android en Android Studio. A veces está ejecutando servicios u otras clases simultáneamente. Si tiene que buscar solo por el nombre de la actividad, entonces no puede ver exactamente cuándo se obtuvo una respuesta de servicio y luego se produjo una acción de su actividad. Un prefijo como CCC ayuda, ya que le brinda registros cronológicamente con la actividad en la que ocurrió.
suku
fuente
1
¡Gran solución! ¡Lo uso! Pero he sustituido Context ctxpor Object ctxy ctx.getClass().getName().replace(ctx.getPackageName(), "")por ctx.getClass().getSimpleName(). De esa manera, puedo llamar a S.L(Object, Object)cualquier lugar (incluso en Fragments que no se extienden Context, por instancia).
Antonio Vinicius Menezes Medei
1

Puede utilizar this.toString()para obtener un identificador único para la clase específica en la que imprime en el registro.

Kaspermoerch
fuente
Esto podría resultar caro dependiendo de lo que toString()haga.
tar
1

A expensas de actualizar estas cadenas cuando muevo código entre métodos o renombro métodos, me gusta hacer lo siguiente. Filosóficamente, también parece ser mejor mantener "ubicación" o "contexto" en la etiqueta, no en el mensaje.

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

}

El beneficio aquí es que puede filtrar un solo método incluso si el contenido no es estático, por ejemplo

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

El único inconveniente es que cuando cambio el nombre f()ag() necesito tener en cuenta esa cadena. Además, la refactorización automática de IDE no los detectará.

Durante un tiempo fui fanático de usar el nombre corto de la clase, quiero decir LOG_TAG = MyClass.class.getSimpleName(). Los encontré más difíciles de filtrar en los registros porque había menos para continuar.

alquitrán
fuente
1

Es una pregunta muy antigua, pero incluso pensando en una respuesta actualizada para julio de 2018, es más preferible usar Timber. Para registrar el registro correcto, se pueden enviar errores y advertencias a bibliotecas de fallas de terceros, como Firebase o Crashlytics.

En la clase que implementa Application debes agregar esto:

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

No olvide la dependencia de la madera.

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

Para aquellos usuarios que visitan esta pregunta:

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

utilizan Timber para la aplicación IOsched 2019 para mostrar información de depuración:

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

tenga en cuenta que esto hace que los registros estén disponibles solo durante el estado DEBUG y le facilita la tarea de eliminarlos manualmente para el lanzamiento en Google Play -

cuando lancemos la aplicación en Play Store, debemos eliminar todas las declaraciones de registro de la aplicación, de modo que ninguno de los datos de la aplicación, como la información del usuario, los datos ocultos de la aplicación, los tokens de autenticación estén disponibles para el usuario en logcat como texto sin formato

consulte este artículo https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d

Dan Alboteanu
fuente
-2

Normalmente uso el nombre del método como etiqueta pero de Thread

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

Esto evita la nueva excepción.

usuario2705093
fuente
-9
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
Surgir
fuente
3
¿Por qué crearías una nueva RuntimeExceptionsolo para obtener el nombre de la clase actual? Muy mal.
pregunta el
Así es como TAGO mis entradas de registro, es la única solución que puedo refactorizar correctamente cuando copio una clase de un proyecto a otro, así que ¿por qué no? Estoy abierto a sugerencias si tiene ideas mejores y más cómodas.
Levántate
1
Si solo está copiando archivos de clase Java de una ubicación a otra, sin ningún cambio de nombre, la solución proporcionada por @gianpi es lo que necesita. De lo contrario, podría hacerlo, this.getClass().getName()aunque tendría que eliminar el alcance estático delTAG
asgs