Jun 30

JUnit y Log4j

 

Cuando hacemos nuestras clases de test de JUnit, puede ser bastante normal testear clases que usan log4j. Si en nuestros test queemos que se muestre la traza de esas clases, debemos configurar log4j. Lo normal es hacerlo en el método setUp() del test (el que se ejecuta justo antes de cada uno de los test) de una forma similar a esta

public void setUp() {
   BasicConfigurator.configure();
}

Quizás, en vez de en el setUp() lo hagamos en el constructor de la clase de test.

Pero esto tiene una pequeña cosa que debemos saber. Cada vez que llamamos al BasicConfigurator.configure(), se añade un ConsoleAppender al log4j. Por ello, cada vez que se ejecuta setUp() (una vez por cada test), se añade un appender nuevo… y la traza empieza a salir repetida, ya que cada appender creado saca el mensaje por consola. Si lo hacemos en el constructor y tenemos varias clases de test, tenemos el mismo problema.

Para evitar esto, lo mas sencillo es llamar a BasicConfigurator.configure() en el método setUp() (y no en el constructor), pero poner tambien un método tearDown(), que JUnit llama automáticamente al final de cada test, y ahí borrar los appenders añadidos

public void tearDown() {
   LogManager.shutdown();
}

De esta forma, por cada test, primero se añadirá el appender y después se borrará. Cada test tendrá un único appender y la salida de log será única.

Mar 02

Incordiando al personal

 

Una de las cosillas que conviene hacer en un programa serio es usar un sistema de logging en condiciones en vez de usar un System.out o un System.err. Sin embargo, aunque se lo dices a la gente, es bastante habitual que muchos se "despisten" o pasen olímpicamente del tema, llenando el código de System.out.println("Voy por aquí") y System.out.println("Entro en el bucle"). Por supuesto, dicen que es temporal, sólo para probar, pero la realidad es que luego eso nunca se quita y queda por los siglos de los siglos.

Aprovechando que la clase System tiene un método setOut() que permite cambiar el System.out por otra cosa, si veo que proliferan los System.out.println(), lo que hago es cambiarlo en el main() de la aplicación (o en algún sitio menos evidente). Una "colleja" amistosa se puede dar con un código como este

package chuidiang.ejemplos;

import java.io.PrintStream;

public class CambiaSystemOut {

    public static void main(String[] args) {
        System.setOut(new PrintStream(System.out) {
            @Override
            public void print(String text) {
                super.print("No seas capullo y usa log4j");
            }

        });

        System.out.println("Hola mundo");
    }
}
 

con lo que cuando alguien pone su System.out.println("salgo del if") y hace la prueba, verá un "No seas capullo y usa el log4j".

Y si quiero dar la "colleja" de forma más vistosa (y tenemos tiempo para permitirnoslo), se puede poner el mismo mensaje pero usando un JOptionPane.showMessage(), que "canta" más. O ya para una "colleja" nada amistosa, un System.setOut(null), que hará que salte una NullPointerException cada vez que hagan un System.out.println().

El que no se divierte, es porque no quiere y yo, a veces, me lo paso como los indios.

Feb 25

Un par de cosillas

 

Un par de cosillas que aunque no son muy de programación, ahí van.

La primera es una pequeña anécdota que me ha pasado hoy. Pregunté a mi compañero cómo se hacía "no sé qué" con log4j, que estaba seguro de que se podía hacer, pero no recordaba cómo. El tampoco sabía, así que miró en google, encontró cómo y me mando un corredo diciendo "me engañas, sí que sabes cómo se hace" y un enlace … ¡ a mi propia página de log4j en la Chuwiki !. Creo que me estoy haciendo mayor y no sólo la mano izquierda no sabe lo que hace la derecha, sino que además no se acuerda.

La otra es sobre un compañero de trabajo, que ha hecho un sitio web sobre  venta de pastores alemanes y cahorros. Aunque es fan de las herramientas de Microsoft, casi le tengo convencido para que la haga con PHP y CSS. Por cierto, si alguien visita la página y se decide a comprar un perro, que le diga que va de mi parte, que me llevo comisión  ; – )

 

 

May 12

log4j 1.2.15

 

Normalmente en mis proyectos maven añado el log4j, siempre la versión 1.2.12. No por ningún motivo en particular. Símplemente era la versión disponible la primera vez que lo añadí a un proyecto maven y luego ha prevalecido el copy-paste de esa dependencia de un proyecto a otro.

El otro día cree un proyecto en casa y no tenía ningún sitio de donde copiar esta dependencia, así que me fuí a internet y busqué cómo ponerla. Puse la 1.2.15, que es la última que encontré disponible para maven.

Me pongo a compilar con maven, a generar el proyecto para eclipse y … ¡¡ Sorpresa !!. Da fallo. Busco el motivo y resulta que entre los jar que no puede bajarse, está el javamail, el activation.jar y algún otro más de los de SUN. Efectivamente, SUN no permite distribuir sus jar, por lo que oficialmente no se puede hacer. En los repositorios maven que hay por el mundo, no están estos jar de SUN, así que maven no se los puede bajar. Hay que bajárselos a mano y ponerlos en tu repositorio local de maven.

Y digo yo… ¿necesito javamail para log4j? Y aunque sea así, ¿voy a usarlo?. Pues más bien no. No tengo ningún interes en recibir por correo el log de mi aplicación y tampoco tengo ningún enemigo al que odie lo bastante como para mandárselo. Mejor dicho, sí lo tengo, pero lo que no tengo son ganas de quedarme de patitas en la calle.

Creo que esta vez se han pasado un poco. Entiendo que un momento dado, ante un error crítico, alguna aplicación crítica quiera enviar un correo a alguien. Pero, ¿es con un log.error(…) la mejor forma de hacerlo?. Desde luego puede ser cómoda en vez de usar javamail directamente, pero ¿tienen que cargar todas las aplicaciones que quieran un uso normal de log4j cargar con javamail?. A mi, desde luego, no me gusta.

Y aquí es donde llegamos a un punto donde siempre he tenido mis dudas. Por un lado la lógica y la elegancia me dicen que debería hacerse algo como log4j-core.jar con lo básico de log4j, es decir, sacar los log por pantalla o por fichero y poco más. Luego, deberían hacerse otros jar de amplicación, como log4j-mail.jar, log4j-bd.jar, etc, de forma que cada uno cargue sólo con lo que necesita. Sin embargo, la pereza me pediría que hubiera un único log4j-con-todo.jar y despreocuparme de andar buscando los que debo. Si me sobra el 90% del jar, da igual, no pasa nada.

Y esas dudas son las que siempre me corroen en el trabajo. Ante un proyecto gigante… ¿hacemos muchos jar pequeñitos por temas, de forma que en otros proyectos podamos llevarnos aquellos mini-jar que necesitamos? o por el contrario ¿hacemos un mega jar con todo y si un proyecto no necesita parte de él no pasa nada?

En la primera opción, al empezar un proyecto, debemos empezar a elegir jars que necesitamos y a coger también los jar de los que dependen esos jar. Afortunadamente maven nos ayuda en el proceso. Sin embargo, la segunda opción es menos elegante pero infinitamente más cómoda. Cuando empiezo el proyecto, me copio el mega-jar-que-lo-tiene-todo y a trabajar, sin más complicaciones.

¿Tú qué eliges?. ¿Elegancia o pereza?