diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2015-06-04 07:31:04 +0200 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2015-06-04 07:58:39 +0200 |
commit | f6d65e533c62f6deb21342d4901ece24497b433e (patch) | |
tree | f28adf0362d14bcd448f7b65a7aaf38650f923aa /includes/debug/logger/monolog | |
parent | c27b2e832fe25651ef2410fae85b41072aae7519 (diff) |
Update to MediaWiki 1.25.1
Diffstat (limited to 'includes/debug/logger/monolog')
-rw-r--r-- | includes/debug/logger/monolog/LegacyFormatter.php | 48 | ||||
-rw-r--r-- | includes/debug/logger/monolog/LegacyHandler.php | 243 | ||||
-rw-r--r-- | includes/debug/logger/monolog/SyslogHandler.php | 96 | ||||
-rw-r--r-- | includes/debug/logger/monolog/WikiProcessor.php | 47 |
4 files changed, 434 insertions, 0 deletions
diff --git a/includes/debug/logger/monolog/LegacyFormatter.php b/includes/debug/logger/monolog/LegacyFormatter.php new file mode 100644 index 00000000..9ec15cb8 --- /dev/null +++ b/includes/debug/logger/monolog/LegacyFormatter.php @@ -0,0 +1,48 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Logger\Monolog; + +use MediaWiki\Logger\LegacyLogger; +use Monolog\Formatter\NormalizerFormatter; + +/** + * Log message formatter that mimics the legacy log message formatting of + * `wfDebug`, `wfDebugLog`, `wfLogDBError` and `wfErrorLog` global functions by + * delegating the formatting to \MediaWiki\Logger\LegacyLogger. + * + * @since 1.25 + * @author Bryan Davis <bd808@wikimedia.org> + * @copyright © 2013 Bryan Davis and Wikimedia Foundation. + * @see \MediaWiki\Logger\LegacyLogger + */ +class LegacyFormatter extends NormalizerFormatter { + + public function __construct() { + parent::__construct( 'c' ); + } + + public function format( array $record ) { + $normalized = parent::format( $record ); + return LegacyLogger::format( + $normalized['channel'], $normalized['message'], $normalized + ); + } +} diff --git a/includes/debug/logger/monolog/LegacyHandler.php b/includes/debug/logger/monolog/LegacyHandler.php new file mode 100644 index 00000000..8405819d --- /dev/null +++ b/includes/debug/logger/monolog/LegacyHandler.php @@ -0,0 +1,243 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Logger\Monolog; + +use LogicException; +use MediaWiki\Logger\LegacyLogger; +use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Logger; +use UnexpectedValueException; + +/** + * Log handler that replicates the behavior of MediaWiki's wfErrorLog() + * logging service. Log output can be directed to a local file, a PHP stream, + * or a udp2log server. + * + * For udp2log output, the stream specification must have the form: + * "udp://HOST:PORT[/PREFIX]" + * where: + * - HOST: IPv4, IPv6 or hostname + * - PORT: server port + * - PREFIX: optional (but recommended) prefix telling udp2log how to route + * the log event. The special prefix "{channel}" will use the log event's + * channel as the prefix value. + * + * When not targeting a udp2log stream this class will act as a drop-in + * replacement for Monolog's StreamHandler. + * + * @since 1.25 + * @author Bryan Davis <bd808@wikimedia.org> + * @copyright © 2013 Bryan Davis and Wikimedia Foundation. + */ +class LegacyHandler extends AbstractProcessingHandler { + + /** + * Log sink descriptor + * @var string $uri + */ + protected $uri; + + /** + * Filter log events using legacy rules + * @var bool $useLegacyFilter + */ + protected $useLegacyFilter; + + /** + * Log sink + * @var resource $sink + */ + protected $sink; + + /** + * @var string $error + */ + protected $error; + + /** + * @var string $host + */ + protected $host; + + /** + * @var int $port + */ + protected $port; + + /** + * @var string $prefix + */ + protected $prefix; + + + /** + * @param string $stream Stream URI + * @param bool $useLegacyFilter Filter log events using legacy rules + * @param int $level Minimum logging level that will trigger handler + * @param bool $bubble Can handled meesages bubble up the handler stack? + */ + public function __construct( + $stream, + $useLegacyFilter = false, + $level = Logger::DEBUG, + $bubble = true + ) { + parent::__construct( $level, $bubble ); + $this->uri = $stream; + $this->useLegacyFilter = $useLegacyFilter; + } + + /** + * Open the log sink described by our stream URI. + */ + protected function openSink() { + if ( !$this->uri ) { + throw new LogicException( + 'Missing stream uri, the stream can not be opened.' ); + } + $this->error = null; + set_error_handler( array( $this, 'errorTrap' ) ); + + if ( substr( $this->uri, 0, 4 ) == 'udp:' ) { + $parsed = parse_url( $this->uri ); + if ( !isset( $parsed['host'] ) ) { + throw new UnexpectedValueException( sprintf( + 'Udp transport "%s" must specify a host', $this->uri + ) ); + } + if ( !isset( $parsed['port'] ) ) { + throw new UnexpectedValueException( sprintf( + 'Udp transport "%s" must specify a port', $this->uri + ) ); + } + + $this->host = $parsed['host']; + $this->port = $parsed['port']; + $this->prefix = ''; + + if ( isset( $parsed['path'] ) ) { + $this->prefix = ltrim( $parsed['path'], '/' ); + } + + if ( filter_var( $this->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) { + $domain = AF_INET6; + + } else { + $domain = AF_INET; + } + + $this->sink = socket_create( $domain, SOCK_DGRAM, SOL_UDP ); + + } else { + $this->sink = fopen( $this->uri, 'a' ); + } + restore_error_handler(); + + if ( !is_resource( $this->sink ) ) { + $this->sink = null; + throw new UnexpectedValueException( sprintf( + 'The stream or file "%s" could not be opened: %s', + $this->uri, $this->error + ) ); + } + } + + + /** + * Custom error handler. + * @param int $code Error number + * @param string $msg Error message + */ + protected function errorTrap( $code, $msg ) { + $this->error = $msg; + } + + + /** + * Should we use UDP to send messages to the sink? + * @return bool + */ + protected function useUdp() { + return $this->host !== null; + } + + + protected function write( array $record ) { + if ( $this->useLegacyFilter && + !LegacyLogger::shouldEmit( + $record['channel'], $record['message'], + $record['level'], $record + ) ) { + // Do not write record if we are enforcing legacy rules and they + // do not pass this message. This used to be done in isHandling(), + // but Monolog 1.12.0 made a breaking change that removed access + // to the needed channel and context information. + return; + } + + if ( $this->sink === null ) { + $this->openSink(); + } + + $text = (string)$record['formatted']; + if ( $this->useUdp() ) { + + // Clean it up for the multiplexer + if ( $this->prefix !== '' ) { + $leader = ( $this->prefix === '{channel}' ) ? + $record['channel'] : $this->prefix; + $text = preg_replace( '/^/m', "{$leader} ", $text ); + + // Limit to 64KB + if ( strlen( $text ) > 65506 ) { + $text = substr( $text, 0, 65506 ); + } + + if ( substr( $text, -1 ) != "\n" ) { + $text .= "\n"; + } + + } elseif ( strlen( $text ) > 65507 ) { + $text = substr( $text, 0, 65507 ); + } + + socket_sendto( + $this->sink, $text, strlen( $text ), 0, $this->host, $this->port + ); + + } else { + fwrite( $this->sink, $text ); + } + } + + + public function close() { + if ( is_resource( $this->sink ) ) { + if ( $this->useUdp() ) { + socket_close( $this->sink ); + + } else { + fclose( $this->sink ); + } + } + $this->sink = null; + } +} diff --git a/includes/debug/logger/monolog/SyslogHandler.php b/includes/debug/logger/monolog/SyslogHandler.php new file mode 100644 index 00000000..008efbc1 --- /dev/null +++ b/includes/debug/logger/monolog/SyslogHandler.php @@ -0,0 +1,96 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Logger\Monolog; + +use Monolog\Handler\SyslogUdpHandler; +use Monolog\Logger; + +/** + * Log handler that supports sending log events to a syslog server using RFC + * 3164 formatted UDP packets. + * + * Monolog's SyslogUdpHandler creates a partial RFC 5424 header (PRI and + * VERSION) and relies on the associated formatter to complete the header and + * message payload. This makes using it with a fixed format formatter like + * Monolog\Formatter\LogstashFormatter impossible. Additionally, the direct + * syslog input for Logstash only handles RFC 3164 syslog packets. + * + * This Handler should work with any Formatter. The formatted message will be + * prepended with an RFC 3164 message header and a partial message body. The + * resulting packet will looks something like: + * + * <PRI>DATETIME HOSTNAME PROGRAM: MESSAGE + * + * This format works as input to rsyslog and can also be processed by the + * default Logstash syslog input handler. + * + * @since 1.25 + * @author Bryan Davis <bd808@wikimedia.org> + * @copyright © 2015 Bryan Davis and Wikimedia Foundation. + */ +class SyslogHandler extends SyslogUdpHandler { + + /** + * @var string $appname + */ + private $appname; + + /** + * @var string $hostname + */ + private $hostname; + + + /** + * @param string $appname Application name to report to syslog + * @param string $host Syslog host + * @param int $port Syslog port + * @param int $facility Syslog message facility + * @param string $level The minimum logging level at which this handler + * will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up + * the stack or not + */ + public function __construct( + $appname, + $host, + $port = 514, + $facility = LOG_USER, + $level = Logger::DEBUG, + $bubble = true + ) { + parent::__construct( $host, $port, $facility, $level, $bubble ); + $this->appname = $appname; + $this->hostname = php_uname( 'n' ); + } + + protected function makeCommonSyslogHeader( $severity ) { + $pri = $severity + $this->facility; + + // Goofy date format courtesy of RFC 3164 :( + // RFC 3164 actually specifies that the day of month should be space + // padded rather than unpadded but this seems to work with rsyslog and + // Logstash. + $timestamp = date( 'M j H:i:s' ); + + return "<{$pri}>{$timestamp} {$this->hostname} {$this->appname}: "; + } +} diff --git a/includes/debug/logger/monolog/WikiProcessor.php b/includes/debug/logger/monolog/WikiProcessor.php new file mode 100644 index 00000000..a52f6366 --- /dev/null +++ b/includes/debug/logger/monolog/WikiProcessor.php @@ -0,0 +1,47 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Logger\Monolog; + +/** + * Injects `wfHostname()` and `wfWikiID()` in all records. + * + * @since 1.25 + * @author Bryan Davis <bd808@wikimedia.org> + * @copyright © 2013 Bryan Davis and Wikimedia Foundation. + */ +class WikiProcessor { + + /** + * @param array $record + * @return array + */ + public function __invoke( array $record ) { + $record['extra'] = array_merge( + $record['extra'], + array( + 'host' => wfHostname(), + 'wiki' => wfWikiID(), + ) + ); + return $record; + } + +} |