1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Yaro\LogEnvelope; |
4
|
|
|
|
5
|
|
|
use Exception; |
6
|
|
|
use SplFileObject; |
7
|
|
|
use Illuminate\Support\Facades\Log; |
8
|
|
|
use Illuminate\Support\Facades\Request; |
9
|
|
|
use Illuminate\Support\Facades\Session; |
10
|
|
|
use Yaro\LogEnvelope\Drivers\DriverFactory; |
11
|
|
|
|
12
|
|
|
class LogEnvelope |
13
|
|
|
{ |
14
|
|
|
|
15
|
|
|
private $config = []; |
16
|
|
|
private $cachedConfig = []; |
17
|
|
|
|
18
|
|
|
public function __construct() |
19
|
|
|
{ |
20
|
|
|
$this->config['except'] = config('yaro.log-envelope.except', []); |
21
|
|
|
$this->config['count'] = config('yaro.log-envelope.lines_count', 6); |
22
|
|
|
$this->config['drivers'] = config('yaro.log-envelope.drivers', []); |
23
|
|
|
} // end __construct |
24
|
|
|
|
25
|
|
|
public function send($exception) |
26
|
|
|
{ |
27
|
|
|
$this->onBefore(); |
28
|
|
|
|
29
|
|
|
try { |
30
|
|
|
$data = $this->getExceptionData($exception); |
31
|
|
|
|
32
|
|
|
if ($this->isSkipException($data['class'])) { |
33
|
|
|
return; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
foreach ($this->config['drivers'] as $driver => $driverConfig) { |
37
|
|
|
DriverFactory::create($driver, $data)->setConfig($driverConfig)->send(); |
38
|
|
|
} |
39
|
|
|
} catch (Exception $e) { |
40
|
|
|
Log::error($e); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
$this->onAfter(); |
44
|
|
|
} // end send |
45
|
|
|
|
46
|
|
|
private function onBefore() |
47
|
|
|
{ |
48
|
|
|
$this->cachedConfig = []; |
49
|
|
|
$forcedConfig = config('yaro.log-envelope.force_config', []); |
50
|
|
|
foreach ($forcedConfig as $configKey => $configValue) { |
51
|
|
|
$this->cachedConfig[$configKey] = config($configKey); |
52
|
|
|
} |
53
|
|
|
if ($forcedConfig) { |
54
|
|
|
config($forcedConfig); |
55
|
|
|
} |
56
|
|
|
} // end onBefore |
57
|
|
|
|
58
|
|
|
private function onAfter() |
59
|
|
|
{ |
60
|
|
|
if ($this->cachedConfig) { |
|
|
|
|
61
|
|
|
config($this->cachedConfig); |
62
|
|
|
} |
63
|
|
|
} // end onAfter |
64
|
|
|
|
65
|
|
|
public function isSkipException($exceptionClass) |
66
|
|
|
{ |
67
|
|
|
return in_array($exceptionClass, $this->config['except']); |
68
|
|
|
} // end isSkipException |
69
|
|
|
|
70
|
|
|
private function getExceptionData($exception) |
|
|
|
|
71
|
|
|
{ |
72
|
|
|
$data = []; |
73
|
|
|
|
74
|
|
|
$data['host'] = Request::server('HTTP_HOST'); |
75
|
|
|
$data['method'] = Request::method(); |
76
|
|
|
$data['fullUrl'] = Request::fullUrl(); |
77
|
|
|
if (php_sapi_name() === 'cli') { |
78
|
|
|
$data['host'] = parse_url(config('app.url'), PHP_URL_HOST); |
79
|
|
|
$data['method'] = 'CLI'; |
80
|
|
|
} |
81
|
|
|
$data['exception'] = $exception->getMessage(); |
82
|
|
|
$data['error'] = $exception->getTraceAsString(); |
83
|
|
|
$data['line'] = $exception->getLine(); |
84
|
|
|
$data['file'] = $exception->getFile(); |
85
|
|
|
$data['class'] = get_class($exception); |
86
|
|
|
$data['storage'] = array( |
87
|
|
|
'SERVER' => Request::server(), |
88
|
|
|
'GET' => Request::query(), |
89
|
|
|
'POST' => $_POST, |
90
|
|
|
'FILE' => Request::file(), |
91
|
|
|
'OLD' => Request::hasSession() ? Request::old() : [], |
92
|
|
|
'COOKIE' => Request::cookie(), |
93
|
|
|
'SESSION' => Request::hasSession() ? Session::all() : [], |
94
|
|
|
'HEADERS' => Request::header(), |
95
|
|
|
); |
96
|
|
|
|
97
|
|
|
$data['storage'] = array_filter($data['storage']); |
98
|
|
|
|
99
|
|
|
$count = $this->config['count']; |
100
|
|
|
|
101
|
|
|
$data['exegutor'] = []; |
102
|
|
|
$data['file_lines'] = []; |
103
|
|
|
|
104
|
|
|
$file = new SplFileObject($data['file']); |
105
|
|
|
for ($i = -1 * abs($count); $i <= abs($count); $i++) { |
106
|
|
|
list($line, $exegutorLine) = $this->getLineInfo($file, $data['line'], $i); |
107
|
|
|
if (!$line && !$exegutorLine) { |
108
|
|
|
continue; |
109
|
|
|
} |
110
|
|
|
$data['exegutor'][] = $exegutorLine; |
111
|
|
|
$data['file_lines'][$data['line'] + $i] = $line; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
// to make Symfony exception more readable |
115
|
|
|
if ($data['class'] == 'Symfony\Component\Debug\Exception\FatalErrorException') { |
116
|
|
|
preg_match("~^(.+)' in ~", $data['exception'], $matches); |
117
|
|
|
if (isset($matches[1])) { |
118
|
|
|
$data['exception'] = $matches[1]; |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
return $data; |
123
|
|
|
} // end getExceptionData |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @param SplFileObject $file |
127
|
|
|
*/ |
128
|
|
|
private function getLineInfo($file, $line, $i) |
129
|
|
|
{ |
130
|
|
|
$currentLine = $line + $i; |
131
|
|
|
// cuz array starts with 0, when file lines start count from 1 |
132
|
|
|
$index = $currentLine - 1; |
133
|
|
|
if ($index < 0) { |
134
|
|
|
return [false, false]; |
135
|
|
|
} |
136
|
|
|
$file->seek($index); |
137
|
|
|
|
138
|
|
|
return [ |
139
|
|
|
$file->__toString(), |
140
|
|
|
[ |
141
|
|
|
'line' => '<span style="color:#aaaaaa;">' . $currentLine . '.</span> ' . SyntaxHighlight::process($file->__toString()), |
142
|
|
|
'wrap_left' => $i ? '' : '<span style="color: #F5F5F5; background-color: #5A3E3E; width: 100%; display: block;">', |
143
|
|
|
'wrap_right' => $i ? '' : '</span>', |
144
|
|
|
] |
145
|
|
|
]; |
146
|
|
|
} // end getLineInfo |
147
|
|
|
|
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
|
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.