File Coverage

blib/lib/Log/Agent/Tag/Caller.pm
Criterion Covered Total %
statement 58 58 100.0
branch 6 8 75.0
condition 2 5 40.0
subroutine 10 10 100.0
pod 3 8 37.5
total 79 89 88.7


line stmt bran cond sub pod time code
1             ###########################################################################
2             #
3             # Caller.pm
4             #
5             # Copyright (C) 1999 Raphael Manfredi.
6             # Copyright (C) 2002-2017 Mark Rogaski, mrogaski@cpan.org;
7             # all rights reserved.
8             #
9             # See the README file included with the
10             # distribution for license information.
11             #
12             ##########################################################################
13              
14 1     1   7 use strict;
  1         2  
  1         47  
15              
16             ########################################################################
17             package Log::Agent::Tag::Caller;
18              
19             require Log::Agent::Tag;
20 1     1   5 use vars qw(@ISA);
  1         1  
  1         883  
21             @ISA = qw(Log::Agent::Tag);
22              
23             #
24             # ->make
25             #
26             # Creation routine.
27             #
28             # Calling arguments: a hash table list.
29             #
30             # The keyed argument list may contain:
31             # -OFFSET value for the offset attribute [NOT DOCUMENTED]
32             # -INFO string of keywords like "package filename line subroutine"
33             # -FORMAT formatting instructions, like "%s:%d", used along with -INFO
34             # -POSTFIX whether to postfix log message or prefix it.
35             # -DISPLAY a string like '($subroutine/$line)', supersedes -INFO
36             # -SEPARATOR separator string to use between tag and message
37             #
38             # Attributes:
39             # indices listref of indices to select in the caller() array
40             # offset how many stack frames are between us and the caller we trace
41             # format how to format extracted caller() info
42             # postfix true if info to append to logged string
43             #
44             sub make {
45 3     3 0 9 my $self = bless {}, shift;
46 3         13 my (%args) = @_;
47              
48 3         12 $self->{'offset'} = 0;
49              
50 3         5 my $info;
51 3         4 my $postfix = 0;
52 3         4 my $separator;
53              
54             my %set = (
55             -offset => \$self->{'offset'},
56             -info => \$info,
57             -format => \$self->{'format'},
58             -postfix => \$postfix,
59 3         13 -display => \$self->{'display'},
60             -separator => \$separator,
61             );
62              
63 3         14 while (my ($arg, $val) = each %args) {
64 9         14 my $vset = $set{lc($arg)};
65 9 50       18 next unless ref $vset;
66 9         31 $$vset = $val;
67             }
68              
69 3         13 $self->_init("caller", $postfix, $separator);
70              
71 3 100       22 return $self if $self->display; # A display string takes precedence
72              
73             #
74             # pre-process info to compute the indices
75             #
76              
77 2         3 my $i = 0;
78 2         5 my %indices = map { $_ => $i++ } qw(pac fil lin sub); # abbrevs
  8         29  
79 2         7 my @indices = ();
80              
81 2         10 foreach my $token (split(' ', $info)) {
82 6         10 my $abbr = substr($token, 0, 3);
83 6 50       18 push(@indices, $indices{$abbr}) if exists $indices{$abbr};
84             }
85              
86 2         8 $self->{'indices'} = \@indices;
87              
88 2         66 return $self;
89             }
90              
91             #
92             # Attribute access
93             #
94              
95 14     14 0 78 sub offset { $_[0]->{'offset'} }
96 5     5 0 12 sub indices { $_[0]->{'indices'} }
97 5     5 1 13 sub format { $_[0]->{'format'} }
98 10     10 0 45 sub display { $_[0]->{'display'} }
99 7     7 1 28 sub postfix { $_[0]->{'postfix'} }
100              
101             #
102             # expand_a
103             #
104             # Expand the %a macro and return new string.
105             #
106 5     5 0 15 if ($] >= 5.005) { eval q{ # if VERSION >= 5.005
  5         18  
  2         11  
  5         15  
107              
108             # 5.005 and later version grok /(?
109             sub expand_a {
110             my ($str, $aref) = @_;
111             $str =~ s/((?
112             return $str;
113             }
114              
115             }} else { eval q{ # else /* VERSION < 5.005 */
116              
117             # pre-5.005 does not grok /(?
118             sub expand_a {
119             my ($str, $aref) = @_;
120             $str =~ s/%%/\01/g;
121             $str =~ s/%a/join(':', @$aref)/ge;
122             $str =~ s/\01/%%/g;
123             return $str;
124             }
125              
126             }} # endif /* VERSION >= 5.005 */
127              
128             #
129             # ->string -- defined
130             #
131             # Compute string with properly formatted caller info
132             #
133             sub string {
134 7     7 1 9 my $self = shift;
135              
136             #
137             # The following code:
138             #
139             # sub foo {
140             # my ($pack, $file, $line, $sub) = caller(0);
141             # print "excuting $sub called at $file/$line in $pack";
142             # }
143             #
144             # will report who called us, except that $sub will be US, not our CALLER!
145             # This is an "anomaly" somehow, and therefore to get the routine name
146             # that called us, we need to move one frame above the ->offset value.
147             #
148              
149 7         15 my @caller = caller($self->offset);
150              
151             # Kludge for anomalies in caller()
152             # Thanks to Jeff Boes for finding the second one!
153 7   50     25 $caller[3] = (caller($self->offset + 1))[3] || '(main)';
154              
155 7         21 my ($package, $filename, $line, $subroutine) = @caller;
156              
157             #
158             # If there is a display, it takes precedence and is formatted accordingly,
159             # with limited variable substitution. The variables that are recognized
160             # are:
161             #
162             # $package or $pack package name of caller
163             # $filename or $file filename of caller
164             # $line line number of caller
165             # $subroutine or $sub routine name of caller
166             #
167             # We recognize both $line and ${line}, the difference being that the
168             # first needs to be at a word boundary (i.e. $lineage would not result
169             # in any expansion).
170             #
171             # Otherwise, the necessary information is gathered from the caller()
172             # output, and formatted via sprintf, along with the special %a macro
173             # which stands for all the information, separated by ':'.
174             #
175             # NB: The default format is "[%a]" for postfixed info, "(%a)" otherwise.
176             #
177              
178 7         17 my $display = $self->display;
179 7 100       15 if ($display) {
180 2         5 $display =~ s/\$pack(?:age)?\b/$package/g;
181 2         5 $display =~ s/\$\{pack(?:age)?}/$package/g;
182 2         4 $display =~ s/\$file(?:name)?\b/$filename/g;
183 2         4 $display =~ s/\$\{file(?:name)?}/$filename/g;
184 2         3 $display =~ s/\$line\b/$line/g;
185 2         6 $display =~ s/\$\{line}/$line/g;
186 2         10 $display =~ s/\$sub(?:routine)?\b/$subroutine/g;
187 2         5 $display =~ s/\$\{sub(?:routine)?}/$subroutine/g;
188             } else {
189 5         9 my @show = map { $caller[$_] } @{$self->indices};
  14         29  
  5         8  
190 5   33     10 my $format = $self->format || ($self->postfix ? "[%a]" : "(%a)");
191 5         114 $format = expand_a($format, \@show); # depends on Perl's version
192 5         23 $display = sprintf $format, @show;
193             }
194              
195 7         25 return $display;
196             }
197              
198             1; # for "require"
199             __END__