RavenHandler::write()   F
last analyzed

Complexity

Conditions 18
Paths 3072

Size

Total Lines 57
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 40
c 0
b 0
f 0
nc 3072
nop 1
dl 0
loc 57
rs 0.7

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Monolog package.
5
 *
6
 * (c) Jordi Boggiano <[email protected]>
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;
0 ignored issues
show
Bug introduced by
The type Raven_Client was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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 <[email protected]>
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $records of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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;
0 ignored issues
show
Documentation Bug introduced by
$formatter is of type Monolog\Formatter\FormatterInterface, but the property $batchFormatter was declared to be of type Monolog\Formatter\LineFormatter. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
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
}
233