File Coverage

blib/lib/Log/Funlog.pm
Criterion Covered Total %
statement 139 170 81.7
branch 62 112 55.3
condition 17 36 47.2
subroutine 13 13 100.0
pod 0 5 0.0
total 231 336 68.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Log::Funlog - Log module with fun inside!
4              
5             =head1 SYNOPSIS
6              
7             use Log::Funlog;
8             *my_sub=Log::Funlog->new(
9             parameter => value,
10             ...
11             );
12              
13             [$string=]my_sub($priority [,$string | @array [,$string | @array [, ... ] ]] );
14              
15             =head1 DESCRIPTION
16              
17             This is a Perl module intended ton manage the logs you want to do from your Perl scripts.
18              
19             It should be easy to use, and provide all the fonctionalities you want.
20              
21             Just initialize the module, then use is as if it was an ordinary function!
22              
23             When you want to log something, just write:
24              
25             your-sub-log(priority,"what"," I ","wanna log is: ",@an_array)
26              
27             then the module will analyse if the priority if higher enough (seeing L option). If yes, your log will be written with the format you decided on STDERR (default) or a file.
28              
29             As more, the module can write funny things to your logs, if you want ;) It can be very verbose, or just ... shy :)
30              
31             L 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.
32              
33             Parameters are: L
, L, L ,L, L, L, L, L, L, L<-n>, L, L
34              
35             L is mandatory.
36              
37             =head2 MANDATORY OPTION
38              
39             =over
40              
41             =item B
42              
43             In the form B/B, where B or B=max.
44              
45             B is the wanted verbosity of your script, B if the maximum verbosity of your script.
46              
47             B can by superior to B. It will just set B=B
48              
49             Everything that is logged with a priority more than B (in case B is numeric) will not be logged.
50              
51             0 if you do not want anything to be printed.
52              
53             The common way to define B is to take it from the command line with Getopt:
54              
55             use Getopt::Long;
56             use Log::Funlog;
57             &GetOptions("verbose=s",\$verbose);
58             *Log=Log::Funlog->new(
59             [...]
60             verbose => "$verbose/5",
61             [...]
62             )
63              
64             In this case, you can say --verbose=max so that it will log with the max verbosity level available (5, here)
65              
66             This option is backward compatible with 0.7.x.x versions.
67              
68             See L
69              
70             =back
71              
72             =head2 NON MANDATORIES OPTIONS
73              
74             =over
75              
76             =item B
77              
78             'all' if you want the stack of subs.
79              
80             'last' if you want the last call.
81              
82             If you specify a number B, it will print the B last calls (yes, if you specify '1', it is equivalent to 'last')
83              
84             If this number is negative, it will print the B first calls.
85              
86             Of course, nothing will happen if no L
is specified, nor %ss in the L
...
87              
88             =item B
89              
90             Put colors in the logs :)
91              
92             If you just put '1', it will use default colors:
93              
94             colors => '1',
95              
96             If you want to override default colors, specify a hash containing item => color
97              
98             colors => {'prog' => 'white', 'date' => 'yellow' },
99              
100             Items are:
101              
102             caller: for the stack of calls,
103             prog: for the name of the program,
104             date: for the current date,
105             level: for the log level,
106             msg: for the log message
107              
108             Colors are:
109             black, red, green, yellow, blue, magenta, cyan, white and none
110              
111             =item B
112              
113             An alphanumeric char to indicate the log level in your logs.
114              
115             There will be as many as these chars as the log level of the string being logged. See L
116              
117             Should be something like 'x', or '*', or '!', or any printable single character.
118              
119             =item B
120              
121             1 if the script should be a daemon. (default is 0: not a daemon)
122              
123             When B=1, L write to L instead of B
124              
125             If you specify B, you must specify L
126              
127             The common way to do is the same that with L: with Getopt
128              
129             =item B
130              
131             Header you want to see in the logs when you call the B function (if you import it, of course)
132              
133             Default is '## Oops! ##'.
134              
135             =item B
136              
137             File to write logs to.
138              
139             MUST be specified if you specify L
140              
141             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.
142              
143             Side effect is that if you tail -f the log file, you won't see them in real time.
144              
145             =item B
146              
147             Probability of fun in your logs.
148              
149             Should be: 0
150              
151             It use Log::Funlog::Lang
152              
153             =item B
154              
155             Pattern specifying the header of your logs.
156              
157             The fields are made like this: %>>>>
158              
159             The B is, for now:
160              
161             s: stack calls
162             d: date
163             p: name of the prog
164             l: verbosity level
165              
166             B is something taken from +-=|!./\<{([ and B is take from +-=|!./\>})] (replacement regexp is s/\%([]*)([*)/$1$2/ ). B will be put before the field once expanded, B after.
167              
168             Example:
169             '%dd %p::p hey %l[]l %s{}s '
170              
171             should produce something like:
172              
173             Wed Sep 22 18:50:34 2004 :gna.pl: hey [x ] {sub48} Something happened
174             ^------this is %dd-----^ ^%p::p^ ^%l[]l^ ^%s{}s^
175              
176             If no header is specified, no header will be written, and you would have:
177              
178             Something happened
179              
180             Although you can specify a pattern like that:
181             ' -{(%d(<>)d)}%p-<>-p %l-<()>-l '
182              
183             is not advisable because the code that whatch for the header is not that smart and will probably won't do what you expect.
184              
185             Putting things in %?? is good only for %ss because stack won't be printed if there is nothing to print:
186             ' {%ss} '
187              
188             will print something like that if you log from elsewhere than a sub:
189             {}
190              
191             Although
192             ' %s{}s '
193              
194             won't print anything if you log from outside a sub. Both will have the same effect if you log from inside a sub.
195              
196             You should probably always write things like:
197             ' -{((<%dd>))}-<%pp>- -<(%ll)>- '
198              
199             =item B
200              
201             Level printing type. Can be B or B.
202              
203             B will print level like that: [xx ]. This is the default.
204              
205             B will print level like that: [2]
206              
207             =item B
208              
209             1 if you want a 'splash log'
210              
211             =item B<-n>
212              
213             You can write stuff like that:
214              
215             Log(1,'-n',"plop");
216             Log(1,"plop");
217              
218             This will output something like:
219              
220             [x] plopplop
221              
222             '-n' parameter allows you to use something else than '-n' to copy the behaviour of the '-n' parameter of L
223              
224             =back
225              
226             =cut
227              
228             package Log::Funlog;
229 2     2   60604 use Carp;
  2         6  
  2         269  
230 2     2   12 use strict;
  2         3  
  2         64  
231 2     2   10 use File::Basename;
  2         8  
  2         238  
232              
233             BEGIN {
234 2     2   16 use Exporter;
  2         4  
  2         530  
235 2     2   5 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK );
236 2         45 @ISA=qw(Exporter);
237 2         4 @EXPORT=qw( );
238 2         6 @EXPORT_OK=qw( &error $VERBOSE $LEVELMAX $VERSION );
239 2         204 $VERSION='0.87';
240             sub VERSION {
241 2     2 0 241 (my $me, my $askedver)=@_;
242 2         6 $VERSION=~s/(.*)_\d+/$1/;
243 2 50       154 croak "Please update: $me is version $VERSION and you asked version $askedver" if ($VERSION < $askedver);
244             }
245             }
246             my @fun;
247             our %args;
248 2     2   1403 eval 'use Log::Funlog::Lang 0.3';
  0         0  
  0         0  
