Server IP : 85.214.239.14 / Your IP : 3.145.37.211 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/3/root/usr/share/perl5/Mail/SpamAssassin/Logger/ |
Upload File : |
# <@LICENSE> # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to you under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # </@LICENSE> =head1 NAME Mail::SpamAssassin::Logger::Syslog - log to syslog =head1 SYNOPSIS loadplugin Mail::SpamAssassin::Logger::Syslog =head1 DESCRIPTION =cut package Mail::SpamAssassin::Logger::Syslog; use strict; use warnings; # use bytes; use re 'taint'; use POSIX qw(:sys_wait_h setsid sigprocmask); use Time::HiRes (); use Sys::Syslog qw(:DEFAULT setlogsock); use Mail::SpamAssassin::Logger; our @ISA = (); # %prio_map maps Logger.pm log level names (warn, error, info, dbg) # into standard Sys::Syslog::syslog() log level names # our %prio_map = (dbg => 'debug', debug => 'debug', info => 'info', notice => 'notice', warn => 'warning', warning => 'warning', error => 'err', err => 'err', crit => 'crit', alert => 'alert', emerg => 'emerg'); # make sure never to hit the CPAN-RT#56826 bug (memory corruption # when closelog() is called twice), fixed in Sys-Syslog 0.28 our $syslog_open = 0; sub new { my $class = shift; $class = ref($class) || $class; my $self = { }; bless ($self, $class); # initialization $self->{already_done_failure_warning} = 0; $self->{disabled} = 0; $self->{consecutive_failures} = 0; $self->{failure_threshold} = 10; $self->{SIGPIPE_RECEIVED} = 0; # parameters my %params = @_; $self->{ident} = $params{ident} || 'spamassassin'; $self->{log_socket} = $params{socket}; $self->{log_facility} = $params{facility}; $self->{timestamp_fmt} = $params{timestamp_fmt}; $self->{escape} = $params{escape} if exists $params{escape}; if (! $self->init()) { die "logger: syslog initialization failed\n"; } return($self); } # logging via syslog is requested sub init { my ($self) = @_; my $log_socket = $self->{log_socket}; $log_socket = '' if !defined $log_socket; my $eval_stat; eval { if ($log_socket eq '') { # calling setlogsock is optional, let Sys::Syslog choose a default } else { dbg("logger: calling setlogsock($log_socket)"); setlogsock($log_socket) or die "setlogsock($log_socket) failed: $!"; } dbg("logger: opening syslog with $log_socket socket"); # the next call is required to actually open the socket openlog($self->{ident}, 'cons,pid,ndelay', $self->{log_facility}); $syslog_open = 1; 1; } or do { $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; dbg("logger: connection to syslog/$log_socket failed: $eval_stat"); }; # Solaris sometimes doesn't support UNIX-domain syslog sockets apparently; # the same is true for perl 5.6.0 build on an early version of Red Hat 7! # In these cases we try it with INET instead. # See also Bug 6267 and Bug 6331. if (defined($eval_stat) && $log_socket ne 'inet') { dbg("logger: trying setlogsock('inet')"); undef $eval_stat; eval { setlogsock('inet') or die "setlogsock('inet') failed: $!"; dbg("logger: opening syslog using inet socket"); openlog($self->{ident}, 'cons,pid,ndelay', $self->{log_facility}); $syslog_open = 1; 1; } or do { $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; dbg("logger: connection to syslog/inet failed: $eval_stat"); }; } # we failed! if (defined $eval_stat) { return 0; } else { dbg("logger: successfully connected to syslog/$log_socket"); return 1; } } sub log_message { my ($self, $level, $msg, $ts) = @_; return if $self->{disabled}; # map level names $level = $prio_map{$level}; if (!defined $level) { # just in case $level = 'err'; $msg = '(bad prio: ' . $_[1] . ') ' . $msg; } if ($self->{escape}) { # Bug 6583, escape Mail::SpamAssassin::Logger::escape_str($msg); } elsif (!exists $self->{escape}) { # Backwards compatible pre-4.0 escaping, if $escape not given # replace control characters with "_", tabs and spaces get # replaced with a single space. $msg =~ tr/\x09\x20\x00-\x1f/ _/s; } # install a new handler for SIGPIPE -- this signal has been # found to occur with syslog-ng after syslog-ng restarts. local $SIG{'PIPE'} = sub { $self->{SIGPIPE_RECEIVED}++; # force a log-close. trap possible die() calls eval { closelog() } if $syslog_open; $syslog_open = 0; }; my $timestamp = ''; my $fmt = $self->{timestamp_fmt}; if (defined $fmt && $fmt ne '') { # for completeness, rarely used my $now = defined $ts ? $ts : Time::HiRes::time; $timestamp = POSIX::strftime($fmt, localtime($now)); } $msg = $timestamp . ' ' . $msg if $timestamp ne ''; # no longer needed since a patch to bug 6745: # # important: do not call syslog() from the SIGCHLD handler # # child_handler(). otherwise we can get into a loop if syslog() # # forks a process -- as it does in syslog-ng apparently! (bug 3625) # $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 1; my $eval_stat; eval { syslog($level, "%s", $msg); 1; } or do { $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; }; # no longer needed since a patch to bug 6745: # $Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER} = 0; if (defined $eval_stat) { if ($self->check_syslog_sigpipe($msg)) { # dealt with } else { warn "logger: syslog failed: $eval_stat\n"; # only write this warning once, it gets annoying fast if (!$self->{already_done_failure_warning}) { warn "logger: try using --syslog-socket={unix,inet} or --syslog=file\n"; $self->{already_done_failure_warning} = 1; } } $self->syslog_incr_failure_counter(); } else { $self->{consecutive_failures} = 0; $self->check_syslog_sigpipe($msg); # check for SIGPIPE anyway (bug 3625) } $SIG{PIPE} = 'IGNORE'; # this may have been reset (bug 4026) } sub check_syslog_sigpipe { my ($self, $msg) = @_; if (!$self->{SIGPIPE_RECEIVED}) { return 0; # didn't have a SIGPIPE } eval { # SIGPIPE received when writing to syslog -- close and reopen # the log handle, then try again. closelog() if $syslog_open; $syslog_open = 0; openlog($self->{ident}, 'cons,pid,ndelay', $self->{log_facility}); $syslog_open = 1; syslog('debug', "%s", "syslog reopened"); syslog('info', "%s", $msg); # now report what happened $msg = "SIGPIPE received, reopening log socket"; dbg("log: $msg"); syslog('info', "%s", $msg); # if we've received multiple sigpipes, logging is probably still broken. if ($self->{SIGPIPE_RECEIVED}) { warn "logger: syslog failure: multiple SIGPIPEs received\n"; $self->{disabled} = 1; } $self->{SIGPIPE_RECEIVED} = 0; return 1; 1; # just to not forget a good habit } or do { # something died? that's not good. my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; dbg("log: failure in check_syslog_sigpipe: $eval_stat"); $self->syslog_incr_failure_counter(); } } sub syslog_incr_failure_counter { my ($self) = @_; $self->{consecutive_failures}++; if ($self->{consecutive_failures}++ > $self->{failure_threshold}) { warn("logger: syslog() failed " . $self->{consecutive_failures} . " times in a row, disabled\n"); $self->{disabled} = 1; return 1; } return 0; } sub close_log { my ($self) = @_; closelog() if $syslog_open; $syslog_open = 0; } 1;