File Coverage

blib/lib/Message/Passing/Input/FileTail.pm
Criterion Covered Total %
statement 27 58 46.5
branch 0 4 0.0
condition 0 2 0.0
subroutine 9 17 52.9
pod 0 1 0.0
total 36 82 43.9


line stmt bran cond sub pod time code
1             package Message::Passing::Input::FileTail;
2 1     1   860 use Moo;
  1         2  
  1         6  
3 1     1   302 use MooX::Types::MooseLike::Base qw/ Str Int /;
  1         1  
  1         55  
4 1     1   5 use AnyEvent;
  1         2  
  1         25  
5 1     1   6 use Scalar::Util qw/ weaken /;
  1         1  
  1         42  
6 1     1   7 use POSIX ":sys_wait_h";
  1         2  
  1         8  
7 1     1   665 use Sys::Hostname::Long;
  1         2333  
  1         51  
8 1     1   718 use AnyEvent::Handle;
  1         15266  
  1         49  
9 1     1   10 use namespace::clean -except => 'meta';
  1         1  
  1         12  
10              
11 1     1   313 use constant HOSTNAME => hostname_long();
  1         2  
  1         4  
12              
13             with 'Message::Passing::Role::Input';
14              
15             has filename => (
16             is => 'ro',
17             isa => Str,
18             required => 1,
19             );
20              
21             has _tail_handle => (
22             is => 'ro',
23             lazy => 1,
24             builder => '_build_tail_handle',
25             clearer => '_clear_tail_handle',
26             );
27              
28             has raw => (
29             is => 'ro',
30             default => sub { 0 },
31             );
32              
33             sub _emit_line {
34 0     0     my ($self, $line) = @_;
35              
36 0 0         my $data = $self->raw ? $line : {
37             filename => $self->filename,
38             message => $line,
39             hostname => HOSTNAME,
40             epochtime => AnyEvent->now,
41             type => 'log_line',
42             };
43 0           $self->output_to->consume($data);
44             }
45              
46             sub _build_tail_handle {
47 0     0     my $self = shift;
48 0           weaken($self);
49 0 0         die("Cannot open filename '" . $self->filename . "'") unless -r $self->filename;
50 0   0       my $child_pid = open(my $r, "-|", "tail", "-F", $self->filename)
51             || die "can't fork: $!";
52              
53 0           my $cv = AnyEvent->condvar;
54              
55 0           my $hdl;
56             $hdl = AnyEvent::Handle->new(
57             fh => $r,
58             on_read => sub {
59 0     0     my ($hdl) = @_;
60             $hdl->push_read(
61             line => sub {
62 0           my ($hdl, $line, $eof) = @_;
63 0           $self->_emit_line($line);
64             }
65 0           );
66             },
67             on_eof => sub {
68             # must re-initialize the original handle to continue tailing.
69             # the timer isn't necessary, but just to be a good citizen.
70 0     0     my $t;
71             $t = AnyEvent->timer( after => 1, cb => sub {
72 0           $t = undef;
73 0           $hdl = init_tailer( $r);
74 0           });
75             },
76             #on_error => $_handle_error,
77 0           );
78             }
79              
80             sub _init_tailer {
81 0     0     my ($self, $fh) = @_;
82              
83 0           my $hdl;
84             $hdl = AnyEvent::Handle->new(
85             fh => $fh,
86             on_read => sub {
87 0     0     my ($hdl) = @_;
88             $hdl->push_read(
89             line => sub {
90 0           my ($hdl, $line, $eof) = @_;
91 0           $self->_emit_line($line);
92             }
93 0           );
94             },
95             on_eof => sub {
96             # must re-initialize the original handle to continue tailing.
97             # the timer isn't necessary, but just to be a good citizen.
98 0     0     my $t;
99             $t = AnyEvent->timer( after => 1, cb => sub {
100 0           $t = undef;
101 0           $self->_init_tailer($fh);
102 0           });
103             },
104 0           );
105             }
106              
107             sub BUILD {
108 0     0 0   my $self = shift;
109 0           $self->_tail_handle;
110             }
111              
112              
113             1;
114              
115             =head1 NAME
116              
117             Message::Passing::Input::FileTail - File tailing input
118              
119             =head1 SYNOPSIS
120              
121             message-pass --input FileTail --input_options '{"filename": "/var/log/foo.log"} --output STDOUT
122             {"filename":"/var/log/foo.log","message":"example line","hostname":"www.example.com","epochtime":"1346705476","type":"log_line"}
123              
124             =head1 DESCRIPTION
125              
126             =head1 ATTRIBUTES
127              
128             =head2 filename
129              
130             The filename of the file to tail.
131              
132             =head2 raw
133              
134             If the file data should be output raw (as just a line). Normally lines are
135             output as a hash of data including the fields showing in the SYNOPSIS.
136              
137             =head1 SEE ALSO
138              
139             L
140              
141             =head1 SPONSORSHIP
142              
143             This module exists due to the wonderful people at Suretec Systems Ltd.
144             who sponsored its development for its
145             VoIP division called SureVoIP for use with
146             the SureVoIP API -
147            
148              
149             =head1 AUTHOR, COPYRIGHT AND LICENSE
150              
151             See L.
152              
153             =cut
154