package AsyncLogWatcher;

# ABSTRACT: Asynchronously watches log files for specific patterns.

use strict;
use warnings;

our $VERSION = '0.01';

use AnyEvent;
use File::Tail;

sub new {
    my ($class, $args) = @_;

    my $self = {
        log_file => $args->{log_file},
        patterns_file => $args->{patterns_file},
        on_match => $args->{on_match} // sub {},
    };

    bless $self, $class;
    return $self;
}

sub watch {
    my ($self) = @_;

    my @patterns;
    open(my $fh, '<', $self->{patterns_file}) or die "Could not open file '$self->{patterns_file}' $!";
    while (my $row = <$fh>) {
        chomp $row;
        push @patterns, $row;
    }
    close($fh);

    my $file_tail = File::Tail->new(name => $self->{log_file});

    my $watcher;
    $watcher = AnyEvent->io(
        fh   => $file_tail,
        poll => 'r',
        cb   => sub {
            while (defined(my $line = $file_tail->read)) {
                foreach my $pattern (@patterns) {
                    if ($line =~ /$pattern/i) {
                        $self->{on_match}->($line);
                    }
                }
            }
        },
    );

    return $watcher;
}

1;

__END__

=head1 NAME

AsyncLogWatcher - Asynchronously watches log files for specific patterns

=head1 VERSION

Version 0.01

=head1 SYNOPSIS

    use AsyncLogWatcher;

    my $watcher = AsyncLogWatcher->new({
        log_file => '/path/to/log',
        patterns_file => '/path/to/patterns',
        on_match => sub {
            my ($line) = @_;
            print "Matched line: $line\n";
        },
    });

    my $guard = $watcher->watch;  # Continues to watch until $guard goes out of scope

=head1 DESCRIPTION

The AsyncLogWatcher module provides a way to asynchronously watch a log file and perform actions when specific patterns are matched. The module uses AnyEvent for asynchronous processing and File::Tail for continuous log file reading.

=head1 METHODS

=head2 new

Creates a new instance of AsyncLogWatcher. It accepts a hashref with the following keys:

=over 4

=item * log_file: The log file to watch.

=item * patterns_file: A file containing patterns to match. Each pattern should be on a new line in the file.

=item * on_match: A callback to be executed when a line in the log file matches a pattern. The matched line is passed to the callback.

=back

=head2 watch

Starts watching the log file for matches against the given patterns. It returns a guard object. As long as the guard is in scope, the watcher will continue watching the log file. 

=head1 AUTHOR

Kawamura Shingo, <pannakoota@gmail.com>

=head1 LICENSE AND COPYRIGHT

Copyright 2023 Kawamura Shingo.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=cut

