Log-Dispatch-Email-Async

 view release on metacpan or  search on metacpan

lib/Log/Dispatch/Email/Async.pm  view on Meta::CPAN

package Log::Dispatch::Email::Async;
use 5.010;
use strict;
use warnings;  # FATAL => 'all';
# use Modern::Perl;
use Carp;

########################################################################################
#  TODOs
#     - add option to silenty fail, not croak, upon network unavailability
#     - in tests
#        - complete test TODOs
#        - group tests into sub-groups, files? or simplify with only 1 test?
#        - write creation-only tests sub-group after ping() - NOT POSSIBLE
#        - change 'detele enails' to 'move to trash - for gmail'
#        - seperate ask() into a own module - NOT NEEDED ANYMORE
#           -  hierarchical args struct? how to self address as in <domain>?
#           - final string in ask() should show secs at close instead of full value
#           - shorten default replys in final string to fit in line
########################################################################################

use threads;
use Thread::Queue;
use Mail::Sender;
use Log::Dispatch::Email;

use parent 'Log::Dispatch::Email';

our $VERSION = '0.01';

sub new {
   my ( $proto, %params ) = @_;
   my $class = ref $proto || $proto;

   my $self = bless {}, $class;
   $self->_basic_init( %params );

   $self->{debug_mode} = $params{debug_mode} || 0;
   delete $params{debug_mode} if exists $params{debug_mode};

   say "creating ", ref( $self ) if $self->{debug_mode} >= 3;

   $self->{timeout} = $params{timeout} || 30;
   delete $params{timeout} if exists $params{timeout};

   $self->{thread_count} = $params{thread_count} || 2;
   delete $params{thread_count} if exists $params{thread_count};

   $self->{stack_size} = $params{stack_size} || 4;
   delete $params{stack_size} if exists $params{stack_size};
   $self->{stack_size} = 4 if $self->{stack_size} < 4;
   # threads->set_stack_size( $self->{stack_size} * 4096 );

   $self->{ident} = 'object';
   $self->{tid} = threads->tid();      
   $self->{ndx} = 0;
   $self->{count} = 0;

   $self->{mailer} = Mail::Sender->new( \%params );
   if ( ref( $self->{mailer} ) eq 'Mail::Sender' ) {
      say ref($self), "\tcreated ", ref( $self->{mailer} ) if $self->{debug_mode} >= 3;
   } else {
      croak ref($self), ": cannot create Mail::Sender: $Mail::Sender::Error"
   }

lib/Log/Dispatch/Email/Async.pm  view on Meta::CPAN

      $self->{mailq}->end();
      my @left = (); 
      unless ( $timeleft ) {
         $_->kill('TERM') for threads->list( threads::running );
         my $args; push @left, $args while defined ($args = $self->{mailq}->dequeue());
      }
      my $sent = 0;
      for my $n ( 1 .. $self->{thread_count} ) {
         $sent += $self->{thread}[$n]->join();
         say ref($self), ": thread ", $self->{thread}[$n]->tid(), " has been joined" 
            if $self->{debug_mode} >= 2;
      }
      if ( $self->{count} != $sent ) { # number queued in main vs. total sent from all threads
         my $left = scalar(@left)." emails\n\t".join("\n\t", map {$_->{subject}} @left);
         carp ref($self), ": queued $self->{count}; sent $sent; throwing away after $self->{timeout} secs, $left\n";
      } else {
         say ref($self), ": closing $self->{ident} \\w tid $self->{tid} after $self->{count} emails queued"
            if $self->{debug_mode} >= 1;
      }
      
      # unless ( $timeleft ) {
      #    $_->kill('TERM') for threads->list( threads::running );
      # }
      # $self->{mailer}->Close(1);
      # $self->{mailq}->end();
      # my ( $sent, @left, $args ) = ( 0, () ); 
      # push @left, $args while defined ($args = $self->{mailq}->dequeue());
      # for my $n ( 1 .. $self->{thread_count} ) {
      #    $sent += $self->{thread}[$n]->join();
      #    say ref($self), ": thread ", $self->{thread}[$n]->tid(), " has been joined" if $self->{debug_mode} >= 1;
      # }
      # if ( $self->{count} != $sent ) { # number queued in main vs. total sent from all threads
      #    my $left = scalar(@left)." emails\n\t".join("\n\t", map {$_->{subject}} @left);
      #    carp ref($self), ": queued $self->{count}; sent $sent; throwing away $left\n";
      # } else {
      #    say ref($self), ": closing $self->{ident} \\w tid $self->{tid} after $self->{count} emails queued"
      #       if $self->{debug_mode} >= 1;
      # }

   } else {
      say ref($self), ": closing $self->{ident} \\w tid $self->{tid} after $self->{count} emails sent"
         if $self->{debug_mode} >= 1;
   }
}

1; # End of Log::Dispatch::Email::Async

__END__

=head1 NAME

Log::Dispatch::Email::Async - A L<Log::Log4Perl> appender for async email

=head1 VERSION

Version 0.01

=head1 SYNOPSIS

   #!/usr/bin/perl
   use Modern::Perl;
   
   use Log::Log4perl qw/:levels/;
   use Log::Log4perl::Layout;
   use Proc::Daemon;
   
   Log::Log4perl::init( 'log4perl.conf' );
   my $fa = Log::Log4perl->appender_by_name( 'File' );
   my $logger = Log::Log4perl->get_logger( 'main' );
   
   Proc::Daemon::Init( {
      dont_close_fh  => [ $fa->{LDF}{fh},  ],   # for File log appender
      dont_close_fd  => [ 1, 2,  ],             # for Screen log appender
   } );
   
   my $email_appender = Log::Log4perl::Appender->new(
      'Log::Dispatch::Email::Async',

      # options for Log::Dispatch::Email::Async
      timeout        => 30,  # optional, default 30 secs
      thread_count   =>  2,  # optional, default 2 thread
      stack_size     => 16,  # optional, default 16 kilobyte
      debug_mode     =>  0,  # optional, default 0

      # options for Mail::Sender
      smtp           => 'smtp.example.com',	
      port           => 587,
      auth           => 'LOGIN',
      tls_required   => 1,
      authid         => 'username',
      authpwd        => 'password',

      # options for Log::Dispatch::Email
      buffered       => 0,
      subject        => "message logged from '$0'",
      from           => 'sender@example.com',
      to             => 'receipent@cpan.org', # reqd.

      # options for Log::Dispatch::Output
      name           => 'Email',              # reqd.
      min_level      => 1,
      max_level      => 5,
   );

   $email_appender->layout( 
      Log::Log4perl::Layout::PatternLayout->new('%p: %m%n%l' );
   $logger->add_appender( $email_appender );
   $logger->level($INFO);

   $logger->info( "start $0\n\nreceipient@domain.org\n\nMessage body . . ." );   

   my $RUN = 1;
   $SIG{TERM} = sub { $RUN = 0; };

   while ( $RUN ) {
      . . .
   }

=head1 DESCRIPTION

=head2 Introduction



( run in 1.304 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )