IVJLogger

About Examples Performance Structure Extensibility Download
 
About IVJLogger

IVJLogger is a small library of classes and functions written in Java designed to assist you with your logging needs. "Why another logger?" you may ask. Well, the main purpose of it is keeping it simple. Simplicity means less bugs, more extensibility, better performance, and happier users. Many loggers I've seen out therer take forever to set up, I am not even talking about all the initialization code, and all the clean-up you have to do just to get them to log one line of code. With IVJLogger you don't need any external files, no clean-up, and initialization code is as simple as instantiating an object. Here's a summary of the best features that make IVJLogger what it is:

  • Simplicity
  • High performance - thanks to very efficient thread pool
  • Less coding - one line to initialize, one line to log, no clean-up
  • No external objects used - include the source with your project and you're ready to go
  • Most recent JVM friendly - created and tested on Java 1.4.2 SE
  • Cross-platform - well, Java kind of took care of that :)
  • Thread-safe - multiple threads may use the same logger to log data simultaneously.

Advanced features include multi-threading and monthly and yearly archivation of old files (this happens automatically, without you EVER having to worry about it).

Back to the menu
 
Examples

Here's an example that demonstrates how easy it is to use IVJLogger. If you want more insights on the structure of IVJLogger, see extensibility section.S


// 1 line initialization
Logger log = new HTMLLogger( new File( "C:\\Warez\\AdminLog.html" ) );
// 1 line to log
log.info("Some info");
// 0 lines to clean-up

Of course, in a real-life situation, it'd be more like this: (in this example I used LogManger instead of Logger; see extensibility section for details)


// Import somwhere at the top
import ivj.logging.*;
.......
// Somewhere in the class attributes
static LogManager log; // YES!  It is thread-safe!
.......
// Somewhere in the constructor
log = new ThreadedLogManager();
log.addLogger( new ArchivedHTMLLogger( new File( "C:\\Warez\\AdminLog.html" ) ) );
.......
// Somewhere in the code
log.info("Some information");
log.debug("x=15");
log.log( Logger.LEVEL_SECURITY_HIGH, "Something's happening!" );
log.hacker( "It's a hacker!" );
// See docs for complete list of different levels and corresponding functions

Besides these examples, I also included an example application ('src/ivj/logging/Example.java'), which emulates some kind of an on-line server. Go through the code and modify file locations in the constructor so that they fit your need. Then simply compile and test. Here's what you get: [HTML trace] [Exceptions log].

There are more examples at the extensibility section.

So, as you can see, IVJLogger is quite simple to use. However, that's not the only thing that deserves it the IVJ marking... read on to find out about other great features that it comes with!

Back to the menu
 
Performance

Although performance wasn't the main target of IVJLogger, unsurprisingly, it turned out to be one of its greatest features. I believe it's the result of simple design that makes coding clearer and results more efficient. There are two classes that are used for real logging: ArchivedFileLogger and ArchivedHTMLLogger, and both of them are extremely efficient.

Before I go into numbers, I must note that I would not be surpirsed if most other loggers work faster than IVJLogger. The catch is that IVJLogger sits in the background with minimal-priority thread pool and collects messages into a queue and writes them when your program isn't doing anything. This means that it doesn't take away any performance from your program (unlike some other loggers that write "10000 lines per second" while your program's performance's trashed).

Well, time for the numbers. I don't see any point of giving you thorough statistics, because they will only belong to my computer's configuration. So, instead, I included a PerformanceTest class that will allow you to see how fast what loggers will work on your system. Simply open up that file in the 'src/ivj/logging/PerformanceTest.class' and go through the code. Comments will explain most of the things, but just in case:

  1. Modify 'messages', 'maxThreads', and 'maxTries' according to comments.
  2. Modify initialization in the 'test' method - initialize only what you want to test.
  3. Compile and run that file (PerformanceTest) and watch the beautiful results.

For the busy investors, the numbers on my machine (P4 2000Mhz IBM DDYS SCSI 36GB HDD 1GB RAM):

  • 367 miliseconds to log 1000 messages of average size with 5 bckg threads to an HTML file as a table.
  • 492 miliseconds to log 1000 message of average size with 2 bckg threads to a file.

Pretty good for a logger that doesn't take away performance from your program, ain't it? :)

Back to the menu
 
Structure

