Back in December, I quietly released the DOMConfigurator module, adding
the ability to initialize log4perl via an XML file rather than a
properties config file. This lets you validate the config syntax
against a DTD, for instance using Xerces' "StdInParse -v -ns <
yourconfig.xml". That release supported the log4j dtd, at least where
the features had been implemented in log4perl.
But we've added config options in log4perl that log4j doesn't have:
#1) oneMessagePerAppender global setting
log4perl.oneMessagePerAppender=1
#2) globally defined user conversion specifiers
log4perl.PatternLayout.cspec.G=sub { return "UID $< GID $("; }
#3) appender-local custom conversion specifiers
log4j.appender.appndr1.layout.cspec.K = sub {return sprintf "%1x", $$ }
#4) nested options
log4j.appender.jabbender = Log::Dispatch::Jabber
#(note how these are nested under 'login')
log4j.appender.jabbender.login.hostname = a.jabber.server
log4j.appender.jabbender.login.port = 5222
log4j.appender.jabbender.login.username = bobjones
#5) not to mention Mike's new filter stuff!!
So we needed to extend the log4j dtd to cover these additions.
Now I could have just taken a 'steal this code' approach and mixed
parts of the log4j dtd into a log4perl dtd, but that would be
cut-n-paste programming. So I've used namespaces and
*) replaced three elements:
<log4perl:configuration> handles #1) and accepts <PatternLayout>
<log4perl:appender> accepts <param-nested> and <param-text>
<log4perl:layout> accepts custom cspecs for #3)
*) added a <param-nested> element (complementing the <param> element)
to handle #4)
*) added a root <PatternLayout> element to handle #2)
*) added <param-text> which lets you put things like perl code
into escaped CDATA between the tags, so you don't have to worry
about escaping characters and quotes
*) added <cspec>
In the name of code re-use the log4perl dtd links to the log4j dtd,
which I've named "log4j-1.2.dtd" to protect us from changes on
the log4j side.
The benefit of this approach over cut-n-paste is that it re-uses the
log4j dtd in situ. The drawback is that it requires an extra namespace
prefix in the config--if you want to use log4perl features in an
appender then you have to say <log4perl:appender...> instead of
just <appender...>. Though that could also be a benefit--if you're in
a situation where you're managing both log4j and log4perl configs (god
forbid!) it would help to keep them straight.
Now the parser I'm using, XML::DOM, isn't namespace aware, it's
only DOM Level 1. XML::GDOME, on the other hand, is DOM Level 2
(with namespaces) but depends on libgdome, a requirement which
sounds unecessarily cumbersome to me. So the namespace handling
in the parser is pretty primitive and it presumes log4perl is
the working prefix, as opposed to whatever prefix the URI is
bound to. But since DTD's aren't really namespace URI aware either
and a DTD is what's supplied to validate against, I don't see that
as a huge problem.
Attached for your convenience are
the log4perl dtd
the relevant parts of the log4j dtd
a sample xml config
The log4perl code in CVS is updated to handle all the new stuff.
I'd be interesting in hearing about anything that looks like bad
practice or not being flexible/scalable enough.
Thanks.
--
Happy Trails . . .
Kevin M. Goess
(and Anne and Frank)
904 Carmel Ave.
Albany, CA 94706
(510) 525-5217
|