Tom Gracey
and 1 contributors

NAME

Log::Log4perl::Layout::ColoredPatternLayout - multicolor log messages

SYNOPSIS

    # in the logger config:

    log4j.appender.appndr1.layout.ColorMap = sub{
        return {
            d => 'blue on_white',
            m => 'blue',
            p => sub { 
                my $colors = {
                    trace => "green",
                    debug => "bold green",
                    info => "white",
                    warn => "yellow",
                    error => "red",
                    fatal => "bold red"
                };
                return +$colors->{ lc($_[0]) };
            }
        };
    }

    log4j.appender.appndr1.layout.ConversionPattern
        = '%d %-5p: %m%n'


    # .. and log as usual in your code

    $logger->debug("A debug message");

    # Logs a debug message with the following colors:
    #
    # 2018-05-02 12:22:16 DEBUG A debug message
    #
    # ^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^  
    #         1             2          3
    #
    # 1 = blue on_white
    # 2 = bold green
    # 3 = blue    


    $logger->info("An info message");

    # Logs an info message with the following colors:
    #
    # 2018-05-02 12:22:16 INFO  An info message
    #
    # ^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^  
    #         1             2          3
    #
    # 1 = blue on_white
    # 2 = white
    # 3 = blue

    

DESCRIPTION

There's no doubt Log::Log4perl is a fantastic logging system. It's a great weight off ones mind not having to worry (much!) about logging since Log::Log4perl seems to pretty much cover every eventuality and is very well battletested.

An appender does exist which can colorise the whole message based on its log level (Log::Log4perl::Appender::ScreenColoredLevel). However, I wanted to colorise individual parts of a message, rather than the whole thing. It can be easier on the eye, and save screen space by reducing the need for separators.

I started with the assumpion that I could do this in a similar way to <Log::Log4perl::Appender::ScreenColoredLevel> - ie by creating an appender. However, unfortunately the log sub only appears to get handed the final formatted message, rather than the message components. There doesn't seem to be any way to access this information from the inherited class.

So instead this module inherits from Log::Log4perl::Layout::PatternLayout in order to solve the conundrum. It can be used as a replacement for Log::Log4perl::Layout::PatternLayout - but remember it only makes sense with screen type appenders (otherwise ANSI color characters will be written to places where they shouldn't be).

USAGE

Usage is straightforward. Declare a color map in your config - basically a hash which maps formatting codes (%p, %d, etc.) to ansi colors. (See Term::ANSIColor for valid color values). See the synopsis for an example.

A value in the color map can be a simple string green, bold blue etc. - or a sub that returns a string

    log4j.appender.appndr1.layout.ColorMap = sub {
        return {
            p => 'blue',    # simple string

            F => sub {      # sub returning simple string

                my ($filename) = @_;
            
                my $color = $filename = 'important.file'?'red':'white'
            
                return $color;
            }

        };    
    };

In this example if the filename where the logging event occurs (corrsponding to %F) happens to be important.file then this will get printed to the terminal in red, while other filenames will be plain white.

color map subs get passed a single parameter, containing the value of the variable corresponding to the formatting code which you can use to determine the output color (e.g. DEBUG, INFO for %p, a date for <%d> etc).

CAVEATS

  1. As mentioned previously, this is for screen output only. Use Log::Log4perl::Layout::PatternLayout for anything else.

  2. You can only colorise parts of the string corresponding to a formatting code. e.g. if your formatting string is:

        log4j.appender.appndr1.layout.ConversionPattern
            = '[%d] %-5p: %m%n'

    then there is no way to colorise those square brackets. Sorry! However, perhaps with color the brackets are not necessary?

  3. This won't work with Log::Log4perl::Appender::ScreenColoredLevel

  4. I'm not entirely comfortable with the fact this inherits from Log::Log4perl::Layout::PatternLayout, and less comfortable still that it overrides new and another big subroutine render just to make minor changes. Unfortunately this seems necessary because those subs are large and the required info is buried somewhere in the middle. Thus an update to Log::Log4perl::Layout::PatternLayout has the potential to break this module. Should this happen I will attempt to review the method in general and fix where possible. But no guarantees.

    Of course if <Log::Log4perl::Appender> does get modified so it receives more information at some point in the future, then this module may not be necessary.

SEE ALSO

Log::Log4perl Log::Log4perl::Appender::Screen Log::Log4perl::Appender::ScreenColoredLevel Log::Log4perl::Layout Log::Log4perl::Layout::PatternLayout Log::Log4perl::Layout::SimpleLayout Term::ANSIColor

AUTHOR

Tom Gracey <tomgracey@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2017 by Tom Gracey

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.