Usar logs en Java (parte 2)

Bueno como ya vimos en la anterior entrada (parte 1) pudimos generar una salida de log muy general, pero ahora veremos como personalizar el funcionamiento de los logs en las siguientes secciones:

  • Filtros
  • Formatos
  • Manejadores

Filtros

Primero veamos los filtros, para entender este punto planteare la siguiente necesidad: reportar únicamente mensajes de depuración (FINE, FINER, FINEST), alarmas (WRNING) y críticos (SEVERE), sin reportar informativos (INFO) y de configuración (CONFIG). Si utilizamos el nivel ALL me mostrará todos los mensajes incluyendo INFO y CONFIG así que será necesario crear una clase de filtro:

package jared.util.logging;

import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class FilterPersonalizado implements Filter {
    public boolean isLoggable(LogRecord record) {
        if (record.getLevel().equals(Level.FINE) ||
                record.getLevel().equals(Level.FINER) ||
                record.getLevel().equals(Level.FINEST) ||
                record.getLevel().equals(Level.WARNING) ||
                record.getLevel().equals(Level.SEVERE)) {
            return true;
        } else {
            return false;
        }
    }
}

Ahora para poder utilizar el filtro lo mostraré de dos formas (usando los ejemplos de la parte 1):

Usando archivo de configuración (log.properties)

...
java.util.logging.FileHandler.filter = 
    jared.util.logging.FilterPersonalizado
...

Desde código fuente

...
public void metodo()
        throws SecurityException, IOException {
    // creando manejador de archivo
    FileHandler fh = new FileHandler(
        "./log/app%g.log", //pattern
        10485760, //limit
        3, // count
        true); //append
    fh.setLevel(Level.ALL); // level
    fh.setFilter(new FilterPersonalizado()); //filtro
    fh.setFormatter(new XMLFormatter()); // formato

    // agregar el manejador de archivo al log
    Logger.global.addHandler(fh);

    // el manejador de consola se agrega automaticamente, solo
    // cambiamos el nivel de detalle a desplegar
    Logger.global.getHandlers()[0].setLevel(Level.SEVERE);

    // se establece el nivel predeterminado global
    Logger.global.setLevel(Level.INFO);
}
...

Formatos

Ahora ya que podemos controlar el detalle de mensajes de log, también podemos personalizar la salida a log, Java cuenta con solo dos tipos de formatos: java.util.logging.SimpleFormatter y java.util.logging.XMLFormatter que en lo personal no me gustan mucho. Les dejo un ejemplo muy básico de como personalizar el formato.

package jared.util.logging;

import java.util.logging.Formatter;
import java.util.logging.LogRecord;

public class FormatterPersonalizado extends Formatter {
    public String format(LogRecord record) {
        return "Log basico de nivel: " +
            record.getLevel().getName();
    }
}

A través de record puedes recuperar el nivel, mensaje, excepción, la clase y método donde fue ejecutado, etc. El valor retornado generará una entrada en el manejador de log, en el caso de FileHandler escribirá el valor retornado en el archivo de log.

Ahora para utilizar este formato también mostraré las dos formas:

Usando archivo de configuración (log.properties)

...
java.util.logging.FileHandler.formatter = 
    jared.util.logging.FormatterPersonalizado
...

Desde código fuente

...
public void metodo()
        throws SecurityException, IOException {
    // creando manejador de archivo
    FileHandler fh = new FileHandler(
        "./log/app%g.log", //pattern
        10485760, //limit
        3, // count
        true); //append
    fh.setLevel(Level.ALL); // level
    fh.setFilter(new FilterPersonalizado()); // filtro
    fh.setFormatter(new FormatterPersonalizado()); // formato

    // agregar el manejador de archivo al log
    Logger.global.addHandler(fh);

    // el manejador de consola se agrega automaticamente, solo
    // cambiamos el nivel de detalle a desplegar
    Logger.global.getHandlers()[0].setLevel(Level.SEVERE);

    // se establece el nivel predeterminado global
    Logger.global.setLevel(Level.INFO);
}
...

