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