2010-06-22 9 views
5

Tengo un código de Java que me gustaría utilizar como instrumento con mensajes de registro para depuración. El código de producción final (compilado), sin embargo, no debe contener ningún registro ya que ralentizaría el tiempo de ejecución. ¿Hay alguna forma en Java para desactivar un registrador en tiempo de compilación?Deshabilitar el registro en Java en tiempo de compilación

No le temo a la huella una comprobación dentro del método de registro de un registrador habilitado/deshabilitado en tiempo de ejecución se sumaría.

if (logging==enabled) {// do logging} 

Pero me gustaría evitar la construcción de parámetros como la siguiente en mi código de producción:

Logger.log("undefined state" + state + " @ " + new Date()); 

estoy usando el compilador de Java del solar.

Respuesta

0

No conozco ninguna funcionalidad del Compilador sobre esto, pero lo que también podría hacer es crear un script de construcción. Este script copiará los archivos fuente originales (depuración) de Java, los copiará en una ubicación temporal, quitará las declaraciones de registro de ellos y luego compilará los nuevos archivos fuente que no tienen código de depuración.

1

No hay una forma incorporada que lo haga posible. Es posible que desee utilizar un Java Preprocessor.

+0

lo pensé cuando estaba buscando en Google ... – Max

2
if(logger.isDebugEnabled()) { 
    logger.debug(expression); 
} 

Cada marco de registro que he usado requiere que utilice el patrón de arriba para evitar la innecesaria la evaluación de la expresión de registro.

+2

Investigar {} -placeholders en slf4j. –

+0

@ Thorbjørn Ravn Andersen - limpio - eso es claramente mejor para muchos casos de uso. Me gustaría hacer una pequeña muestra sobre la creación de instancias de matriz de objetos, el potencial de autoboxing innecesario, etc., pero de todos modos, gran parte de eso debe ser compilado JIT en el tiempo de ejecución. La API slf4j no excluye el uso de guardias booleanas cuando sea necesario. – McDowell

+0

Eso es una cuestión de gusto. Para mí, la {} -notación da como resultado menos código (no si) y menos desorden (sin concatenación de cadenas). –

1

Una forma es hacer un control fuera del método de registro. Casi el mismo cheque como usted ha mencionado, pero lo hace usted mismo:

if (LOGGER.isLoggable(Level.DEBUG)) { 
    LOGGER.log("undefined state" + state + " @ " + new Date()); 
} 

Este método se puede utilizar con cualquier nivel de registro. ver Logger#isLoggable(Level) para más información. Observe que es la forma recomendada de evitar la construcción de parámetros del método de registro.

+0

¡Me ganaste en esta! – Riduidel

+0

Inventar la llamada de registro no es mi opción preferida, ya que agrega mucho desorden. – Max

+0

, entonces las opciones están preprocesando la fuente o usando cosas como AOP para agregar el registro cuando lo necesite. – unbeli

0

un feo corte que podría funcionar es ocultar la implementación de la biblioteca Logger con una implementación vacía. El optimizador los alineará y la eliminación del código muerto eliminará la construcción del parámetro. Esto no funcionará cuando la construcción del parámetro contenga efectos secundarios.

Ahora bien, esta es la teoría, no he probado esto en la práctica. Tengo curiosidad acerca de esto sin embargo. Tal vez esto justifica una pregunta por separado?

+0

No estaba seguro de si el compilador sería lo suficientemente "inteligente" como para optar por eso. Podría intentarlo ... – Max

+0

El compilador no parece estar optimizando el código. El tiempo de ejecución para llamar a un método vacío mientras se pasa una cadena estática frente a uno que se ha concatenado difiere en órdenes de magnitud (al menos sin las opciones especiales del compilador activadas). – Max

+0

En cualquier caso, no confiaría en eso. Cifré mi IDE para expandir 'logd' a if (log.isDebugEnabled()) {log.debug ("yadayada");} y así sucesivamente. –

0

Realmente debería utilizar un indicador de nivel para sus mensajes de registro, Level.SEVERE -> Level.FINEST.

Hay métodos predefinidos en el registrador de este ejemplo:

Logger.info(msg); 
Logger.finest(msg); // debug/trace message. 

Logger.log(Level.CONFIG, "config message"); 

Esto le permitirá configurar el nivel de registro minumim a nivel de aplicación y el interruptor ON/OFF esos mensajes por debajo del nivel configurado, utilizando el comando línea, archivos de configuración o manualmente usando LogManager

+0

Claro, pero si desea pasar una cadena que está construida (vea mi ejemplo), se llamará a la construcción antes de verificar el nivel de registro. – Max

+0

Puede escribir su propia implementación de inserción de parámetros, usando varargs, para usar con el registro que verifica el nivel de registro actual deseado. También consulte log4j o slf4j –

5

¿Ha considerado el enfoque slf4j con {} -placeholders. Eso permite la construcción demorada de toString(), lo que significa que log.debug (...) es barato si el registro de depuración está deshabilitado.

log.debug("in loop() - a={}, b={}", a, b); 
+0

Sí, he considerado este enfoque de pasar todos los parámetros y construirlos después de la comprobación, pero todavía esperaba obtener una respuesta positiva al manejar esto en el nivel de compilación. Esta es mi forma preferida en este momento. – Max

+1

Luego considere la declaración de afirmación que le permite deshabilitar completamente las partes de código. Lamentablemente, la API slf4j devuelve el vacío, por lo que no se puede utilizar con esto; tendrá que pasar su propio contenedor. –

0

entiendo que el compilador Java es capaz de eliminar los bloques de código que se vigilada por una expresión constante de tiempo de compilación. Por lo tanto, en teoría, debería ser capaz de hacer esto con algo como esto:

public class Logging { 
    public static final boolean ENABLED = true; // change to false 
} 

public class Something 
    .... 

    if (Logging.ENABLED) { 
      logger.debug("hello mum"); 
    } 
} 

Por desgracia, es necesario volver a compilar todas las clases que depende de la bandera Logging.ENABLED cada vez que cambie su valor. Así que me gusta mucho más el siguiente:

public class Something 
    .... 

    if (logger.isDebugEnabled()) { 
      logger.debug("hello mum"); 
    } 
} 

que tiene la ventaja de que se pueden hacer ajustes de grano fino de los niveles de registro en tiempo de configuración o incluso en tiempo de ejecución; p.ej. utilizando un depurador, JMX, etc. Además, la sobrecarga de llamar al logger.isDebugEnabled() en log4j es lo suficientemente baja como para que no sea notable a menos que tenga una gran cantidad de inicios de sesión en su base de código.

2

Es posible el procesamiento posterior de los archivos de clase Java utilizando Proguard y utilice la opción -assumenosideeffects para eliminar las llamadas de registro. Esto se realiza con mayor frecuencia para Android usando:

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

para eliminar todas las llamadas a Log.d(TAG, "message"), etc ...

+0

Bienvenido a SO.Su estilo de preguntar es bueno usando código en su pregunta es buena práctica – khan

Cuestiones relacionadas