Completed
Push — master ( e44348...b1141f )
by Russell
03:58
created

src/Handler/SentryMonologHandler.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Class: SentryMonologHandler.
5
 *
6
 * @author  Russell Michell 2017 <[email protected]>
7
 * @package phptek/sentry
8
 */
9
10
namespace PhpTek\Sentry\Handler;
11
12
use Exception;
13
use Monolog\Logger;
14
use PhpTek\Sentry\Adaptor\RavenClient;
15
use PhpTek\Sentry\Adaptor\SentryClientAdaptor;
16
use PhpTek\Sentry\Log\SentryLogger;
17
use PhpTek\Sentry\Monolog\Handler\SentryRavenHandler;
18
use SilverStripe\Core\Config\Config;
19
use SilverStripe\Dev\Backtrace;
20
use SilverStripe\Security\Member;
21
use SilverStripe\Security\Security;
22
23
/**
24
 * Monolog Handler for Sentry via Raven
25
 */
26
class SentryMonologHandler extends SentryRavenHandler
27
{
28
    /**
29
     * @var RavenClient
30
     */
31
    protected $client;
32
33
    /**
34
     * @param  int   $level
35
     * @param  bool  $bubble
36
     * @param  array $extras Extra parameters that will become "tags" in Sentry.
37
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
38
     */
39
    public function __construct($level = Logger::WARNING, $bubble = true, $extras = [])
40
    {
41
        // Returns an instance of {@link SentryLogger}
42
        $logger = SentryLogger::factory($extras);
43
        $sdk = $logger->getClient()->getSDK();
0 ignored issues
show
The method getClient() does not seem to exist on object<PhpTek\Sentry\Log\SentryLogger>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
44
        $this->client = $logger->getClient();
0 ignored issues
show
The method getClient() does not seem to exist on object<PhpTek\Sentry\Log\SentryLogger>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
45
        $this->client->setData('user', $this->getUserData(null, $logger));
46
47
        $log_level = Config::inst()->get(self::class, 'log_level');
48
        $level = ($log_level) ? constant(Logger::class . '::'. $log_level) : $level;
49
50
        parent::__construct($sdk, $level, $bubble);
51
    }
52
53
    /**
54
     * @return SentryClientAdaptor
55
     */
56
    public function getClient()
57
    {
58
        return $this->client;
59
    }
60
61
    /**
62
     * write() forms the entry point into the physical sending of the error. The
63
     * sending itself is done by the current adaptor's `send()` method.
64
     *
65
     * @param  array $record An array of error-context metadata with the following
66
     *                       available keys:
67
     *
68
     *                       - message
69
     *                       - context
70
     *                       - level
71
     *                       - level_name
72
     *                       - channel
73
     *                       - datetime
74
     *                       - extra
75
     *                       - formatted
76
     *
77
     * @return void
78
     */
79
    protected function write(array $record)
80
    {
81
        $record = array_merge($record, [
82
            'timestamp'  => $record['datetime']->getTimestamp(),
83
            'stacktrace' => $this->backtrace($record),
84
        ]);
85
86
        // write() calls one of RavenHandler::captureException() or RavenHandler::captureMessage()
87
        // depending on if $record['context']['exception'] is an instance of Exception or not
88
        parent::write($record);
89
    }
90
91
    /**
92
     * Generate a cleaned-up backtrace of the event that got us here.
93
     *
94
     * @param  array $record
95
     * @return array
96
     */
97 View Code Duplication
    private function backtrace($record)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
98
    {
99
        // Provided trace
100
        if (!empty($record['context']['trace'])) {
101
            return $record['context']['trace'];
102
        }
103
104
        // Generate trace from exception
105
        if (isset($record['context']['exception'])) {
106
            /** @var Exception $exception */
107
            $exception = $record['context']['exception'];
108
            return $exception->getTrace();
109
        }
110
111
        // Failover: build custom trace
112
        $bt = debug_backtrace();
113
114
        // Push current line into context
115
        array_unshift($bt, [
116
            'file'     => !empty($bt['file']) ? $bt['file'] : 'N/A',
117
            'line'     => !empty($bt['line']) ? $bt['line'] : 'N/A',
118
            'function' => '',
119
            'class'    => '',
120
            'type'     => '',
121
            'args'     => [],
122
        ]);
123
124
        $bt = Backtrace::filter_backtrace($bt, [
125
            '',
126
            'Monolog\\Handler\\AbstractProcessingHandler->handle',
127
            'Monolog\\Logger->addRecord',
128
            'Monolog\\Logger->log',
129
            'Monolog\\Logger->warn',
130
            'PhpTek\\Sentry\\Handler\\SentryMonologHandler->write',
131
            'PhpTek\\Sentry\\Handler\\SentryMonologHandler->backtrace',
132
        ]);
133
134
        return $bt;
135
    }
136
137
    /**
138
     * Returns a default set of additional data specific to the user's part in
139
     * the request.
140
     *
141
     * @param  Member       $member
142
     * @param  SentryLogger $logger
143
     * @return array
144
     */
145 View Code Duplication
    private function getUserData(Member $member = null, $logger)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
    {
147
        if (!$member) {
148
            $member = Security::getCurrentUser();
149
        }
150
151
        return [
152
            'IPddress' => $logger->getIP(),
153
            'ID'       => $member ? $member->getField('ID') : SentryLogger::SLW_NOOP,
154
            'Email'    => $member ? $member->getField('Email') : SentryLogger::SLW_NOOP,
155
        ];
156
    }
157
}
158