File Coverage

blib/lib/Perlbal/Plugin/Syslogger.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Perlbal::Plugin::Syslogger;
2              
3 2     2   630701 use strict;
  2         6  
  2         198  
4 2     2   44 use warnings;
  2         7  
  2         345  
5              
6             our $VERSION = '1.00';
7              
8 2     2   11996 use Log::Syslog::Constants 1.00;
  2         27053  
  2         128  
9 2     2   1199 use Log::Syslog::DangaSocket 1.05;
  0            
  0            
10             use Log::Syslog::Fast;
11             use Perlbal;
12             use Sys::Hostname;
13              
14             use base 'Exporter';
15              
16             our @EXPORT_OK = qw/ send_syslog_msg replace_perlbal_log /;
17              
18             sub load {
19             my $class = shift;
20              
21             Perlbal::Service::add_tunable(
22             syslog_transport => {
23             check_role => '*',
24             des => "Transport type (udp, tcp, or unix)",
25             default => 'udp',
26             check_type => sub {
27             my ($self, $val, $errref) = @_;
28             $val = lc $val;
29             return 1 if $val eq 'udp' || $val eq 'tcp' || $val eq 'unix';
30             $$errref = "Expecting transport of udp, tcp, or unix";
31             return 0;
32             },
33             }
34             );
35             Perlbal::Service::add_tunable(
36             syslog_host => {
37             check_role => '*',
38             des => "Host where the syslogd is running (tcp/udp), or log socket (unix).",
39             default => '127.0.0.1',
40             }
41             );
42             Perlbal::Service::add_tunable(
43             syslog_port => {
44             check_role => '*',
45             des => "Port on syslog_host where syslogd listens.",
46             default => 514,
47             check_type => 'int',
48             }
49             );
50             Perlbal::Service::add_tunable(
51             syslog_source => {
52             check_role => '*',
53             des => "Name of the submitting service (gets included in the log message)",
54             default => 'Perlbal',
55             }
56             );
57             Perlbal::Service::add_tunable(
58             syslog_name => {
59             check_role => '*',
60             des => "Host of the submitting service (gets included in the log message)",
61             default => hostname() || 'localhost',
62             }
63             );
64             Perlbal::Service::add_tunable(
65             syslog_facility => {
66             check_role => '*',
67             des => "Facility to log to; may be named or numeric",
68             default => Log::Syslog::Constants::LOG_LOCAL0,
69             }
70             );
71             Perlbal::Service::add_tunable(
72             syslog_severity => {
73             check_role => '*',
74             des => "Severity level to log to; may be named or numeric",
75             default => Log::Syslog::Constants::LOG_NOTICE,
76             }
77             );
78             }
79              
80             sub register {
81             my ($class, $svc) = @_;
82              
83             # stash the object that does all our work within the service configuration
84             my $cfg = $svc->{extra_config} ||= {};
85              
86             my $facility = $cfg->{syslog_facility};
87             if ($facility =~ /\D/) {
88             $facility = Log::Syslog::Constants::get_facility($facility);
89             die "unknown syslog facility $facility\n" unless defined $facility;
90             }
91              
92             my $severity = $cfg->{syslog_severity};
93             if ($severity =~ /\D/) {
94             $severity = Log::Syslog::Constants::get_severity($facility);
95             die "unknown syslog severity $severity\n" unless defined $severity;
96             }
97              
98             my $transport = lc $cfg->{syslog_transport};
99             if ($transport eq 'udp') {
100             $cfg->{_syslogger} = Log::Syslog::Fast->new(
101             Log::Syslog::Fast::LOG_UDP,
102             $cfg->{syslog_host},
103             $cfg->{syslog_port},
104             $facility,
105             $severity,
106             $cfg->{syslog_source},
107             $cfg->{syslog_name}
108             );
109             }
110             elsif ($transport eq 'tcp' || $transport eq 'unix') {
111             $cfg->{_syslogger} = Log::Syslog::DangaSocket->new(
112             $transport,
113             $cfg->{syslog_host},
114             $cfg->{syslog_port},
115             $cfg->{syslog_source},
116             $cfg->{syslog_name},
117             $facility,
118             $severity,
119             1,
120             );
121             }
122              
123             die "couldn't create syslogger: $!\n" unless $cfg->{_syslogger};
124              
125             return 1;
126             }
127              
128             sub unregister {
129             my ($class, $svc) = @_;
130             delete $svc->{extra_config}{_syslogger};
131             return 1;
132             }
133              
134             sub send_syslog_msg {
135             $_[0]->{extra_config}{_syslogger}->send($_[1]);
136             }
137              
138             sub replace_perlbal_log {
139             my $service = shift;
140             my $logger = $service->{extra_config}{_syslogger};
141              
142             die "need a service with configured syslogger" unless $logger;
143              
144             my $old_perlbal_log = \&Perlbal::log;
145              
146             no warnings 'redefine';
147             *Perlbal::log = sub {
148             my ($level, $message) = @_;
149              
150             my $severity = Log::Syslog::Constants::get_severity($level);
151             return unless defined $severity;
152              
153             my $old_severity = $logger->get_severity;
154              
155             $logger->set_severity($severity);
156              
157             $message .= "\n" unless $message =~ /\n$/;
158             $logger->send(@_ ? sprintf($message, @_) : $message);
159              
160             $logger->set_severity($old_severity);
161             };
162              
163             return $old_perlbal_log;
164             }
165              
166             sub capture_std_handles {
167             my $service = shift;
168             my $logger = $service->{extra_config}{_syslogger};
169              
170             die "need a service with configured syslogger" unless $logger;
171              
172             tie *STDOUT, LineHandler => $logger;
173             tie *STDERR, LineHandler => $logger;
174             }
175              
176             package LineHandler;
177              
178             use base 'Tie::Handle';
179              
180             sub TIEHANDLE {
181             my ($class, $logger) = @_;
182             return bless \$logger, $class;
183             }
184              
185             sub WRITE {
186             my $lref = shift;
187             my ($buf, $len, $offset) = @_;
188             $offset ||= 0;
189             $$lref->send(substr $buf, $offset, $len);
190             }
191              
192             __END__