[logback-dev] Re: Logback Chainsaw Bridge

Ceki Gulcu ceki at qos.ch
Thu Sep 27 21:00:16 CEST 2007


Hi Maarten,

I really like the idea.

The existing socketAppender could be adapted to convert a logback LoggingEvent 
into log4j format before sending it off to chainsaw. A lot less code to maintain.

Anyway, maybe we should aim for 1.2.x compatibility instead of 1.3?

Slightly off topic but do you use Chainsaw regularly? How would you rate it on a 
scale of 1 to 10?

Maarten Bosteels wrote:
> I forgot to mention that the code currently depends on log4j-1.3
> (which is an abandoned version) because otherwise chainsaw wouldn't
> show the location-info.
> 
> Maarten
> 
> On 9/26/07, Maarten Bosteels <maarten at apache.org> wrote:
>> Hello,
>>
>> I've written a Logback Chainsaw Bridge: your programs can use logback
>> and you can receive the events in Chainsaw using the SImpleReceiver.
>>
>> The idea is pretty simple:
>>
>> * You specify a "ch.qos.logback.classic.net.SocketAppender" in logback.xml
>> * LogbackChainsawBridge reads incoming logback events from the wire
>> * LogbackChainsawBridge converts the events to Log4j events
>> * LogbackChainsawBridge sends the events  to chainsaw using a SocketAppender
>>
>> It's certainly not a perfect solution, I hope there will be a cool
>> LogBackViewer someday that can compete with chainsaw. (maybe when I
>> have lots of time...)
>> Or does it exist already ?
>>
>> In the meantime, some of you might find it interesting.
>> The following attributes are sent to chainsaw:
>> * ThreadName
>> * Logger
>> * Timestamp
>> * Message
>> * Level
>> * MDC
>> * CallerData (LocationInfo)
>> * Throwable
>>
>> Feedback welcome.
>>
>> Maarten
>>
>>
>> package ch.org.logback;
>>
>> import java.net.ServerSocket;
>> import java.net.Socket;
>> import java.io.ObjectInputStream;
>> import java.io.BufferedInputStream;
>> import java.io.IOException;
>> import java.io.EOFException;
>> import java.util.Map;
>> import java.util.Hashtable;
>>
>> /**
>>  * This program will listen on the specified port for Logback logging events
>>  * and forward them as Log4j events to another port (to be received by Chainsaw)
>>  */
>> public class LogbackChainsawBridge {
>>
>>   static int port;
>>
>>   static boolean includeCallerData = false;
>>
>>   public static void main(String argv[]) throws Exception {
>>     if (argv.length == 0) {
>>       init("5555", "false");
>>     }
>>     if (argv.length == 1) {
>>       init(argv[0], "false");
>>     }
>>     if (argv.length == 2) {
>>       init(argv[0], argv[1]);
>>     }
>>
>>     if (argv.length > 2) {
>>       usage("too many arguments");
>>     }
>>     runServer();
>>   }
>>
>>   static void runServer() {
>>     org.apache.log4j.net.SocketAppender socketAppender
>>         = new org.apache.log4j.net.SocketAppender("localhost", 4445);
>>     try {
>>       info("Listening on port " + port);
>>       ServerSocket serverSocket = new ServerSocket(port);
>>       //noinspection InfiniteLoopStatement
>>       while (true) {
>>         info("Waiting to accept a new client.");
>>         Socket socket = serverSocket.accept();
>>         info("Connected to client at " + socket.getInetAddress());
>>         info("Starting new socket node.");
>>         new Thread(new SocketHandler(socket, socketAppender)).start();
>>       }
>>     } catch (Exception e) {
>>       e.printStackTrace();
>>     }
>>   }
>>
>>   static void usage(String msg) {
>>     System.err.println(msg);
>>     System.err.println("Usage: java " +
>> MySimpleSocketServer.class.getName() + "[port] [includeCallerData]");
>>     System.err.println("  port : on which port the logback events are
>> coming on");
>>     System.err.println("  includeCallerData : true when you want to
>> include caller data");
>>     System.exit(1);
>>   }
>>
>>   private static void info(String message) {
>>     System.out.println(message);
>>   }
>>
>>   static void init(String portStr, String includeCallerDataStr) {
>>     try {
>>       port = Integer.parseInt(portStr);
>>     } catch (NumberFormatException e) {
>>       e.printStackTrace();
>>       usage("Could not interpret port number [" + portStr + "].");
>>     }
>>     includeCallerData = Boolean.parseBoolean(includeCallerDataStr);
>>   }
>>
>>   private static org.apache.log4j.spi.ThrowableInformation
>> convertToLog4jhTrowableInformation (
>>       ch.qos.logback.classic.spi.ThrowableInformation throwableInformation) {
>>
>>     if (throwableInformation == null ||
>>         throwableInformation.getThrowableStrRep() == null ||
>>         throwableInformation.getThrowableStrRep().length == 0) {
>>       return null;
>>     }
>>     return new org.apache.log4j.spi.ThrowableInformation(throwableInformation.getThrowableStrRep());
>>   }
>>
>>   private static org.apache.log4j.spi.LocationInfo convertToLog4jLocationInfo (
>>       ch.qos.logback.classic.spi.CallerData[] callerData) {
>>     if (!includeCallerData || callerData == null || callerData.length == 0) {
>>       return org.apache.log4j.spi.LocationInfo.NA_LOCATION_INFO;
>>     }
>>     ch.qos.logback.classic.spi.CallerData data = callerData[0];
>>     return new org.apache.log4j.spi.LocationInfo(
>>         data.getFileName(),
>>         data.getClassName(),
>>         data.getMethodName(),
>>         String.valueOf(data.getLineNumber()));
>>   }
>>
>>   private static org.apache.log4j.spi.LoggingEvent convertToLog4jEvent (
>>       ch.qos.logback.classic.spi.LoggingEvent event) {
>>     String fqnOfCategoryClass = "todo: fqn";
>>     long timestamp = event.getTimeStamp();
>>     org.apache.log4j.Level level = org.apache.log4j.Level.toLevel(
>> event.getLevel().toInt() );
>>     String message = event.getFormattedMessage();
>>     String threadName = event.getThreadName();
>>     String loggerName = event.getLoggerRemoteView().getName();
>>     org.apache.log4j.spi.ThrowableInformation throwableInformation
>>         = convertToLog4jhTrowableInformation(event.getThrowableInformation());
>>     String ndc = null; // not supported by SLF4J and LogBack ?
>>
>>
>>     org.apache.log4j.spi.LocationInfo locationInfo =
>> convertToLog4jLocationInfo(event.getCallerData());
>>
>>
>>     Map<String,String> mdc = event.getMDCPropertyMap();
>>
>>     org.apache.log4j.spi.LoggingEvent log4jEvent = new
>> org.apache.log4j.spi.LoggingEvent();
>>
>>     log4jEvent.setFQNOfLoggerClass(fqnOfCategoryClass);
>>     log4jEvent.setLoggerName(loggerName);
>>     log4jEvent.setTimeStamp(timestamp);
>>     log4jEvent.setLevel(level);
>>     log4jEvent.setMessage(message);
>>     log4jEvent.setThreadName(threadName);
>>     log4jEvent.setThrowableInformation(throwableInformation);
>>     if (mdc != null) {
>>       //noinspection unchecked
>>       log4jEvent.setProperties(new Hashtable(mdc));
>>     }
>>     log4jEvent.setLocationInformation(locationInfo);
>>     log4jEvent.setNDC(ndc);
>>     //log4jEvent.setSequenceNumber(4);
>>     log4jEvent.setRenderedMessage(message);
>>     return log4jEvent;
>>   }
>>
>>
>>   private static class SocketHandler implements Runnable {
>>
>>     Socket socket;
>>     ObjectInputStream ois;
>>     org.apache.log4j.net.SocketAppender log4jAppender;
>>
>>     public SocketHandler(Socket socket,
>> org.apache.log4j.net.SocketAppender log4jAppender) {
>>       this.socket = socket;
>>       this.log4jAppender = log4jAppender;
>>       try {
>>         ois = new ObjectInputStream(new BufferedInputStream(socket
>>             .getInputStream()));
>>       } catch (Exception e) {
>>         System.err.println("Could not open ObjectInputStream to " + socket);
>>         e.printStackTrace();
>>       }
>>     }
>>
>>
>>     public void run() {
>>       ch.qos.logback.classic.spi.LoggingEvent event;
>>       try {
>>         while (true) {
>>           // read an event from the wire
>>           try {
>>             event = (ch.qos.logback.classic.spi.LoggingEvent) ois.readObject();
>>           } catch (EOFException e) {
>>             info("client disconnected");
>>             break;
>>           } catch (IOException e) {
>>             e.printStackTrace();
>>             break;
>>           } catch (ClassNotFoundException e) {
>>             e.printStackTrace();
>>             break;
>>           }
>>
>>           if (event == null) {
>>             continue;
>>           }
>>           org.apache.log4j.spi.LoggingEvent log4jEvent =
>> convertToLog4jEvent(event);
>>
>>           log4jAppender.append(log4jEvent);
>>
>>         }
>>       } catch (Exception e) {
>>         System.err.println("Unexpected exception. Closing connection.");
>>         e.printStackTrace();
>>       }
>>
>>       try {
>>         ois.close();
>>       } catch (Exception e) {
>>         System.err.println("Could not close connection.");
>>         e.printStackTrace();
>>       }
>>     }
>>   }
>>
>> }
>>
> _______________________________________________
> logback-dev mailing list
> logback-dev at qos.ch
> http://qos.ch/mailman/listinfo/logback-dev
> 

-- 
Ceki Gülcü
Logback: The reliable, generic, fast and flexible logging framework for Java.
http://logback.qos.ch



More information about the logback-dev mailing list