Recipe 17.7 Network Logging


Problem

Your class is running inside a server container, and its debugging output is hard to obtain.

Solution

Use a network-based logger like the JDK 1.4 Logging API, Apache Logging Services Project's log4j, or the simple one shown here.

Discussion

Getting the debug output from a desktop client is fairly easy on most operating systems. But if the program you want to debug is running in a "container" like a servlet engine or an EJB server, it can be difficult to obtain debugging output, particularly if the container is running on a remote computer. It would be convenient if you could have your program send messages back to a program on your desktop machine for immediate display. Needless to say, it's not that hard to do this with Java's socket mechanism.

Several logging APIs can handle this. As of JDK 1.4, Java has a standard logging API (discussed in Recipe 17.9) that talks to various logging mechanisms including Unix syslog. The Apache Logging Services Project produces log4j , which is used in most open source projects that require logging (see Recipe 17.8). And, before these became widely used, I wrote a small, simple API to handle this type of logging function. The JDK logging API and log4j are more fully fleshed out and can write to such destinations as a file, an OutputStream or Writer, or a remote log4j, Unix syslog, or Windows Event Log server.

The program being debugged is the "client" from the logging API's point of view even though it may be running in a server-side container such as a web server or application server since the "network client" is the program that initiates the connection. The program that runs on your desktop machine is the "server" program for sockets since it waits for a connection to come along.

Example 17-10 is a simple client program, NetLogSimple, using my simple Netlog API.

Example 17-10. NetLogSimple.java
/* A simple example of using the NetLog program.  * Unrealistic in that it's standalone; this API is  * intended for use inside another program, possibly  * a servlet or EJB.  */ public class NetLogSimple {     public static void main(String[] args) throws java.io.IOException {         System.out.println("NetLogSimple: Starting...");         // Get the connection to the NetLog         NetLog nl = new NetLog(  );         // Show sending a String         nl.log("Hello Java");         // Show sending Objects         nl.log(new java.util.Date(  ));         nl.log(nl);         // Show sending null and "" (normally an accident...)         nl.log(null);         nl.log("");         // All done, close the log         nl.close(  );         System.out.println("NetLogSimple: Done...");     } }

In Figure 17-3, I show both the server and client running side by side.

Figure 17-3. NetLog server and client
figs/jcb2_1703.gif


The client-side API and the server code are both online. Example 17-11 shows the code for the key parts of my NetLog server.

Example 17-11. NetLogServer.java
public class NetLogServer {     public static final int PORT = 65432;     public static final int NUM_THREADS = 8;     JFrame theFrame;     JTextArea theTextArea;     /** Main method, to start the servers. */     public static void main(String[] av)     {         new NetLogServer(PORT, NUM_THREADS);     }     /** Constructor */     public NetLogServer(int port, int numThreads)     {         ServerSocket servSock;         Socket clientSocket;         try {             servSock = new ServerSocket(PORT);         } catch(IOException e) {             /* Crash the server if IO fails. Something bad has happened */             System.err.println("Could not create ServerSocket " + e);             System.exit(1);             return;  /*NOTREACHED*/         }         // Build the GUI - must be before Handler constructors!         theFrame  = new JFrame("NetLog Server");         theTextArea = new JTextArea(24, 80);         theTextArea.setEditable(false);         theTextArea.setBorder(BorderFactory.createTitledBorder("NetLogServer"));         theFrame.getContentPane(  ).add(new JScrollPane(theTextArea));         // Now start the Threads         for (int i=0; i<numThreads; i++) {             new Handler(servSock, i).start(  );         }         theFrame.pack(  );         theFrame.setVisible(true);         theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     }     public synchronized void log(int tid, String s) {         StringBuffer sb = new StringBuffer(  );         sb.append(tid);         sb.append(": ");         if (s == null) {             sb.append("(null)");         }         else if (s.length(  ) == 0) {             sb.append("(null string)");         }         else             sb.append(s);         sb.append('\n');         theTextArea.append(sb.toString(  ));         theTextArea.setCaretPosition(theTextArea.getText(  ).length(  ));         theFrame.toFront(  );     }     /** A Thread subclass to handle one client conversation. */     class Handler extends Thread {         ServerSocket servSock;         int tid;         /** Construct a Handler. */         Handler(ServerSocket s, int i) {             super(  );             servSock = s;             tid = i;             setName("Thread " + tid);         }         public void run(  )         {             /* Wait for a connection */             while (true){                 try {                     // log(tid, getName(  ) + " waiting");                     Socket clientSocket = servSock.accept(  );                     log(tid,getName(  ) + " START, IP=" +                         clientSocket.getInetAddress(  ));                     BufferedReader is = new BufferedReader(                         new InputStreamReader(clientSocket.getInputStream(  )));                     String line;                     while ((line = is.readLine(  )) != null) {                         // System.out.println(">> " + line);                         log(tid,line);                     }                     log(tid,getName(  ) + " ENDED ");                     clientSocket.close(  );                 } catch (IOException ex) {                     log(tid, getName(  ) + ": IO Error on socket " + ex);                     return;                 }             }         }     } }

See Also

Better network loggers are available. The Apache Foundation Logging Services Project (http://logging.apache.org) offers log4j, which provides a similar service (see Recipe 17.8). JDK 1.4 includes an Event Logger mechanism, described in Recipe 17.9.

If you want to run any network-based logger , you need to be very aware of security issues. One common form of attack is a simple denial-of-service during which the attacker makes a lot of connections to your server in order to slow it down. If you had extended this program by writing the log to disk, the attacker could fill up your disk by sending lots of garbage. However, because this example displays the log on the screen, you would see this happening. Don't leave the server running while you're not around to watch it!

The simplest non-network logger around is probably my Debug class described in Recipe 1.11.



Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net