File Coverage

blib/lib/Zonemaster/Engine/Logger/Entry.pm
Criterion Covered Total %
statement 71 75 94.6
branch 12 18 66.6
condition 3 6 50.0
subroutine 18 18 100.0
pod 5 5 100.0
total 109 122 89.3


line stmt bran cond sub pod time code
1             package Zonemaster::Engine::Logger::Entry;
2              
3 26     26   53481 use version; our $VERSION = version->declare("v1.1.4");
  26         1476  
  26         969  
4              
5 26     26   2539 use 5.014002;
  26         91  
6 26     26   133 use warnings;
  26         54  
  26         877  
7              
8 26     26   2106 use Time::HiRes qw[time];
  26         7142  
  26         192  
9 26     26   6177 use JSON::PP;
  26         76669  
  26         1823  
10 26     26   684 use Moose;
  26         381400  
  26         168  
11 26     26   158649 use Zonemaster::Engine;
  26         67  
  26         1011  
12              
13 26     26   172 use overload '""' => \&string;
  26         55  
  26         237  
14              
15             our %numeric = (
16             DEBUG3 => -2,
17             DEBUG2 => -1,
18             DEBUG => 0,
19             INFO => 1,
20             NOTICE => 2,
21             WARNING => 3,
22             ERROR => 4,
23             CRITICAL => 5,
24             );
25              
26             our $start_time = time();
27              
28             my $json = JSON::PP->new->allow_blessed->convert_blessed->canonical;
29              
30             has 'module' => ( is => 'ro', isa => 'Str', lazy_build => 1 );
31             has 'tag' => ( is => 'ro', isa => 'Str', required => 1 );
32             has 'args' => ( is => 'ro', isa => 'Maybe[HashRef]', required => 0 );
33             has 'timestamp' => ( is => 'ro', isa => 'Num', default => sub { time() - $start_time } );
34             has 'trace' => ( is => 'ro', isa => 'ArrayRef[ArrayRef]', builder => '_build_trace' );
35             has 'level' => ( is => 'ro', isa => 'Str', lazy_build => 1, writer => '_set_level' );
36              
37             sub _build_trace {
38 89240     89240   187953 my ( $self ) = @_;
39 89240         145737 my @trace;
40              
41 89240         136361 my $i = 0;
42              
43             # 0 1 2 3 4 5 6 7 8 9 10
44             # $package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash
45 89240         853431 while ( my @line = caller( $i++ ) ) {
46 1933490 100       4335529 next unless index( $line[3], 'Zonemaster::Engine' ) == 0;
47 1813494         10422923 push @trace, [ @line[ 0, 3 ] ];
48             }
49              
50 89240         2773012 return \@trace;
51             }
52              
53             sub _build_module {
54 275     275   563 my ( $self ) = @_;
55              
56 275         474 foreach my $e ( @{ $self->trace } ) {
  275         7311  
57 3107 100 100     5657 if ( $e->[1] eq 'Zonemaster::Engine::Util::info'
58             and $e->[0] =~ /^Zonemaster::Engine::Test::(.*)$/ )
59             {
60 22         644 return uc $1;
61             }
62             }
63              
64 253         6560 return 'SYSTEM';
65             }
66              
67             sub _build_level {
68 10     10   26 my ( $self ) = @_;
69 10         18 my $string;
70              
71 10 100       35 if ( Zonemaster::Engine->config->policy->{ $self->module }{ $self->tag } ) {
72 4         19 $string = uc Zonemaster::Engine->config->policy->{ $self->module }{ $self->tag };
73             }
74             else {
75 6         13 $string = 'DEBUG';
76             }
77              
78 10 100       38 if ( defined $numeric{$string} ) {
79 9         240 return $string;
80             }
81             else {
82 1         11 die "Unknown level string: $string";
83             }
84             }
85              
86             sub numeric_level {
87 10     10 1 23 my ( $self ) = @_;
88              
89 10         282 return $numeric{ $self->level };
90             }
91              
92             sub levels {
93 3     3 1 37 return %numeric;
94             }
95              
96             sub string {
97 10     10 1 1314 my ( $self ) = @_;
98 10         18 my $argstr = q{};
99             ## no critic (TestingAndDebugging::ProhibitNoWarnings)
100 26     26   14912 no warnings 'uninitialized';
  26         113  
  26         7229  
101              
102 10 50       291 if ( $self->args ) {
103 10         26 my $p_args = $self->printable_args;
104             $argstr = join( q{; },
105 13 50       56 map { $_ . q{=} . ( ref( $p_args->{$_} ) ? $json->encode( $p_args->{$_} ) : $p_args->{$_} ) }
106 10         20 sort keys %{$p_args} );
  10         34  
107             }
108              
109 10         268 return sprintf( '%s:%s %s', $self->module, $self->tag, $argstr );
110             }
111              
112             sub printable_args {
113 11     11 1 22 my ( $self ) = @_;
114              
115 11 50       264 if ( $self->args ) {
116 11         21 my %p_args;
117 11         18 foreach my $key_arg ( keys %{ $self->args } ) {
  11         258  
118 14 50 0     331 if ( not ref( $self->args->{$key_arg} ) ) {
    0          
119 14         323 $p_args{$key_arg} = $self->args->{$key_arg};
120             }
121             elsif ( $key_arg eq q{asn} and ref( $self->args->{$key_arg} ) eq q{ARRAY} ) {
122 0         0 $p_args{q{asn}} = join( q{,}, @{ $self->args->{$key_arg} } );
  0         0  
123             }
124             else {
125 0         0 $p_args{$key_arg} = $self->args->{$key_arg};
126             }
127             }
128 11         35 return \%p_args;
129             }
130              
131 0         0 return;
132             } ## end sub printable_args
133              
134             ###
135             ### Class method
136             ###
137              
138             sub start_time_now {
139 250     250 1 882 $start_time = time();
140 250         554 return;
141             }
142              
143 26     26   177 no Moose;
  26         104  
  26         148  
