File Coverage

blib/lib/Log/ger/Output/File.pm
Criterion Covered Total %
statement 40 47 85.1
branch 16 30 53.3
condition 8 14 57.1
subroutine 7 8 87.5
pod 0 2 0.0
total 71 101 70.3


line stmt bran cond sub pod time code
1             ## no critic (InputOutput::RequireBriefOpen)
2              
3             package Log::ger::Output::File;
4              
5             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
6             our $DATE = '2020-03-11'; # DATE
7             our $DIST = 'Log-ger-Output-File'; # DIST
8             our $VERSION = '0.012'; # VERSION
9              
10 1     1   2074 use strict;
  1         2  
  1         25  
11 1     1   5 use warnings;
  1         2  
  1         25  
12              
13             # supply object methods for filehandles, required for older perls e.g. 5.10
14 1     1   386 use FileHandle;
  1         1974  
  1         4  
15              
16             our %lock_handles;
17              
18             sub meta { +{
19 5     5 0 9415 v => 2,
20             } }
21              
22             sub get_hooks {
23 5     5 0 58 my %plugin_conf = @_;
24              
25 5         7 my $lazy = $plugin_conf{lazy};
26 5 50       7 my $autoflush = $plugin_conf{autoflush}; $autoflush = 1 unless defined $autoflush;
  5         12  
27 5   50     19 my $lock_mode = $plugin_conf{lock_mode} || 'none';
28              
29 5 100 100     23 (defined($plugin_conf{path}) || $plugin_conf{handle}) or
30             die "Please specify 'path' or 'handle'";
31 4 50       19 $lock_mode =~ /\A(none|write|exclusive)\z/ or
32             die "Invalid lock_mode, please choose none|write|exclusive";
33             $lock_mode ne 'none' && $plugin_conf{handle} and
34 4 0 33     9 die "Locking using handle not supported for now";
35              
36             my $code_lock = sub {
37 0     0   0 require File::Flock::Retry;
38 0 0       0 my $key = defined($plugin_conf{path}) ? ":$plugin_conf{path}" : $plugin_conf{handle};
39 0 0       0 if ($lock_handles{$key}) {
40 0         0 return $lock_handles{$key};
41             }
42 0         0 $lock_handles{$key} = File::Flock::Retry->lock("$plugin_conf{path}.lck");
43             #Scalar::Util::weaken($lock_handles{$key});
44             # XXX how do we purge old %lock_handles keys?
45 0         0 return $lock_handles{$key};
46 4         18 };
47              
48 4         6 my $fh;
49             my $code_open = sub {
50 4 50   4   7 return if $fh;
51 4 100       9 if (defined(my $path = $plugin_conf{path})) {
52 3 50       153 open $fh, ">>", $path or die "Can't open log file '$path': $!";
53             } else {
54 1         1 $fh = $plugin_conf{handle};
55             }
56 4         10 $fh;
57 4         8 };
58              
59 4 50       9 if ($lock_mode eq 'exclusive') {
60 0         0 $code_lock->();
61             }
62              
63 4 100       13 $code_open->() unless $lazy;
64              
65             return {
66             create_outputter => [
67             __PACKAGE__, # key
68             50, # priority
69             sub { # hook
70 12     12   1830 my %hook_args = @_; # see Log::ger::Manual::Internals/"Arguments passed to hook"
71              
72             my $outputter = sub {
73 4         3908 my ($per_target_conf, $msg, $per_msg_conf) = @_;
74 4         9 my $lock_handle;
75 4 100 66     13 $code_open->() if $lazy && !$fh;
76 4 50       9 $lock_handle = $code_lock->() if $lock_mode eq 'write';
77 4         21 print $fh $msg;
78 4 50       14 print $fh "\n" unless $msg =~ /\R\z/;
79 4 50 33     111 $fh->flush if $autoflush || $lock_handle;
80 4         17 undef $lock_handle;
81 12         33 };
82 12         46 [$outputter];
83 4         30 }],
84             };
85             }
86              
87             1;
88             # ABSTRACT: Send logs to file
89              
90             __END__