Any one use log4j?

I extracted the latest version of odejava last night and came across it’s new need for log4j.

I’ve not used this before at all, and if I’ve needed logging have either used a very simple logger facility or System.out.println(…)

Has anyone around here use log4j in anger at all? if so is it any good? if not why not? are there any better alternatives? etc.

If any one has time I would be curious to see if it’s worth using for my own stuff or if it would just get in the way.

Cheers,
Dan.

I promise that as soon as you get used to a logger-API you’ll NEVER go back to System.out.println()…it quickly becomes as essential as syntax-highlighting, auto-complete, “IDE instead of notepad” etc. :slight_smile:

Whether or not you agree with my feelings on L4J, if the alternative is “use nothing” then you should definitely use L4J… (although it might get you into bad habits and cause you some considerable pain; if you can, try and find a better API)

IMHO it’s one of the those frustrating utility API’s: good, but missing one or two absolutely key features … like java.util when Sun chose not to include List etc (argh!) for the first few years…and omitted regular expressions for many years >:(

On the whole, it’s very well designed and a great API. But they made a brain-dead decision that castrates the API somewhat. They take the open-source/free-software programmers somewhat “interesting” approach to logging: you cannot “choose” what you want to log, you can only log “more” or “less”.

Anyone with experience of moderately complex projects is liable to quickly run into the brick wall “I want full debug info on methods X Y and Z of class X, but just normal info on the other methods, and Log4j will only let me do ‘all debug info on EVERYTHING’ or ‘normal info on EVERYTHING’”. It’s like someone giving you a hammer and forgetting to include the handle :(.

The problem is really just that every logging call in l4j has a “priority” which MUST BE an int. And…it REALLY MATTERS which int you choose for your priorities - you cannot select “sets” of ints to log or not log, you can only select “greater than 5” or “less than 3” etc.

This was done originally to achieve high-performance. This is a bit depressing, since there are group-membership tests that could be done with almost the same level of performance that would make the API a hundred times more useful.

I find it annoying and selfish that they make the entirely false claim that it has “arbitrarily fine granularity” since this is precisely what it DOESN’T have. There are plenty of other logging API’s around that are based on sets of priorities, or groups, or flags (e.g. bit-strings), instead of the stupid l4j decision to be based on a single int. (I’ve run into several in java, although I’m not sure which are free and which are not. We currently use one that is similar to l4j but fixes some of the problems…but it’s a lot slower :().

If you do want to choose, you (as programmer) have to manually write all the code to do it, and encode it into your application. If you are always working for the same company, you can just make a harness for this (takes a while, pain in the butt, but once it’s done doesn’t need much tweaking). But…it takes you no less time to do that than to build an entire logging API of your own :(. And many programmers simply can’t take code they write for one employer with them when they move to a next job :frowning: :(.

Even when you have the harness, unless you make it a really complex one with lots of reflection (nb: reflection is probably still expensive enough in terms of performance that it completely negates all the speed of l4j) you’re going to be writing 50+ lines of code in EVERY CLASS that is only there in order to coax l4j into working like a proper logging API.

Oh, there is another way - use “aspects” together with l4j. Aspect-oriented-programming is a whole mega-topic of it’s own, but it’s a very neat way of overcoming most of l4j’s shortcomings. Again, though, I suspect that by the time you’ve done that you’ll have so little of l4j left that you needn’t bother with the l4j parts.

Wow! thanks for replying I see it is a bigger topic than I had thought.

At the moment my uses are quite basic as I only really use java at home. So I guess that I could probably live with the linitations. I had a quick google and found a number of other options but I don’t really have the time to try time all out and compare them.

I had a very quick look at java.util.logging and it seemed quite similar to log4j, do you know if it suffers from similar problems? It’s just that as it is part of java it is, for me, a more attractive and maybe the bets option.

Cheers,
Dan.

[quote]So I guess that I could probably live with the linitations.
[/quote]
Yup. As I said, though the limitations are painful, the overall system is so good that it’s definitely worth using in the abscence of anything else.

It’s the same thing ;D. It’s a frozen-version of l4j, so you could go to the l4j website and get a more recent version if you really wanted. You may find extra features in the latest l4j version, or better performance - but probably also more bugs.

IIRC you can actually download l4j, drop it in the correct place in your Java installation, and java automatically goes “aha! That’s a newer version of one of those optional libraries I have built-in; I will use this newer version instead”. So, you can chop-and-change which version you are using without rewriting any code or recompiling. Look in the java API docs for the “authorised extension mechanism” or something like that (can’t remember the name…).

Thanks again.

I think I’ll probably give it a go. At least I’m aware of the limitation.

No wonder they looked the same :wink:

Cheers,
Dan.

I use the logger built in to the JRE, and one thing that is available in a log entry is the class and method that generated the log entry… so it seems it would be trivial to add a filter in a log handler that could choose to display or discard a log entry based on the method that made the log entry.

For FlyingGuns tries to keep download size as small as possible, I try to avoid 3rd party jars whereever I can. FG uses the buildin JRE logger and for now, it feels ok.

[quote]I use the logger built in to the JRE, and one thing that is available in a log entry is the class and method that generated the log entry… so it seems it would be trivial to add a filter in a log handler that could choose to display or discard a log entry based on the method that made the log entry.
[/quote]
What is that logger ?

Erm… is that actually correct or just based on a brief look at both APIs? Because I seem to recall – in the dim dark recesses of my rapidly deteriorating mind – there was some controversy around Sun’s decision over a logging api. Log4j had the largest community and what seemed to be the preferred API. Sun chose the other, I believe because it had been submitted to the JCP – although general commentary at the time suggested it was inferior.

Ancient history of course (here’s some related reading from 2001: http://lists.xml.org/archives/xml-dev/200109/msg00187.html), but still important to remember if you’re telling someone they can just chop and change, because there may be -some- significant differences because of that history.

Just my 2c.

I had read it somewhere, and then checked the API’s for confirmation.

Since I have no idea where I read it, it could well have been a misunderstanding that I’ve just attempted to spread :).

I have a vague memory that someone from Grex did actually check on this before, but perhaps they found out the APIs were different and I just forgot :(.

Looking at them in detail, java.util.logging does appear considerably different from what I recall of l4j and perhaps more feature-rich - e.g. IIRC l4j doesn’t do localization of logging messages? - but it certainly repeats the same brainded (IMHO) mistake of using a single-dimensional sliding scale of log messages, which frustrates me beyond the ability of words to express :(. It’s like…“let’s make a great logging API” followed by “let’s do something that makes it entirely unusable for any complex system”. You simply cannot force people to log on a single dimension, that’s no way near flexible enough, and yet you could easily do efficient log/no-log comparisons on set-inclusion for moderate sized sets.

(wonders how much the performance cost is for doing a bitwise-comparison and testing each log-call against a 32-bit int allowing 32 possible logging flags? Also wonders if this is any more expensive than the hard-coded int-compare?)

With regard to logger control for java.util.logging, I find that setting the logging level on a suitable subtree provides adequate control — I get the logging I need without being swamped with messages from other areas of the system. How well this works depends on how you name your loggers. If you want to be able to enable messages for somewhat arbitrary sets, why not have a named logger for each set. Then you can change the logging level on each set independently.

Usually I use logger names which correspond to the package or class name in which the messages originate, but this is just a convention.

Combined with method-tracing, that sounds like a trivial way to support sets, which makes me wonder why we never tried it (surely we can’t have simply not realised? Maybe no-one quite grokked the arbitrarily-named-loggers concept (which I too hadn’t fully appreciated until recently)).

So AIUI, you’re suggesting e.g. for a class “HelloWorld” in pkg “org.jgo” you could have loggers:

  • “org.jgo.HelloWorld.systemoutprinting”
  • “org.jgo.HelloWorld.staticmethods”
  • “org.jgo.HelloWorld.methodentryexit”
  • etc

Each of which is only used for specific types of logging messages, that are intermingled throughout the source.

Is there some reason why this doesn’t work? Are there any practical problems with having 1000+ loggers in your app? (with this method, we’d expect an average of 4-8 loggers per class) Howabout, for a large app, 5000 loggers?

AFAIK, ability to print out method name in log comes at great cost (they extract stack frame from exception or one of the security methods and then find the method name). Enabling it makes sure that logging will be only thing which shows up in profile top-ten - but at least you can make it super-fine-grained level and do not pay the cost in normal case. With any filter based on method names, log is sure to be major performance hog, as log will need to extract method name even if it is not logged.

There is a workaround - use AOP. AFAIK, you can easily add method names to every log call and will be done statically at compile time - and probably come up with any combination of static and dynamic rules for logging. But his is not a ‘pure’ java…

I use log4j at work and it works mostly acceptable - except few cases where one or two lines of log made perfomance hundred times worse (avoid logging inside inner loops of perfomance critical methods… seems obvious, you put it there only for testing and then forget to remove…).

Yeah, as I suggested above, AOP seems a particularly good tool for complex logging.

[quote]So AIUI, you’re suggesting e.g. for a class “HelloWorld” in pkg “org.jgo” you could have loggers:

  • “org.jgo.HelloWorld.systemoutprinting”
  • “org.jgo.HelloWorld.staticmethods”
  • “org.jgo.HelloWorld.methodentryexit”
  • etc
    [/quote]
    Exactly, although I would probably share loggers across groups of classes (within a package). I don’t think loggers are particularly expensive, roughly 100 bytes each depending on the length of the name and number of child loggers.

For large projects (think EJB based apps for a national bank) we typically create a logger for each class file, as a static final member. The logger’s name is the class’s fully qualified class name. Since classes are kept pretty small (for good design reasons), we’ve never needed per-method loggers. In the log4j.conf file, we then specify which class/priority levels we want logged. It’s pretty simple. I believe the java.util.logging stuff can do the same.

-Tab

[quote]For large projects (think EJB based apps for a national bank) we typically create a logger for each class file, as a static final member. The logger’s name is the class’s fully qualified class name. Since classes are kept pretty small (for good design reasons), we’ve never needed per-method loggers. In the log4j.conf file, we then specify which class/priority levels we want logged. It’s pretty simple. I believe the java.util.logging stuff can do the same.
[/quote]
Our need for multiple loggers per class is independent of class size; it’s to do with how complex the control flow / system changes that are passing through the class (e.g. a 300 line class could be something relatively simple on it’s own, but be link number 2 in a chain/pipeline of 12 classes that together provide an extremely complex system, and be re-used in 3 different ways by the other 11 classes … the type of info that has to be logged can vary enormously depending upon the other items in the chain, and most of this is stuff that has to be able to run at runtime with thousands of requests per minute without generating too much logfile-spam :)).

We had one case a few months before product release where an early-access licensee turned on almost all log messages (trying to track down a non-deterministic bug). Running a low-stress system test they filled up a 97% empty 60Gb hard disk within one day I think. (a case of “a bit too much information” :)).

I suspect that our systems are a lot more complex than a bank’s though. Banks can have upwards of 20 separate systems involved in a single transaction IIRC, but most of those systems are doing pretty straightforward stuff - it’s not like data-mining or something really nasty like that.

an interesting point blar*3 - I didn’t think of that before - but some way of logging only statements originating in a given method/class would be very nice.

My method is similar to previous posters, I just use a new logger when the need arises. For example with Odejava, the new XML stuff has it’s own logger which can be very verbose.

Will.