Monday, September 6, 2010

Simple Log server with java SocketHandler and centralization of log records

A common requirement for all enterprise systems is the centralization of log records.

This systems simply use the SocketHandlers to store/display ongoing event logs.

SocketHandler is a subclasses of StreamHandler. Others classes are consoleHandler, FileHandler and SocketHandler.

In a distributed system nobody can perform a healty monitoring activity on the whole system without a centraliazed log system.

Let's have look at SocketHandler.

The following class will produce logs and sent to LogServer.

package socketLogger;

import java.io.*;
import java.util.logging.*;

public class LogTest {
    private static Logger logger = Logger.getAnonymousLogger ();
   
    public static void main (String argv[]) throws IOException {
        Handler handler = new SocketHandler ("localhost", 5000);
        //set handler log level
        handler.setLevel (Level.FINEST);
        //set logger log level
        logger.setLevel(Level.FINEST);
        //add socket handler to sent our logs to log server..
        logger.addHandler (handler);

        //lets make some noice
        logger.log (Level.SEVERE, "Hello, World");
        logger.log (Level.INFO, "Welcome Home");
        logger.log (Level.CONFIG, "Config ....");
        logger.log (Level.FINE, "Fine ....");
        logger.log (Level.FINEST, "Finest ....");
        logger.log (Level.WARNING, "Warning ....");
    }
}


And our log server which listens incoming logs and prints them to console.You can build your own log server with a nice gui and filtering/searching capabilities by enhancing this.

package socketLogger;

import javax.net.ssl.*;
import javax.net.*;
import java.io.*;
import java.net.*;

public class LogServer {
    private static final int PORT_NUM = 5000;
    private static ServerSocket serverSocket;
   
    public static void main (String args[]) {
        serverSocket = createServerSocket ();
        listenAndPrintLogMessages ();
    }

    private static void listenAndPrintLogMessages () {
        while (true) {
            Socket socket = null;
            try {
                System.out.println (" >> Server waiting for log messages...");
                socket = serverSocket.accept ();

                InputStream is = socket.getInputStream ();
                BufferedReader br = new BufferedReader (new InputStreamReader (is, "US-ASCII"));
                String line = null;
                while ((line = br.readLine ()) != null) {
                    System.out.println (line);
                }
            } catch (Exception e) {
                e.printStackTrace ();
            } finally {
                if (socket != null) {
                    try {
                        socket.close ();
                    } catch (IOException ignored) {
                    }
                }
            }
        }
    }

    private static ServerSocket createServerSocket () {
        ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault ();
        try {
            serverSocket = serverSocketFactory.createServerSocket (PORT_NUM);
        } catch (IOException ioEx) {
            System.err.println ("Unable to create server");
            ioEx.printStackTrace();
            System.exit ( -1);
        }
        return serverSocket;
    }
}

see in action


And here is our logs which is captured from ServerSocket and printed to console in. By default the XMLFormatter class is used for formatting in the socket handler.So we have very nice log records now :)

 >> Server waiting for log messages...
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2010-09-06T23:01:02</date>
  <millis>1283803262382</millis>
  <sequence>0</sequence>
  <level>SEVERE</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Hello, World</message>
</record>
<record>
  <date>2010-09-06T23:01:03</date>
  <millis>1283803263161</millis>
  <sequence>1</sequence>
  <level>INFO</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Welcome Home</message>
</record>
<record>
  <date>2010-09-06T23:01:03</date>
  <millis>1283803263162</millis>
  <sequence>2</sequence>
  <level>CONFIG</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Config ....</message>
</record>
<record>
  <date>2010-09-06T23:01:03</date>
  <millis>1283803263162</millis>
  <sequence>3</sequence>
  <level>FINE</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Fine ....</message>
</record>
<record>
  <date>2010-09-06T23:01:03</date>
  <millis>1283803263172</millis>
  <sequence>4</sequence>
  <level>FINEST</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Finest ....</message>
