Tuesday, December 20, 2011

Log4J Powers Unveiled-III - Defining my own Level.



"It is possible, but rarely appropriate. The request is commonly for a level named something like "audit" that doesn't obviously fit in the progression "trace", "debug", "info", "warn", "error" and "fatal". In that case, the request for a level is really a request for a mechanism to specify a different audience. The appropriate mechanism is to use a distinct logger name (or tree) for "audit" related messages." -- From Log4J.


If you need to add your own logging level in log4j, then you can do it as follows. You will have to create your own class which will extend from Level. Here's a sample code for the same: 

MyTraceLevel.java: 
view plaincopy to clipboardprint?
  1. package org.myapp.log;  
  2.   
  3. import org.apache.log4j.Level;  
  4. /** 
  5.  * My own {@link org.apache.log4j.Level} for logging.  
  6.  *  
  7.  * @author Jaikiran Pai  
  8.  *  
  9.  */   
  10. public class MyTraceLevel extends Level {   
  11.   
  12.  /**  
  13.   * Value of my trace level. This value is lesser than  
  14.   * {@link org.apache.log4j.Priority#DEBUG_INT}  
  15.   * and higher than {@link org.apache.log4j.Level#TRACE_INT}  
  16.   */   
  17.  public static final int MY_TRACE_INT = DEBUG_INT - 10;   
  18.    
  19.  /**  
  20.   * {@link Level} representing my log level  
  21.   */   
  22.  public static final Level MY_TRACE = new MyTraceLevel(MY_TRACE_INT,"MY_TRACE",7);  
  23.   
  24.      /** 
  25.        * Constructor 
  26.         * 
  27.        * @param arg0 
  28.        * @param arg1 
  29.        * @param arg2 
  30.         */  
  31.      protected MyTraceLevel(int arg0, String arg1, int arg2) {  
  32.          super(arg0, arg1, arg2);  
  33.   
  34.      }  
  35.   
  36.      /** 
  37.       * Checks whether sArg is "MY_TRACE" level. If yes then returns  
  38.       * {@link MyTraceLevel#MY_TRACE}, else calls  
  39.       * {@link MyTraceLevel#toLevel(String, Level)} passing it  
  40.       * {@link Level#DEBUG} as the defaultLevel. 
  41.        * 
  42.        * @see Level#toLevel(java.lang.String) 
  43.        * @see Level#toLevel(java.lang.String, org.apache.log4j.Level) 
  44.        * 
  45.        */  
  46.      public static Level toLevel(String sArg) {  
  47.          if (sArg != null && sArg.toUpperCase().equals("MY_TRACE")) {  
  48.              return MY_TRACE;  
  49.          }  
  50.          return (Level) toLevel(sArg, Level.DEBUG);  
  51.      }  
  52.   
  53.      /** 
  54.       * Checks whether val is {@link MyTraceLevel#MY_TRACE_INT}.  
  55.   * If yes then returns {@link MyTraceLevel#MY_TRACE}, else calls  
  56.   * {@link MyTraceLevel#toLevel(int, Level)} passing it {@link Level#DEBUG} 
  57.   * as the defaultLevel 
  58.   * 
  59.        * @see Level#toLevel(int) 
  60.        * @see Level#toLevel(int, org.apache.log4j.Level) 
  61.        * 
  62.        */  
  63.      public static Level toLevel(int val) {  
  64.          if (val == MY_TRACE_INT) {  
  65.              return MY_TRACE;  
  66.          }  
  67.          return (Level) toLevel(val, Level.DEBUG);  
  68.      }  
  69.   
  70.      /** 
  71.       * Checks whether val is {@link MyTraceLevel#MY_TRACE_INT}.  
  72.       * If yes then returns {@link MyTraceLevel#MY_TRACE}, 
  73.       * else calls {@link Level#toLevel(int, org.apache.log4j.Level)} 
  74.       * 
  75.       * @see Level#toLevel(int, org.apache.log4j.Level) 
  76.       */  
  77.      public static Level toLevel(int val, Level defaultLevel) {  
  78.          if (val == MY_TRACE_INT) {  
  79.              return MY_TRACE;  
  80.          }  
  81.          return Level.toLevel(val,defaultLevel);  
  82.      }  
  83.   
  84.      /** 
  85.       * Checks whether sArg is "MY_TRACE" level.  
  86.   * If yes then returns {@link MyTraceLevel#MY_TRACE}, else calls 
  87.   * {@link Level#toLevel(java.lang.String, org.apache.log4j.Level)} 
  88.   * 
  89.   * @see Level#toLevel(java.lang.String, org.apache.log4j.Level) 
  90.   */  
  91.  public static Level toLevel(String sArg, Level defaultLevel) {       
  92.         if(sArg != null && sArg.toUpperCase().equals("MY_TRACE")) {  
  93.             return MY_TRACE;  
  94.         }  
  95.         return Level.toLevel(sArg,defaultLevel);  
  96.  }  
  97. }  

