Log.pm 2.6 KB

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