Mixed Output Streams with Log4perl Screen Appender
•
Sun Feb 13 2022
(updated
Sat May 31 2025)
#perl
“Today’s latte, The Perl Foundation. 25!” by yukop

“Today’s latte, The Perl Foundation. 25!” by yukop

Log4perl provides a powerful framework for logging in Perl, based off the now infamous Log4j module. While it doesn’t support JNDI to execute remote code arbitrarily, it does just about anything else you could reasonably want it to.

Log4perl is a modular framework that allows you to append to many different sources, e.g. files, sockets, DBI, and of course, directly to the screen. While using the Log::Log4perl::Appender::Screen module in a project, I noticed it only supported printing either to STDOUT or to STDERR, whether that log message was FATAL or just INFO:

# Legacy - all levels to STDOUT
log4perl.appender.Screen.stderr = 0

# Legacy - all levels to STDERR
log4perl.appender.Screen.stderr = 1

Usually when logging, we reserve STDERR for actual errors and the rest goes to STDOUT. This is even more important when it comes to monitoring a script that logs with Log4perl. When running a script in CI/CD, any output to STDERR could cause a pipeline to fail. If Log4perl does not support mixed STDOUT/STDERR, we lose the ability to detect errors easily in CI/CD pipelines. Our debug or info statements could be interpreted as an error, or our errors could be ignored!

I created this PR to add that feature! We can now have a configuration like below, while still supporting legacy configurations from above:

# New - only ERROR and FATAL to STDERR, the rest to STDOUT
log4perl.appender.Screen.stderr.ERROR = 1
log4perl.appender.Screen.stderr.FATAL = 1

Adding that feature was as simple as below, Log::Log4perl::Appender::Screen::log:

my $fh = \*STDOUT;
if (ref $self->{stderr}) {
    $fh = \*STDERR if $self->{stderr}{ $params{'log4p_level'} }
                        || $self->{stderr}{ lc $params{'log4p_level'} };
} elsif ($self->{stderr}) {
    $fh = \*STDERR;
}

print $fh $params{message};

With this change, we would also get new test coverage for both the legacy methods of setting STDERR and the new method to support mixed output!

Update

This feature was merged into Log4perl June 1, 2022, in version 1.55.