]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/debug/logger/monolog/LineFormatter.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / includes / debug / logger / monolog / LineFormatter.php
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
21 namespace MediaWiki\Logger\Monolog;
22
23 use Exception;
24 use Monolog\Formatter\LineFormatter as MonologLineFormatter;
25 use MWExceptionHandler;
26
27 /**
28  * Formats incoming records into a one-line string.
29  *
30  * An 'exeception' in the log record's context will be treated specially.
31  * It will be output for an '%exception%' placeholder in the format and
32  * excluded from '%context%' output if the '%exception%' placeholder is
33  * present.
34  *
35  * Exceptions that are logged with this formatter will optional have their
36  * stack traces appended. If that is done, MWExceptionHandler::redactedTrace()
37  * will be used to redact the trace information.
38  *
39  * @since 1.26
40  * @copyright © 2015 Wikimedia Foundation and contributors
41  */
42 class LineFormatter extends MonologLineFormatter {
43
44         /**
45          * @param string $format The format of the message
46          * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
47          * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
48          * @param bool $ignoreEmptyContextAndExtra
49          * @param bool $includeStacktraces
50          */
51         public function __construct(
52                 $format = null, $dateFormat = null, $allowInlineLineBreaks = false,
53                 $ignoreEmptyContextAndExtra = false, $includeStacktraces = false
54         ) {
55                 parent::__construct(
56                         $format, $dateFormat, $allowInlineLineBreaks,
57                         $ignoreEmptyContextAndExtra
58                 );
59                 $this->includeStacktraces( $includeStacktraces );
60         }
61
62         /**
63          * @inheritDoc
64          */
65         public function format( array $record ) {
66                 // Drop the 'private' flag from the context
67                 unset( $record['context']['private'] );
68
69                 // Handle exceptions specially: pretty format and remove from context
70                 // Will be output for a '%exception%' placeholder in format
71                 $prettyException = '';
72                 if ( isset( $record['context']['exception'] ) &&
73                         strpos( $this->format, '%exception%' ) !== false
74                 ) {
75                         $e = $record['context']['exception'];
76                         unset( $record['context']['exception'] );
77
78                         if ( $e instanceof Exception ) {
79                                 $prettyException = $this->normalizeException( $e );
80                         } elseif ( is_array( $e ) ) {
81                                 $prettyException = $this->normalizeExceptionArray( $e );
82                         } else {
83                                 $prettyException = $this->stringify( $e );
84                         }
85                 }
86
87                 $output = parent::format( $record );
88
89                 if ( strpos( $output, '%exception%' ) !== false ) {
90                         $output = str_replace( '%exception%', $prettyException, $output );
91                 }
92                 return $output;
93         }
94
95         /**
96          * Convert an Exception to a string.
97          *
98          * @param Exception $e
99          * @return string
100          */
101         protected function normalizeException( $e ) {
102                 return $this->normalizeExceptionArray( $this->exceptionAsArray( $e ) );
103         }
104
105         /**
106          * Convert an exception to an array of structured data.
107          *
108          * @param Exception $e
109          * @return array
110          */
111         protected function exceptionAsArray( Exception $e ) {
112                 $out = [
113                         'class' => get_class( $e ),
114                         'message' => $e->getMessage(),
115                         'code' => $e->getCode(),
116                         'file' => $e->getFile(),
117                         'line' => $e->getLine(),
118                         'trace' => MWExceptionHandler::redactTrace( $e->getTrace() ),
119                 ];
120
121                 $prev = $e->getPrevious();
122                 if ( $prev ) {
123                         $out['previous'] = $this->exceptionAsArray( $prev );
124                 }
125
126                 return $out;
127         }
128
129         /**
130          * Convert an array of Exception data to a string.
131          *
132          * @param array $e
133          * @return string
134          */
135         protected function normalizeExceptionArray( array $e ) {
136                 $defaults = [
137                         'class' => 'Unknown',
138                         'file' => 'unknown',
139                         'line' => null,
140                         'message' => 'unknown',
141                         'trace' => [],
142                 ];
143                 $e = array_merge( $defaults, $e );
144
145                 $str = "\n[Exception {$e['class']}] (" .
146                         "{$e['file']}:{$e['line']}) {$e['message']}";
147
148                 if ( $this->includeStacktraces && $e['trace'] ) {
149                         $str .= "\n" .
150                                 MWExceptionHandler::prettyPrintTrace( $e['trace'], '  ' );
151                 }
152
153                 if ( isset( $e['previous'] ) ) {
154                         $prev = $e['previous'];
155                         while ( $prev ) {
156                                 $prev = array_merge( $defaults, $prev );
157                                 $str .= "\nCaused by: [Exception {$prev['class']}] (" .
158                                         "{$prev['file']}:{$prev['line']}) {$prev['message']}";
159
160                                 if ( $this->includeStacktraces && $prev['trace'] ) {
161                                         $str .= "\n" .
162                                                 MWExceptionHandler::prettyPrintTrace(
163                                                         $prev['trace'], '  '
164                                                 );
165                                 }
166
167                                 $prev = isset( $prev['previous'] ) ? $prev['previous'] : null;
168                         }
169                 }
170                 return $str;
171         }
172 }