123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- <?php
- namespace MediaWiki\Logger\Monolog;
- /**
- * LogstashFormatter squashes the base message array and the context and extras subarrays into one.
- * This can result in unfortunately named context fields overwriting other data (T145133).
- * This class modifies the standard LogstashFormatter to rename such fields and flag the message.
- * Also changes exception JSON-ification which is done poorly by the standard class.
- *
- * Compatible with Monolog 1.x only.
- *
- * @since 1.29
- */
- class LogstashFormatter extends \Monolog\Formatter\LogstashFormatter {
- /** @var array Keys which should not be used in log context */
- protected $reservedKeys = [
- // from LogstashFormatter
- 'message', 'channel', 'level', 'type',
- // from WebProcessor
- 'url', 'ip', 'http_method', 'server', 'referrer',
- // from WikiProcessor
- 'host', 'wiki', 'reqId', 'mwversion',
- // from config magic
- 'normalized_message',
- ];
- /**
- * Prevent key conflicts
- * @param array $record
- * @return array
- */
- protected function formatV0( array $record ) {
- if ( $this->contextPrefix ) {
- return parent::formatV0( $record );
- }
- $context = !empty( $record['context'] ) ? $record['context'] : [];
- $record['context'] = [];
- $formatted = parent::formatV0( $record );
- $formatted['@fields'] = $this->fixKeyConflicts( $formatted['@fields'], $context );
- return $formatted;
- }
- /**
- * Prevent key conflicts
- * @param array $record
- * @return array
- */
- protected function formatV1( array $record ) {
- if ( $this->contextPrefix ) {
- return parent::formatV1( $record );
- }
- $context = !empty( $record['context'] ) ? $record['context'] : [];
- $record['context'] = [];
- $formatted = parent::formatV1( $record );
- $formatted = $this->fixKeyConflicts( $formatted, $context );
- return $formatted;
- }
- /**
- * Check whether some context field would overwrite another message key. If so, rename
- * and flag.
- * @param array $fields Fields to be sent to logstash
- * @param array $context Copy of the original $record['context']
- * @return array Updated version of $fields
- */
- protected function fixKeyConflicts( array $fields, array $context ) {
- foreach ( $context as $key => $val ) {
- if (
- in_array( $key, $this->reservedKeys, true ) &&
- isset( $fields[$key] ) && $fields[$key] !== $val
- ) {
- $fields['logstash_formatter_key_conflict'][] = $key;
- $key = 'c_' . $key;
- }
- $fields[$key] = $val;
- }
- return $fields;
- }
- /**
- * Use a more user-friendly trace format than NormalizerFormatter
- * @param \Exception|\Throwable $e
- * @return array
- */
- protected function normalizeException( $e ) {
- if ( !$e instanceof \Exception && !$e instanceof \Throwable ) {
- throw new \InvalidArgumentException( 'Exception/Throwable expected, got '
- . gettype( $e ) . ' / ' . get_class( $e ) );
- }
- $data = [
- 'class' => get_class( $e ),
- 'message' => $e->getMessage(),
- 'code' => $e->getCode(),
- 'file' => $e->getFile() . ':' . $e->getLine(),
- 'trace' => \MWExceptionHandler::getRedactedTraceAsString( $e ),
- ];
- $previous = $e->getPrevious();
- if ( $previous ) {
- $data['previous'] = $this->normalizeException( $previous );
- }
- return $data;
- }
- }
|