The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
package Carp::Syslog;

use v5.10;
use strict;
use Sys::Syslog;

our $VERSION = '0.01';

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

    # Defaults.
    my $ident    = $0;
    my $logopt   = '';
    my $facility = 'user';

    if ( defined $args ) {
        if ( ref $args eq 'HASH' ) {
            $ident    = $args->{'ident'}    if exists $args->{'ident'};
            $logopt   = $args->{'logopt'}   if exists $args->{'logopt'};
            $facility = $args->{'facility'} if exists $args->{'facility'};
        }
        else {
            $facility = $args;
        }
    }

    openlog( $ident, $logopt, $facility );

    $SIG{'__WARN__'} = sub {
        if ( ( caller 0 )[10]->{'Carp::Syslog'} ) { # hint on?
            ( my $message = $_[0] ) =~ s/\n$//;
            syslog( 'warning', $message );
        }

        warn $_[0];
    };

    $SIG{'__DIE__'} = sub {
        if ( ( caller 0 )[10]->{'Carp::Syslog'} ) { # hint on?
            my $message;

            if ( ref $_[0] ) {
                # We only want to to log references if they can stringify.
                require overload;
                if ( "$_[0]" ne overload::StrVal( $_[0] ) ) {
                    $message = "$_[0]";
                }
            }
            else {
                $message = $_[0];
            }

            if ( defined $message ) {
                $message =~ s/\n$//;
                syslog( 'err', $message );
            }
        }

        die $_[0];
    };

    # Also export Carp's defaults to calling namespace.
    require Carp;
    {
        no strict 'refs';
        my $caller = caller 0;

        *{ $caller . '::carp' }    = \&Carp::carp;
        *{ $caller . '::croak' }   = \&Carp::croak;
        *{ $caller . '::confess' } = \&Carp::confess;
    }

    $^H{'Carp::Syslog'} = 1;
}

sub unimport {
    $^H{'Carp::Syslog'} = 0;
}

END {
    closelog();
}

1;

=head1 NAME

Carp::Syslog - Send warn and die messages to syslog

=head1 SYNOPSIS

    # Defaults shown.
    use Carp::Syslog { ident => $0, logopt => '', facility => 'user' };

    warn '...';    # logs to user:warning

    die '...';     # logs to user:err

    # Shortcut for simplicity.
    use Carp::Syslog 'user';

    {
        no Carp::Syslog;

        warn '...';    # doesn't log to syslog
        die '...';     # ditto
    }

    # Also useful on the command line.
    perl -MCarp::Syslog=user script.pl

=head1 DESCRIPTION

I got tired of writing this all the time:

    use Sys::Syslog;
    use File::Basename qw( basename );

    BEGIN {
        openlog( basename($0), 'pid', 'local1' );
        $SIG{'__WARN__'} = sub { syslog( 'warning', @_ ); warn @_ };
        $SIG{'__DIE__'}  = sub { syslog( 'err', @_ ); die @_ };
    }
    END { closelog() }

Sure, there are modules like L<Log::Log4perl> and L<Log::Dispatch>, but those
are overly complicated for quick, system administrator style scripts.  The
C<Carp::Syslog> module allows, in one line (or less if used on the command
line), to send all warn() and die() calls to the system's syslog.

=head1 CAVEATS

The C<__WARN__> and C<__DIE__> signal handlers are overridden.

Calling cluck() or confess() will really fill up your logs.

=head1 AUTHOR

Chris Grau L<mailto:cgrau@cpan.org>

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2011-2012, Chris Grau.

=head1 SEE ALSO

L<Sys::Syslog>

=cut