
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(); } } } }