</record>
<record>
  <date>2010-09-06T23:01:03</date>
  <millis>1283803263172</millis>
  <sequence>5</sequence>
  <level>WARNING</level>
  <class>socketLogger.LogTest</class>
  <method>main</method>
  <thread>10</thread>
  <message>Warning ....</message>
</record>
 >> Server waiting for log messages...

About JVM Options

  • Options that begin with -X are non-standard (not guaranteed to be supported on all VM implementations), and are subject to change without notice in subsequent releases of the JDK.
  • Options that are specified with -XX are not stable and are not recommended for casual use. These options are subject to change without notice. 
Don't expect to see abnormal tps increasement by using an option something like [-XX:+StringCache] this is why i am telling this here.

-XX:+StringCache : Enables caching of commonly allocated strings.

But it would be GREET :) if works huh ?

    Tuesday, August 24, 2010

    How to get tcp dump & snoop

    Snoop to file
    # snoop -xv -o snoopfilename port portNo


    Read from file with Snoop
    # snoop -xv -i snoopfilename port portNo

    TcpDump
    # tcpdump -i eth0 -s 0 -w snoopfilename port portNo

    Wednesday, August 18, 2010

    Vector vs ArrayList vs HashSet

    List syncList = Collections.synchronizedList(new ArrayList());

    Set syncSet = Collections.synchronizedSet(new HashSet());

    Vector is naturally synchronized.

    Performance Test Result
    #1 :ArrayList
    #2 :Vector
    #3 : HashSet

    Read more: Java Code Geeks: Java Best Practices – Vector vs ArrayList vs HashSet

    http://www.javacodegeeks.com/2010/08/java-best-practices-vector-arraylist.html#ixzz0wxSNUeuS

    Saturday, August 14, 2010

    Scalability hints

    Avoid lock on static variables or static methods:
    It locks your class. Even worse than locking your object!

    private static Object myVar = null;
    private foo{
        synchronized (myVar){// do not do that
           ....
       }
    }
    private static synchronized myMethod(){
         .....
    }

    Use lock free data structures
    Use java.util.concurrent.atomic package.It uses lock-free algorithms under the help with hardware synchronization primitives without using native code.

    Reduce lock granularity:

    Try to prefer  "block locks" instead of "method locks" if possible.synchronized methods locks the Object instance as you know.
    public class SchemaManager {
    private HashMap schema;
    private HashMap treeNodes;
    //Bad way!
    public boolean synchronized updateSchema(HashMap nodeTree) {
              String nodeName = (String)nodeTree.get("nodeName");
              String nodeAttributes = (List)nodeTree.get("attributes");
              if (nodeName == null)
                      return false;
              else
                      return schema.update(nodeName,nodeAttributes);
    }
    //Good Way
    public boolean updateSchema(HashMap nodeTree) {
    String nodeName = (String)nodeTree.get("nodeName");
    String nodeAttributes = (List)nodeTree.get("attributes");
    synchronized (schema) {
              if (nodeName == null)
                       return false;
              else
                       return schema.update(nodeName,nodeAttributes); }
    }
    public boolean synchronized updateTreeNodes() { ...... } }


    Make synchronized blocks as short as possible
    Move the thread safe code outside of the synchronized block.
     
    public boolean updateSchema(HashMap nodeTree) {
                   synchronized (schema) {
                              String nodeName = (String)nodeTree.get("nodeName");
                              String nodeAttributes = (List)nodeTree.get("attributes");
                              if (nodeName == null)
                                     return false;
                              else
                                     return schema.update(nodeName,nodeAttributes);
                    }
    }
     
    public boolean updateSchema(HashMap nodeTree) {
               String nodeName = (String)nodeTree.get("nodeName");
               String nodeAttributes = (List)nodeTree.get("attributes");
               synchronized (schema) {
                         if (nodeName == null)
                                return false;
                         else
                                return schema.update(nodeName,nodeAttributes);
              }
    }




    Try to use ThreadLocal variables if possible.