Archivo de la categoría: Log4js-ext

Log4js-ext 2.0 is out!

I have added a major feature to log4js-ext, remote logging support, that allows sending log data to your remote web server.

There is built-in support for all major Java logging frameworks: Log4j, Slf4j and Apache Commons Logger. To learn how to use it, visit this link.

Another major addition to log4js-ext 2.0 is a powerful search & highlight feature to log4js-ext log window: now, it is possible for you to filter logs, and then perform fine grained searches for specific values.

If you click the image below, you will see that there is a new search toolbar, and that the logged text is highlighted in several log entries: this is a real time saver when digging into a ton of data.

search and highlight

To make life easier I am hosting the API documentation online.

Log4js-ext is developed using Test Driven Development, to guarantee is is a high quality product. Want proof? Take a look at the test results for version 2.0.

Log4js-ext is Open Source, you can download and start using it now, free of charge.

Enjoy!

Remote logging for log4js-ext 2.0

The biggest new feature in log4js-ext 2.0 is its support for remote logging to Java web apps.

Providing this feature means that you can perform logging in your ExtJs javascript code, and send it to the server too, where logs will be routed to Log4j, Slf4j or the Apache Commons Logger. All of them are supported.

Configuration: the server side

Steps to add server side support to your Java web app:

  1. Add log4js-ext-remoting-xxx.jar to your Java app -yes, xxx is the library version
  2. Configure the remote logging servlet, as follows:
    <servlet>
      <servlet-name>Log4jsExtServlet</servlet-name>
      <servlet-class>com.softwarementors.log4jsext.remote.Log4jsExtServlet
      </servlet-class>
    
      <servlet-mapping>
        <servlet-name>Log4jsExtServlet</servlet-name>
        <url-pattern>/remotelogrequest</url-pattern>
      </servlet-mapping>
    </servlet>
    

That’s it!

Of course, you will have to provide the logging jars for Log4j, Slf4j or the Apache Commons Logger -but you already knew that!

Configuration: the client side

You can keep your current logs as they are, there is no need to modify your logging code in the client side. That transparency is one of the reason why you are using log4js-ext for your logging needs.

All you need to do is register one or more of the new appenders: they know how to send log data to your remote application.

Here is source code that registers appenders for Log4js, Slf4j and Apache Commons Logger with the root logger: this causes all client side logs to go to the remote web app by default.

// Configure simple remote logging
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createLog4jAppender(
    "/log4js-ext/remotelogrequest") );
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createSlf4jAppender(
    "/log4js-ext/remotelogrequest") );
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createApacheCommonsLoggingAppender(
    "/log4js-ext/remotelogrequest") );

Now, if this has not convinced you of the power of log4js-ext, I don’t know what will do…

Log4js-ext 1.0.1 is out!

Log4js-ext 1.0.1 is out!

This version just adds API documentation, generated via JSDuck, and a fix for IE 8. The documentation looks like this:

Log4js-ext API documentation

I have to say that I’m quite happy with JSDuck as a doc generation tool for javascript!

Unfortunately, the documentation is not inline due to googlecode hosting limitations: to take a look at it, open index.hml in the installation directory and click the API documentation link.

Version 1.0.1 provides a fix for IE 8, too, so that log4js-ext works ok when the development tools are not active.

Log4js-ext 1.0 is out!

Version 1.0 of log4js-ext, my logging library for ExtJs, is out!

It adds some extra functionality over 0.9 (which was almost a 1.0 candidate), but the main attraction is that it’s been polished to the point of being a product. You know: documentation, multiple file consolidation into a single file, minification, etc.

