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         45  
15            
16             ########################################################################
17             package Log::Agent::Tag::Caller;
18            
19             require Log::Agent::Tag;
20 1     1   5 use vars qw(@ISA);
  1         2  
  1         780  
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 8 my $self = bless {}, shift;
46 3         11 my (%args) = @_;
47            
48 3         11 $self->{'offset'} = 0;
49            
50 3         5 my $info;
51 3         4 my $postfix = 0;
52 3         5 my $separator;
53            
54             my %set = (
55             -offset => \$self->{'offset'},
56             -info => \$info,
57             -format => \$self->{'format'},
58             -postfix => \$postfix,
59 3         12 -display => \$self->{'display'},
60             -separator => \$separator,
61             );
62            
63 3         12 while (my ($arg, $val) = each %args) {
64 9         16 my $vset = $set{lc($arg)};
65 9 50       18 next unless ref $vset;
66 9         28 $$vset = $val;
67             }
68            
69 3         12 $self->_init("caller", $postfix, $separator);
70            
71 3 100       23 return $self if $self->display; # A display string takes precedence
72            
73             #
74             # pre-process info to compute the indices
75             #
76            
77 2         5 my $i = 0;
78 2         4 my %indices = map { $_ => $i++ } qw(pac fil lin sub); # abbrevs
  8         19  
79 2         4 my @indices = ();
80            
81 2         6 foreach my $token (split(' ', $info)) {
82 6         14 my $abbr = substr($token, 0, 3);
83 6 50       14 push(@indices, $indices{$abbr}) if exists $indices{$abbr};
84             }
85            
86 2         5 $self->{'indices'} = \@indices;
87            
88 2         57 return $self;
89             }
90            
91             #
92             # Attribute access
93             #
94            
95 14     14 0 71 sub offset { $_[0]->{'offset'} }
96 5     5 0 13 sub indices { $_[0]->{'indices'} }
97 5     5 1 12 sub format { $_[0]->{'format'} }
98 10     10 0 44 sub display { $_[0]->{'display'} }
99 7     7 1 18 sub postfix { $_[0]->{'postfix'} }
100            
101             #
102             # expand_a
103             #
104             # Expand the %a macro and return new string.
105             #
106 5     5 0 16 if ($] >= 5.005) { eval q{ # if VERSION >= 5.005
  5         19  
  2         10  
  5         14  
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         14 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     16 $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         15 my $display = $self->display;
179 7 100       15 if ($display) {
180 2         3 $display =~ s/\$pack(?:age)?\b/$package/g;
181 2         4 $display =~ s/\$\{pack(?:age)?}/$package/g;
182 2         3 $display =~ s/\$file(?:name)?\b/$filename/g;
183 2         4 $display =~ s/\$\{file(?:name)?}/$filename/g;
184 2         2 $display =~ s/\$line\b/$line/g;
185 2         7 $display =~ s/\$\{line}/$line/g;
186 2         9 $display =~ s/\$sub(?:routine)?\b/$subroutine/g;
187 2         4 $display =~ s/\$\{sub(?:routine)?}/$subroutine/g;
188             } else {
189 5         8 my @show = map { $caller[$_] } @{$self->indices};
  14         28  
  5         7  
190 5   33     10 my $format = $self->format || ($self->postfix ? "[%a]" : "(%a)");
191 5         112 $format = expand_a($format, \@show); # depends on Perl's version
192 5         25 $display = sprintf $format, @show;
193             }
194            
195 7         21 return $display;
196             }
197            
198             1; # for "require"
199             __END__