144             __PACKAGE__->meta->make_immutable;
145              
146             1;
147              
148             =head1 NAME
149              
150             Zonemaster::Engine::Logger::Entry - module for single log entries
151              
152             =head1 SYNOPSIS
153              
154             Zonemaster::Engine->logger->add( TAG => { some => 'arguments' });
155              
156             There should never be a need to create a log entry object in isolation. They should always be associated with and created via a logger object.
157              
158             =head1 CLASS METHODS
159              
160             =over
161              
162             =item levels
163              
164             Returns a hash where the keys are log levels as strings and the corresponding values their numeric value.
165              
166             =item start_time_now()
167              
168             Set the logger's start time to the current time.
169              
170             =back
171              
172             =head1 ATTRIBUTES
173              
174             =over
175              
176             =item module
177              
178             An auto-generated identifier of the module that created the log entry. If it was generated from a module under Zonemaster::Engine::Test, it will be an
179             uppercased version of the part of the name after "Zonemaster::Engine::Test". For example, "Zonemaster::Engine::Test::Basic" gets the module identifier "BASIC". If the
180             entry was generated from anywhere else, it will get the module identifier "SYSTEM".
181              
182             =item tag
183              
184             The tag that was set when the entry was created.
185              
186             =item args
187              
188             The argument hash reference that was provided when the entry was created.
189              
190             =item timestamp
191              
192             The time after the current program started running when this entry was created. This is a floating-point value with the precision provided by
193             L<Time::HiRes>.
194              
195             =item trace
196              
197             A partial stack trace for the call that created the entry. Used to create the module tag. Almost certainly not useful for anything else.
198              
199             =back
200              
201             =head1 METHODS
202              
203             =over
204              
205             =item string
206              
207             Simple method to generate a string representation of the log entry. Overloaded to the stringification operator.
208              
209             =item printable_args
210              
211             Used to transform data from an internal/JSON representation to a "user friendly" representation one.
212              
213             =item numeric_level
214              
215             Returns the log level of the entry in numeric form.
216              
217             =back
218              
219             =cut