Here is the new features and improvements list:

  • Detail view for individual log entries:
    The built-in log viewer can show log details in an expanded view.
    That’s great for complex logged objects that will be happier formatted as multiple line JSON.
  • Documentation:
    The wiki provides information for users to be proficient with log4js-ext in no time.
  • Javascript and CSS consolidation and minification:
    This makes using log4js-ext easier as now all that’s needed is to add a single .js and a single .css to use all of log4js-ext.
    Besides, minification has reduced size to less than a third of the original size.
  • Refactored formatters to layouts:
    This is to follow log4j naming, a good thing because there is a thousand pages about log4j out there that might be useful in one way or other to log4js-ext users.
    Should have zero impact, as I doubt there is anybody out there creating custom formatters/layouts as of version 0.9

Besides, the library passes almost thirty unit tests in the latest Firefox, Chrome, Internet Explorer, Safari and even Opera versions.

Javascript remote logging with Log4j & log4js-ext

I released log4js-ext several days ago, and I’m planning to add remote logging support. I would love to consolidate client and server side logging at the server to help me debug complex browser/server app interactions.

The first logging system I would like to support is Log4j, with slf4j a close second.

Log4js-ext remote logger sends information that I will gather in my RemoteLoggingEvent Java class, as follows:

public class RemoteLoggingEvent {
   String level;
   String category;
   String formattedMessage;
   String ndc;
   long   timeMillis;
   boolean hasLoggedObject;
   String formattedLoggedObject;
   String formattedTime;
   
   // ************************************************************************
   // javascript side information ommitted on purpose because there is not
   // much the server can do with this raw data
   // ************************************************************************
   // Date time;
   // String message;
   // Object[] formatParams;
   // Object loggedObject;
   // int levelLevel;

   // ...
}

My first thought was to simply redirect the data to a Log4j logger, much like this:

Logger logger = Logger.getLogger(remoteLog.getCategory());
logger.log( getPriority(remoteLog.getLevel()), remoteLog.getMessage() );

This works, but there is a *BIG* but. The logged timestamp will correspond to the moment when we called the log method at the server, not the client side timestamp.

Due to the asynchronous nature of web requests, it might well happen that two logs A and B that were created in that order at the client could be received in the server in B, A order. Then the call to logger.log will generate slightly different timestamps, telling lies about the ordering of client-side actions. Really bad for debugging purposes.

It is important to note that I’m implementing remote logging with an eye to help debug during development. During development we tend to run the client an the remote app in the same computer, and then we have the guarantee that the client and server side timestamps are coherent. In that scenario, using the client generated log timestamps will be a real boon, providing correct sequencing information.

That can be so useful for debugging that I decided to byspass the Log4j loggers and log directly against their appenders, which have a nice doAppend method that receives a LoggingEvent accepting not only messages, but a timestamp, an NDC, etc.

The following code will create a LoggingEvent based on the remote information provided to the server in my own RemoteLoggingEvent object:

private static LoggingEvent adaptLoggingEvent(RemoteLoggingEvent log, 
      Logger logger) 
{
   long millis = log.getTimeMillis();
   // A configuration setting very useful during development
   if( !PREFER_REMOTE_TIME_AS_LOG_TIME ) {
      millis = (new Date()).getTime();
   }
   String message = getMessage(log);
   ThrowableInformation exceptionInfo = null;
   if( log.getException() != null ) {
      exceptionInfo = new ThrowableInformation(log.getException());
   }
   LoggingEvent le = new LoggingEvent(
         log.getCategory(), logger, millis, getLevel(log.getLevel()),
         message, log.getThreadName(!APPEND_NDC_AT_THREAD_NAME_END), 
         exceptionInfo, 
         log.getNdc(), null, null );

   return le;
}

Now, the problem is Log4j loggers do log following certain rules, and calling its appenders doAppend method would bypass them all.

To follow the rules we have to take into account several things:

  • We have to log to appenders *only* when the log level/priority (error, warn, info, etc.) is greater than the logger priority.

  • We need to write to the logger appenders, and then to all parent appenders, and to the parent parent’s appenders, and so on. But *only* if the current logger additivity is set to true, else the only appenders I have to write to are those directly attached to the logger (maybe none).

