File Coverage

blib/lib/Log/ger.pm
Criterion Covered Total %
statement 62 68 91.1
branch 39 52 75.0
condition 5 5 100.0
subroutine 7 9 77.7
pod 0 3 0.0
total 113 137 82.4


line stmt bran cond sub pod time code
1             package Log::ger;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-03-11'; # DATE
5             our $DIST = 'Log-ger'; # DIST
6             our $VERSION = '0.037'; # VERSION
7              
8             #IFUNBUILT
9             # use strict 'subs', 'vars';
10             # use warnings;
11             #END IFUNBUILT
12              
13             our $re_addr = qr/\(0x([0-9a-f]+)/o;
14              
15             our %Levels = (
16             fatal => 10,
17             error => 20,
18             warn => 30,
19             info => 40,
20             debug => 50,
21             trace => 60,
22             );
23              
24             our %Level_Aliases = (
25             off => 0,
26             warning => 30,
27             );
28              
29             our $Current_Level = 30;
30              
31             our $Caller_Depth_Offset = 0;
32              
33             # a flag that can be used by null output to skip using formatter
34             our $_outputter_is_null;
35              
36             our $_dumper;
37              
38             our %Global_Hooks;
39              
40             # in Log/ger/Heavy.pm
41             # our %Default_Hooks = (
42              
43             our %Package_Targets; # key = package name, value = \%per_target_conf
44             our %Per_Package_Hooks; # key = package name, value = { phase => hooks, ... }
45              
46             our %Hash_Targets; # key = hash address, value = [$hashref, \%per_target_conf]
47             our %Per_Hash_Hooks; # key = hash address, value = { phase => hooks, ... }
48              
49             our %Object_Targets; # key = object address, value = [$obj, \%per_target_conf]
50             our %Per_Object_Hooks; # key = object address, value = { phase => hooks, ... }
51              
52 2     2   64 my $sub0 = sub {0};
53 0     0   0 my $sub1 = sub {1};
54             my $default_null_routines;
55              
56             sub install_routines {
57 75     75 0 129 my ($target, $target_arg, $routines, $name_routines) = @_;
58              
59 75 100 100     276 if ($name_routines && !defined &subname) {
60 8 50       12 if (eval { require Sub::Name; 1 }) {
  8         3305  
  8         3765  
61 8         26 *subname = \&Sub::Name::subname;
62             } else {
63 0     0   0 *subname = sub {};
64             }
65             }
66              
67 75 100       169 if ($target eq 'package') {
    100          
    50          
68             #IFUNBUILT
69             # no warnings 'redefine';
70             #END IFUNBUILT
71 40         66 for my $r (@$routines) {
72 481         757 my ($code, $name, $lnum, $type) = @$r;
73 481 100       1146 next unless $type =~ /_sub\z/;
74             #print "D:installing $name to package $target_arg\n";
75 469         490 *{"$target_arg\::$name"} = $code;
  469         1476  
76 469 100       1810 subname("$target_arg\::$name", $code) if $name_routines;
77             }
78             } elsif ($target eq 'object') {
79             #IFUNBUILT
80             # no warnings 'redefine';
81             #END IFUNBUILT
82 26         34 my $pkg = ref $target_arg;
83 26         39 for my $r (@$routines) {
84 324         541 my ($code, $name, $lnum, $type) = @$r;
85 324 100       712 next unless $type =~ /_method\z/;
86 312         335 *{"$pkg\::$name"} = $code;
  312         1214  
87 312 100       1222 subname("$pkg\::$name", $code) if $name_routines;
88             }
89             } elsif ($target eq 'hash') {
90 9         16 for my $r (@$routines) {
91 108         144 my ($code, $name, $lnum, $type) = @$r;
92 108 100       204 next unless $type =~ /_sub\z/;
93 54         139 $target_arg->{$name} = $code;
94             }
95             }
96             }
97              
98             sub add_target {
99 13     13 0 4235 my ($target_type, $target_name, $per_target_conf, $replace) = @_;
100 13 100       37 $replace = 1 unless defined $replace;
101              
102 13 100       37 if ($target_type eq 'package') {
    100          
    50          
103 11 50       26 unless ($replace) { return if $Package_Targets{$target_name} }
  1 100       2  
104 11         23 $Package_Targets{$target_name} = $per_target_conf;
105             } elsif ($target_type eq 'object') {
106 1         5 my ($addr) = "$target_name" =~ $re_addr;
107 1 0       4 unless ($replace) { return if $Object_Targets{$addr} }
  0 50       0  
108 1         3 $Object_Targets{$addr} = [$target_name, $per_target_conf];
109             } elsif ($target_type eq 'hash') {
110 1         8 my ($addr) = "$target_name" =~ $re_addr;
111 1 0       3 unless ($replace) { return if $Hash_Targets{$addr} }
  0 50       0  
112 1         5 $Hash_Targets{$addr} = [$target_name, $per_target_conf];
113             }
114             }
115              
116             sub _set_default_null_routines {
117             $default_null_routines ||= [
118 2   100 2   7 (map {(
119             [$sub0, "log_$_", $Levels{$_}, 'logger_sub'],
120             [$Levels{$_} > $Current_Level ? $sub0 : $sub1, "log_is_$_", $Levels{$_}, 'level_checker_sub'],
121             [$sub0, $_, $Levels{$_}, 'logger_method'],
122 6 100       30 [$Levels{$_} > $Current_Level ? $sub0 : $sub1, "is_$_", $Levels{$_}, 'level_checker_method'],
    100          
123             )} keys %Levels),
124             ];
125             }
126              
127             sub get_logger {
128 1     1 0 48 my ($package, %per_target_conf) = @_;
129              
130 1         2 my $caller = caller(0);
131             $per_target_conf{category} = $caller
132 1 50       4 if !defined($per_target_conf{category});
133 1         2 my $obj = []; $obj =~ $re_addr;
  1         6  
134 1         4 my $pkg = "Log::ger::Obj$1"; bless $obj, $pkg;
  1         4  
135 1         3 add_target(object => $obj, \%per_target_conf);
136 1 50       9 if (keys %Global_Hooks) {
137 0         0 require Log::ger::Heavy;
138 0         0 init_target(object => $obj, \%per_target_conf);
139             } else {
140             # if we haven't added any hooks etc, skip init_target() process and use
141             # this preconstructed routines as shortcut, to save startup overhead
142 1         3 _set_default_null_routines();
143 1         2 install_routines(object => $obj, $default_null_routines, 0);
144             }
145 1         2 $obj; # XXX add DESTROY to remove from list of targets
146             }
147              
148             sub _import_to {
149 10     10   57 my ($package, $target_pkg, %per_target_conf) = @_;
150              
151             $per_target_conf{category} = $target_pkg
152 10 50       38 if !defined($per_target_conf{category});
153 10         29 add_target(package => $target_pkg, \%per_target_conf);
154 10 100       80 if (keys %Global_Hooks) {
155 9         66 require Log::ger::Heavy;
156 9         34 init_target(package => $target_pkg, \%per_target_conf);
157             } else {
158             # if we haven't added any hooks etc, skip init_target() process and use
159             # this preconstructed routines as shortcut, to save startup overhead
160 1         2 _set_default_null_routines();
161 1         3 install_routines(package => $target_pkg, $default_null_routines, 0);
162             }
163             }
164              
165             sub import {
166 10     10   406 my ($package, %per_target_conf) = @_;
167              
168 10         22 my $caller = caller(0);
169 10         32 $package->_import_to($caller, %per_target_conf);
170             }
171              
172             1;
173             # ABSTRACT: A lightweight, flexible logging framework
174              
175             __END__