File Coverage

blib/lib/Log/File/Rolling.pm
Criterion Covered Total %
statement 72 76 94.7
branch 17 24 70.8
condition 11 25 44.0
subroutine 12 12 100.0
pod 2 2 100.0
total 114 139 82.0


line stmt bran cond sub pod time code
1             package Log::File::Rolling;
2              
3 5     5   67088 use 5.006001;
  5         14  
4 5     5   20 use strict;
  5         5  
  5         84  
5 5     5   13 use warnings;
  5         8  
  5         115  
6              
7 5     5   2261 use Time::Piece;
  5         46950  
  5         22  
8 5     5   326 use Fcntl ':flock'; # import LOCK_* constants
  5         7  
  5         3480  
9              
10             our $VERSION = '0.101';
11              
12              
13              
14             sub new {
15 3     3 1 56 my $proto = shift;
16 3   33     18 my $class = ref $proto || $proto;
17              
18 3         9 my %p = @_;
19              
20 3         6 my $self = bless {}, $class;
21              
22             # base class initialization
23             #$self->_basic_init(%p);
24              
25 3   50     24 $self->{timezone} = $p{timezone} || 'gmtime';
26             die "unsupported timezone: '$self->{timezone}' (currently must be 'localtime' or 'gmtime')"
27 3 50 33     24 if $self->{timezone} ne 'localtime' && $self->{timezone} ne 'gmtime';
28              
29 3         6 $self->{filename_format} = $p{filename};
30              
31 3 100       6 if (exists $p{current_symlink}) {
32 1         2 $self->{current_symlink} = $p{current_symlink};
33             }
34              
35 3         10 $self->{rolling_fh_pid} = $$;
36 3         10 $self->_createFilename();
37 3         11 $self->_rolling_open_file();
38              
39 3         11 return $self;
40             }
41              
42             sub log { # parts borrowed from Log::Dispatch::FileRotate, Thanks!
43 4     4 1 1455 my $self = shift;
44 4         6 my $message = shift;
45              
46 4 50       10 if ($self->_createFilename()) {
47 0         0 $self->{rolling_fh_pid} = 'x'; # force reopen
48             }
49              
50 4 100 50     58 if (defined $self->{fh} and ($self->{rolling_fh_pid}||'') eq $$ and defined fileno $self->{fh}) { # flock won't work after a fork()
      33        
      66        
51 3         28 my $inode = (stat($self->{fh}))[1]; # get real inode
52 3         26 my $finode = (stat($self->{filename}))[1]; # Stat the name for comparision
53 3 50 33     34 if(!defined($finode) || $inode != $finode) { # Oops someone moved things on us. So just reopen our log
    100          
54 0         0 $self->_rolling_open_file;
55             } elsif (!$self->{current_symlink_inited}) {
56 2         4 $self->_update_current_symlink;
57             }
58 3         11 $self->_lock();
59 3         4 my $fh = $self->{fh};
60 3         17 print $fh $message;
61 3         11 $self->_unlock();
62             } else {
63 1         2 $self->{rolling_fh_pid} = $$;
64 1         3 $self->_rolling_open_file;
65 1         2 $self->_lock();
66 1         1 my $fh = $self->{fh};
67 1         4 print $fh $message;
68 1         2 $self->_unlock();
69             }
70             }
71              
72             sub _rolling_open_file {
73 4     4   4 my $self = shift;
74              
75             open my $fh, '>>:raw', $self->{filename}
76 4 50       299 or die "Cannot write to '$self->{filename}': $!";
77 4         9 $self->{fh} = $fh;
78              
79 4         13 $self->_update_current_symlink;
80             }
81              
82             sub _update_current_symlink {
83 6     6   7 my $self = shift;
84              
85 6 100       23 return if !exists $self->{current_symlink};
86              
87 1         9 my $current_symlink_value = readlink($self->{current_symlink});
88              
89 1 50 33     16 if (!defined $current_symlink_value || $current_symlink_value ne $self->{filename}) {
90 1         5 my $temp_symlink_file = "$self->{current_symlink}.temp$$";
91 1         14 unlink($temp_symlink_file);
92              
93 1 50       31 symlink($self->{filename}, $temp_symlink_file)
94             || die "unable to create symlink '$temp_symlink_file': $!";
95              
96 1 50       33 if (!rename($temp_symlink_file, $self->{current_symlink})) {
97 0         0 unlink($temp_symlink_file);
98 0         0 die "unable to overwrite symlink '$self->{current_symlink}': $!";
99             }
100             }
101              
102 1         3 $self->{current_symlink_inited} = 1;
103             }
104              
105             sub _lock { # borrowed from Log::Dispatch::FileRotate, Thanks!
106 4     4   27 my $self = shift;
107 4         19 flock($self->{fh},LOCK_EX);
108             # Make sure we are at the EOF
109 4         29 seek($self->{fh}, 0, 2);
110 4         5 return 1;
111             }
112              
113             sub _unlock { # borrowed from Log::Dispatch::FileRotate, Thanks!
114 4     4   27 my $self = shift;
115 4         115 flock($self->{fh},LOCK_UN);
116 4         10 return 1;
117             }
118              
119              
120             ## Returns true if the filename changed
121             sub _createFilename {
122 7     7   10 my $self = shift;
123              
124 7         9 my $time = time();
125 7 100 66     44 return 0 if defined $self->{current_filename_time} && $time == $self->{current_filename_time};
126              
127 3         5 $self->{filename} = Time::Piece->${\$self->{timezone}}->strftime($self->{filename_format});
  3         27  
128 3         429 $self->{current_filename_time} = $time;
129 3         5 return 1;
130             }
131              
132             1;
133              
134              
135              
136              
137             __END__