.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.48) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Config::LDAPConfigurator 3" .TH Config::LDAPConfigurator 3 2026-08-17 "perl v5.44.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .Vb 2 \& my $parser = $PARSER_CLASS\->new; \& my $doc = $parser\->parse (join(\*(Aq\*(Aq,@$text)); \& \& my $l4p_tree = {}; \& \& my $config = $doc\->getElementsByTagName("$LOG4J_PREFIX:configuration")\->item(0)|| \& $doc\->getElementsByTagName("$LOG4PERL_PREFIX:configuration")\->item(0); \& \& my $threshold = uc(subst($config\->getAttribute(\*(Aqthreshold\*(Aq))); \& if ($threshold) { \& $l4p_tree\->{threshold}{value} = $threshold; \& } \& \& if (subst($config\->getAttribute(\*(AqoneMessagePerAppender\*(Aq)) eq \*(Aqtrue\*(Aq) { \& $l4p_tree\->{oneMessagePerAppender}{value} = 1; \& } \& \& for my $kid ($config\->getChildNodes){ \& \& next unless $kid\->getNodeType == ELEMENT_NODE; \& \& my $tag_name = $kid\->getTagName; \& \& if ($tag_name =~ $APPENDER_TAG) { \& &parse_appender($l4p_tree, $kid); \& \& }elsif ($tag_name eq \*(Aqcategory\*(Aq || $tag_name eq \*(Aqlogger\*(Aq){ \& &parse_category($l4p_tree, $kid); \& #Treating them the same is not entirely accurate, \& #the dtd says \*(Aqlogger\*(Aq doesn\*(Aqt accept \& #a \*(Aqclass\*(Aq attribute while \*(Aqcategory\*(Aq does. \& #But that\*(Aqs ok, log4perl doesn\*(Aqt do anything with that attribute \& \& }elsif ($tag_name eq \*(Aqroot\*(Aq){ \& &parse_root($l4p_tree, $kid); \& \& }elsif ($tag_name =~ $FILTER_TAG){ \& #parse log4perl\*(Aqs chainable boolean filters \& &parse_l4p_filter($l4p_tree, $kid); \& \& }elsif ($tag_name eq \*(Aqrenderer\*(Aq){ \& warn "Log4perl: ignoring renderer tag in config, unimplemented"; \& #"log4j will render the content of the log message according to \& # user specified criteria. For example, if you frequently need \& # to log Oranges, an object type used in your current project, \& # then you can register an OrangeRenderer that will be invoked \& # whenever an orange needs to be logged. " \& \& }elsif ($tag_name eq \*(AqPatternLayout\*(Aq){#log4perl only \& &parse_patternlayout($l4p_tree, $kid); \& } \& } \& $doc\->dispose; \& \& return $l4p_tree; .Ve .PP } .PP #this is just for toplevel log4perl.PatternLayout tags #holding the custome cspecs sub parse_patternlayout { my ($l4p_tree, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my $l4p_branch = {}; \& \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& \& my $name = subst($child\->getAttribute(\*(Aqname\*(Aq)); \& my $value; \& \& foreach my $grandkid ($child\->getChildNodes){ \& if ($grandkid\->getNodeType == TEXT_NODE) { \& $value .= $grandkid\->getData; \& } \& } \& $value =~ s/^ +//; #just to make the unit tests pass \& $value =~ s/ +$//; \& $l4p_branch\->{$name}{value} = subst($value); \& } \& $l4p_tree\->{PatternLayout}{cspec} = $l4p_branch; \&} .Ve .PP #for parsing the root logger, if any sub parse_root { my ($l4p_tree, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my $l4p_branch = {}; \& \& &parse_children_of_logger_element($l4p_branch, $node); \& \& $l4p_tree\->{category}{value} = $l4p_branch\->{value}; .Ve .PP } .PP #this parses a custom log4perl\-specific filter set up under #the root element, as opposed to children of the appenders sub parse_l4p_filter { my ($l4p_tree, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my $l4p_branch = {}; \& \& my $name = subst($node\->getAttribute(\*(Aqname\*(Aq)); \& \& my $class = subst($node\->getAttribute(\*(Aqclass\*(Aq)); \& my $value = subst($node\->getAttribute(\*(Aqvalue\*(Aq)); \& \& if ($class && $value) { \& die "Log4perl: only one of class or value allowed, not both, " \& ."in XMLConfig filter \*(Aq$name\*(Aq"; \& }elsif ($class || $value){ \& $l4p_branch\->{value} = ($value || $class); \& \& } \& \& for my $child ($node\->getChildNodes) { \& \& if ($child\->getNodeType == ELEMENT_NODE){ \& \& my $tag_name = $child\->getTagName(); \& \& if ($tag_name =~ /^(param|param\-nested|param\-text)$/) { \& &parse_any_param($l4p_branch, $child); \& } \& }elsif ($child\->getNodeType == TEXT_NODE){ \& my $text = $child\->getData; \& next unless $text =~ /\eS/; \& if ($class && $value) { \& die "Log4perl: only one of class, value or PCDATA allowed, " \& ."in XMLConfig filter \*(Aq$name\*(Aq"; \& } \& $l4p_branch\->{value} .= subst($text); \& } \& } \& \& $l4p_tree\->{filter}{$name} = $l4p_branch; \&} .Ve .PP #for parsing a category/logger element sub parse_category { my ($l4p_tree, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my $name = subst($node\->getAttribute(\*(Aqname\*(Aq)); \& \& $l4p_tree\->{category} ||= {}; \& \& my $ptr = $l4p_tree\->{category}; \& \& for my $part (split /\e.|::/, $name) { \& $ptr\->{$part} = {} unless exists $ptr\->{$part}; \& $ptr = $ptr\->{$part}; \& } \& \& my $l4p_branch = $ptr; \& \& my $class = subst($node\->getAttribute(\*(Aqclass\*(Aq)); \& $class && \& $class ne \*(AqLog::Log4perl\*(Aq && \& $class ne \*(Aqorg.apache.log4j.Logger\*(Aq && \& warn "setting category $name to class $class ignored, only Log::Log4perl implemented"; \& \& #this is kind of funky, additivity has its own spot in the tree \& my $additivity = subst(subst($node\->getAttribute(\*(Aqadditivity\*(Aq))); \& if (length $additivity > 0) { \& $l4p_tree\->{additivity} ||= {}; \& my $add_ptr = $l4p_tree\->{additivity}; \& \& for my $part (split /\e.|::/, $name) { \& $add_ptr\->{$part} = {} unless exists $add_ptr\->{$part}; \& $add_ptr = $add_ptr\->{$part}; \& } \& $add_ptr\->{value} = &parse_boolean($additivity); \& } \& \& &parse_children_of_logger_element($l4p_branch, $node); \&} .Ve .PP # parses the children of a category element sub parse_children_of_logger_element { my ($l4p_branch, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my (@appenders, $priority); \& \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& \& my $tag_name = $child\->getTagName(); \& \& if ($tag_name eq \*(Aqparam\*(Aq) { \& my $name = subst($child\->getAttribute(\*(Aqname\*(Aq)); \& my $value = subst($child\->getAttribute(\*(Aqvalue\*(Aq)); \& if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)^/) { \& $value = uc $value; \& } \& $l4p_branch\->{$name} = {value => $value}; \& \& }elsif ($tag_name eq \*(Aqappender\-ref\*(Aq){ \& push @appenders, subst($child\->getAttribute(\*(Aqref\*(Aq)); \& \& }elsif ($tag_name eq \*(Aqlevel\*(Aq || $tag_name eq \*(Aqpriority\*(Aq){ \& $priority = &parse_level($child); \& } \& } \& $l4p_branch\->{value} = $priority.\*(Aq, \*(Aq.join(\*(Aq,\*(Aq, @appenders); \& \& return; \&} .Ve .PP sub parse_level { my \f(CW$node\fR = shift; .PP .Vb 1 \& my $level = uc (subst($node\->getAttribute(\*(Aqvalue\*(Aq))); \& \& die "Log4perl: invalid level in config: $level" \& unless Log::Log4perl::Level::is_valid($level); \& \& return $level; \&} .Ve .PP sub parse_appender { my ($l4p_tree, \f(CW$node\fR) = \f(CW@_\fR; .PP .Vb 1 \& my $name = subst($node\->getAttribute("name")); \& \& my $l4p_branch = {}; \& \& my $class = subst($node\->getAttribute("class")); \& \& $l4p_branch\->{value} = $class; \& \& print "looking at $name\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\en" if _INTERNAL_DEBUG; \& \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& \& my $tag_name = $child\->getTagName(); \& \& my $name = unlog4j(subst($child\->getAttribute(\*(Aqname\*(Aq))); \& \& if ($tag_name =~ /^(param|param\-nested|param\-text)$/) { \& \& &parse_any_param($l4p_branch, $child); \& \& my $value; \& \& }elsif ($tag_name =~ /($LOG4PERL_PREFIX:)?layout/){ \& $l4p_branch\->{layout} = parse_layout($child); \& \& }elsif ($tag_name =~ $FILTER_TAG){ \& $l4p_branch\->{Filter} = parse_filter($child); \& \& }elsif ($tag_name =~ $FILTER_REF_TAG){ \& $l4p_branch\->{Filter} = parse_filter_ref($child); \& \& }elsif ($tag_name eq \*(AqerrorHandler\*(Aq){ \& die "errorHandlers not supported yet"; \& \& }elsif ($tag_name eq \*(Aqappender\-ref\*(Aq){ \& #dtd: Appenders may also reference (or include) other appenders. \& #This feature in log4j is only for appenders who implement the \& #AppenderAttachable interface, and the only one that does that \& #is the AsyncAppender, which writes logs in a separate thread. \& #I don\*(Aqt see the need to support this on the perl side any \& #time soon. \-\-kg 3/2003 \& die "Log4perl: in config file, tag is unsupported in "; \& }else{ \& die "Log4perl: in config file, <$tag_name> is unsupported\en"; \& } \& } \& $l4p_tree\->{appender}{$name} = $l4p_branch; \&} .Ve .PP sub parse_any_param { my ($l4p_branch, \f(CW$child\fR) = \f(CW@_\fR; .PP .Vb 3 \& my $tag_name = $child\->getTagName(); \& my $name = subst($child\->getAttribute(\*(Aqname\*(Aq)); \& my $value; \& \& print "parse_any_param: <$tag_name name=$name\en" if _INTERNAL_DEBUG; \& \& # \& #note we don\*(Aqt set it to { value => $value } \& #and we don\*(Aqt test for multiple values \& if ($tag_name eq \*(Aqparam\-nested\*(Aq){ \& \& if ($l4p_branch\->{$name}){ \& die "Log4perl: in config file, multiple param\-nested tags for $name not supported"; \& } \& $l4p_branch\->{$name} = &parse_param_nested($child); \& \& return; \& \& # \& }elsif ($tag_name eq \*(Aqparam\*(Aq) { \& \& $value = subst($child\->getAttribute(\*(Aqvalue\*(Aq)); \& \& print "parse_param_nested: got param $name = $value\en" \& if _INTERNAL_DEBUG; \& \& if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)$/) { \& $value = uc $value; \& } \& \& if ($name !~ /warp_message|filter/ && \& $child\->getParentNode\->getAttribute(\*(Aqname\*(Aq) ne \*(Aqcspec\*(Aq) { \& $value = eval_if_perl($value); \& } \& # \& }elsif ($tag_name eq \*(Aqparam\-text\*(Aq){ \& \& foreach my $grandkid ($child\->getChildNodes){ \& if ($grandkid\->getNodeType == TEXT_NODE) { \& $value .= $grandkid\->getData; \& } \& } \& if ($name !~ /warp_message|filter/ && \& $child\->getParentNode\->getAttribute(\*(Aqname\*(Aq) ne \*(Aqcspec\*(Aq) { \& $value = eval_if_perl($value); \& } \& } \& \& $value = subst($value); \& \& #multiple values for the same param name \& if (defined $l4p_branch\->{$name}{value} ) { \& if (ref $l4p_branch\->{$name}{value} ne \*(AqARRAY\*(Aq){ \& my $temp = $l4p_branch\->{$name}{value}; \& $l4p_branch\->{$name}{value} = [$temp]; \& } \& push @{$l4p_branch\->{$name}{value}}, $value; \& }else{ \& $l4p_branch\->{$name} = {value => $value}; \& } \&} .Ve .PP #handles an appender\*(Aqs elements sub parse_param_nested { my ($node) = shift; .PP .Vb 1 \& my $l4p_branch = {}; \& \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& \& my $tag_name = $child\->getTagName(); \& \& if ($tag_name =~ /^param|param\-nested|param\-text$/) { \& &parse_any_param($l4p_branch, $child); \& } \& } \& \& return $l4p_branch; \&} .Ve .PP #this handles filters that are children of appenders, as opposed #to the custom filters that go under the root element sub parse_filter { my \f(CW$node\fR = shift; .PP .Vb 1 \& my $filter_tree = {}; \& \& my $class_name = subst($node\->getAttribute(\*(Aqclass\*(Aq)); \& \& $filter_tree\->{value} = $class_name; \& \& print "\etparsing filter on class $class_name\en" if _INTERNAL_DEBUG; \& \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& \& my $tag_name = $child\->getTagName(); \& \& if ($tag_name =~ \*(Aqparam|param\-nested|param\-text\*(Aq) { \& &parse_any_param($filter_tree, $child); \& \& }else{ \& die "Log4perl: don\*(Aqt know what to do with a ".$child\->getTagName() \& ."inside a filter element"; \& } \& } \& return $filter_tree; \&} .Ve .PP sub parse_filter_ref { my \f(CW$node\fR = shift; .PP .Vb 1 \& my $filter_tree = {}; \& \& my $filter_id = subst($node\->getAttribute(\*(Aqid\*(Aq)); \& \& $filter_tree\->{value} = $filter_id; \& \& return $filter_tree; \&} .Ve .PP sub parse_layout { my \f(CW$node\fR = shift; .PP .Vb 1 \& my $layout_tree = {}; \& \& my $class_name = subst($node\->getAttribute(\*(Aqclass\*(Aq)); \& \& $layout_tree\->{value} = $class_name; \& # \& print "\etparsing layout $class_name\en" if _INTERNAL_DEBUG; \& for my $child ($node\->getChildNodes) { \& next unless $child\->getNodeType == ELEMENT_NODE; \& if ($child\->getTagName() eq \*(Aqparam\*(Aq) { \& my $name = subst($child\->getAttribute(\*(Aqname\*(Aq)); \& my $value = subst($child\->getAttribute(\*(Aqvalue\*(Aq)); \& if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)$/) { \& $value = uc $value; \& } \& print "\etparse_layout: got param $name = $value\en" \& if _INTERNAL_DEBUG; \& $layout_tree\->{$name}{value} = $value; \& \& }elsif ($child\->getTagName() eq \*(Aqcspec\*(Aq) { \& my $name = subst($child\->getAttribute(\*(Aqname\*(Aq)); \& my $value; \& foreach my $grandkid ($child\->getChildNodes){ \& if ($grandkid\->getNodeType == TEXT_NODE) { \& $value .= $grandkid\->getData; \& } \& } \& $value =~ s/^ +//; \& $value =~ s/ +$//; \& $layout_tree\->{cspec}{$name}{value} = subst($value); \& } \& } \& return $layout_tree; \&} .Ve .PP sub parse_boolean { my \f(CW$a\fR = shift; .PP .Vb 8 \& if ($a eq \*(Aq0\*(Aq || lc $a eq \*(Aqfalse\*(Aq) { \& return \*(Aq0\*(Aq; \& }elsif ($a eq \*(Aq1\*(Aq || lc $a eq \*(Aqtrue\*(Aq){ \& return \*(Aq1\*(Aq; \& }else{ \& return $a; #probably an error, punt \& } \&} .Ve .SH NAME Log::Log4perl::Config::LDAPConfigurator \- configures log4perl via LDAP .SH SYNOPSIS .IX Header "SYNOPSIS" .SH DESCRIPTION .IX Header "DESCRIPTION" This module implements .SH WHY .IX Header "WHY" .SH HOW .IX Header "HOW" .SH "VARIABLE SUBSTITUTION" .IX Header "VARIABLE SUBSTITUTION" ??? .PP This supports variable substitution like \f(CW\*(C`${foobar}\*(C'\fR in text and in attribute values except for appender\-ref. If an environment variable is defined for that name, its value is substituted. So you can do stuff like .PP .Vb 2 \& \& ${currentsysadmin}@foo.com .Ve .SH REQUIRES .IX Header "REQUIRES" .SH CAVEATS .IX Header "CAVEATS" .SH CHANGES .IX Header "CHANGES" 0.01 2004\-05\-12 initial version .SH "SEE ALSO" .IX Header "SEE ALSO" t/047\-ldap.t .PP ldap/log4perl.schema DEBUG .PP Log::Log4perl::Config .SH LICENSE .IX Header "LICENSE" Copyright 2002\-2026 by Mike Schilli and Kevin Goess . .PP This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.