¿Cómo puedo activar / desactivar los niveles de registro en Android?

Estoy teniendo muchas declaraciones de registro para depurar por ejemplo.

Log.v(TAG, "Message here"); Log.w(TAG, " WARNING HERE"); 

Al desplegar esta aplicación en el teléfono del dispositivo, quiero desactivar el registro detallado desde donde puedo habilitar / deshabilitar el registro.

Una forma común es crear un int denominado loglevel, y definir su nivel de depuración basado en loglevel.

 public static int LOGLEVEL = 2; public static boolean ERROR = LOGLEVEL > 0; public static boolean WARN = LOGLEVEL > 1; ... public static boolean VERBOSE = LOGLEVEL > 4; if (VERBOSE) Log.v(TAG, "Message here"); // Won't be shown if (WARN) Log.w(TAG, "WARNING HERE"); // Still goes through 

Posteriormente, sólo puede cambiar LOGLEVEL para todos los niveles de salida de depuración.

La documentación de Android dice lo siguiente acerca de los niveles de registro :

La verbosidad nunca debe ser compilada en una aplicación excepto durante el desarrollo. Los registros de depuración se compilan pero se eliminan en tiempo de ejecución. Los registros de error, advertencia e información se guardan siempre.

Por lo tanto, es posible que desee despojarse de las declaraciones de registro de registro Verbose fuera, posiblemente utilizando ProGuard como se sugiere en otra respuesta .

De acuerdo con la documentación, puede configurar el registro en un dispositivo de desarrollo mediante Propiedades del sistema. La propiedad que se debe establecer es log.tag.<YourTag> y debe establecerse en uno de los siguientes valores: VERBOSE , DEBUG , INFO , WARN , ERROR , ASSERT o SUPPRESS . Hay más información disponible en la documentación del método isLoggable() .

Puede establecer las propiedades temporalmente mediante el comando setprop . Por ejemplo:

 C:\android>adb shell setprop log.tag.MyAppTag WARN C:\android>adb shell getprop log.tag.MyAppTag WARN 

Como alternativa, puede especificarlas en el archivo '/data/local.prop' de la siguiente manera:

 log.tag.MyAppTag=WARN 

Las versiones posteriores de Android parecen requerir que /data/local.prop sea de sólo lectura . Este archivo se lee durante el arranque, por lo que deberá reiniciarlo después de actualizarlo. Si /data/local.prop es escribible en todo el mundo, probablemente será ignorado.

Finalmente, puede establecerlas mediante programación utilizando el método System.setProperty() .

La forma más fácil es probablemente ejecutar su JAR compilado a través de ProGuard antes del despliegue, con una configuración como:

 -assumenosideeffects class android.util.Log { public static int v(...); } 

Aparte de todas las otras optimizaciones de ProGuard, eliminará cualquier sentencia verbosa directamente del bytecode.

Tomé una ruta simple – la creación de una clase de envoltorio que también hace uso de listas de parámetros variables.

  public class Log{ public static int LEVEL = android.util.Log.WARN; static public void d(String tag, String msgFormat, Object...args) { if (LEVEL<=android.util.Log.DEBUG) { android.util.Log.d(tag, String.format(msgFormat, args)); } } static public void d(String tag, Throwable t, String msgFormat, Object...args) { if (LEVEL<=android.util.Log.DEBUG) { android.util.Log.d(tag, String.format(msgFormat, args), t); } } //...other level logging functions snipped 

La mejor manera es usar SLF4J API + parte de su implementación.

Para aplicaciones de Android, puede utilizar lo siguiente:

  1. Android Logger es la implementación de SLF4J ligera pero fácil de configurar (<50 Kb).
  2. LOGBack es la implementación más potente y optimizada, pero su tamaño es de aproximadamente 1 Mb.
  3. Cualquier otro por su gusto: slf4j-android, slf4android.

Deberías usar

  if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "my log message"); } 

Desmontar el registro con proguard (ver respuesta de @ Christophe) fue fácil y rápido, pero causó que los rastreos de la pila de la producción no coincidieran con la fuente si había algún registro de depuración en el archivo.