This part goes into details about the structure of IVJLogger and how would you go about extending it to fit YOUR needs. First of all, I should say that ease of extension was one of the primary goals of IVJLogger, and I believe I have achieved it. So, here we go...

There are two primary interfaces that control the entire flow: Logger and LogManager. Loggers play the role of doing the actual logging: in case of FileLogger, it has to open the output stream, format the message, write it, and close the output stream. LogManagers' role is to keep Loggers "under the hood" and dispatch data between them. In other words, LogManagers keep a list of all the Loggers that were assigned to them, and whenever you request them to log something, they iterate through the list, and give every logger a reference to that message.

If you're confused right now, that's good. We'll look at the structure in a real-life situation later on, right now I want to describe what Loggers and LogManagers come with IVJLogger. Here's a list of Loggers:

  1. Logger - interface that defines all the functions that all your loggers should have. If you want to create your own logger, I would not suggest implementing this interface; instead, extend one of the existing classes, since they have most of the junk-work ( warning, info, debug functions that simply point to log function ) done.
  2. SimpleLogger - takes care of all the junk work and logs to console by default. Do not use it, only extend it. Use ConsoleLogger instead.
  3. ConsoleLogger - Simply write to System.out.
  4. FileLogger - Simply writes to files... I suggest using #5 instead, since it also archives files (otherwise they grow huge and get hard to manitain).
  5. ArchivedFileLogger - same as above, only it keeps monthly and yearly archives of old logs.
  6. HTMLLogger - eGenerates HTML files with nice table format (see examples for a sample). I'd suggest using HTMLLogger instead of FileLogger at any time, since it's more efficient, more portable, and much easier to see with a naked eye.
  7. ArchivedHTMLLogger - same as above, only it keeps monthly and yearly archives of old logs.

Here's a list of LogManagers:

  1. LogManager - interface that defines all the functions that your log manager should have. It also extends the Logger interface, (so that you can use the same functions with both Loggers and LogManagers - info,debug,fatal,etc) which allows for some complicated nested structures (which aren't recommended :)). I would not suggest implementing this interface; instead, extend some of the existing classes, since they have most of the junk-work ( warning, info, debug functions that simply point to log function ) done.
  2. SimpleLogManager - do not use for logging purpose. This class only serves as an example, and a foundation for the rest of the log managers, because it takes care of all the junk work.
  3. ThreadedLogManager - extends SimpleLogManager. This is THE log manager to use. It uses a simple, yet powerful thread pool, where you can specify maximum amount of threads to be used (see performance). If you want to achieve maximum performance and eliminate bottlenecks, while preserving your program's performance, use ThreadedLogManager... everything else is crap compared to it :).
  4. TimedLogmanager - extends SimpleLogManager. Do not use this. It's there as an example - what it does is collects your messages into a queue and dispatches them to all the assigned loggers once every X seconds (1 by default). I do not suggest using it since it might cause your system to run out of memory (if you log 1000000 messages in a non-stop loop) and you have to clean-up after it (terminate it on exit).

Now that you know what kind of loggers and log managers there are, let's see how they cooperate in a real-life example.


We are making some stupid GUI program, that we'll sell to the users. It's not finished yet, but we'll sell it anyway, and in case users get crashes, we want to find out the cause... So, we want to keep track of few things:

  1. Every click\movement that the user makes.
  2. Every exception that is thrown.

We also want to have a simple trace in the console... just for the hell of it.

One thing is for sure: we'll be using ThreadedLogManager, since it's a commercial program, and we want the user to get as much as possible (haha), and as we know, it's the most efficient log manager there is. So, first we need to initialize the log manager, which will hold different Loggers and dispatch messages between them:

private static LogManager log = new ThreadedLogManager();

Now, we want to add a logger that will give us a trace in the console. Luckily, we have a ConsoleLogger, so we do the following somewhere in the constructor:

log.addLogger( new ConsoleLogger() );

Now, let's think of a logger that will record every click that a user makes... We can choose between HTML and plain text... I'd stick with the beauty... Do we need to archive? Yes I think so... in case user uses this thing for years (yeah right :)), we want to easily find any time location, so let's go with ArchivedHTMLLogger:

log.addLogger( new ArchivedHTMLLogger("your_program/log/EveryMove.html") );

There's one more logger left - the exceptions logger. There are two approaches we can take:

  1. Declare a separate LogManager which we will use for exception purposes only.
  2. Extend some Logger and filter out everything that's not exceptions, and use only 1 instance of LogManager.

