Log.pm 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package Trog::Log;
  2. use strict;
  3. use warnings;
  4. use POSIX qw{strftime};
  5. use Log::Dispatch;
  6. use Log::Dispatch::DBI;
  7. use Log::Dispatch::Screen;
  8. use Log::Dispatch::FileRotate;
  9. use File::Basename qw{dirname};
  10. use Trog::SQLite;
  11. use Trog::Log::DBI;
  12. use Exporter 'import';
  13. our @EXPORT_OK = qw{log_init is_debug INFO DEBUG WARN FATAL};
  14. our %EXPORT_TAGS = ( 'all' => \@EXPORT_OK );
  15. my ($LEVEL, $LOGDIR);
  16. our ( $log, $user );
  17. $Trog::Log::user = 'nobody';
  18. $Trog::Log::ip = '0.0.0.0';
  19. sub log_init {
  20. my ($LOGNAME, $LEVEL) =@_;
  21. die "Cannot initialize logs without log name and log level" unless $LOGNAME && $LEVEL;
  22. $LOGNAME //= 'logs/tcms.log';
  23. $LEVEL //= 'info';
  24. $LOGDIR = dirname($LOGNAME);
  25. # By default only log requests & warnings.
  26. # Otherwise emit debug messages.
  27. my $rotate = Log::Dispatch::FileRotate->new(
  28. name => 'tcms',
  29. filename => $LOGNAME,
  30. min_level => $LEVEL,
  31. 'mode' => 'append',
  32. size => 10 * 1024 * 1024,
  33. max => 6,
  34. );
  35. # Only send fatal events/errors to prod-web.log
  36. my $screen = Log::Dispatch::Screen->new(
  37. name => 'screen',
  38. min_level => 'error',
  39. );
  40. # Send things like requests in to the stats log
  41. my $dblog = Trog::Log::DBI->new(
  42. name => 'dbi',
  43. min_level => $LEVEL,
  44. dbh => _dbh(),
  45. );
  46. $log = Log::Dispatch->new();
  47. $log->add($rotate);
  48. $log->add($screen);
  49. $log->add($dblog);
  50. uuid("INIT");
  51. return 1;
  52. }
  53. #memoize
  54. my $rq;
  55. sub _dbh {
  56. return Trog::SQLite::dbh( 'schema/log.schema', "$LOGDIR/log.db" );
  57. }
  58. sub is_debug {
  59. return $LEVEL eq 'debug';
  60. }
  61. sub uuid {
  62. my $requestid = shift;
  63. $rq = $requestid if $requestid;
  64. $requestid //= return $rq;
  65. }
  66. sub _log {
  67. my ( $msg, $level ) = @_;
  68. $msg //= "No message passed. This is almost certainly a bug. ";
  69. #XXX Log lines must start as an ISO8601 date, anything else breaks fail2ban's beautiful mind
  70. my $tstamp = strftime "%Y-%m-%dT%H:%M:%SZ", gmtime;
  71. my $uuid = uuid();
  72. return "$tstamp [$level]: RequestId $uuid From $Trog::Log::ip |$Trog::Log::user| $msg\n";
  73. }
  74. sub DEBUG {
  75. $log->debug( _log( shift, 'DEBUG' ) );
  76. }
  77. sub INFO {
  78. $log->info( _log( shift, 'INFO' ) );
  79. }
  80. sub WARN {
  81. $log->warning( _log( shift, 'WARN' ) );
  82. }
  83. sub FATAL {
  84. $log->log_and_die( level => 'error', message => _log( shift, 'FATAL' ) );
  85. }
  86. 1;