En su lugar, aquí está una técnica que utiliza diferentes niveles de registro en desarrollo vs. producción, asumiendo que proguard sólo se utiliza en la producción. Reconoce la producción viendo si proguard ha renombrado un nombre de clase dado (en el ejemplo, yo uso "com.foo.Bar" – reemplazaría esto con un nombre de clase completamente calificado que usted sabe que será renombrado por proguard).

Esta técnica hace uso de registros comunes.

 private void initLogging() { Level level = Level.WARNING; try { // in production, the shrinker/obfuscator proguard will change the // name of this class (and many others) so in development, this // class WILL exist as named, and we will have debug level Class.forName("com.foo.Bar"); level = Level.FINE; } catch (Throwable t) { // no problem, we are in production mode } Handler[] handlers = Logger.getLogger("").getHandlers(); for (Handler handler : handlers) { Log.d("log init", "handler: " + handler.getClass().getName()); handler.setLevel(level); } } 

Log4j o slf4j también pueden utilizarse como marcos de registro en Android junto con logcat. Ver el proyecto android-logging-log4j o log4j en android

Hay un reemplazo pequeño drop-in para la clase de registro android estándar – https://github.com/zserge/log

Básicamente todo lo que tienes que hacer es reemplazar las importaciones de android.util.Log a trikita.log.Log . A continuación, en Application.onCreate() o en algún initalizador estático, compruebe el BuilConfig.DEBUG o cualquier otro indicador y utilice Log.level(Log.D) o Log.level(Log.E) para cambiar el nivel de registro mínimo. Puede utilizar Log.useLog(false) para desactivar el registro en absoluto.

Puede ser que pueda ver esta clase de extensión de registro: https://github.com/dbauduin/Android-Tools/tree/master/logs .

Le permite tener un control fino en los registros. Por ejemplo, puede desactivar todos los registros o sólo los registros de algunos paquetes o clases.

Además, añade algunas funcionalidades útiles (por ejemplo, no tiene que pasar una etiqueta para cada registro).

He creado una utilidad / envoltorio que resuelve este problema + otros problemas comunes alrededor de registro.

Una utilidad de depuración con las siguientes características:

  • Las características habituales proporcionadas por la clase Log que envuelve LogMode s.
  • Registro de método: registros de salida: se puede desactivar mediante un conmutador
  • Depuración selectiva: Depurar clases específicas.
  • Método de Ejecución-Tiempo Medida: Medida Tiempo de ejecución para los métodos individuales, así como el tiempo colectivo dedicado a todos los métodos de una clase.

¿Cómo utilizar?

  • Incluya la clase en su proyecto.
  • Utilícelo como si utilizara métodos android.util.Log, para empezar.
  • Utilice la función Registro de entradas-salidas colocando llamadas a los métodos entry_log () – exit_log () al principio y al final de los métodos de la aplicación.

He tratado de hacer la documentación auto suffiecient.

Sugerencias para mejorar esta Utilidad son bienvenidas.

Libre de usar / compartir.

Descárguelo desde GitHub .

Aquí hay una solución más compleja. Obtendrá una traza de pila completa y el método toString () será llamado sólo si es necesario (Performance). El atributo BuildConfig.DEBUG será falso en el modo de producción para que se eliminen todos los registros de rastreo y depuración. El compilador de puntos de acceso tiene la oportunidad de eliminar las llamadas debido a propiedades estáticas finales.

 import java.io.ByteArrayOutputStream; import java.io.PrintStream; import android.util.Log; public class Logger { public enum Level { error, warn, info, debug, trace } private static final String DEFAULT_TAG = "Project"; private static final Level CURRENT_LEVEL = BuildConfig.DEBUG ? Level.trace : Level.info; private static boolean isEnabled(Level l) { return CURRENT_LEVEL.compareTo(l) >= 0; } static { Log.i(DEFAULT_TAG, "log level: " + CURRENT_LEVEL.name()); } private String classname = DEFAULT_TAG; public void setClassName(Class<?> c) { classname = c.getSimpleName(); } public String getClassname() { return classname; } public boolean isError() { return isEnabled(Level.error); } public boolean isWarn() { return isEnabled(Level.warn); } public boolean isInfo() { return isEnabled(Level.info); } public boolean isDebug() { return isEnabled(Level.debug); } public boolean isTrace() { return isEnabled(Level.trace); } public void error(Object... args) { if (isError()) Log.e(buildTag(), build(args)); } public void warn(Object... args) { if (isWarn()) Log.w(buildTag(), build(args)); } public void info(Object... args) { if (isInfo()) Log.i(buildTag(), build(args)); } public void debug(Object... args) { if (isDebug()) Log.d(buildTag(), build(args)); } public void trace(Object... args) { if (isTrace()) Log.v(buildTag(), build(args)); } public void error(String msg, Throwable t) { if (isError()) error(buildTag(), msg, stackToString(t)); } public void warn(String msg, Throwable t) { if (isWarn()) warn(buildTag(), msg, stackToString(t)); } public void info(String msg, Throwable t) { if (isInfo()) info(buildTag(), msg, stackToString(t)); } public void debug(String msg, Throwable t) { if (isDebug()) debug(buildTag(), msg, stackToString(t)); } public void trace(String msg, Throwable t) { if (isTrace()) trace(buildTag(), msg, stackToString(t)); } private String buildTag() { String tag ; if (BuildConfig.DEBUG) { StringBuilder b = new StringBuilder(20); b.append(getClassname()); StackTraceElement stackEntry = Thread.currentThread().getStackTrace()[4]; if (stackEntry != null) { b.append('.'); b.append(stackEntry.getMethodName()); b.append(':'); b.append(stackEntry.getLineNumber()); } tag = b.toString(); } else { tag = DEFAULT_TAG; } } private String build(Object... args) { if (args == null) { return "null"; } else { StringBuilder b = new StringBuilder(args.length * 10); for (Object arg : args) { if (arg == null) { b.append("null"); } else { b.append(arg); } } return b.toString(); } } private String stackToString(Throwable t) { ByteArrayOutputStream baos = new ByteArrayOutputStream(500); baos.toString(); t.printStackTrace(new PrintStream(baos)); return baos.toString(); } } 

Utilizar de esta manera:

 Loggor log = new Logger(); Map foo = ... List bar = ... log.error("Foo:", foo, "bar:", bar); // bad example (avoid something like this) // log.error("Foo:" + " foo.toString() + "bar:" + bar); 

En un escenario de registro muy simple, en el que literalmente sólo está tratando de escribir en la consola durante el desarrollo con fines de depuración, podría ser más fácil hacer una búsqueda y reemplazar antes de la generación de producción y comentar todas las llamadas a Log o System. Out.println.

Por ejemplo, suponiendo que no utilice el "Registro". En cualquier lugar fuera de una llamada a Log.d o Log.e, etc, simplemente podría hacer un encontrar y reemplazar en toda la solución para reemplazar "Registro". Con "// Log". Para comentar todas sus llamadas de registro, o en mi caso sólo estoy usando System.out.println en todas partes, así que antes de ir a la producción voy a hacer simplemente una búsqueda completa y reemplazar por "System.out.println" y reemplazar con "//System.out.println".

Sé que esto no es ideal, y sería bueno si la capacidad de encontrar y comentar las llamadas a Log y System.out.println se construyeran en Eclipse, pero hasta que eso suceda la manera más fácil y rápida y mejor de hacer esto es Para comentar por búsqueda y reemplazar. Si lo hace, no tiene que preocuparse por la falta de coincidencia entre los números de línea de seguimiento de pila, ya que está editando su código fuente y no agrega ninguna sobrecarga al comprobar alguna configuración de nivel de registro, etc.

En mis aplicaciones tengo una clase que envuelve la clase Log que tiene una variable booleana estática llamada "state". A lo largo de mi código comprobar el valor de la variable "estado" utilizando un método estático antes de escribir en el registro. Luego tengo un método estático para establecer la variable "estado" que garantiza que el valor es común en todas las instancias creadas por la aplicación. Esto significa que puedo habilitar o deshabilitar todo el registro de la aplicación en una sola llamada, incluso cuando la aplicación se está ejecutando. Útil para las llamadas de soporte … Significa que usted tiene que atenerse a sus armas al depurar y no regresar a usar la clase de registro estándar aunque …

También es útil (conveniente) que Java interprete una variable booleana como falsa si no se le ha asignado un valor, lo que significa que puede dejarse como falso hasta que necesite activar el registro 🙂

Podemos usar la clase Log nuestro componente local y definir los métodos como v / i / e / d. Basado en la necesidad de que podamos hacer la llamada más lejos.
Ejemplo se muestra a continuación.

  public class Log{ private static boolean TAG = false; public static void d(String enable_tag, String message,Object...args){ if(TAG) android.util.Log.d(enable_tag, message+args); } public static void e(String enable_tag, String message,Object...args){ if(TAG) android.util.Log.e(enable_tag, message+args); } public static void v(String enable_tag, String message,Object...args){ if(TAG) android.util.Log.v(enable_tag, message+args); } } if we do not need any print(s), at-all make TAG as false for all else remove the check for type of Log (say Log.d). as public static void i(String enable_tag, String message,Object...args){ // if(TAG) android.util.Log.i(enable_tag, message+args); } 

Aquí el mensaje es para string y args es el valor que desea imprimir.

Para mí a menudo es útil poder establecer diferentes niveles de registro para cada TAG.

Estoy utilizando esta clase de contenedor muy simple:

 public class Log2 { public enum LogLevels { VERBOSE(android.util.Log.VERBOSE), DEBUG(android.util.Log.DEBUG), INFO(android.util.Log.INFO), WARN( android.util.Log.WARN), ERROR(android.util.Log.ERROR); int level; private LogLevels(int logLevel) { level = logLevel; } public int getLevel() { return level; } }; static private HashMap<String, Integer> logLevels = new HashMap<String, Integer>(); public static void setLogLevel(String tag, LogLevels level) { logLevels.put(tag, level.getLevel()); } public static int v(String tag, String msg) { return Log2.v(tag, msg, null); } public static int v(String tag, String msg, Throwable tr) { if (logLevels.containsKey(tag)) { if (logLevels.get(tag) > android.util.Log.VERBOSE) { return -1; } } return Log.v(tag, msg, tr); } public static int d(String tag, String msg) { return Log2.d(tag, msg, null); } public static int d(String tag, String msg, Throwable tr) { if (logLevels.containsKey(tag)) { if (logLevels.get(tag) > android.util.Log.DEBUG) { return -1; } } return Log.d(tag, msg); } public static int i(String tag, String msg) { return Log2.i(tag, msg, null); } public static int i(String tag, String msg, Throwable tr) { if (logLevels.containsKey(tag)) { if (logLevels.get(tag) > android.util.Log.INFO) { return -1; } } return Log.i(tag, msg); } public static int w(String tag, String msg) { return Log2.w(tag, msg, null); } public static int w(String tag, String msg, Throwable tr) { if (logLevels.containsKey(tag)) { if (logLevels.get(tag) > android.util.Log.WARN) { return -1; } } return Log.w(tag, msg, tr); } public static int e(String tag, String msg) { return Log2.e(tag, msg, null); } public static int e(String tag, String msg, Throwable tr) { if (logLevels.containsKey(tag)) { if (logLevels.get(tag) > android.util.Log.ERROR) { return -1; } } return Log.e(tag, msg, tr); } } 

Ahora solo establece el nivel de registro por TAG al principio de cada clase:

 Log2.setLogLevel(TAG, LogLevels.INFO); 
  • ¿Hay alguna manera de reemplazar el estándar Iniciar sesión en Android?
  • Android: ¿cómo funciona la aplicación Application Protector?
  • Android Studio no muestra los registros según el nombre del paquete
  • Registros de Android 'GC_EXTERNAL_ALLOC' 'GC_FOR_MALLOC'
  • Cómo agregar nombres de clase y función automáticamente a mi registro
  • Niveles de registro de Android
  • Android: Cómo capturar o redirigir los registros de LogCat a un archivo mediante ECLIPSE IDE
  • Estrategia de registro
  • Cómo ver los troncos de Slog
  • ¿Cómo registrar un int en Android?
  • ¿Cómo redirigir mi salida de registro de logcat a la tarjeta SD en un dispositivo Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.