Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

log4j - outputting header twice for RollingFileAppender

897 views
Skip to first unread message

crazy fo sheezy

unread,
Nov 10, 2009, 3:56:02 PM11/10/09
to
Hi. I have a RollingFileAppender where I’ve created a custom layout.
And, in the custom layout, all I’m doing is adding a header row to my
log file (see below).

public class NoMatchingTranscriptPatternLayout extends PatternLayout {

public NoMatchingTranscriptPatternLayout() {
super();
}

public String getHeader() {
return (new String("Date of Download\tPdf\n"));
}
}

Now, I have a job that’s scheduled to run on a daily basis so the log
files get updated daily. However, when the log file gets updated, the
header gets outputted to the log file each time the job is run. I
have log4j version 1.2.15. Is this a bug? Shouldn’t the header only
get generated if the file is new? Please advise.

Thanks

Noel

unread,
Nov 11, 2009, 12:47:52 PM11/11/09
to
On Nov 10, 12:56 pm, crazy fo sheezy <brendan.w...@gmail.com> wrote:
> Hi.  I have a RollingFileAppender where I’ve created a custom layout.
> [...]

> Now, I have a job that’s scheduled to run on a daily basis so the log
> files get updated daily.  However, when the log file gets updated, the
> header gets outputted to the log file each time the job is run.  I
> have log4j version 1.2.15.  Is this a bug?  Shouldn’t the header only
> get generated if the file is new?  Please advise.

Are you instantiating a new RollingFileAppender every time the program
runs (e.g., the program itself is re-instantiated for every
execution) ?

A RollingFileAppender / FileAppender will write out the header string
to its file every time it is instantiated.

crazy fo sheezy

unread,
Nov 11, 2009, 9:17:39 PM11/11/09
to
I'm not sure if a new one gets instantiated each time the program gets
run. I know for sure I'm not manually instantiating it because all of
the configuration is in a properties file.

So, how do people get around this problem? In the getHeader() method,
are you checking to see if the log already exists and then returning
null if it does?

Noel

unread,
Nov 12, 2009, 12:51:42 AM11/12/09
to
crazy fo sheezy wrote:
> I'm not sure if a new one gets instantiated each time the program gets
> run. I know for sure I'm not manually instantiating it because all of
> the configuration is in a properties file.

You may have a log4j configuration file that parametrizes your appender
instantiation, but until something creates your Logger via
Logger.getLogger method calls, your appender/layout isn't instantiated.

So, either your application is in fact itself instantiating its logger,
or it's being hosted by an application server/container that's doing
dependency injection for you.

> So, how do people get around this problem? In the getHeader() method,
> are you checking to see if the log already exists and then returning
> null if it does?

Barring hard-coded log file locations, your Layout implementation does
not have enough information to be able to achieve this computation.

It's not a problem that I've seen software bother to "get around." Take
an application server with file size-based log rollover, and restart it
several times, and you'll get multiple headers in the same log file.

If you must have a log file rollover system that outputs the header only
once per file, and you can't deploy your application as a long-lived
process (or configure whatever app container is hosting it to make your
logger object long-lived), then I think you're going to have to subclass
RollingFileAppender.

... well, or, do a manual rollover after your program does its work.

----- code sketch -----
*** log4j.properties: ***
log4j.logger.Foo=ALL, MyAppender
log4j.appender.MyAppender=org.apache.log4j.RollingFileAppender
log4j.appender.MyAppender.layout=bar.foo.NoMatchingTranscriptPatternLayout
log4j.appender.MyAppender.append=false
log4j.appender.MyAppender.maxBackupIndex=5
log4j.appender.MyAppender.file=Foo.log

*** your program: ***
import org.apache.log4j.Appender;
import org.apache.log4j.Logger;

// do work
Logger logger = ...;
...
Appender appender = logger.getAppender("MyAppender");

if (appender != null && appender instanceof RollingFileAppender) {
((RollingFileAppender) appender).rollOver();
}
----- code sketch -----

The problem with this workaround is that the most recent non-empty log
will be Foo.log.1. Foo.log will always be empty.

If you do the rollover *before* your program performs its work, the
least recent log file will always be empty.

crazy fo sheezy

unread,
Nov 12, 2009, 3:22:44 PM11/12/09
to
I took the route of subclassing RollingFileAppender, like you had
said. And, it seems to work:

public class MyAppender extends RollingFileAppender {

protected void writeHeader() {
File f = new File(getFile());
if (f.length() == 0) {
//System.out.println("size of log file = " + f.length());
qw.write(getLayout().getHeader());
} else
System.out.println("log file already exists");

}
}

Thanks for the suggestion!

0 new messages