Completed
Push — master ( 1c3deb...35780f )
by Marcel
01:29 queued 12s
created

Flare::handleError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 4
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
namespace Facade\FlareClient;
4
5
use Exception;
6
use Throwable;
7
use Illuminate\Pipeline\Pipeline;
8
use Facade\FlareClient\Glows\Glow;
9
use Facade\FlareClient\Http\Client;
10
use Facade\FlareClient\Glows\Recorder;
11
use Facade\FlareClient\Concerns\HasContext;
12
use Facade\FlareClient\Enums\MessageLevels;
13
use Facade\FlareClient\Middleware\AddGlows;
14
use Illuminate\Contracts\Container\Container;
15
use Facade\FlareClient\Middleware\AnonymizeIp;
16
use Facade\FlareClient\Context\ContextContextDetector;
17
use Facade\FlareClient\Context\ContextDetectorInterface;
18
19
class Flare
20
{
21
    use HasContext;
22
23
    /** @var \Facade\FlareClient\Http\Client */
24
    private $client;
25
26
    /** @var \Facade\FlareClient\Api */
27
    private $api;
28
29
    /** @var array */
30
    private $middleware = [];
31
32
    /** @var \Facade\FlareClient\Glows\Recorder */
33
    private $recorder;
34
35
    /** @var string */
36
    private $applicationPath;
37
38
    /** @var \Illuminate\Contracts\Container\Container|null */
39
    private $container;
40
41
    /** @var ContextDetectorInterface */
42
    private $contextDetector;
43
44
    /** @var callable|null */
45
    private $previousExceptionHandler;
46
47
    /** @var callable|null */
48
    private $previousErrorHandler;
49
50
    public static function register(string $apiKey, string $apiSecret = null, ContextDetectorInterface $contextDetector = null, Container $container = null)
51
    {
52
        $client = new Client($apiKey, $apiSecret);
53
54
        return new static($client, $contextDetector, $container);
55
    }
56
57
    public function __construct(Client $client, ContextDetectorInterface $contextDetector = null, Container $container = null, array $middleware = [])
58
    {
59
        $this->client = $client;
60
        $this->recorder = new Recorder();
61
        $this->contextDetector = $contextDetector ?? new ContextContextDetector();
62
        $this->container = $container;
63
        $this->middleware = $middleware;
64
        $this->api = new Api($this->client);
65
66
        $this->registerDefaultMiddleware();
67
    }
68
69
    public function getMiddleware(): array
70
    {
71
        return $this->middleware;
72
    }
73
74
    public function registerFlareHandlers()
75
    {
76
        $this->registerExceptionHandler();
77
        $this->registerErrorHandler();
78
    }
79
80
    public function registerExceptionHandler()
81
    {
82
        $this->previousExceptionHandler = set_exception_handler([$this, 'handleException']);
83
84
        return $this;
85
    }
86
87
    public function registerErrorHandler()
88
    {
89
        $this->previousErrorHandler = set_error_handler([$this, 'handleError']);
90
91
        return $this;
92
    }
93
94
    private function registerDefaultMiddleware()
95
    {
96
        return $this->registerMiddleware(new AddGlows($this->recorder));
97
    }
98
99
    public function registerMiddleware($callable)
100
    {
101
        $this->middleware[] = $callable;
102
103
        return $this;
104
    }
105
106
    public function getMiddlewares(): array
107
    {
108
        return $this->middleware;
109
    }
110
111
    public function glow(
112
        string $name,
113
        string $messageLevel = MessageLevels::INFO,
114
        array $metaData = []
115
    ) {
116
        $this->recorder->record(new Glow($name, $messageLevel, $metaData));
117
    }
118
119
    public function handleException(Throwable $throwable)
120
    {
121
        $this->report($throwable);
122
123
        if ($this->previousExceptionHandler) {
124
            call_user_func($this->previousExceptionHandler, $throwable);
125
        }
126
    }
127
128
    public function handleError($code, $message, $file = '', $line = 0)
129
    {
130
        $exception = new \ErrorException($message, 0, $code, $file, $line);
131
132
        $this->report($exception);
133
134
        if ($this->previousErrorHandler) {
135
            return call_user_func(
136
                $this->previousErrorHandler,
137
                $message,
138
                $code,
139
                $file,
140
                $line
141
            );
142
        }
143
    }
144
145
    public function applicationPath(string $applicationPath)
146
    {
147
        $this->applicationPath = $applicationPath;
148
149
        return $this;
150
    }
151
152
    public function report(Throwable $throwable, callable $callback = null)
153
    {
154
        $report = $this->createReport($throwable);
155
156
        if (! is_null($callback)) {
157
            call_user_func($callback, $report);
158
        }
159
160
        $this->sendReportToApi($report);
161
    }
162
163
    public function reportMessage(string $message, string $logLevel, callable $callback = null)
164
    {
165
        $report = $this->createReportFromMessage($message, $logLevel);
166
167
        if (! is_null($callback)) {
168
            call_user_func($callback, $report);
169
        }
170
171
        $this->sendReportToApi($report);
172
    }
173
174
    public function sendTestReport(Throwable $throwable)
175
    {
176
        $this->api->sendTestReport($this->createReport($throwable));
177
    }
178
179
    private function sendReportToApi(Report $report)
180
    {
181
        try {
182
            $this->api->report($report);
183
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
184
        }
185
    }
186
187
    public function reset()
188
    {
189
        $this->api->sendQueuedReports();
190
191
        $this->userProvidedContext = [];
192
        $this->recorder->reset();
193
    }
194
195
    private function applyAdditionalParameters(Report $report)
196
    {
197
        $report
198
            ->stage($this->stage)
199
            ->messageLevel($this->messageLevel)
200
            ->setApplicationPath($this->applicationPath)
201
            ->userProvidedContext($this->userProvidedContext);
202
    }
203
204
    public function anonymizeIp()
205
    {
206
        $this->registerMiddleware(new AnonymizeIp);
207
208
        return $this;
209
    }
210
211
    public function createReport(Throwable $throwable): Report
212
    {
213
        $report = Report::createForThrowable(
214
            $throwable,
215
            $this->contextDetector->detectCurrentContext(),
216
            $this->applicationPath
217
        );
218
219
        return $this->applyMiddlewareToReport($report);
220
    }
221
222
    public function createReportFromMessage(string $message, string $logLevel): Report
223
    {
224
        $report = Report::createForMessage(
225
            $message,
226
            $logLevel,
227
            $this->contextDetector->detectCurrentContext(),
228
            $this->applicationPath
229
        );
230
231
        return $this->applyMiddlewareToReport($report);
232
    }
233
234
    protected function applyMiddlewareToReport(Report $report): Report
235
    {
236
        $this->applyAdditionalParameters($report);
237
238
        $report = (new Pipeline($this->container))
239
            ->send($report)
240
            ->through($this->middleware)
241
            ->then(function ($report) {
242
                return $report;
243
            });
244
245
        return $report;
246
    }
247
}
248