The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Clustericious::Log;

use strict;
use warnings;
use List::Util qw( first );
use Log::Log4perl qw( :easy );
use MojoX::Log::Log4perl;
use File::ReadBackwards;
use Clustericious;

# ABSTRACT: A Log::Log4perl wrapper for use with Clustericious.
our $VERSION = '1.16'; # VERSION


sub import {
    my $class = shift;
    my $dest = caller;
    my %args = @_;
    if (my $app_name = $args{-init_logging}) {
        init_logging($app_name);
    }
    @_ = ($class, ':easy');
    goto \&Log::Log4perl::import;
}


our $initPid;
sub init_logging {
    my $app_name = shift;
    $app_name = shift if $app_name eq __PACKAGE__;
    $app_name = $ENV{MOJO_APP} unless $app_name && $app_name ne 'Clustericious::App';

    # Force reinitialization after a fork
    $Log::Log4perl::Logger::INITIALIZED = 0 if $initPid && $initPid != $$;
    $initPid = $$;

    # Logging
    $ENV{LOG_LEVEL} ||= 'WARN';

    my $l4p_dir; # dir with log config file.
    my $l4p_pat; # pattern for screen logging
    my $l4p_file; # file (global or app specific)

    $l4p_dir  = first { -d $_ && (-e "$_/log4perl.conf" || -e "$_/$app_name.log4perl.conf") } Clustericious->_config_path;
    $l4p_pat  = "[%d] [%Z %H %P] %5p: %m%n";
    if ($l4p_dir) {
        $l4p_file = first {-e "$l4p_dir/$_"} ("$app_name.log4perl.conf", "log4perl.conf");
    }

    Log::Log4perl::Layout::PatternLayout::add_global_cspec('Z', sub {$app_name});

    my $logger = MojoX::Log::Log4perl->new( $l4p_dir ? "$l4p_dir/$l4p_file":
      { # default config
       ($ENV{LOG_FILE} ? (
          "log4perl.rootLogger"              => "$ENV{LOG_LEVEL}, File1",
          "log4perl.appender.File1"          => "Log::Log4perl::Appender::File",
          "log4perl.appender.File1.layout"   => "PatternLayout",
          "log4perl.appender.File1.filename" => "$ENV{LOG_FILE}",
          "log4perl.appender.File1.layout.ConversionPattern" => "[%d] [%Z %H %P] %5p: %m%n",
        ):(
          "log4perl.rootLogger"               => "$ENV{LOG_LEVEL}, SCREEN",
          "log4perl.appender.SCREEN"          => "Log::Log4perl::Appender::Screen",
          "log4perl.appender.SCREEN.layout"   => "PatternLayout",
          "log4perl.appender.SCREEN.layout.ConversionPattern" => "$l4p_pat",
       )),
      # These categories (%c) are too verbose by default :
       "log4perl.logger.Mojolicious"                     => "WARN",
       "log4perl.logger.Mojolicious.Plugin.RequestTimer" => "WARN",
       "log4perl.logger.MojoX.Dispatcher.Routes"         => "WARN",
    });

    INFO("Initialized logger");
    INFO("Log config found : $l4p_dir/$l4p_file") if $l4p_dir;
    # warn "# started logging ($l4p_dir/log4perl.conf)\n" if $l4p_dir;
    return $logger;
}


sub tail {
    my $self = shift;
    my %args = @_;
    my $count = $args{lines} || 10;
    my %appenders = %{ Log::Log4perl->appenders };
    my ($first) = sort keys %appenders;
    my $obj = $appenders{$first}->{appender};
    $obj->can("filename") or return "no filename for appender $first";
    my $filename = $obj->filename;
    my $fp = File::ReadBackwards->new($filename) or return "Can't read $filename : $!";
    my @lines;
    my $line;
    while ( defined( $line = $fp->readline ) ) {
        unshift @lines, $line;
        last if ( (0 + @lines) >= $count);
    };
    return join '', @lines;
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Clustericious::Log - A Log::Log4perl wrapper for use with Clustericious.

=head1 VERSION

version 1.16

=head1 SYNOPSIS

 use Clustericious::Log -init_logging => "appname";
 
 use Clustericious::Log;
 INFO "Hi there!";

=head1 DESCRIPTION

This is a simple wrapper around L<Log::Log4perl> for use with
Clustericious.  It handles initialization and exporting of
convenient logging functions, and a default set of logging
patterns.  It also makes the name of the application available
for logging patterns (see the example).

=head1 EXAMPLE

Here is a sample C<~/etc/log4perl.conf> :

 log4perl.rootLogger=TRACE, LOGFILE
 log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
 log4perl.appender.LOGFILE.filename=/tmp/some.log
 log4perl.appender.LOGFILE.mode=append
 log4perl.appender.LOGFILE.layout=PatternLayout
 log4perl.appender.LOGFILE.layout.ConversionPattern=[%d{HH:mm:ss}] [%8.8Z] %C (%F{1}+%L) %5p: %m%n
 # Note 'Z' is the name of the Clustericious application.

=head1 METHODS

=over

=item init_logging

Start logging.  Looks for C<log4perl.conf> or C<$app.log4perl.conf>
in C<~/etc> and C</etc>.

=item tail

Returns a string with the last $n lines of the logfile.

If multiple log files are defined, it only uses the first one alphabetically.

=back

=head1 ENVIRONMENT

The following variables affect logging :

 LOG_LEVEL
 LOG_FILE
 MOJO_APP

=head1 SEE ALSO

L<Log::Log4perl>, L<Clustericious>

=head1 AUTHOR

Original author: Brian Duggan

Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Curt Tilmes

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by NASA GSFC.

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

=cut