The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


Log::Funlog - Log module with fun inside!


 use Log::Funlog;
        parameter => value,

 [$string=]my_sub($priority [,$string | @array [,$string | @array [, ... ] ]] );


This is a Perl module intended ton manage the logs you want to do from your Perl scripts.

It should be easy to use, and provide all the fonctionalities you want.

Just initialize the module, then use is as if it was an ordinary function!

When you want to log something, just write:

 your-sub-log(priority,"what"," I ","wanna log is: ",@an_array)

then the module will analyse if the priority if higher enough (seeing verbose option). If yes, your log will be written with the format you decided on STDERR (default) or a file.

As more, the module can write funny things to your logs, if you want ;) It can be very verbose, or just ... shy :)

Log::Funlog may export an 'error' function: it logs your message with a priority of 1 and with an specific (parametrable) string. You can use it when you want to highlight error messages in your logsi with a pattern.

Parameters are: header, error_header, cosmetic ,verbose, file, daemon, fun, colors, splash, -n, caller, ltype

verbose is mandatory.



In the form n/m, where n<m or n=max.

n is the wanted verbosity of your script, m if the maximum verbosity of your script.

n can by superior to m. It will just set n=m

Everything that is logged with a priority more than n (in case n is numeric) will not be logged.

0 if you do not want anything to be printed.

The common way to define n is to take it from the command line with Getopt:

 use Getopt::Long;
 use Log::Funlog;
        verbose => "$verbose/5",

In this case, you can say --verbose=max so that it will log with the max verbosity level available (5, here)

This option is backward compatible with 0.7.x.x versions.




'all' if you want the stack of subs.

'last' if you want the last call.

If you specify a number n, it will print the n last calls (yes, if you specify '1', it is equivalent to 'last')

If this number is negative, it will print the n first calls.

Of course, nothing will happen if no header is specified, nor %ss in the header ...


Put colors in the logs :)

If you just put '1', it will use default colors:

 colors => '1',

If you want to override default colors, specify a hash containing item => color

 colors => {'prog' => 'white', 'date' => 'yellow' },

Items are:

        caller: for the stack of calls,
        prog: for the name of the program,
        date: for the current date,
        level: for the log level,
        msg: for the log message

Colors are: black, red, green, yellow, blue, magenta, cyan, white and none


An alphanumeric char to indicate the log level in your logs.

There will be as many as these chars as the log level of the string being logged. See "EXAMPLE"

Should be something like 'x', or '*', or '!', or any printable single character.


1 if the script should be a daemon. (default is 0: not a daemon)

When daemon=1, Log::Funlog write to file instead of STDERR

If you specify daemon, you must specify file

The common way to do is the same that with verbose: with Getopt


Header you want to see in the logs when you call the error function (if you import it, of course)

Default is '## Oops! ##'.


File to write logs to.

MUST be specified if you specify daemon

File is opened when initializing, and never closed by the module. That is mainly to avoid open and close the file each time you log something and then increase speed.

Side effect is that if you tail -f the log file, you won't see them in real time.


Probability of fun in your logs.

Should be: 0<fun<=100

It use Log::Funlog::Lang

Pattern specifying the header of your logs.

The fields are made like this: %<letter><delimiters1><delimiters2><same_letter>

The letter is, for now:

        s: stack calls
        d: date
        p: name of the prog
        l: verbosity level