Manejadores

Realmente en manejadores de log Java es muy completo y posee los siguientes manejadores:

  • java.util.logging.ConsoleHandler: Muestra mensajes a consola.
  • java.util.logging.FileHandler: Guarda los mensajes a archivos.
  • java.util.logging.MemoryHandler: Guarda los mensajes en memoría.
  • java.util.logging.SocketHandler: Envia los mensajes a un socket.
  • java.util.logging.StreamHandler: Envia los mensajes a un flujo de bytes.

Ya hemos visto como utilizar ConsoleHandler y FileHandler, para está entrada solo mostraré como utilizar SocketHandler por considerar que puede ser el mas usado después de ConsoleHandler y FileHandler.

Mostraré como utilizarlo también de las dos formas:

Usando archivo de configuración (log.properties)

...
# nivel soportado para socket
java.util.logging.SocketHandler.level = ALL
# filtro de mensajes
java.util.logging.SocketHandler.filter = 
    jared.util.logging.FilterPersonalizado
# formato de salida
java.util.logging.SocketHandler.formatter = 
    jared.util.logging.FormatterPersonalizado
# host donde se recibirá la información
java.util.logging.SocketHandler.host = ubuntu-laptop
# puerto donde se recibirá la información
java.util.logging.SocketHandler.port = 1000
...

Desde código fuente

...
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SocketHandler;
...
public void metodo() throws IOException {
    SocketHandler sh = new SocketHandler(
        "ubuntu-laptop", 1000);
    sh.setFilter(null);
    sh.setFormatter(null);
    sh.setLevel(Level.ALL);
    Logger.global.addHandler(sh);
}
...

Bueno con esto ya estaría, ahora necesitamos el concentrador de logs en red que no es mas que un ServerSocket común. Les dejo un ejemplo de como recibir los mensajes desde un SocketHandler que imprime la salida a pantalla. (que esta medio macabro, espero y funcione, no lo probé, esta todo mezclado, recuerda que en la vida real debe de realizarse con el menos dos “threads” en dos clases separadas, pero se da ha entender, espero…):

...
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
...
public void metodo() throws IOException {
    ServerSocket serverLog = new ServerSocket(1000);
    while (true) {
        final Socket socket = serverLog.accept();
        new Thread() {
            public void run() {
                try {
                    BufferedReader buffer = new BufferedReader(
                        new InputStreamReader(
                            socket.getInputStream()));
                    String line = "";
                    while ((line = buffer.readLine()) != null)
                        System.out.println(line);
                    buffer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}
...

Y con esto termina la segunda entrega. Saludos!
🙂

Anuncios

6 pensamientos en “Usar logs en Java (parte 2)

  1. Hola Jared,

    Muy interesante tu artículo, como sugerencia te recomiendo que subas el código completo (como complemento al artículo) y cuidar un poco la gramática.

    Fuera de eso esta muy interesante, sigue escribiendo. Saludos!

  2. Interesante artículo Jared, te recomiendo cuidar la ortografía y gramática, puedes ir a mi blog orlandoolguin.wordpress.com en el post Mejorando nuestro español, para ver algunos tips acerca de esto y de más cosas.

    Saludos.

  3. hola … quisiera hacer una aplicación en java que me permita leer archivos .log !!! y de ello extraer información como la ip, el usuario, la fecha, el enlace , y así otros parametros… no se si me puedan ayudar

  4. Definitely imagine that that you said. Your favorite justification seemed to be at the internet the easiest
    factor to understand of. I say to you, I definitely get irked even as other people
    think about issues that they plainly don’t know about. You controlled to hit the nail upon the highest as smartly as defined out the entire thing with no need side effect , other people could take a signal. Will likely be again to get more. Thanks

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s