Here is the code that takes all of this into account:

public void log(RemoteLoggingEvent log) {
   Logger logger = getLocalLogger(log);
   LoggingEvent le = adaptLoggingEvent(log, logger);
      
   Category cat = logger;
   // Because we are not logging through the Logger interface, we 
   // need to take care of logging only when level is ok
   if( le.getLevel().isGreaterOrEqual(cat.getEffectiveLevel())) {
      // We traverse all appenders upwards -unless additivity is set to false
      // This simulates calling Logger.log, which we don't call because 
      // it would create the wrong timestamp, the wrong 'thread', etc. 😦
      while( cat != null ) {
         @SuppressWarnings({"unchecked" })
         Enumeration<Appender> appenders = cat.getAllAppenders();
         while( appenders.hasMoreElements()) {
            Appender appender = appenders.nextElement();
            appender.doAppend(le);
         }
         if( cat.getAdditivity()) {
            cat = cat.getParent();
          }
          else {
             cat = null;
          }
      }
   }
}

I wanted to get the same level of support for slf4j, but I just found that there is not an easy way to log timestamps and other additional information. In the end I just wrote the slf4j adapter by calling Logger.info, error, etc., with the corresponding timestamps being server generated.

This will make into log4js-ext in the following weeks, probably using my own DirectJNgine to perform remote communication, so that I can benefit from the built-in support for batching, etc.

log4js-ext published

As of lately I’ve been having some extra fun with ExtJs, and I decided I needed a serious javascript logging library for ExtJs. Something that closely resembled log4j or the thousand java logging libraries out there.

When I made a list of desired feature the logging library should provide, this is what I got:

  • It was a must to have a good GUI based viewer that allowed me to filter logs by different criteria: category, priority (info, error, debug, warn…), message content, etc.

  • I needed some way to group related logs so that I could distinguish what logs were part of a certain complex operation. I decided to support the NDC concept Log4j supports. Of course, the GUI viewer allows NDC filtering.
     
  • I needed to log arbitrary objects and see them as nicely highlighted JSON. And, of course, I should be able to search any value in the logged objects with a viewer.

  • I needed an easy way to format log messages, avoiding hand-made concatenations and formating as much as possible.

  • I wanted it to be extensible, meaning I should be able to add support for things such as remote logging, to define new ways to format messages, etc.

  • I wanted it to be easy to use and familiar to users of popular log libraries for other languages, such as log4j, logback, etc. Log4js-ext closely resembles log4j.

  • And, of course, I needed robustness. This means, among other things, lots of automated tests.

In the end, I decided the best thing I could do was to implement my own utility. It is a small project, worth 3 or 4 days of work to have it fully tested and production ready, and therefore feasible.

Now that the project is finished, the standard log viewer looks like this -well, much better, due to image scaling!

Standard log viewer

If you don’t like this, you can get things logged to your browser console (or both). This is what it looks like for Chrome:

Log output in Chrome's console

I hope you notice the object logging capability built-in, just look at the last logging entry in both viewers. What’s nice is that you can search for values in the logged object, a must when you have tons of logging output.

I would like to thank the author of the JSON highlighter I used to make the logged object output more readable, though I don’t know who he is. I just found the code here, so I’ll assume the guy that gave the answer is the author. Again, thanks a lot!

The version 0.9 of the library is available in GoogleCode.

The library is quite robust, and it has more than 25 automated JsTestDriver tests (it is small, to be true), but I decided to publish a 0.9 version to get some feedback before committing to a 1.0 version.

I expect to have 1.0 out as soon as possible, as the only things missing are some healthy extra user feedback and some code refactoring I’m undertaking right now.

Tests with JsTestDriver

BTW, here are the JsTestDriver test reports, I just can’t help it…

The test results for version 0.9

I have to say that I find JsTestDriver very interesting. I have still not selected my definitive TDD tool for Javascript, but JsTestDriver is a strong contender right now.