delimiters1 is something taken from +-=|!./\<{([ and delimiters2 is take from +-=|!./\>})] (replacement regexp is s/\%<letter>([<delimiters1>]*)([<delimiters2>*)<letter>/$1<field>$2/ ). delimiters1 will be put before the field once expanded, delimiters2 after.

Example: '%dd %p::p hey %l[]l %s{}s '

should produce something like:

 Wed Sep 22 18:50:34 2004 hey [x    ] {sub48} Something happened
 ^------this is %dd-----^ ^%p::p^      ^%l[]l^ ^%s{}s^

If no header is specified, no header will be written, and you would have:

 Something happened

Although you can specify a pattern like that: ' -{(%d(<>)d)}%p-<>-p %l-<()>-l '

is not advisable because the code that whatch for the header is not that smart and will probably won't do what you expect.

Putting things in %?? is good only for %ss because stack won't be printed if there is nothing to print: ' {%ss} '

will print something like that if you log from elsewhere than a sub: {}

Although ' %s{}s '

won't print anything if you log from outside a sub. Both will have the same effect if you log from inside a sub.

You should probably always write things like: ' -{((<%dd>))}-<%pp>- -<(%ll)>- '


Level printing type. Can be sequential or numeric.

sequential will print level like that: [xx ]. This is the default.

numeric will print level like that: [2]


1 if you want a 'splash log'


You can write stuff like that:


This will output something like:

 [x] plopplop

'-n' parameter allows you to use something else than '-n' to copy the behaviour of the '-n' parameter of echo(3)


Here is an example with almost all of the options enabled:

 $ vi
 #!/usr/bin/perl -w
 use Log::Funlog qw( error );
 *Log=new Log::Funlog(
                file => "zou.log",              #name of the file
                verbose => "3/5",                       #verbose 3 out of a maximum of 5
                daemon => 0,                    #I am not a daemon
                cosmetic => 'x',                #crosses for the level
                fun => 10,                      #10% of fun (que je passe autour de moi)
                error_header => 'Groumpf... ',  #Header for true errors
                header => '%dd %p[]p %l[]l %s{}s ',     #The header
                caller => 1);                   #and I want the name of the last sub

 Log(1,"I'm logged...");
 Log(3,"Me too...");
 Log(4,"Me not!");          #because 4>verbose
 sub ze_sub {


 $ perl
 Tue Jul 26 15:39:41 2005 [] [x    ]  I'm logged...
 Tue Jul 26 15:39:41 2005 [] [xxx  ]  Me too...
 Tue Jul 26 15:39:41 2005 [] [x    ] {ze_sub} Onetwo1C++
 Tue Jul 26 15:39:41 2005 [] [x    ] {ze_sub} Groumpf...  oups!
 Tue Jul 26 15:39:41 2005 [] [x    ]  Groumpf...  Zut




 header => '-(%dd)--( %p)><(p )-( %l)-<>-(l %s)<>(s '

won't do what you expect ( this is the ')><(' )

Workaround is:

 header => '-(%dd)--( )>%pp<( )-( %l)-<>-(l %s)<>(s '

And this kind of workaround work for everything but %ss, as it is not calculated during initialization.

  colors => 1,
  colors => {
         date => 'white'

Is not the same as:

  colors => {
         date => 'white'
  colors => 1,

First case will do what you expect, second case will put default colors.

To avoid that, specify EITHER colors => 1 OR colors => {<something>}


Log::Funlog::Lang > 0.3 : provide the funny messages.


As you can see, the 'new' routine return a pointer to a sub. It's the easiest way I found to make this package as easy as possible to use.

I guess that calling the sub each time you want to log something (and even if it won't print anything due to the too low level of the priority given) is not really fast...

Especially if you look at the code, and you see all the stuffs the module do before printing something.

But in fact, I tried to make it rather fast, that mean that if the module try to know as fast as possible if it will write something, and what to write

If you want a really fast routine of log, please propose me a way to do it, or do it yourself, or do not log :)

You can probably say:

 my Log::Funlog $log = new Log::Funlog;         # $log is now an Log::Funlog object. $log contain the address of the sub used to write.



But it is probably not convenient.


I'm doing quite a lot of Perl scripts, and I wanted the scripts talk to me. So I searched a log routine.

As I didn't found it on the web, and I wanted something more 'personnal' than syslog (I didn't want my script write to syslog), I started to write a very little routine, that I copied to all the scripts I made.

As I copied this routine, I added some stuff to match my needs; I wanted something rather fast, easy to use, easy to understand (even for me :P ), quite smart and ... a little bit funny :)

The I wrote this module, that I 'use Log::Funlog' in each of my scripts.


See Changelog


Gabriel Guillon, from Cashew team


(remove you-know-what :)


As Perl itself.

Let me know if you have added some features, or removed some bugs ;)