package OVH::SimpleLog;

# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;

# Simple package to log either to a file, to syslog, or to both
# Exports the _log, _warn and _err routines to do so

use base qw (Exporter);
our @EXPORT = qw(_log _warn _err);    ## no critic (ProhibitAutomaticExportation)

use Term::ANSIColor;
use Sys::Syslog qw{};

# Log file handler
my $LOG_FH;

# Syslog
my $FACILITY;

# Program name
my $PROGNAME;

# Incremented at each call of _err and _warn, count can be
# fetched with nb_errors() and nb_warnings()
my $NB_ERRORS   = 0;
my $NB_WARNINGS = 0;

BEGIN {
    # Extract program base name
    $PROGNAME = $0;
    if ($PROGNAME =~ /\/([^\/]+)$/) {
        $PROGNAME = $1;
    }
}

# Set a log file
sub setLogFile {
    my $filename = shift;
    if (not open($LOG_FH, '>>', $filename)) {
        _warn("Unable to open log file '$filename' ($!)");
        return 0;
    }
    return 1;
}

sub setSyslog {

    # if we previously opened syslog, close it
    closeSyslog();

    # then (re)open it with the wanted facility
    $FACILITY = shift;
    Sys::Syslog::openlog($PROGNAME . "[$$]", 'nofatal', $FACILITY);

    return 1;
}

sub closeSyslog {

    Sys::Syslog::closelog() if $FACILITY;
    undef $FACILITY;

    return 1;
}

sub _log  { _display('LOG', @_); return 1; }                     ## no critic (ProhibitUnusedPrivateSubroutines)
sub _warn { _display('WARN', @_); $NB_WARNINGS++; return 1; }
sub _err  { _display('ERR',  @_); $NB_ERRORS++;   return 1; }    ## no critic (ProhibitUnusedPrivateSubroutines)

#   Display a message
sub _display {
    my $level   = shift;
    my $message = shift;

    #   Prepare message and possibly color
    my $color   = '';
    my $fullmsg = $message;
    my $OUT     = 'STDOUT';
    if ($level eq 'ERR') {
        $color   = 'red';
        $fullmsg = "ERROR: $message";
        $OUT     = 'STDERR';
    }
    elsif ($level eq 'WARN') {
        $color   = 'yellow';
        $fullmsg = "WARN: $message";
        $OUT     = 'STDERR';
    }

    # If it's not for a terminal, don't colorize log
    # perlcritic doesn't like -t, but IO::Interactive is not in core as per corelist
    $color = '' if not -t $OUT;    ## no critic (ProhibitInteractiveTest)

    my $coloredmsg = $fullmsg;
    $coloredmsg = colored($fullmsg, $color) if $color;
    if ($OUT eq 'STDERR') {
        print STDERR $coloredmsg . "\n";
    }
    else {
        print $coloredmsg. "\n";
    }

    # Print on a log file (if needed)
    if ($LOG_FH) {
        printf $LOG_FH "%s [%6s] %s: %s\n", scalar(localtime()), $level, $PROGNAME, $message;
    }

    # Push to syslog (only if a facility has been defined, which means openlog() has been called)
    if ($FACILITY) {

        # valid levels: DEBUG, INFO, NOTICE, WARNING, ERR, EMERG
        my $priority = uc($level);
        $priority = 'WARNING' if $priority eq 'WARN';
        $priority = 'INFO'    if (!grep { $priority eq $_ } qw{ DEBUG NOTICE WARNING ERR EMERG });
        eval { Sys::Syslog::syslog($priority, $fullmsg); };
        if ($@) {
            print STDERR "Couldn't syslog, report to administrator ($@)\n";
        }
    }

    return 1;
}

sub nb_errors   { return $NB_ERRORS; }
sub nb_warnings { return $NB_WARNINGS; }

END {
    close($LOG_FH)          if (defined $LOG_FH);
    Sys::Syslog::closelog() if (defined $FACILITY);
}

1;
