Syslog.pm 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package Trog::Log::Syslog;
  2. use 5.040;
  3. use re '/aasx';
  4. use warnings FATAL => 'all';
  5. use parent qw{Log::Dispatch::Output};
  6. use Log::Syslog::Fast qw{:protos :formats};
  7. =head1 Trog::Log::Syslog
  8. A Log::Dispatch output which hands each line to the syslog of the machine, over
  9. its unix socket. From there journald and rsyslog have it, and whatever they
  10. forward it to.
  11. Name it in the C<loggers> of tpsgi.ini:
  12. loggers = Trog::Log::Syslog
  13. tPSGI then adds it to its own logger, and TCMS passes the same list to
  14. log_init(), so both write here as well as to the rotated file.
  15. Lines go out as C<daemon>, tagged C<tcms>, at the severity of their level.
  16. Each keeps the timestamp that Trog::Log puts at its front, so a line on a log
  17. collector reads the same as the line in the file.
  18. =head1 Termination Conditions
  19. new() dies when it cannot connect to the socket. A line that cannot be sent
  20. later is dropped without a word: the file output has it, and a request that
  21. fails because its log line did not arrive is worse than a line that did not
  22. arrive.
  23. =head1 METHODS
  24. =head2 new(%options) = Trog::Log::Syslog
  25. Takes what tPSGI hands every logger, C<min_level> and C<log_dir>, and ignores
  26. C<log_dir>. C<socket> is where to send, F</dev/log> unless a test says
  27. otherwise. C<ident> is the tag, C<tcms> unless given.
  28. =cut
  29. # LOG_DAEMON, from sys/syslog.h.
  30. my $DAEMON = 3;
  31. sub new ( $class, %p ) {
  32. my $self = bless( {}, $class );
  33. $self->_basic_init( map { exists $p{$_} ? ( $_ => $p{$_} ) : () } qw{name min_level max_level} );
  34. my $socket = $p{socket} // '/dev/log';
  35. my $ident = $p{ident} // 'tcms';
  36. # The sender is left out of the format, as syslog(3) leaves it out when it
  37. # writes to this socket, because the receiver is this machine.
  38. $self->{syslog} = Log::Syslog::Fast->new( LOG_UNIX, $socket, 0, $DAEMON, 6, '', $ident );
  39. $self->{syslog}->set_format(LOG_RFC3164_LOCAL);
  40. return $self;
  41. }
  42. =head2 log_message(%p)
  43. Called by Log::Dispatch for each line at or above C<min_level>.
  44. =cut
  45. sub log_message ( $self, %p ) {
  46. # Log::Dispatch numbers its levels from debug at 0 to emergency at 7, and
  47. # syslog numbers its severities the other way round.
  48. my $severity = 7 - $self->_level_as_number( $p{level} );
  49. # Trog::Log ends every line with a newline, which a syslog message does
  50. # not carry.
  51. chomp( my $message = $p{message} );
  52. local $@;
  53. eval {
  54. $self->{syslog}->set_severity($severity);
  55. $self->{syslog}->send( $message, time );
  56. 1;
  57. } or return;
  58. return;
  59. }
  60. 1;