Now, you will have to configure your log4j.xml: 
view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">   
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"debug="false">   
  4. <!-- ================================= -->   
  5. <!-- Preserve messages in a local file -->   
  6. <!-- ================================= -->   
  7. <!-- A size based rolling appender -->   
  8. <appender name="FILE" class="org.apache.log4j.FileAppender">   
  9. <param name="File" value="D:/log/myLogFile.log"/>   
  10. <param name="Append" value="false"/>   
  11. <layout class="org.apache.log4j.PatternLayout">   
  12. <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c] %m%n"/>   
  13. </layout>   
  14. </appender>   
  15. <!-- ============================== -->   
  16. <!-- Append messages to the console -->   
  17. <!-- ============================== -->   
  18. <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">   
  19. <param name="Target" value="System.out"/>   
  20. <param name="Threshold" value="INFO"/>   
  21. <layout class="org.apache.log4j.PatternLayout">   
  22. <!-- The default pattern: Date Priority [Category] Message\n -->   
  23. <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{1}] %m%n"/>   
  24. </layout>   
  25. </appender>   
  26. <!-- ================ -->   
  27. <!-- Limit categories -->   
  28. <!-- ================ -->   
  29. <category name="org.myapp">   
  30. <priority value="MY_TRACE" class="org.myapp.log.MyTraceLevel" />   
  31. <appender-ref ref="FILE"/>   
  32. </category>   
  33. <!-- ======================= -->   
  34. <!-- Setup the Root category -->   
  35. <!-- ======================= -->   
  36. <root>   
  37. <appender-ref ref="CONSOLE"/>   
  38. </root>   
  39. </log4j:configuration>   


Here's a test program which can be used for testing whether the new log level that you introduced is being identified or not: 

TestMyLogLevel.java:
  1. package org.myapp.core;   
  2.   
  3. import org.apache.log4j.Level;   
  4. import org.apache.log4j.Logger;   
  5. import org.myapp.log.MyTraceLevel;   
  6.   
  7. /**  
  8.  * Tests whether the new log level {@link org.myapp.log.MyTraceLevel#MY_TRACE}  
  9.  * is working  
  10.  *  
  11.  * @author Jaikiran Pai  
  12.  *  
  13.  */   
  14. public class TestMyLogLevel {   
  15.   
  16.  /**  
  17.   * Writes a log message with {@link org.myapp.log.MyTraceLevel#MY_TRACE}  
  18.   * and another message with {@link Level#DEBUG} 
  19.        * 
  20.        * @param args 
  21.        */  
  22.  public static void main(String[] args) {  
  23.   Logger logger = Logger.getLogger(TestMyLogLevel.class);  
  24.   logger.log(MyTraceLevel.MY_TRACE,"I am MY_TRACE log");  
  25.   logger.log(Level.DEBUG ,"I am a debug message");  
  26.  }  
  27. }  

Finally, here's the log file that got generated: 
  1. 2006-07-12 13:45:40,633 MY_TRACE [org.myapp.core.TestMyLogLevel] I am MY_TRACE log   
  2. 2006-07-12 13:45:40,633 DEBUG [org.myapp.core.TestMyLogLevel] I am a debug message   

Points to note: 

- The int value that you specify for your log level is important. Here i have defined "MY_TRACE" log level is to be higher than the DEBUG level but lower than the TRACE level provided by log4j. So whenever you have set a priority level to DEBUG on the category(in your log4j.xml file), the MY_TRACE level logs will *NOT* make it to the log file. 

No comments:

Post a Comment