Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: printing output of a perl script to the Email body

by davies (Prior)
on Jan 29, 2021 at 12:47 UTC ( [id://11127633]=note: print w/replies, xml ) Need Help??


in reply to printing output of a perl script to the Email body

Having a wish to do what the OP wants and being endowed with the super-power of reading :-), I followed the pointers to Email::Stuffer and wrote myself the script below to parse nginx logs & email me every day about who has been trying to access my server (only a few of us should do that). I have given the whole script in case you or anyone wants to trace everything, but the relevant parts are:

use Email::Stuffer; Email::Stuffer->to($opt_email) ->from('nginxlog@davies.systems') ->subject($subject) ->text_body($body) ->transport($transport) ->send;

It's not that different from MIME::Lite. The entire modulino:

package Nginxlog; use strict; use warnings; use feature 'say'; use Data::Dumper; #for debugging use Email::Sender::Transport::SMTP; use Email::Stuffer; use Email::Valid; use Getopt::Long; use Net::Whois::IP; use Pod::Usage; use Regexp::Common qw (net); use Scalar::Util qw(openhandle); my ($opt_debug, $opt_help, $opt_man, $opt_versions, $opt_ignore, $opt_log, $opt_server, $opt_email); GetOptions( 'debug!' => \$opt_debug, 'help!' => \$opt_help, 'man!' => \$opt_man, 'versions!' => \$opt_versions, 'ignore:s' => \$opt_ignore, 'log=s' => \$opt_log, 'email=s' => \$opt_email, 'server=s' => \$opt_server, ) or pod2usage(-verbose => 1) && exit; pod2usage(-verbose => 1) && exit if defined $opt_help; pod2usage(-verbose => 2) && exit if defined $opt_man; END{ if(defined $opt_versions){ print "\nModules, Perl, OS, Program info:\n", " Data::Dumper $Data::Dumper::VERSION\n", " Email::Stuffer $Email::Stuffer::VERSION\n", " Email::Sender::Transport::SMTP $Email::Sender::Transport::SMTP::VER +SION\n", " Getopt::Long $Getopt::Long::VERSION\n", " Net::Whois::IP $Net::Whois::IP::VERSION\n", " Pod::Usage $Pod::Usage::VERSION\n", " Regexp::Common $Regexp::Common::VERSION\n", " Scalar::Util $Scalar::Util::VERSION\n", " strict $strict::VERSION\n", " Perl $]\n", " $0 0.0.1\n", "\n\n"; } } main() unless caller(); my $report; my $ignore; sub main { my $log; $log = setlog($opt_log); $opt_ignore = setignore($opt_ignore); checkemail($opt_email); checkserver($opt_server); open my $fhlog, '<', $opt_log or die "Error opening log file: $!"; open my $fhignore, '<', $opt_ignore; # May be nothing to ignore if (openhandle($fhignore)) { say 'Reading ignore list from file' if $opt_debug; $ignore = do {local $/; <$fhignore>;}; close $fhignore; } $ignore //= ''; say "Ignore list is ->$ignore<-." if $opt_debug; parselog($fhlog); say $report if $opt_debug; sendreport() unless ($opt_debug); } sub setlog { my $log = shift; $log //= '/var/log/nginx/access.log.1'; return $log; } sub setignore { my $ignore = shift; $ignore //= '/var/lib/nginx/ignore'; return $ignore; } sub checkemail { my $email = shift; unless (defined $email) { print "Email address is compulsory\n"; pod2usage(-verbose => 1) && exit; } my $valid = Email::Valid->address($email); return if $valid; print "Email address ->$email<- is invalid\n"; pod2usage(-verbose => 1) && exit; } sub checkserver { my $server = shift; unless (defined $server) { print "Outbound email server is compulsory\n"; pod2usage(-verbose => 1) && exit; } } sub parselog { my ($fh) = @_; for my $line (<$fh>) { parseline($line); } } sub parseline { my ($line) = @_; say "Log entry = ->$line<-" if $opt_debug; my ($ip) = $line =~ m/^($RE{net}{IPv4})/; return unless $ip; say "IP address = ->$ip<-" if $opt_debug; return if $ignore =~ m/$ip;/m; $ignore .= $ip . ';'; $report .= "\n$line"; my $whois = Net::Whois::IP::whoisip_query($ip); print Dumper $whois if $opt_debug; for my $key (qw(source country netname person org-name e-mail phon +e origin inetnum Country NetName OrgAbuseName OrgName OrgAbuseEmail O +rgAbusePhone OriginAS NetRange)) { $report .= "$key: $$whois{$key}\n" if defined $$whois{$key}; } } sub sendreport { my $transport = Email::Sender::Transport::SMTP->new({ host => $opt_server, port => 25, }); my $subject = 'Gogs access logs clear'; $subject = 'Unexpected gogs access attempts' if $report; my $body = $report; $body //= ''; Email::Stuffer->to($opt_email) ->from('nginxlog@davies.systems') ->subject($subject) ->text_body($body) ->transport($transport) ->send; } =pod =head1 NAME Nginxlog.pm =head1 SYNOPSIS perl Nginxlog.pm --email invalid@example.com --server sendmail.exa +mple.com options =head1 DESCRIPTION This modulino parses nginx access logs for signs of inappropriate access. =head1 ARGUMENTS All arguments can be specified with a single minus sign and the first letter if preferred. Two are compulsory, the rest have defaults. --email The destination email address for the report. --email or -e IS COMPULSORY. --server The outbound email server --server or -s IS COMPULSORY. --log The location of the log file. Defaults to /var/log/nginx/access.log.1. This implies that the run will take place after logrotate has opened a new log file, meaning that the modulino will not interfere with or be confused by actions in progress. --ignore The location of a file containing IP addresses that ca +n safely be ignored. Defaults to /var/lib/nginx/ignore. This must be maintained manuall +y. =head1 OPTIONS --help Print Usage, Arguments & Options --man Print entire POD --versions Print Modules, Perl, OS, Program info --debug Print debugging information =head1 AUTHOR John Davies =head1 CREDITS https://www.perlmonks.org/?node_id=155288 https://perlmaven.com/modulino-both-script-and-module =head1 BUGS None TTBOMK. =head1 UPDATES 0.0.1 First development version =cut 1;

Regards,

John Davies

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11127633]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (9)
As of 2024-04-18 11:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found