[logback-dev] Re: Logback Chainsaw Bridge
Maarten Bosteels
maarten at apache.org
Wed Sep 26 11:41:13 CEST 2007
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();
> }
> }
> }
>
> }
>
More information about the logback-dev
mailing list