249             if ($@) {
250             @fun=();
251             } else {
252             @fun=@{ (Log::Funlog::Lang->new())[1] };
253             }
254             #use Sys::Syslog;
255             my $count=0;
256 2     2   12 use vars qw( %args $me $error_header $error $metaheader);
  2         3  
  2         2165  
257              
258             # Defined here, used later!
259             #####################################
260             my $rexpleft=q/<>{}()[]/; #Regular expression that are supposed to be on the left of the thing to print
261             my $rexprite=$rexpleft;
262             $rexprite=~tr/><}{)(][/<>{}()[]/; #tr same for right
263             my $rexpsym=q'+-=|!.\/'; #These can by anywhere (left or right)
264             $rexpleft=quotemeta $rexpleft;
265             $rexprite=quotemeta $rexprite;
266             $rexpsym=quotemeta $rexpsym;
267             my $level;
268             my $LOCK_SH=1;
269             my $LOCK_EX=2;
270             my $LOCK_NB=4;
271             my $LOCK_UN=8;
272             my $handleout; #Handle of the output
273             my %whattoprint;
274             my %colortable=(
275             'black' => "\e[30;1m",
276             'red' => "\e[31;1m",
277             'green' => "\e[32;1m",
278             'yellow' => "\e[33;1m",
279             'blue' => "\e[34;1m",
280             'magenta' => "\e[35;1m",
281             'cyan' => "\e[36;1m",
282             'white' => "\e[37;1m",
283             'none' => "\e[0m"
284             );
285             my %defaultcolors=(
286             'level' => $colortable{'red'},
287             'caller' => $colortable{'none'},
288             'date' => $colortable{'none'},
289             'prog' => $colortable{'magenta'},
290             'msg' => $colortable{'yellow'}
291             );
292             my @authorized_level_types=('numeric','sequential'); #Level types
293             my %colors; #will contain the printed colors. It is the same than %defaultcolors, but probably different :)
294             our $hadnocr=0; #Remember if previous call had $nocr (to print header at first call with $nocr, but not further)
295              
296             ################################################################################################################################
297             sub replace { #replace things like %l<-->l by things like <-** ->
298 26     26 0 35 my $header=shift;
299 26         29 my $what=shift;
300 26         27 my $center=shift;
301 26 100       39 if ($center) {
302 21         111 $header=~s/\%$what$what/$center/; # for cases like %dd
303             #
304             # Now, for complicated cases like %d<-->d or %d-<>-d
305             #
306 21         316 $header=~s/\%$what(.*[$rexpleft]+)([$rexprite]+.*)$what/$1$center$2/; #%d-<>-d -> --
307             #%d<-->d -> <-->
308 21         310 $header=~s/\%$what(.*[$rexpsym]+)([$rexpsym]+.*)$what/$1$center$2/; #-- -> --
309             #<--> -> <-plop->
310             } else {
311 5         43 $header=~s/\%$what.*$what//;
312             }
313 26         119 return $header;
314             }
315             ################################################################################################################################
316             ################################################################################################################################
317             sub new {
318 13     13 0 641 my $this = shift;
319 13   33     75 my $class = ref($this) || $this;
320 13         73 %args=@_; #getting args to a hash
321              
322              
323             # Okay, now sanity checking!
324             # This is cool because we have time, so we can do all kind of checking, calculating, things like that
325             #########################################
326 13 100 100     66 if (defined $args{daemon} and $args{daemon}) {
327 3 100       201 croak 'You want me to be a daemon, but you didn\'t specifie a file to log to...' unless (defined $args{file});
328             }
329 12 100       337 croak "'verbose' option is mandatory." if (! $args{'verbose'});
330 11 100 66     260 croak "'verbose' should be of the form n/m or max/m" if (($args{'verbose'} !~ /^\d+\/\d+$/) and ($args{'verbose'} !~ /^[mM][aA][xX]\/\d+$/));
331              
332             # Parsing 'ltype' option
333             #########################################
334 10 50       57 if (defined $args{ltype}) {
335 0 0       0 if (! grep(/$args{ltype}/,@authorized_level_types)) {
336 0         0 croak "Unknow ltype '$args{ltype}'";
337             }
338             } else {
339 10         31 $args{ltype}='sequential';
340             }
341              
342             # Parsing 'verbose' option...
343             #########################################
344 10         53 my ($verbose,$levelmax)=split('/',$args{verbose});
345 10 50       23 $levelmax=$levelmax ? $levelmax : ""; #in case it is not defined...
346 10 100       30 $verbose=$levelmax if ($verbose =~ /^[mM][aA][xX]$/);
347 10 50 33     94 if (($verbose !~ /\d+/) or ($levelmax !~ /\d+/)) {
348 0         0 carp "Arguments in 'verbose' should be of the form n/m, where n and m are numerics.\nAs this is a new feature, I'll assume you didn't upgraded your script so I'll make it compatible...\nAnyhow, consider upgrading soon!\n";
349 0 0       0 croak "No 'levelmax' provided" unless ($args{levelmax});
350             } else {
351 10         24 $args{verbose}=$verbose;
352 10         20 $args{levelmax}=$levelmax;
353             }
354 10 50       84 if ($args{verbose} > $args{levelmax}) {
355 0         0 carp "You ask verbose $args{verbose} and the max is $args{levelmax}. I set your verbose at $args{levelmax}.\n";
356 0         0 $args{verbose}=$args{levelmax};
357             }
358              
359              
360             # Time for fun!
361             #########################################
362 10 50       30 if (defined $args{fun}) {
363 0 0       0 croak "'fun' should only be a number (between 0 and 100, bounds excluded)." if ($args{fun} !~ /^\d+$/);
364 0 0 0     0 croak "0100 or $args{fun}<=0);
365 0 0       0 croak "You want fun but Log::Funlog::Lang is not available, or is too old." if ($#fun <= 0);
366             }
367              
368             # Colors
369             #########################################
370             #We will build %colors here.
371             #If color is wanted:
372             # if default is wanted, %colors = %defaultcolors
373             # if not, %colors = %defaultcolors, overriden by the parameters provided
374             #If no colors is wanted, %colors will be filled with the 'none' colors.
375             #
376             #This way of doing should be quicker :)
377             #
378 10 100 66     41 if (exists $args{'colors'} and $args{'colors'} ) { #If color is wanted
379 2     2   13 use Config;
  2         3  
  2         4108  
380 3 50       42 if ($Config{'osname'} eq 'MSWin32') { #Oh oh!
381 0         0 carp 'Colors wanted, but MSwin detected. Colors deactivated (because not implemented yet)';
382 0         0 delete $args{'colors'};
383 0         0 $colortable{'none'}=''; #putting 'none' color to void
384 0         0 foreach my $color (keys %defaultcolors) {
385 0         0 $colors{$color}=$colortable{'none'}; #and propagating it
386             }
387             # no Config;
388             } else { #We are not in MSWin...
389 3 100       18 if (ref(\$args{'colors'}) eq 'SCALAR') { #default colors?
    100          
390 1 50       10 %colors=%defaultcolors if ($args{'colors'});
391             } elsif(ref($args{'colors'}) eq 'HASH') { #No... Overridden colors :)
392 1         4 foreach my $item (keys %defaultcolors) {
393 5         18 $colors{$item}=exists ${ #If the color is provided
394             $args{'colors'}
395             }{$item}?
396             $colortable{
397 3         8 ${
398 5 100       6 $args{'colors'} #we take it
399             }{$item}
400             }:$defaultcolors{$item}; #if not, we take the default one
401             }
402             } else {
403 1         207 croak("'colors' must be type of SCALAR or HASH, not ".ref($args{'colors'})."\n");
404             }
405             }
406             } else { #no colors? so the color table will contain the color 'none'
407 7         18 $colortable{'none'}=''; #Avoid printing "\e[0m" :)
408 7         37 foreach my $item (keys %defaultcolors) {
409 35         68 $colors{$item}=$colortable{'none'};
410             }
411             }
412              
413              
414             # Error handler
415             #########################################
416 9 50       42 $error_header=defined $args{error_header} ? $args{error_header} : '## Oops! ##';
417              
418             # We define default cosmetic if no one was defined
419             #########################################
420 9 100       38 if (not defined $args{cosmetic}) {
    100          
421 5         14 $args{'cosmetic'}='x';
422             } elsif ($args{'cosmetic'} !~ /^[[:^cntrl:]]$/) {
423 3         567 croak("'cosmetic' must be one character long, and printable.");
424             }
425              
426             # Parsing header. Goal is to avoid work in the wr() function
427             #########################################
428 6 100       12 if (defined $args{header}) {
429              
430 1         3 $metaheader=$args{header};
431              
432             # if %ll is present, we can be sure that it will always be, but it will vary so we replace by a variable
433 1 50       8 if ($metaheader=~/\%l.*l/) {
434 1         2 $whattoprint{'l'}=1;
435 1         4 $metaheader=replace($metaheader,"l","\$level");
436             }
437              
438             # same for %dd
439 1 50       8 $whattoprint{'d'}=1 if ($metaheader=~/\%d.*d/);
440 1         5 $metaheader=replace($metaheader,"d",$colors{'date'}."\$date".$colortable{'none'});
441              
442             # but %pp won't vary
443 1         69 $me=basename("$0");
444 1         4 chomp $me;
445 1 50       7 $whattoprint{'p'}=1 if ($metaheader=~/\%p.*p/);
446 1         5 $metaheader=replace($metaheader,"p",$colors{'prog'}.$me.$colortable{'none'});
447             # and stack will be present or not, depending of the state of the stack
448 1 50       7 $whattoprint{'s'}=1 if ($metaheader=~/\%s.*s/);
449              
450 1 50 33     7 if ((! defined $args{'caller'}) and ($metaheader=~/\%s.*s/)) {
451 0         0 carp "\%ss is defined but 'caller' option is not specified.\nI assume 'caller => 1'";
452 0         0 $args{'caller'}=1;
453             }
454             } else {
455 5         12 $metaheader="";
456             }
457              
458             # Daemon. We calculate here the output handle to use
459             ##########################################
460 6 100       18 if ($args{'daemon'}) {
461 2 50       214 open($handleout,">>$args{'file'}") or croak "$!";
462             } else {
463 4         603 $handleout=\*STDERR;
464             }
465             # -n handling
466             ##########################################
467 6 50       26 $args{'-n'}='-n' unless $args{'-n'};
468              
469             ##########################################
470             # End of parsing
471             ##########################################
472              
473 6         13 my $self = \≀
474 6         43 bless $self, $class; #The function's address is now a Log::Funlog object
475             # return $self; #Return the function's address, that is an object Log::Funlog
476             }
477              
478             ########################################################################################
479             ########################################################################################
480             # This is the main function
481             ########################################################################################
482             ########################################################################################
483             sub wr {
484 25     25 0 7910 my $level=shift; #log level wanted by the user
485 25 100 66     137 return if ($level > $args{verbose} or $level == 0); #and exit if it is greater than the verbosity
486              
487 24         61 my $prevhandle=select $handleout;
488              
489 24         74 my $return_code;
490             my $nocr;
491              
492             # Header building!!
493             #####################################
494 24 50       55 if ($_[0] eq $args{'-n'}) {
495 0         0 shift;
496 0         0 $nocr=1;
497             } else {
498 24         37 $nocr=0;
499             };
500 24 100 66     96 if ($metaheader and not $hadnocr) { #Hey hey! Won't calculate anything if there is nothing to print!
501 23         36 my $header=$metaheader;
502 23 50       46 if ($whattoprint{'s'}) { #if the user want to print the call stack
503 23         21 my $caller;
504 23 50 33     101 if (($args{'caller'} =~ /^last$/) or ($args{'caller'} =~ /^1$/)) {
505 0 0       0 $caller=(caller($error?2:1))[3];
506             } else { #okay... I will have to unstack all the calls to an array...
507 23         23 my @stack;
508 23         26 my $i=1;
509 23 100       137 while (my $tmp=(caller($error?$i+1:$i))[3]) { #turn as long as there is something on the stack
510 36         53 push @stack,($tmp);
511 36         166 $i++;
512             };
513 23         29 @stack=reverse @stack;
514 23 50       45 if ($args{'caller'} eq "all") {; #all the calls
515 23         63 $caller=join(':',@stack);
516             } else {
517 0 0       0 if ($#stack >= 0) {
518 0         0 my $num=$args{'caller'};
519 0 0       0 $num=$#stack if ($num>=$#stack); #in case the stack is greater that the number of call we want to print
520 0 0       0 if ($args{'caller'} eq "all") { #all the cals
    0          
    0          
521 0         0 $caller=join(':',@stack);
522             } elsif ($args{'caller'} =~ /^-\d+$/) { #the n first calls
523 0         0 $caller=join(':',splice(@stack,0,-$num));
524             } elsif ($args{'caller'} =~ /^\d+$/) { #just the n last calls
525 0         0 $caller=join(':',splice(@stack,1+$#stack-$num));
526             }
527             }
528             }
529             }
530              
531 23 100       34 if ($caller) { #if there were something on the stack (ie: we are not in 'main')
532 18         60 $caller=~s/main\:\://g; #wipe 'main'
533 18         51 my @a=split(/\//,$caller); #split..
534 18         19 @a=reverse @a; #reverse...
535 18         65 $header=replace($header,"s",$colors{'caller'}.join(':',@a).$colortable{'none'});
536             } else {
537 5         10 $header=replace($header,"s");
538             }
539             } else {
540 0         0 $header=replace($header,"s");
541             }
542 23 50       67 if ($whattoprint{'d'}) {
543 23         753 my $tmp=scalar localtime;
544 23         87 $header=~s/\$date/$tmp/;
545             }
546 23 50       58 if ($whattoprint{'l'}) {
547 23         24 my $tmp;
548 23 50       76 if ($args{ltype} eq 'numeric') {
    50          
549 0         0 $tmp=$colors{'level'}.$level.$colortable{'none'};
550             } elsif ($args{ltype} eq 'sequential') {
551 23         118 $tmp=$colors{'level'}.$args{cosmetic} x $level. " " x ($args{levelmax} - $level).$colortable{'none'}; # [xx ]
552             }
553 23         79 $header=~s/\$level/$tmp/;
554             }
555              
556             #####################################
557             # End of header building
558             #####################################
559 23         177 print $header; #print the header
560             }
561 24         207 print $colors{'msg'};
562 24         66 while (my $tolog=shift) { #and then print all the things the user wants me to print
563 30         117 print $tolog;
564 30         95 $return_code.=$tolog;
565             }
566 24         41 print $colortable{'none'};
567 24 50       125 print "\n" unless $nocr;
568             #Passe le fun autour de toi!
569 24 0 33     63 print $fun[1+int(rand $#fun)],"\n" if ($args{fun} and (rand(100)<$args{fun}) and ($count>10)); #write a bit of fun, but not in the first 10 lines
      33        
570             #print "nc:$nocr\n";
571 24         23 $count++;
572 24 50       36 if ($nocr) {
573 0         0 $hadnocr=1;
574             } else {
575 24         30 $hadnocr=0;
576             }
577             #print "hnc:$hadnocr\n";
578              
579 24         71 select($prevhandle);
580 24         95 return $return_code;
581             }
582             sub error {
583 3     3 0 1278 $error=1;
584 3         8 my $ec=wr(1,$error_header," ",@_);
585 3         5 $error=0;
586 3         25 return $ec;
587             }
588             1;
589             =pod
590              
591             =head1 EXAMPLE
592              
593             Here is an example with almost all of the options enabled:
594              
595             $ vi gna.pl
596             #!/usr/bin/perl -w
597             use Log::Funlog qw( error );
598             *Log=new Log::Funlog(
599             file => "zou.log", #name of the file
600             verbose => "3/5", #verbose 3 out of a maximum of 5
601             daemon => 0, #I am not a daemon
602             cosmetic => 'x', #crosses for the level
603             fun => 10, #10% of fun (que je passe autour de moi)
604             error_header => 'Groumpf... ', #Header for true errors
605             header => '%dd %p[]p %l[]l %s{}s ', #The header
606             caller => 1); #and I want the name of the last sub
607              
608             Log(1,"I'm logged...");
609             Log(3,"Me too...");
610             Log(4,"Me not!"); #because 4>verbose
611             sub ze_sub {
612             $hop=1;
613             Log(1,"One","two",$hop,"C"."++");
614             error("oups!");
615             }
616             ze_sub;
617             error("Zut");
618              
619             :wq
620              
621             $ perl gna.pl
622             Tue Jul 26 15:39:41 2005 [gna.pl] [x ] I'm logged...
623             Tue Jul 26 15:39:41 2005 [gna.pl] [xxx ] Me too...
624             Tue Jul 26 15:39:41 2005 [gna.pl] [x ] {ze_sub} Onetwo1C++
625             Tue Jul 26 15:39:41 2005 [gna.pl] [x ] {ze_sub} Groumpf... oups!
626             Tue Jul 26 15:39:41 2005 [gna.pl] [x ] Groumpf... Zut
627              
628             =head1 BUGS
629              
630             =over
631              
632             =item 1-
633              
634             This:
635              
636             header => '-(%dd)--( %p)><(p )-( %l)-<>-(l %s)<>(s '
637              
638             won't do what you expect ( this is the ')><(' )
639              
640             Workaround is:
641              
642             header => '-(%dd)--( )>%pp<( )-( %l)-<>-(l %s)<>(s '
643              
644             And this kind of workaround work for everything but %ss, as it is not calculated during initialization.
645              
646             =item 2-
647              
648             *Log=Log::Funlog->new(
649             colors => 1,
650             colors => {
651             date => 'white'
652             }
653             )
654              
655             Is not the same as:
656              
657             *Log=Log::Funlog->new(
658             colors => {
659             date => 'white'
660             },
661             colors => 1,
662             )
663              
664             First case will do what you expect, second case will put default colors.
665              
666             To avoid that, specify EITHER colors => 1 OR colors => {}
667              
668             =back
669              
670             =head1 DEPENDENCIES
671              
672             Log::Funlog::Lang > 0.3 : provide the funny messages.
673              
674             =head1 DISCUSSION
675              
676             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.
677              
678             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...
679              
680             Especially if you look at the code, and you see all the stuffs the module do before printing something.
681              
682             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
683              
684             If you want a I fast routine of log, please propose me a way to do it, or do it yourself, or do not log :)
685              
686             You can probably say:
687              
688             my Log::Funlog $log = new Log::Funlog; # $log is now an Log::Funlog object. $log contain the address of the sub used to write.
689              
690             Then:
691              
692             &{$log}(1,'plop');
693              
694             But it is probably not convenient.
695              
696             =head1 HISTORY
697              
698             I'm doing quite a lot of Perl scripts, and I wanted the scripts talk to me. So I searched a log routine.
699              
700             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.
701              
702             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 :)
703              
704             The I wrote this module, that I 'use Log::Funlog' in each of my scripts.
705              
706             =head1 CHANGELOG
707              
708             See Changelog
709              
710             =head1 AUTHOR
711              
712             Gabriel Guillon, from Cashew team
713              
714             korsani-spam@caramail(spaaaaaammmm).com[spppam]
715              
716             (remove you-know-what :)
717              
718             =head1 LICENCE
719              
720             As Perl itself.
721              
722             Let me know if you have added some features, or removed some bugs ;)
723              
724             =cut
725