Merge "Drop index oi_name_archive_name on table oldimage"
[lhc/web/wiklou.git] / includes / debug / logger / monolog / LogstashFormatter.php
1 <?php
2
3 namespace MediaWiki\Logger\Monolog;
4
5 /**
6 * LogstashFormatter squashes the base message array and the context and extras subarrays into one.
7 * This can result in unfortunately named context fields overwriting other data (T145133).
8 * This class modifies the standard LogstashFormatter to rename such fields and flag the message.
9 * Also changes exception JSON-ification which is done poorly by the standard class.
10 *
11 * Compatible with Monolog 1.x only.
12 *
13 * @since 1.29
14 */
15 class LogstashFormatter extends \Monolog\Formatter\LogstashFormatter {
16 /** @var array Keys which should not be used in log context */
17 protected $reservedKeys = [
18 // from LogstashFormatter
19 'message', 'channel', 'level', 'type',
20 // from WebProcessor
21 'url', 'ip', 'http_method', 'server', 'referrer',
22 // from WikiProcessor
23 'host', 'wiki', 'reqId', 'mwversion',
24 // from config magic
25 'normalized_message',
26 ];
27
28 /**
29 * Prevent key conflicts
30 * @param array $record
31 * @return array
32 */
33 protected function formatV0( array $record ) {
34 if ( $this->contextPrefix ) {
35 return parent::formatV0( $record );
36 }
37
38 $context = !empty( $record['context'] ) ? $record['context'] : [];
39 $record['context'] = [];
40 $formatted = parent::formatV0( $record );
41
42 $formatted['@fields'] = $this->fixKeyConflicts( $formatted['@fields'], $context );
43 return $formatted;
44 }
45
46 /**
47 * Prevent key conflicts
48 * @param array $record
49 * @return array
50 */
51 protected function formatV1( array $record ) {
52 if ( $this->contextPrefix ) {
53 return parent::formatV1( $record );
54 }
55
56 $context = !empty( $record['context'] ) ? $record['context'] : [];
57 $record['context'] = [];
58 $formatted = parent::formatV1( $record );
59
60 $formatted = $this->fixKeyConflicts( $formatted, $context );
61 return $formatted;
62 }
63
64 /**
65 * Check whether some context field would overwrite another message key. If so, rename
66 * and flag.
67 * @param array $fields Fields to be sent to logstash
68 * @param array $context Copy of the original $record['context']
69 * @return array Updated version of $fields
70 */
71 protected function fixKeyConflicts( array $fields, array $context ) {
72 foreach ( $context as $key => $val ) {
73 if (
74 in_array( $key, $this->reservedKeys, true ) &&
75 isset( $fields[$key] ) && $fields[$key] !== $val
76 ) {
77 $fields['logstash_formatter_key_conflict'][] = $key;
78 $key = 'c_' . $key;
79 }
80 $fields[$key] = $val;
81 }
82 return $fields;
83 }
84
85 /**
86 * Use a more user-friendly trace format than NormalizerFormatter
87 * @param \Exception|\Throwable $e
88 * @return array
89 */
90 protected function normalizeException( $e ) {
91 if ( !$e instanceof \Exception && !$e instanceof \Throwable ) {
92 throw new \InvalidArgumentException( 'Exception/Throwable expected, got '
93 . gettype( $e ) . ' / ' . get_class( $e ) );
94 }
95
96 $data = [
97 'class' => get_class( $e ),
98 'message' => $e->getMessage(),
99 'code' => $e->getCode(),
100 'file' => $e->getFile() . ':' . $e->getLine(),
101 'trace' => \MWExceptionHandler::getRedactedTraceAsString( $e ),
102 ];
103
104 $previous = $e->getPrevious();
105 if ( $previous ) {
106 $data['previous'] = $this->normalizeException( $previous );
107 }
108
109 return $data;
110 }
111 }