summaryrefslogtreecommitdiff
path: root/includes/debug/logger/monolog
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2015-06-04 07:31:04 +0200
committerPierre Schmitz <pierre@archlinux.de>2015-06-04 07:58:39 +0200
commitf6d65e533c62f6deb21342d4901ece24497b433e (patch)
treef28adf0362d14bcd448f7b65a7aaf38650f923aa /includes/debug/logger/monolog
parentc27b2e832fe25651ef2410fae85b41072aae7519 (diff)
Update to MediaWiki 1.25.1
Diffstat (limited to 'includes/debug/logger/monolog')
-rw-r--r--includes/debug/logger/monolog/LegacyFormatter.php48
-rw-r--r--includes/debug/logger/monolog/LegacyHandler.php243
-rw-r--r--includes/debug/logger/monolog/SyslogHandler.php96
-rw-r--r--includes/debug/logger/monolog/WikiProcessor.php47
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;
+ }
+
+}