| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Debug::Easy 2.24; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
160011
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
73
|
|
|
4
|
|
|
|
|
|
|
# use warnings; |
|
5
|
|
|
|
|
|
|
use constant { |
|
6
|
1
|
|
|
|
|
98
|
TRUE => 1, |
|
7
|
|
|
|
|
|
|
FALSE => 0, |
|
8
|
1
|
|
|
1
|
|
7
|
}; |
|
|
1
|
|
|
|
|
1
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
6
|
use Config; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
64
|
|
|
11
|
1
|
|
|
1
|
|
7
|
use Term::ANSIColor; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
84
|
|
|
12
|
1
|
|
|
1
|
|
8
|
use Time::HiRes qw(time); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
9
|
|
|
13
|
1
|
|
|
1
|
|
155
|
use File::Basename qw(fileparse); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
83
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
717
|
use Data::Dumper; # Included in Perl |
|
|
1
|
|
|
|
|
11463
|
|
|
|
1
|
|
|
|
|
136
|
|
|
16
|
|
|
|
|
|
|
eval { # Data::Dumper::Simple is preferred. Try to load it without dying. |
|
17
|
|
|
|
|
|
|
require Data::Dumper::Simple; |
|
18
|
|
|
|
|
|
|
Data::Dumper::Simple->import(); |
|
19
|
|
|
|
|
|
|
1; |
|
20
|
|
|
|
|
|
|
}; |
|
21
|
|
|
|
|
|
|
|
|
22
|
1
|
|
|
1
|
|
13
|
use if ($Config{'useithreads'}), 'threads'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
107
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
BEGIN { |
|
25
|
1
|
|
|
1
|
|
8
|
require Exporter; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Inherit from Exporter to export functions and variables |
|
28
|
1
|
|
|
|
|
22
|
our @ISA = qw(Exporter); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Functions and variables which are exported by default |
|
31
|
1
|
|
|
|
|
3
|
our @EXPORT = qw(); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Functions and variables which can be optionally exported |
|
34
|
1
|
|
|
|
|
4594
|
our @EXPORT_OK = qw(fileparse @Levels); |
|
35
|
|
|
|
|
|
|
} ## end BEGIN |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# This can be optionally exported for whatever |
|
38
|
|
|
|
|
|
|
our @Levels = qw( ERR WARN NOTICE INFO VERBOSE DEBUG DEBUGMAX ); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# For quick level checks to speed up execution |
|
41
|
|
|
|
|
|
|
our %LevelLogic; |
|
42
|
|
|
|
|
|
|
for (my $count = 0; $count < scalar(@Levels); $count++) { |
|
43
|
|
|
|
|
|
|
$LevelLogic{ $Levels[$count] } = $count; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
our $PARENT = $$; # This needs to be defined at the very beginning before new |
|
47
|
|
|
|
|
|
|
our ($SCRIPTNAME, $SCRIPTPATH, $suffix) = fileparse($0); |
|
48
|
|
|
|
|
|
|
# our @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); |
|
49
|
|
|
|
|
|
|
# our @days = qw(Sun Mon Tue Wed Thu Fri Sat Sun); |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=encoding utf8 |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head1 NAME |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Debug::Easy - A Handy Debugging Module With Colorized Output and Formatting |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use Debug::Easy; |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $debug = Debug::Easy->new( 'LogLevel' => 'DEBUG', 'Color' => 1 ); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
'LogLevel' is the maximum level to report, and ignore the rest. The method names correspond to their loglevels, when outputting a specific message. This identifies to the module what type of message [...] |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
The following is a list, in order of level, of the logging methods: |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
ERR = Error |
|
68
|
|
|
|
|
|
|
WARN = Warning |
|
69
|
|
|
|
|
|
|
NOTICE = Notice |
|
70
|
|
|
|
|
|
|
INFO = Information |
|
71
|
|
|
|
|
|
|
VERBOSE = Special version of INFO that does not output any |
|
72
|
|
|
|
|
|
|
Logging headings. Very useful for verbose modes in your |
|
73
|
|
|
|
|
|
|
scripts. |
|
74
|
|
|
|
|
|
|
DEBUG = Level 1 Debugging messages |
|
75
|
|
|
|
|
|
|
DEBUGMAX = Level 2 Debugging messages (typically more terse like dumping |
|
76
|
|
|
|
|
|
|
variables) |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
The parameter is either a string or a reference to an array of strings to output as multiple lines. |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Each string can contain newlines, which will also be split into a separate line and formatted accordingly. |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
$debug->ERR( ['Error message']); |
|
83
|
|
|
|
|
|
|
$debug->ERROR( ['Error message']); |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
$debug->WARN( ['Warning message']); |
|
86
|
|
|
|
|
|
|
$debug->WARNING( ['Warning message']); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
$debug->NOTICE( ['Notice message']); |
|
89
|
|
|
|
|
|
|
$debug->INFO( ['Information and VERBOSE mode message']); |
|
90
|
|
|
|
|
|
|
$debug->INFORMATION(['Information and VERBOSE mode message']); |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
$debug->DEBUG( ['Level 1 Debug message']); |
|
93
|
|
|
|
|
|
|
$debug->DEBUGMAX( ['Level 2 (terse) Debug message']); |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my @messages = ( |
|
96
|
|
|
|
|
|
|
'First Message', |
|
97
|
|
|
|
|
|
|
'Second Message', |
|
98
|
|
|
|
|
|
|
"Third Message First Line\nThird Message Second Line", |
|
99
|
|
|
|
|
|
|
\%hash_reference |
|
100
|
|
|
|
|
|
|
); |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$debug->INFO([\@messages]); |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
This module makes it easy to add debugging features to your code, Without having to re-invent the wheel. It uses STDERR and ANSI color formatted text output, as well as indented and multiline text fo [...] |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Benchmarking is automatic, to make it easy to spot bottlenecks in code. It automatically stamps from where it was called, and makes debug coding so much easier, without having to include the location [...] |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
It also allows multiple output levels from errors only, to warnings, to notices, to verbose information, to full on debug output. All of this fully controllable by the coder. |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Generally all you need are the defaults and you are ready to go. |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 B |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 B<@Levels> |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
A simple list of all the acceptable debug levels to pass as "LogLevel" in the {new} method. Not normally needed for coding, more for reference. Only exported if requested. |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=cut |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub DESTROY { # We spit out one last message before we die, the total execute time. |
|
123
|
6
|
|
|
6
|
|
6332
|
my $self = shift; |
|
124
|
|
|
|
|
|
|
my $bench = (! $self->{'COLOR'}) |
|
125
|
|
|
|
|
|
|
? sprintf('%06.2f', (time - $self->{'MASTERSTART'})) |
|
126
|
6
|
50
|
|
|
|
214
|
: colored(['bright_cyan'], sprintf('%06.2f', (time - $self->{'MASTERSTART'}))); |
|
127
|
6
|
|
|
|
|
390
|
my $name = $SCRIPTNAME; |
|
128
|
6
|
50
|
|
|
|
63
|
$name .= ' [child]' if ($PARENT ne $$); |
|
129
|
6
|
50
|
|
|
|
29
|
unless ($self->{'COLOR'}) { |
|
130
|
0
|
|
|
|
|
0
|
$self->DEBUG(["$bench ---- $name complete ----"]); |
|
131
|
|
|
|
|
|
|
} else { |
|
132
|
6
|
|
|
|
|
50
|
$self->DEBUG([$bench . ' ' . colored(['black on_white'], "---- $name complete ----")]); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
} ## end sub DESTROY |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head1 B |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 B |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
* The parameter names are case insensitive as of Version 0.04. |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=over 4 |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item B [level] |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
This adjusts the global log level of the Debug object. It requires a string. |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=back |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=over 8 |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
B (default) |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
This level shows only error messages and all other messages are not shown. |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
B |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
This level shows error and warning messages. All other messages are not shown. |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
B |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
This level shows error, warning, and notice messages. All other messages are not shown. |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
B |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
This level shows error, warning, notice, and information messages. Only debug level messages are not shown. |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
B |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
This level can be used as a way to do "Verbose" output for your scripts. It ouputs INFO level messages without logging headers and on STDOUT instead of STDERR. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
B |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
This level shows error, warning, notice, information, and level 1 debugging messages. Level 2 Debug messages are not shown. |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
B |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
This level shows all messages up to level 2 debugging messages. |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
NOTE: It has been asked "Why have two debugging levels?" Well, I have had many times where I would like to see what a script is doing without it showing what I consider garbage overhead it may gene [...] |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=back |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=over 4 |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item B [boolean] (Not case sensitive) |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
B<0>, B, or B (Off) |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
This turns off colored output. Everything is plain text only. |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
B<1>, B, or B (On - Default) |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This turns on colored output. This makes it easier to spot all of the different types of messages throughout a sea of debug output. You can read the output with "less", and see color, by using it' [...] |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=back |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=over 4 |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item B [pattern] |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
This is global |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
A string that is parsed into the output prefix. |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
DEFAULT: '%Date% %Time% %Benchmark% %Loglevel%[%Subroutine%][%Lastline%] ' |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
%Date% = Date (Uses format of "DateStamp" below) |
|
209
|
|
|
|
|
|
|
%Time% = Time (Uses format of "TimeStamp" below) |
|
210
|
|
|
|
|
|
|
%Epoch% = Epoch (Unix epoch) |
|
211
|
|
|
|
|
|
|
%Benchmark% = Benchmark - The time it took between the last benchmark display |
|
212
|
|
|
|
|
|
|
of this loglevel. If in an INFO level message, it benchmarks |
|
213
|
|
|
|
|
|
|
the time until the next INFO level message. The same rule is |
|
214
|
|
|
|
|
|
|
true for all loglevels. |
|
215
|
|
|
|
|
|
|
%Loglevel% = Log Level |
|
216
|
|
|
|
|
|
|
%Lines% = Line Numbers of all nested calls |
|
217
|
|
|
|
|
|
|
%Module% = Module and subroutine of call (can be a lot of stuff!) |
|
218
|
|
|
|
|
|
|
%Subroutine% = Just the last subroutine |
|
219
|
|
|
|
|
|
|
%Lastline% = Just the last line number |
|
220
|
|
|
|
|
|
|
%PID% = Process ID |
|
221
|
|
|
|
|
|
|
%date% = Just Date (typically used internally only, use %Date%) |
|
222
|
|
|
|
|
|
|
%time% = Just time (typically used internally only, use %Time%) |
|
223
|
|
|
|
|
|
|
%epoch% = Unix epoch (typically used internally only, use %Epoch%) |
|
224
|
|
|
|
|
|
|
%Filename% = Script Filename (parsed $0) |
|
225
|
|
|
|
|
|
|
%Fork% = Running in parent or child? |
|
226
|
|
|
|
|
|
|
P = Parent |
|
227
|
|
|
|
|
|
|
C = Child |
|
228
|
|
|
|
|
|
|
%Thread% = Running in Parent or Thread |
|
229
|
|
|
|
|
|
|
P = Parent |
|
230
|
|
|
|
|
|
|
T## = Thread # = Thread ID |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item B<[loglevel]-Prefix> [pattern] |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
You can define a prefix for a specific log level. |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
ERR-Prefix |
|
237
|
|
|
|
|
|
|
WARN-Prefix |
|
238
|
|
|
|
|
|
|
NOTICE-Prefix |
|
239
|
|
|
|
|
|
|
INFO-Prefix |
|
240
|
|
|
|
|
|
|
DEBUG-Prefix |
|
241
|
|
|
|
|
|
|
DEBUGMAX-Prefix |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
If one of these are not defined, then the global value is used. |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item B [pattern] |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
(See Log::Fast for specifics on these) |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
I suggest you just use Prefix above, but here it is anyway. |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
Make this an empty string to turn it off, otherwise: |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=back |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=over 8 |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
B<%T> |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
Formats the timestamp as HH:MM:SS. This is the default for the timestamp. |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
B<%S> |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Formats the timestamp as seconds.milliseconds. Normally not needed, as the benchmark is more helpful. |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
B<%T %S> |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
Combines both of the above. Normally this is just too much, but here if you really want it. |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=back |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=over 4 |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=item B [pattern] |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
I suggest you just use Prefix above, but here it is anyway. |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Make this an empty string to turn it off, otherwise: |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=back |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=over 8 |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
B<%D> |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Formats the datestamp as YYYY-MM-DD. It is the default, and the only option. |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=back |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=over 4 |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item B |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
File handle to write log messages. |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=item B |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
Contains a hash reference describing the various colored debug level labels |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
The default definition (using Term::ANSIColor) is as follows: |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=back |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=over 8 |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
'ANSILevel' => { |
|
306
|
|
|
|
|
|
|
'ERR' => colored(['white on_red'], '[ ERROR ]'), |
|
307
|
|
|
|
|
|
|
'WARN' => colored(['black on_yellow'], '[WARNING ]'), |
|
308
|
|
|
|
|
|
|
'NOTICE' => colored(['yellow'], '[ NOTICE ]'), |
|
309
|
|
|
|
|
|
|
'INFO' => colored(['black on_white'], '[ INFO ]'), |
|
310
|
|
|
|
|
|
|
'DEBUG' => colored(['bold green'], '[ DEBUG ]'), |
|
311
|
|
|
|
|
|
|
'DEBUGMAX' => colored(['bold black on_green'], '[DEBUGMAX]'), |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=back |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=cut |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub new { |
|
319
|
6
|
|
|
6
|
1
|
203926
|
my $class = shift; |
|
320
|
6
|
|
|
|
|
276
|
my ($filename, $dir, $suffix) = fileparse($0); |
|
321
|
6
|
|
|
|
|
33
|
my $tm = time; |
|
322
|
6
|
|
|
|
|
66
|
my $self = { # The keys are set to upper-case later in the initialization |
|
323
|
|
|
|
|
|
|
'LOGLEVEL' => 'ERR', # Default is errors only |
|
324
|
|
|
|
|
|
|
'TYPE' => 'fh', # Default is a filehandle |
|
325
|
|
|
|
|
|
|
'PATH' => '/var/log', # Default path should type be unix |
|
326
|
|
|
|
|
|
|
'FILEHANDLE' => \*STDERR, # Default filehandle is STDERR |
|
327
|
|
|
|
|
|
|
'MASTERSTART' => $tm, |
|
328
|
|
|
|
|
|
|
'ANY_LASTSTAMP' => $tm, # Initialize main benchmark |
|
329
|
|
|
|
|
|
|
'ERR_LASTSTAMP' => $tm, # Initialize the ERR benchmark |
|
330
|
|
|
|
|
|
|
'WARN_LASTSTAMP' => $tm, # Initialize the WARN benchmark |
|
331
|
|
|
|
|
|
|
'INFO_LASTSTAMP' => $tm, # Initialize the INFO benchmark |
|
332
|
|
|
|
|
|
|
'NOTICE_LASTSTAMP' => $tm, # Initialize the NOTICE benchmark |
|
333
|
|
|
|
|
|
|
'DEBUG_LASTSTAMP' => $tm, # Initialize the DEBUG benchmark |
|
334
|
|
|
|
|
|
|
'DEBUGMAX_LASTSTAMP' => $tm, # Initialize the DEBUGMAX benchmark |
|
335
|
|
|
|
|
|
|
'COLOR' => TRUE, # Default to colorized output |
|
336
|
|
|
|
|
|
|
'DATESTAMP' => colored(['yellow'], '%date%'), |
|
337
|
|
|
|
|
|
|
'TIMESTAMP' => colored(['yellow'], '%time%'), |
|
338
|
|
|
|
|
|
|
'EPOCH' => colored(['cyan'], '%epoch%'), |
|
339
|
|
|
|
|
|
|
'PADDING' => -20, # Default padding is 20 spaces |
|
340
|
|
|
|
|
|
|
'LINES-PADDING' => -2, |
|
341
|
|
|
|
|
|
|
'SUBROUTINE-PADDING' => 0, |
|
342
|
|
|
|
|
|
|
'LINE-PADDING' => 0, |
|
343
|
|
|
|
|
|
|
'PARENT' => $$, |
|
344
|
|
|
|
|
|
|
'GLOBAL-PREFIX' => '%Date% %Time% %Benchmark% %Loglevel%[%Subroutine%][%Lastline%] ', |
|
345
|
|
|
|
|
|
|
'DEBUGMAX-PREFIX' => '%Date% %Time% %Benchmark% %Loglevel%[%Module%][%Lines%] ', |
|
346
|
|
|
|
|
|
|
'FILENAME' => '[' . colored(['magenta'], $filename) . ']', |
|
347
|
|
|
|
|
|
|
'ANSILEVEL' => { |
|
348
|
|
|
|
|
|
|
'ERR' => colored(['white on_red'], '[ ERROR ]'), |
|
349
|
|
|
|
|
|
|
'WARN' => colored(['black on_yellow'], '[WARNING ]'), |
|
350
|
|
|
|
|
|
|
'NOTICE' => colored(['yellow'], '[ NOTICE ]'), |
|
351
|
|
|
|
|
|
|
'INFO' => colored(['black on_white'], '[ INFO ]'), |
|
352
|
|
|
|
|
|
|
'DEBUG' => colored(['bold green'], '[ DEBUG ]'), |
|
353
|
|
|
|
|
|
|
'DEBUGMAX' => colored(['bold black on_green'], '[DEBUGMAX]'), |
|
354
|
|
|
|
|
|
|
}, |
|
355
|
|
|
|
|
|
|
}; |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# This pretty much makes all hash keys uppercase |
|
358
|
6
|
|
|
|
|
3359
|
my @Keys = (keys %{$self}); # Hash is redefined on the fly, so get the list before |
|
|
6
|
|
|
|
|
46
|
|
|
359
|
6
|
|
|
|
|
29
|
foreach my $Key (@Keys) { |
|
360
|
150
|
|
|
|
|
307
|
my $upper = uc($Key); |
|
361
|
150
|
50
|
|
|
|
517
|
if ($Key ne $upper) { |
|
|
|
100
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
$self->{$upper} = $self->{$Key}; |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# This fixes a documentation error for past versions |
|
365
|
0
|
0
|
|
|
|
0
|
if ($upper eq 'LOGLEVEL') { |
|
366
|
0
|
0
|
|
|
|
0
|
$self->{$upper} = 'ERR' if ($self->{$upper} =~ /^ERROR$/i); |
|
367
|
0
|
|
|
|
|
0
|
$self->{$upper} = uc($self->{$upper}); # Make loglevels case insensitive |
|
368
|
|
|
|
|
|
|
} |
|
369
|
0
|
|
|
|
|
0
|
delete($self->{$Key}); # Get rid of the bad key |
|
370
|
|
|
|
|
|
|
} elsif ($Key eq 'LOGLEVEL') { # Make loglevels case insensitive |
|
371
|
6
|
|
|
|
|
26
|
$self->{$upper} = uc($self->{$upper}); |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
} ## end foreach my $Key (@Keys) |
|
374
|
|
|
|
|
|
|
{ # This makes sure the user overrides actually override |
|
375
|
6
|
|
|
|
|
14
|
my %params = (@_); |
|
|
6
|
|
|
|
|
39
|
|
|
376
|
6
|
|
|
|
|
23
|
foreach my $Key (keys %params) { |
|
377
|
18
|
|
|
|
|
89
|
$self->{ uc($Key) } = $params{$Key}; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# Cache numeric log level value for quick comparisons |
|
382
|
6
|
|
|
|
|
34
|
$self->{'LOGLEVEL_VALUE'} = $LevelLogic{ $self->{'LOGLEVEL'} }; |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Cache thread support check for hot path |
|
385
|
6
|
50
|
|
|
|
124
|
$self->{'USE_THREADS'} = ($Config{'useithreads'}) ? 1 : 0; |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# This instructs the ANSIColor library to turn off coloring, |
|
388
|
|
|
|
|
|
|
# if the Color attribute is set to zero. |
|
389
|
6
|
50
|
|
|
|
34
|
unless ($self->{'COLOR'}) { |
|
390
|
|
|
|
|
|
|
# If COLOR is FALSE, then clear color data from ANSILEVEL, as these were |
|
391
|
|
|
|
|
|
|
# defined before color was turned off. |
|
392
|
0
|
|
|
|
|
0
|
$self->{'ANSILEVEL'} = { |
|
393
|
|
|
|
|
|
|
'ERR' => '[ ERROR ]', |
|
394
|
|
|
|
|
|
|
'WARN' => '[WARNING ]', |
|
395
|
|
|
|
|
|
|
'NOTICE' => '[ NOTICE ]', |
|
396
|
|
|
|
|
|
|
'INFO' => '[ INFO ]', |
|
397
|
|
|
|
|
|
|
'DEBUG' => '[ DEBUG ]', |
|
398
|
|
|
|
|
|
|
'DEBUGMAX' => '[DEBUGMAX]', |
|
399
|
|
|
|
|
|
|
}; |
|
400
|
0
|
|
|
|
|
0
|
$self->{'DATESTAMP'} = '%date%'; |
|
401
|
0
|
|
|
|
|
0
|
$self->{'TIMESTAMP'} = '%time%'; |
|
402
|
0
|
|
|
|
|
0
|
$self->{'EPOCH'} = '%epoch%'; |
|
403
|
0
|
|
|
|
|
0
|
$self->{'FILENAME'} = '[' . $filename . ']'; # Ensure filename without color |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
6
|
|
|
|
|
21
|
foreach my $lvl (@Levels) { # Set any undefined prefix to the global prefix |
|
407
|
42
|
100
|
66
|
|
|
213
|
$self->{"$lvl-PREFIX"} = $self->{'GLOBAL-PREFIX'} unless (exists($self->{"$lvl-PREFIX"}) && defined($self->{"$lvl-PREFIX"})); |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# Precompute static prefix templates per level to minimize per-line substitutions. |
|
411
|
|
|
|
|
|
|
# We will leave dynamic tokens (%date%, %time%, %epoch%, %Benchmark%) for runtime. |
|
412
|
6
|
|
|
|
|
22
|
$self->{'_PREFIX_TEMPLATES'} = {}; |
|
413
|
6
|
|
|
|
|
17
|
foreach my $lvl (@Levels) { |
|
414
|
42
|
|
|
|
|
145
|
my $tmpl = $self->{"$lvl-PREFIX"} . ''; # copy |
|
415
|
42
|
50
|
|
|
|
205
|
my $forked = ($PARENT ne $$) ? 'C' : 'P'; |
|
416
|
42
|
|
|
|
|
73
|
my $threaded = 'PT-'; |
|
417
|
42
|
50
|
|
|
|
106
|
if ($self->{'USE_THREADS'}) { |
|
418
|
0
|
0
|
|
|
|
0
|
my $tid = threads->can('tid') ? threads->tid() : 0; |
|
419
|
0
|
0
|
0
|
|
|
0
|
$threaded = ($tid && $tid > 0) ? sprintf('T%02d', $tid) : 'PT-'; |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
my %mp = ( |
|
423
|
|
|
|
|
|
|
'PID' => $$, |
|
424
|
|
|
|
|
|
|
'Loglevel' => $self->{'ANSILEVEL'}->{$lvl}, |
|
425
|
42
|
|
|
|
|
290
|
'Filename' => $self->{'FILENAME'}, |
|
426
|
|
|
|
|
|
|
'Fork' => $forked, |
|
427
|
|
|
|
|
|
|
'Thread' => $threaded, |
|
428
|
|
|
|
|
|
|
); |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# Static substitutions |
|
431
|
42
|
|
|
|
|
285
|
$tmpl =~ s/\%(PID|Loglevel|Filename|Fork|Thread)\%/$mp{$1}/gei; |
|
|
42
|
|
|
|
|
305
|
|
|
432
|
|
|
|
|
|
|
|
|
433
|
42
|
|
|
|
|
219
|
$self->{'_PREFIX_TEMPLATES'}->{$lvl} = $tmpl; |
|
434
|
|
|
|
|
|
|
} |
|
435
|
|
|
|
|
|
|
|
|
436
|
6
|
|
|
|
|
16
|
my $fh = $self->{'FILEHANDLE'}; |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Signal the script has started (and logger initialized) |
|
439
|
6
|
|
|
|
|
19
|
my $name = $SCRIPTNAME; |
|
440
|
6
|
50
|
|
|
|
41
|
$name .= ' [child]' if ($PARENT ne $$); |
|
441
|
6
|
50
|
|
|
|
66
|
my $string = (! $self->{'COLOR'}) ? "----- $name begin -----" : colored(['black on_white'], "----- $name begin -----"); |
|
442
|
6
|
100
|
|
|
|
513
|
print $fh sprintf(' %.02f%s %s%s', 0, $self->{'ANSILEVEL'}->{'DEBUG'}, $string, " (To View in 'less', use it's '-r' switch)"), "\n" if ($self->{'LOGLEVEL'} !~ /ERR/); |
|
443
|
|
|
|
|
|
|
|
|
444
|
6
|
|
|
|
|
23
|
bless($self, $class); |
|
445
|
6
|
|
|
|
|
57
|
return ($self); |
|
446
|
|
|
|
|
|
|
} ## end sub new |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=head2 debug |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
NOTE: This is a legacy method for backwards compatibility. Please use the direct methods instead. |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
The parameters must be passed in the order given |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=over 4 |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=item B |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
The log level with which this message is to be triggered |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=item B |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
A string or a reference to a list of strings to output line by line. |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=back |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub debug { |
|
469
|
114
|
|
|
114
|
1
|
110389
|
my $self = shift; |
|
470
|
114
|
|
|
|
|
298
|
my $level = uc(shift); |
|
471
|
114
|
|
|
|
|
236
|
my $msgs = shift; |
|
472
|
|
|
|
|
|
|
|
|
473
|
114
|
50
|
|
|
|
1015
|
if ($level !~ /ERR.*|WARN.*|NOTICE|INFO.*|DEBUG/i) { # Compatibility with older versions. |
|
474
|
0
|
|
|
|
|
0
|
$level = uc($msgs); # It tosses the legacy __LINE__ argument |
|
475
|
0
|
|
|
|
|
0
|
$msgs = shift; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
114
|
|
|
|
|
499
|
$level =~ s/(OR|ING|RMATION)$//; # Strip off the excess |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
# A much quicker bypass when the log level is below what is needed |
|
480
|
|
|
|
|
|
|
# This minimizes the execution overhead for log levels not active. |
|
481
|
114
|
100
|
|
|
|
632
|
return if ($self->{'LOGLEVEL_VALUE'} < $LevelLogic{$level}); |
|
482
|
|
|
|
|
|
|
|
|
483
|
65
|
|
|
|
|
110
|
my @messages; |
|
484
|
65
|
50
|
|
|
|
298
|
if (ref($msgs) =~ /HASH|CODE|FORMAT|IO/) { |
|
|
|
100
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
0
|
push(@messages, _send_to_Dumper($msgs)); |
|
486
|
|
|
|
|
|
|
} elsif (ref($msgs) eq 'ARRAY') { |
|
487
|
23
|
|
|
|
|
44
|
@messages = @{$msgs}; |
|
|
23
|
|
|
|
|
80
|
|
|
488
|
|
|
|
|
|
|
} else { |
|
489
|
42
|
|
|
|
|
96
|
push(@messages, $msgs); |
|
490
|
|
|
|
|
|
|
} |
|
491
|
65
|
|
|
|
|
245
|
my ($sname, $cline, $nested, $subroutine, $thisBench, $sline, $short) = ('', '', '', '', '', '', ''); |
|
492
|
|
|
|
|
|
|
# Figure out the proper caller tree and line number ladder |
|
493
|
|
|
|
|
|
|
# But only if it's part of the effective level prefix, else don't waste time. |
|
494
|
|
|
|
|
|
|
# The effective level prefix can be different for each call to debug. It cannot be cached. |
|
495
|
65
|
|
33
|
|
|
233
|
my $effective_prefix = $self->{ $level . '-PREFIX' } || $self->{'GLOBAL-PREFIX'}; |
|
496
|
65
|
50
|
|
|
|
550
|
if ($effective_prefix =~ /\%(Subroutine|Module|Lines|Lastline)\%/i) { # %P = Subroutine, %l = Line number(s) |
|
497
|
65
|
|
|
|
|
140
|
my $package = ''; |
|
498
|
65
|
|
|
|
|
102
|
my $count = 1; |
|
499
|
65
|
|
|
|
|
114
|
my $nest = 0; |
|
500
|
65
|
|
|
|
|
274
|
while (my @array = caller($count)) { |
|
501
|
6
|
100
|
|
|
|
22
|
if ($array[3] !~ /Debug::Easy/) { |
|
502
|
2
|
|
|
|
|
5
|
$package = $array[0]; |
|
503
|
2
|
|
|
|
|
6
|
my $subroutine = $array[3]; |
|
504
|
2
|
|
|
|
|
29
|
$subroutine =~ s/^$package\:\://; |
|
505
|
2
|
|
|
|
|
16
|
$sname =~ s/$subroutine//; |
|
506
|
2
|
50
|
|
|
|
10
|
if ($sname eq '') { |
|
507
|
2
|
50
|
|
|
|
9
|
$sname = ($subroutine ne '') ? $subroutine : $package; |
|
508
|
2
|
|
|
|
|
6
|
$cline = $array[2]; |
|
509
|
|
|
|
|
|
|
} else { |
|
510
|
0
|
|
|
|
|
0
|
$sname = $subroutine . '::' . $sname; |
|
511
|
0
|
|
|
|
|
0
|
$cline = $array[2] . '/' . $cline; |
|
512
|
|
|
|
|
|
|
} |
|
513
|
2
|
50
|
|
|
|
7
|
if ($count == 2) { |
|
514
|
0
|
|
|
|
|
0
|
$short = $array[3]; |
|
515
|
0
|
|
|
|
|
0
|
$sline = $array[2]; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
2
|
|
|
|
|
5
|
$nest++; |
|
518
|
|
|
|
|
|
|
} ## end if ($array[3] !~ /Debug::Easy/) |
|
519
|
6
|
|
|
|
|
36
|
$count++; |
|
520
|
|
|
|
|
|
|
} ## end while (my @array = caller...) |
|
521
|
65
|
100
|
|
|
|
162
|
if ($package ne '') { |
|
522
|
2
|
|
|
|
|
6
|
$sname = $package . '::' . $sname; |
|
523
|
2
|
50
|
|
|
|
8
|
$nested = ' ' x $nest if ($nest); |
|
524
|
|
|
|
|
|
|
} else { |
|
525
|
63
|
|
|
|
|
124
|
my @array = caller(1); |
|
526
|
63
|
|
|
|
|
122
|
$cline = $array[2]; |
|
527
|
63
|
50
|
33
|
|
|
240
|
if (!defined($cline) || $cline eq '') { |
|
528
|
63
|
|
|
|
|
445
|
@array = caller(0); |
|
529
|
63
|
|
|
|
|
159
|
$cline = $array[2]; |
|
530
|
|
|
|
|
|
|
} |
|
531
|
63
|
|
|
|
|
110
|
$sname = 'main'; |
|
532
|
63
|
|
|
|
|
139
|
$sline = $cline; |
|
533
|
63
|
|
|
|
|
195
|
$short = $sname; |
|
534
|
|
|
|
|
|
|
} ## end else [ if ($package ne '') ] |
|
535
|
65
|
50
|
|
|
|
160
|
$subroutine = ($sname ne '') ? $sname : 'main'; |
|
536
|
65
|
50
|
|
|
|
233
|
$self->{'PADDING'} = 0 - length($subroutine) if (length($subroutine) > abs($self->{'PADDING'})); |
|
537
|
65
|
50
|
|
|
|
228
|
$self->{'LINES-PADDING'} = 0 - length($cline) if (length($cline) > abs($self->{'LINES-PADDING'})); |
|
538
|
65
|
100
|
|
|
|
197
|
$self->{'SUBROUTINE-PADDING'} = 0 - length($short) if (length($short) > abs($self->{'SUBROUTINE-PADDING'})); |
|
539
|
65
|
100
|
|
|
|
165
|
$self->{'LINE-PADDING'} = 0 - length($sline) if (length($sline) > abs($self->{'LINE-PADDING'})); |
|
540
|
65
|
|
|
|
|
272
|
$cline = sprintf('%' . $self->{'LINES-PADDING'} . 's', $cline); |
|
541
|
65
|
50
|
|
|
|
485
|
$subroutine = (! $self->{'COLOR'}) ? sprintf('%' . $self->{'PADDING'} . 's', $subroutine) : colored(['bold cyan'], sprintf('%' . $self->{'PADDING'} . 's', $subroutine)); |
|
542
|
65
|
|
|
|
|
4412
|
$sline = sprintf('%' . $self->{'LINE-PADDING'} . 's', $sline); |
|
543
|
65
|
50
|
|
|
|
379
|
$short = (! $self->{'COLOR'}) ? sprintf('%' . $self->{'SUBROUTINE-PADDING'} . 's', $short) : colored(['bold cyan'], sprintf('%' . $self->{'SUBROUTINE-PADDING'} . 's', $short)); |
|
544
|
|
|
|
|
|
|
} ## end if ($effective_prefix ...) |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# Figure out the benchmarks, but only if it is in the prefix |
|
547
|
65
|
50
|
|
|
|
4262
|
if ($effective_prefix =~ /\%Benchmark\%/i) { |
|
548
|
|
|
|
|
|
|
# For multiline output, only output the bench data on the first line. Use padded spaces for the rest. |
|
549
|
65
|
|
|
|
|
686
|
$thisBench = sprintf('%7s', sprintf(' %.02f', time - $self->{'ANY_LASTSTAMP'})); |
|
550
|
|
|
|
|
|
|
} ## end if ($effective_prefix ...) |
|
551
|
65
|
|
|
|
|
121
|
my $first = TRUE; # Set the first line flag. |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# Buffer lines to reduce syscalls for multi-line messages |
|
554
|
65
|
|
|
|
|
116
|
my $buffer = ''; |
|
555
|
|
|
|
|
|
|
|
|
556
|
65
|
|
|
|
|
163
|
my $fh = $self->{'FILEHANDLE'}; |
|
557
|
65
|
50
|
66
|
|
|
291
|
if ($level eq 'INFO' && $self->{'LOGLEVEL'} eq 'VERBOSE') { |
|
558
|
|
|
|
|
|
|
# For verbose, we need to print messages without prefixes. |
|
559
|
|
|
|
|
|
|
# Extract lines and print only message contents. |
|
560
|
0
|
|
|
|
|
0
|
foreach my $msg (@messages) { |
|
561
|
0
|
0
|
|
|
|
0
|
if (ref($msg) ne '') { |
|
562
|
0
|
|
|
|
|
0
|
$msg = _send_to_Dumper($msg); |
|
563
|
|
|
|
|
|
|
} |
|
564
|
0
|
0
|
|
|
|
0
|
if ($msg =~ /\n/s) { |
|
565
|
0
|
|
|
|
|
0
|
my @message = split(/\n/, $msg); |
|
566
|
0
|
|
|
|
|
0
|
foreach my $line (@message) { |
|
567
|
0
|
|
|
|
|
0
|
print $fh "$line\n"; |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
} else { |
|
570
|
0
|
|
|
|
|
0
|
print $fh "$msg\n"; |
|
571
|
|
|
|
|
|
|
} |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
} else { |
|
574
|
65
|
|
|
|
|
1969
|
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(); |
|
575
|
65
|
|
|
|
|
363
|
my $Date = sprintf('%02d/%02d/%04d', $mday, ($mon + 1), (1900 + $year)); |
|
576
|
65
|
|
|
|
|
226
|
my $Time = sprintf('%02d:%02d:%02d', $hour, $min, $sec); |
|
577
|
65
|
|
|
|
|
200
|
my $epoch = time; |
|
578
|
|
|
|
|
|
|
|
|
579
|
65
|
|
|
|
|
212
|
foreach my $msg (@messages) { # Loop through each line of output and format accordingly. |
|
580
|
107
|
50
|
|
|
|
328
|
if (ref($msg) =~ /HASH|ARRAY|CODE|FORMAT|IO/) { |
|
581
|
0
|
|
|
|
|
0
|
$msg = _send_to_Dumper($msg); |
|
582
|
|
|
|
|
|
|
} |
|
583
|
107
|
100
|
|
|
|
297
|
if ($msg =~ /\n/s) { # If the line contains newlines, then it too must be split into multiple lines. |
|
584
|
21
|
|
|
|
|
78
|
my @message = split(/\n/, $msg); |
|
585
|
21
|
|
|
|
|
45
|
foreach my $line (@message) { # Loop through the split lines and format accordingly. |
|
586
|
42
|
|
|
|
|
172
|
$buffer .= $self->_format_line($level, $nested, $line, $first, $thisBench, $subroutine, $cline, $sline, $short, $Date, $Time, $epoch); |
|
587
|
42
|
|
|
|
|
88
|
$buffer .= "\n"; |
|
588
|
42
|
|
|
|
|
136
|
$first = FALSE; # Clear the first line flag. |
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
} else { # This line does not contain newlines. Treat it as a single line. |
|
591
|
86
|
|
|
|
|
332
|
$buffer .= $self->_format_line($level, $nested, $msg, $first, $thisBench, $subroutine, $cline, $sline, $short); |
|
592
|
86
|
|
|
|
|
195
|
$buffer .= "\n"; |
|
593
|
|
|
|
|
|
|
} |
|
594
|
107
|
|
|
|
|
314
|
$first = FALSE; # Clear the first line flag. |
|
595
|
|
|
|
|
|
|
} ## end foreach my $msg (@messages) |
|
596
|
65
|
100
|
|
|
|
168
|
if ($level eq 'DEBUGMAX') { # Special version of DEBUG. Extremely verbose debugging and quite noisy |
|
597
|
3
|
50
|
|
|
|
10
|
if ($self->{'LOGLEVEL'} eq 'DEBUGMAX') { |
|
598
|
3
|
|
|
|
|
19
|
print $fh $buffer; |
|
599
|
|
|
|
|
|
|
} |
|
600
|
|
|
|
|
|
|
} else { |
|
601
|
62
|
|
|
|
|
425
|
print $fh $buffer; |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
|
|
605
|
65
|
|
|
|
|
250
|
$self->{'ANY_LASTSTAMP'} = time; |
|
606
|
65
|
|
|
|
|
526
|
$self->{ $level . '_LASTSTAMP' } = time; |
|
607
|
|
|
|
|
|
|
} ## end sub debug |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub _send_to_Dumper { |
|
610
|
0
|
|
|
0
|
|
0
|
local $Data::Dumper::Terse = TRUE; |
|
611
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = TRUE; |
|
612
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useqq = TRUE; |
|
613
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Deparse = TRUE; |
|
614
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Quotekeys = TRUE; |
|
615
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Trailingcomma = TRUE; |
|
616
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sortkeys = TRUE; |
|
617
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Purity = TRUE; |
|
618
|
0
|
|
|
|
|
0
|
return(Dumper(@_)); |
|
619
|
|
|
|
|
|
|
} |
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# Internal: format a single line for logging (without printing) |
|
622
|
|
|
|
|
|
|
sub _format_line { |
|
623
|
128
|
|
|
128
|
|
489
|
my ($self, $level, $padding, $msg, $first, $thisBench, $subroutine, $cline, $sline, $shortsub, $Date, $Time, $epoch) = @_; |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# Build prefix based on precomputed template and runtime substitutions |
|
626
|
128
|
|
|
|
|
374
|
my $tmpl = $self->{'_PREFIX_TEMPLATES'}->{$level}; |
|
627
|
128
|
50
|
|
|
|
310
|
$tmpl = $self->{"$level-PREFIX"} . '' unless defined $tmpl; # Fallback safety |
|
628
|
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
# Clone template since we mutate |
|
630
|
128
|
|
|
|
|
241
|
my $prefix = "$tmpl"; |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
my %mp = ( # Create a temporary index |
|
633
|
|
|
|
|
|
|
'Benchmark' => ($first) ? $thisBench : ' ' x length($thisBench), |
|
634
|
|
|
|
|
|
|
'Lines' => $cline, |
|
635
|
|
|
|
|
|
|
'Lastline' => $cline, |
|
636
|
|
|
|
|
|
|
'Subroutine' => $shortsub, |
|
637
|
|
|
|
|
|
|
'Module' => $subroutine, |
|
638
|
|
|
|
|
|
|
'Date' => $self->{'DATESTAMP'}, |
|
639
|
|
|
|
|
|
|
'Time' => $self->{'TIMESTAMP'}, |
|
640
|
128
|
100
|
|
|
|
1255
|
'Epoch' => $self->{'EPOCH'}, |
|
641
|
|
|
|
|
|
|
'date' => $Date, |
|
642
|
|
|
|
|
|
|
'time' => $Time, |
|
643
|
|
|
|
|
|
|
'epoch' => $epoch, |
|
644
|
|
|
|
|
|
|
); |
|
645
|
128
|
|
|
|
|
809
|
$prefix =~ s/\%(Lines|Lastline|Subroutine|Module|Date|Time|Epoch|date|time|epoch)\%/$mp{$1}/ge; |
|
|
512
|
|
|
|
|
2263
|
|
|
646
|
|
|
|
|
|
|
|
|
647
|
128
|
|
|
|
|
957
|
return "$prefix$padding$msg"; |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=head2 B or B |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
Sends ERROR level debugging output to the log. Errors are always shown. |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=over 4 |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=item B |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
=back |
|
661
|
|
|
|
|
|
|
=cut |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub ERR { |
|
664
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
665
|
0
|
|
|
|
|
0
|
$self->debug('ERR', @_); |
|
666
|
|
|
|
|
|
|
} |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
sub ERROR { |
|
669
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
670
|
0
|
|
|
|
|
0
|
$self->debug('ERR', @_); |
|
671
|
|
|
|
|
|
|
} |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=head2 B or B |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
If the log level is WARN or above, then these warnings are logged. |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=over 4 |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=item B |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=back |
|
684
|
|
|
|
|
|
|
=cut |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
sub WARN { |
|
687
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
688
|
0
|
|
|
|
|
0
|
$self->debug('WARN', @_); |
|
689
|
|
|
|
|
|
|
} |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
sub WARNING { |
|
692
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
693
|
0
|
|
|
|
|
0
|
$self->debug('WARN', @_); |
|
694
|
|
|
|
|
|
|
} |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=head2 B or B |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
If the loglevel is NOTICE or above, then these notices are logged. |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=over 4 |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=item B |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=back |
|
707
|
|
|
|
|
|
|
=cut |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
sub NOTICE { |
|
710
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
711
|
0
|
|
|
|
|
0
|
$self->debug('NOTICE', @_); |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
sub ATTENTION { |
|
715
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
716
|
0
|
|
|
|
|
0
|
$self->debug('NOTICE', @_); |
|
717
|
|
|
|
|
|
|
} |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=head2 B or B |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
If the loglevel is INFO (or VERBOSE) or above, then these information messages are displayed. |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
=over 4 |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=item B |
|
726
|
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=back |
|
730
|
|
|
|
|
|
|
=cut |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
sub INFO { |
|
733
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
734
|
0
|
|
|
|
|
0
|
$self->debug('INFO', @_); |
|
735
|
|
|
|
|
|
|
} |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
sub INFORMATION { |
|
738
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
739
|
0
|
|
|
|
|
0
|
$self->debug('INFO', @_); |
|
740
|
|
|
|
|
|
|
} |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=head2 B |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
If the Loglevel is DEBUG or above, then basic debugging messages are logged. DEBUG is intended for basic program flow messages for easy tracing. Best not to place variable contents in these messages [...] |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=over 4 |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item B |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=back |
|
753
|
|
|
|
|
|
|
=cut |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
sub DEBUG { |
|
756
|
6
|
|
|
6
|
1
|
419
|
my $self = shift; |
|
757
|
6
|
|
|
|
|
23
|
$self->debug('DEBUG', @_); |
|
758
|
|
|
|
|
|
|
} |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=head2 B |
|
761
|
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
If the loglevel is DEBUGMAX, then all messages are shown, and terse debugging messages as well. Typically DEBUGMAX is used for variable dumps and detailed data output for heavy tracing. This is a ve [...] |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=over 4 |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=item B |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
Either a single string or a reference to a list of strings |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=back |
|
771
|
|
|
|
|
|
|
=cut |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
sub DEBUGMAX { |
|
774
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
775
|
0
|
|
|
|
|
|
$self->debug('DEBUGMAX', @_); |
|
776
|
|
|
|
|
|
|
} |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
1; |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=head1 B |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
Since it is possible to duplicate the object in a fork or thread, the output formatting may be mismatched between forks and threads due to the automatic padding adjustment of the subroutine name field [...] |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
Ways around this are to separately create a Debug::Easy object in each fork or thread, and have them log to separate files. |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
The "less" pager is the best for viewing log files generated by this module. It's switch "-r" allows you to see them in all their colorful glory. |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=head1 B |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
To install this module, run the following commands: |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
perl Makefile.PL |
|
793
|
|
|
|
|
|
|
make |
|
794
|
|
|
|
|
|
|
make test |
|
795
|
|
|
|
|
|
|
[sudo] make install |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
=head1 AUTHOR |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
Richard Kelsch |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=head1 B |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
Version 2.19 |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
=head1 B |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
C |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
or if you have "man" installed, then |
|
814
|
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
C |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
You can also look for information at: L |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
=head1 B |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
I coded this module because it filled a gap when I was working for a major chip manufacturing company (which I coded at home on my own time). It gave the necessary output the other coders asked for, [...] |
|
822
|
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
If you have any features you wish added, or functionality improved or changed, then I welcome them, and will very likely incorporate them sooner than you think. |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
=head1 B |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Copyright 2013-2025 Richard Kelsch. |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
L |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, [...] |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of t [...] |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent cla [...] |
|
840
|
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A [...] |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=head1 B |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
Perl modules available on github - L |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
And available on CPAN: |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
* BBS::Universal |
|
850
|
|
|
|
|
|
|
* Debug::Easy |
|
851
|
|
|
|
|
|
|
* Graphics::Framebuffer |
|
852
|
|
|
|
|
|
|
* Term::ANSIEncode |
|
853
|
|
|
|
|
|
|
* BBS::Universal - A Perl based Internet BBS server |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=cut |
|
856
|
|
|
|
|
|
|
|