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

src/Handler/SentryMonologHandler.php (2 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
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)
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)
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