File Coverage

blib/lib/Log/Funlog.pm
Criterion Covered Total %
statement 138 170 81.1
branch 62 112 55.3
condition 19 39 48.7
subroutine 13 13 100.0
pod 0 5 0.0
total 232 339 68.4


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