File Coverage

blib/lib/Log/ger/Layout/Pattern.pm
Criterion Covered Total %
statement 44 45 97.7
branch 8 10 80.0
condition 12 15 80.0
subroutine 10 10 100.0
pod 0 2 0.0
total 74 82 90.2


line stmt bran cond sub pod time code
1             package Log::ger::Layout::Pattern;
2              
3 1     1   2807 use 5.010001;
  1         3  
4 1     1   5 use strict;
  1         42  
  1         37  
5 1     1   6 use warnings;
  1         2  
  1         34  
6              
7 1     1   564 use Devel::Caller::Util;
  1         435  
  1         55  
8 1     1   8 use Log::ger ();
  1         2  
  1         20  
9 1     1   585 use Time::HiRes qw(time);
  1         1556  
  1         6  
10              
11             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
12             our $DATE = '2021-08-24'; # DATE
13             our $DIST = 'Log-ger-Layout-Pattern'; # DIST
14             our $VERSION = '0.008'; # VERSION
15              
16             our $time_start = time();
17             our $time_now = $time_start;
18             our $time_last = $time_start;
19              
20             my %per_message_data;
21             my %cache;
22              
23             our %format_for = (
24             'c' => sub { $_[1]{category} },
25             'C' => sub { $per_message_data{caller0}[0] },
26             'd' => sub {
27             my @t = localtime($time_now);
28             sprintf(
29             "%04d-%02d-%02dT%02d:%02d:%02d",
30             $t[5]+1900, $t[4]+1, $t[3],
31             $t[2], $t[1], $t[0],
32             );
33             },
34             'D' => sub {
35             my @t = gmtime($time_now);
36             sprintf(
37             "%04d-%02d-%02dT%02d:%02d:%02d",
38             $t[5]+1900, $t[4]+1, $t[3],
39             $t[2], $t[1], $t[0],
40             );
41             },
42             'F' => sub { $per_message_data{caller0}[1] },
43             'H' => sub {
44             require Sys::Hostname;
45             Sys::Hostname::hostname();
46             },
47             'l' => sub {
48             sprintf(
49             "%s (%s:%d)",
50             $per_message_data{caller1}[3] // '',
51             $per_message_data{caller0}[1],
52             $per_message_data{caller0}[2],
53             );
54             },
55             'L' => sub { $per_message_data{caller0}[2] },
56             'm' => sub { $_[0] },
57             'M' => sub {
58             $per_message_data{caller1}[3] // '';
59             },
60             'n' => sub { "\n" },
61             'p' => sub { $_[3] },
62             'P' => sub { $$ },
63             'r' => sub { sprintf("%.3f", $time_now - $time_start) },
64             'R' => sub { sprintf("%.3f", $time_now - $time_last ) },
65             'T' => sub {
66             join(", ", map { "$_->[3] called at $_->[1] line $_->[2]" }
67             @{ $per_message_data{callers} });
68             },
69             '_{vmsize}' => sub {
70             unless ($cache{pid_stat_time} &&
71             $cache{pid_stat_time} >= $time_now-1) {
72             open my $fh, "<", "/proc/$$/stat" or die;
73             $cache{pid_stat} = [split /\s+/, scalar(<$fh>)];
74             $cache{pid_stat_time} = $time_now;
75             close $fh;
76             }
77             sprintf("%d", $cache{pid_stat}[22]/1024);
78             },
79              
80             # test
81             #'z' => sub { use DD; my $i = 0; while (my @c = caller($i++)) { dd \@c } },
82             '%' => sub { '%' },
83             );
84              
85             sub meta { +{
86 17     17 0 52301 v => 2,
87             } }
88              
89             my $re = qr/%(_\{\w+\}|[A-Za-z%])/;
90             sub _layout {
91 17     17   48 my $format = shift;
92 17         41 my $packages_to_ignore = shift;
93 17         53 my $subroutines_to_ignore = shift;
94              
95 17         99 ($time_last, $time_now) = ($time_now, time());
96 17         67 %per_message_data = ();
97              
98 17         36 my %mentioned_formats;
99 17         187 while ($format =~ m/$re/g) {
100 20 50       111 if (exists $format_for{$1}) {
101 20         110 $mentioned_formats{$1} = 1;
102             } else {
103 0         0 die "Unknown format '%$1'";
104             }
105             }
106              
107 17 100 100     197 if ($mentioned_formats{C} ||
      100        
      100        
108             $mentioned_formats{F} ||
109             $mentioned_formats{L} ||
110             $mentioned_formats{l}
111             ) {
112             $per_message_data{caller0} =
113 4         25 [Devel::Caller::Util::caller (0, 0, $packages_to_ignore, $subroutines_to_ignore)];
114             }
115 17 100 66     465 if ($mentioned_formats{l} ||
116             $mentioned_formats{M}
117             ) {
118             $per_message_data{caller1} =
119 1         5 [Devel::Caller::Util::caller (1, 0, $packages_to_ignore, $subroutines_to_ignore)];
120             }
121 17 100       133 if ($mentioned_formats{T}) {
122             $per_message_data{callers} =
123 1         7 [Devel::Caller::Util::callers(0, 0, $packages_to_ignore, $subroutines_to_ignore)];
124             }
125              
126 17         377 $format =~ s#$re#$format_for{$1}->(@_)#eg;
  20         91  
127 17         116 $format;
128             }
129              
130             sub get_hooks {
131 17     17 0 322 my %plugin_conf = @_;
132              
133 17 50       73 $plugin_conf{format} or die "Please specify format";
134 17   33     171 $plugin_conf{packages_to_ignore} //= qr/\A(?:Try::Tiny|Log::ger(?:::.+)?)\z/;
135              
136             return {
137             create_layouter => [
138             __PACKAGE__, # key
139             50, # priority
140             sub { # hook
141 17     17   4313 my %hook_args = @_; # see Log::ger::Manual::Internals/"Arguments passed to hook"
142             my $layouter = sub {
143 17         21732 _layout($plugin_conf{format}, $plugin_conf{packages_to_ignore}, $plugin_conf{subroutines_to_ignore}, @_);
144 17         64 };
145 17         67 [$layouter];
146 17         163 }],
147             };
148             }
149              
150             1;
151             # ABSTRACT: Pattern layout
152              
153             __END__