MwlogHandler.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. /**
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. * http://www.gnu.org/copyleft/gpl.html
  17. *
  18. * @file
  19. */
  20. namespace MediaWiki\Logger\Monolog;
  21. use Monolog\Handler\SyslogUdpHandler;
  22. use Monolog\Logger;
  23. /**
  24. * Log handler that will append the record's channel to a fixed 'application
  25. * prefix' given at construction time.
  26. *
  27. * The use case for this handler is to deprecate udp2log with a localhost
  28. * syslog endpoint. The application name is then used to reconstruct the
  29. * message's channel.
  30. *
  31. * @since 1.32
  32. * @copyright © 2019 Wikimedia Foundation and contributors
  33. */
  34. class MwlogHandler extends SyslogUdpHandler {
  35. /**
  36. * @var string $appprefix
  37. */
  38. private $appprefix;
  39. /**
  40. * @var string $hostname
  41. */
  42. private $hostname;
  43. /**
  44. * @param string $appprefix Application prefix to use, channel will be appended.
  45. * @param string $host Syslog host
  46. * @param int $port Syslog port
  47. * @param int $facility Syslog message facility
  48. * @param int $level The minimum logging level at which this handler
  49. * will be triggered
  50. * @param bool $bubble Whether the messages that are handled can bubble up
  51. * the stack or not
  52. */
  53. public function __construct(
  54. $appprefix,
  55. $host,
  56. $port = 514,
  57. $facility = LOG_USER,
  58. $level = Logger::DEBUG,
  59. $bubble = true
  60. ) {
  61. parent::__construct( $host, $port, $facility, $level, $bubble );
  62. $this->appprefix = $appprefix;
  63. $this->hostname = php_uname( 'n' );
  64. }
  65. protected function syslogHeader( $severity, $app ) {
  66. $pri = $severity + $this->facility;
  67. // Goofy date format courtesy of RFC 3164 :(
  68. // RFC 3164 actually specifies that the day of month should be space
  69. // padded rather than unpadded but this seems to work with rsyslog and
  70. // Logstash.
  71. $timestamp = date( 'M j H:i:s' );
  72. return "<{$pri}>{$timestamp} {$this->hostname} {$app}: ";
  73. }
  74. private function splitMessageIntoLines( $message ): array {
  75. if ( is_array( $message ) ) {
  76. $message = implode( "\n", $message );
  77. }
  78. return preg_split( '/$\R?^/m', (string)$message, -1, PREG_SPLIT_NO_EMPTY );
  79. }
  80. protected function write( array $record ) {
  81. $lines = $this->splitMessageIntoLines( $record['formatted'] );
  82. $header = $this->syslogHeader(
  83. $this->logLevels[$record['level']],
  84. $this->appprefix . $record['channel'] );
  85. foreach ( $lines as $line ) {
  86. $this->socket->write( $line, $header );
  87. }
  88. }
  89. }