]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / monolog / monolog / src / Monolog / Handler / RavenHandler.php
1 <?php
2
3 /*
4  * This file is part of the Monolog package.
5  *
6  * (c) Jordi Boggiano <j.boggiano@seld.be>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Monolog\Handler;
13
14 use Monolog\Formatter\LineFormatter;
15 use Monolog\Formatter\FormatterInterface;
16 use Monolog\Logger;
17 use Raven_Client;
18
19 /**
20  * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server
21  * using raven-php (https://github.com/getsentry/raven-php)
22  *
23  * @author Marc Abramowitz <marc@marc-abramowitz.com>
24  */
25 class RavenHandler extends AbstractProcessingHandler
26 {
27     /**
28      * Translates Monolog log levels to Raven log levels.
29      */
30     private $logLevels = array(
31         Logger::DEBUG     => Raven_Client::DEBUG,
32         Logger::INFO      => Raven_Client::INFO,
33         Logger::NOTICE    => Raven_Client::INFO,
34         Logger::WARNING   => Raven_Client::WARNING,
35         Logger::ERROR     => Raven_Client::ERROR,
36         Logger::CRITICAL  => Raven_Client::FATAL,
37         Logger::ALERT     => Raven_Client::FATAL,
38         Logger::EMERGENCY => Raven_Client::FATAL,
39     );
40
41     /**
42      * @var string should represent the current version of the calling
43      *             software. Can be any string (git commit, version number)
44      */
45     private $release;
46
47     /**
48      * @var Raven_Client the client object that sends the message to the server
49      */
50     protected $ravenClient;
51
52     /**
53      * @var LineFormatter The formatter to use for the logs generated via handleBatch()
54      */
55     protected $batchFormatter;
56
57     /**
58      * @param Raven_Client $ravenClient
59      * @param int          $level       The minimum logging level at which this handler will be triggered
60      * @param Boolean      $bubble      Whether the messages that are handled can bubble up the stack or not
61      */
62     public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
63     {
64         parent::__construct($level, $bubble);
65
66         $this->ravenClient = $ravenClient;
67     }
68
69     /**
70      * {@inheritdoc}
71      */
72     public function handleBatch(array $records)
73     {
74         $level = $this->level;
75
76         // filter records based on their level
77         $records = array_filter($records, function ($record) use ($level) {
78             return $record['level'] >= $level;
79         });
80
81         if (!$records) {
82             return;
83         }
84
85         // the record with the highest severity is the "main" one
86         $record = array_reduce($records, function ($highest, $record) {
87             if ($record['level'] > $highest['level']) {
88                 return $record;
89             }
90
91             return $highest;
92         });
93
94         // the other ones are added as a context item
95         $logs = array();
96         foreach ($records as $r) {
97             $logs[] = $this->processRecord($r);
98         }
99
100         if ($logs) {
101             $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
102         }
103
104         $this->handle($record);
105     }
106
107     /**
108      * Sets the formatter for the logs generated by handleBatch().
109      *
110      * @param FormatterInterface $formatter
111      */
112     public function setBatchFormatter(FormatterInterface $formatter)
113     {
114         $this->batchFormatter = $formatter;
115     }
116
117     /**
118      * Gets the formatter for the logs generated by handleBatch().
119      *
120      * @return FormatterInterface
121      */
122     public function getBatchFormatter()
123     {
124         if (!$this->batchFormatter) {
125             $this->batchFormatter = $this->getDefaultBatchFormatter();
126         }
127
128         return $this->batchFormatter;
129     }
130
131     /**
132      * {@inheritdoc}
133      */
134     protected function write(array $record)
135     {
136         $previousUserContext = false;
137         $options = array();
138         $options['level'] = $this->logLevels[$record['level']];
139         $options['tags'] = array();
140         if (!empty($record['extra']['tags'])) {
141             $options['tags'] = array_merge($options['tags'], $record['extra']['tags']);
142             unset($record['extra']['tags']);
143         }
144         if (!empty($record['context']['tags'])) {
145             $options['tags'] = array_merge($options['tags'], $record['context']['tags']);
146             unset($record['context']['tags']);
147         }
148         if (!empty($record['context']['fingerprint'])) {
149             $options['fingerprint'] = $record['context']['fingerprint'];
150             unset($record['context']['fingerprint']);
151         }
152         if (!empty($record['context']['logger'])) {
153             $options['logger'] = $record['context']['logger'];
154             unset($record['context']['logger']);
155         } else {
156             $options['logger'] = $record['channel'];
157         }
158         foreach ($this->getExtraParameters() as $key) {
159             foreach (array('extra', 'context') as $source) {
160                 if (!empty($record[$source][$key])) {
161                     $options[$key] = $record[$source][$key];
162                     unset($record[$source][$key]);
163                 }
164             }
165         }
166         if (!empty($record['context'])) {
167             $options['extra']['context'] = $record['context'];
168             if (!empty($record['context']['user'])) {
169                 $previousUserContext = $this->ravenClient->context->user;
170                 $this->ravenClient->user_context($record['context']['user']);
171                 unset($options['extra']['context']['user']);
172             }
173         }
174         if (!empty($record['extra'])) {
175             $options['extra']['extra'] = $record['extra'];
176         }
177
178         if (!empty($this->release) && !isset($options['release'])) {
179             $options['release'] = $this->release;
180         }
181
182         if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
183             $options['extra']['message'] = $record['formatted'];
184             $this->ravenClient->captureException($record['context']['exception'], $options);
185         } else {
186             $this->ravenClient->captureMessage($record['formatted'], array(), $options);
187         }
188
189         if ($previousUserContext !== false) {
190             $this->ravenClient->user_context($previousUserContext);
191         }
192     }
193
194     /**
195      * {@inheritDoc}
196      */
197     protected function getDefaultFormatter()
198     {
199         return new LineFormatter('[%channel%] %message%');
200     }
201
202     /**
203      * Gets the default formatter for the logs generated by handleBatch().
204      *
205      * @return FormatterInterface
206      */
207     protected function getDefaultBatchFormatter()
208     {
209         return new LineFormatter();
210     }
211
212     /**
213      * Gets extra parameters supported by Raven that can be found in "extra" and "context"
214      *
215      * @return array
216      */
217     protected function getExtraParameters()
218     {
219         return array('checksum', 'release', 'event_id');
220     }
221
222     /**
223      * @param string $value
224      * @return self
225      */
226     public function setRelease($value)
227     {
228         $this->release = $value;
229
230         return $this;
231     }
232 }