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