15 March 2011  ·  javaprogrammazionelinux

Logging tramite LOG4J e SysLog


Uno dei framework per il logging più popolare disponibile in ambiente Java è sicuramente Log4j. Si ha a volte l'esigenza di fare confluire i log generati da un programma Java in quelli di sistema; in ambiente Linux i log sono gestiti dal demone Syslog (o qualche sua variante).

Log4J ci mette a disposizione un "appender" che si occupa di trasferire i messaggi di log al syslog. Tale appender è il SyslogAppender; vediamo un esempio di come sia possibile utilizzarlo.

// inizio file HelloWorld.java 

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class HelloWorld {

public static void main(String[] args) {
        PropertyConfigurator.configure("log4j.properties");
        Logger logger = Logger.getLogger(HelloWorld.class);
        logger.info("Hello world");
        }
}

// fine file HelloWorld.java

Per riuscire a redirigere il messaggio di log "Hello world" si deve utilizzare il seguente file di configurazione di log4j:

 --- inizio file log4j.properties ---
log4j.rootLogger=INFO, SYSLOG
log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender
log4j.appender.SYSLOG.syslogHost=127.0.0.1
log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.SYSLOG.facility=DAEMON
--- fine file log4j.properties ---

Nota: ho effettuato le prove su una Ubuntu 10.10 che come demone utilizza RSYSLOG; per riuscire a far ricevere a rsyslog i messaggi di log4j è stato necessario aggiungere le seguenti righe al file /etc/rsyslog.conf (dopo aver effettuato le modifiche è necessario riavviare il servizio con 'restart rsyslog'):
$ModLoad imudp
$UDPServerRun 514

La comunicazione tra Log4j e Syslog avviene dunque attraverso messaggi UDP verso localhost. Lavorando in locale potrebbe essere preferibile non ricorre alla comunicazione via rete, ma accedere direttamente alla API C per l'utilizzo di syslog. Adesso vedremo un possibile approccio che ricorre a JNA.
Le API C (visualizzabili tramite il comando 'man syslog') sono:

void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);

Ecco l'interfaccia Java/JNA necessaria per il loro utilizzo:

// inizio file C.java 
public interface C extends Library {
        C LIB = (C) Native.loadLibrary("c", C.class);    
        public void openlog(String ident, int option, int facility);
        public void syslog(int priority, String format, String ...args);
        public void closelog();
}
// fine file C.java

A questo punto possiamo scrivere un nostro appender che utlizza queste API (attenzione è solo un proof of concept con diverse limitazioni: utilizza la facilty fissa DAEMON ed un livello di logging fisso ad INFO)

// inizio file SyslogJnaAppender.java
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
 
import com.sun.jna.Library;
import com.sun.jna.Native;
 
public class SyslogJnaAppender extends AppenderSkeleton {
 
        private static final int LOG_DAEMON = 24;
        private static final int LOG_NDELAY = 8;
        private static final int LOG_INFO = 6;
        
        private String ident = "";
        private boolean opened = false;
        
        @Override
        public boolean requiresLayout() {
                return false;
        }
        
        @Override
        protected void append(LoggingEvent event) {
                if(!opened) {
                        C.LIB.openlog(ident, LOG_NDELAY, LOG_DAEMON);
                        opened = true;
                }
                C.LIB.syslog(LOG_INFO, "%s", event.getMessage().toString());
        }
        
        @Override
        public void close() {
                if(opened) {
                        C.LIB.closelog();
                }
        }
        
        public void setIdent(String ident) {
                this.ident = ident;
        }
        
}
// fine file SyslogJnaAppender.java 

Vediamo come va invece modificato il file log4j.properties per utilizzare il nostro appender jna:
log4j.rootLogger=INFO, SYSLOG
log4j.appender.SYSLOG=SyslogJnaAppender
log4j.appender.SYSLOG.ident=prova

Riassumendo, abbiamo quindi visto come configurare LOG4J per comunicare con i sistema di logging di ogni distribuzione Linux, cioè con syslog. La comunicazione LOG4J/SYSLOG può avvenire tramite protocollo UDP (funzionalità di default già integrata in log4j) oppure tramite chiamate dirette a librerie C (scrivendo un appender ad hoc che si interfaccia alla libc tramite JNA).


← Tutti gli articoli