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   1000 use Moo;
  1         3  
  1         5  
3 1     1   319 use MooX::Types::MooseLike::Base qw/ Str Int /;
  1         2  
  1         90  
4 1     1   8 use AnyEvent;
  1         3  
  1         25  
5 1     1   7 use Scalar::Util qw/ weaken /;
  1         2  
  1         43  
6 1     1   5 use POSIX ":sys_wait_h";
  1         2  
  1         8  
7 1     1   814 use Sys::Hostname::Long;
  1         2677  
  1         60  
8 1     1   846 use AnyEvent::Handle;
  1         18703  
  1         51  
9 1     1   10 use namespace::clean -except => 'meta';
  1         4  
  1         10  
10              
11 1     1   803 use constant HOSTNAME => hostname_long();
  1         3  
  1         6  
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<Message::Passing>
140              
141             =head1 SPONSORSHIP
142              
143             This module exists due to the wonderful people at Suretec Systems Ltd.
144             <http://www.suretecsystems.com/> who sponsored its development for its
145             VoIP division called SureVoIP <http://www.surevoip.co.uk/> for use with
146             the SureVoIP API -
147             <http://www.surevoip.co.uk/support/wiki/api_documentation>
148              
149             =head1 AUTHOR, COPYRIGHT AND LICENSE
150              
151             See L<Message::Passing>.
152              
153             =cut
154