Second option sounds better, but there's a few difficulties:

  • We have to extend and filter, and that's a lot of extra work (we are lazy, after all)
  • Even if we filter out exceptions in that particular logger, the rest of the loggers will still log the exceptions, including the console trace... and we don't neccessarily want that.

So, I am going to stick with the first approach (just like I did in the Example program ('src/ivj/logging/Example.java')). Since this is going to be a separate logger, we may declare it alone, without any LogManager. But that means we won't take advantage of the ThreadedLogManager, which makes everything smoother, faster, and nicer. So here's what we'll do:

private static LogManager exceptions = new ThreadedLogManager(); // somewhere in attributes

And add a logger in the constructor:

exceptions.addLogger( new ArchivedFileLogger("your_program/log/exceptions.txt") );

I decided to use ArchivedFileLogger instead of ArchivedHTMLLogger because... no reason. I think Exceptions look better in naked text than HTML.

Ok, so what have we created so far: a 'log' LogManager with a console logger and a movement logger, and an 'exceptions' log manager where we'll put all our exceptions. Now, the program part. Whenever you have an exception, here's what you have to do:

exceptions.exception( e );

Whenever you have some kind of a button click or a text enter, you'd do the following:

log.info( "User clicked the button!" );

And that's all you have to do to have 100% professional and efficient logigng in your program. Remember, ThreadedLogManager is thread safe, so you can really pump data into it from all over the place, and it'll just take it in and barf it out (into a file, of course :)).


I hope after reading this section you understand how LogManagers and Loggers cooperate. If you're still confused, look over PerformanceTest and Example programs... they're well documented and they demonstrate everything. Also, don't hesitate to look at the source... It's not rocket science.

Back to the menu
 
Extensibility

Now it's time to talk about extensibility. There are many cases when this might come in handy, but usualy it'd be used purely for filtering out whatever. Remember, you can extend Loggers as well as LogManagers... and it is ENCOURAGED. This section assumes you've read the structure section and understand the realtionship between loggers and log managers.

So, suppose you want to have a logger that only logs exceptions, and nothing else. This may sound familiar, since we had the same problem in the structure section, but this time we're going to take a different approach. What we want to do, is to extend a logger (in our case, FileLogger), and to intercept every message that's about to get logged. Then we need to see if that message is an exception, and if it is, then we'll let it through. Sounds like a lot of work huh? You'd be surpised how simple it is, though. In fact, it's so simple, I am going to paste the code right in:


import ivj.logging.*;

public class ExceptionLogger extends ArchivedFileLogger
{
    
    // To keep it simple - file name goes in here
    public ExceptionLogger()
    {
        super("your_program/log/exceptions.txt");
    }
    
    // This is the method that's called by all other logigng methods
    // such as info(), debug(), fatal(), etc
    public void log(int level, Object data)
    {
        // is this an exception?
        if ( level == Logger.LEVEL_EXCEPTION_PROGRAM || level == Logger.LEVEL_EXCEPTION_USER )
            super.log(level,data); // yes, it's an exception... send it to FileLogger
        else
            return; // no it's something else - ignore it.
    }
    
}

... Comments say it all. Now, all you'll have to do to add that Logger to your main LogManager:

myLogManager.addLogger( new ExceptionLogger() );

And then log as normally.. Is that simple or what? You can do the exact same thing with LogManager - I'd suggest extending ThreadedLogManager and overriding its log(int,Object) method. Same as the code above, only change some names.

There is, of course, an annonymous-class approach, that looks something like this:


log.addLogger( new FileLogger("C:\\Warez\\logg.txt"){
public void log( int level, Object data )
{
	// your filters here
	if ( level == Logger.LEVEL_INFO )
		return;
	else
		super.log( level, data );
}
});

Well, this section was short, wasn't it? It's because that's pretty much all there is to IVJLogger. Simplicity, simplicity, simplicity...

Back to the menu
 
Download

So you've read everything and now you're drooling all over your keyboard thinking how much you gonna have to pay for this thing? Heh I know you're not drooling and I know that you know that its free since its hosted by SourceForge.net :). So, here's some links:

Author: Ivan Jouikov (ivj@comcast.net)

SF page: IVJLogger // download the most recent version from there

Back to the menu

SourceForge.net Logo