1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Rap2hpoutre\LaravelLogViewer; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Class LaravelLogViewer |
7
|
|
|
* @package Rap2hpoutre\LaravelLogViewer |
8
|
|
|
*/ |
9
|
|
|
class LaravelLogViewer |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* @var string file |
13
|
|
|
*/ |
14
|
|
|
private $file; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @var string folder |
18
|
|
|
*/ |
19
|
|
|
private $folder; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var string storage_path |
23
|
|
|
*/ |
24
|
|
|
private $storage_path; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Why? Uh... Sorry |
28
|
|
|
*/ |
29
|
|
|
const MAX_FILE_SIZE = 52428800; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var Level level |
33
|
|
|
*/ |
34
|
|
|
private $level; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var Pattern pattern |
38
|
|
|
*/ |
39
|
|
|
private $pattern; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* LaravelLogViewer constructor. |
43
|
|
|
*/ |
44
|
|
|
public function __construct() |
45
|
|
|
{ |
46
|
|
|
$this->level = new Level(); |
47
|
|
|
$this->pattern = new Pattern(); |
48
|
|
|
$this->storage_path = function_exists('config') ? config('logviewer.storage_path', storage_path('logs')) : storage_path('logs'); |
49
|
|
|
|
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param string $folder |
54
|
|
|
*/ |
55
|
|
|
public function setFolder($folder) |
56
|
|
|
{ |
57
|
|
|
if (app('files')->exists($folder)) { |
58
|
|
|
$this->folder = $folder; |
59
|
|
|
} |
60
|
|
|
if(is_array($this->storage_path)){ |
61
|
|
View Code Duplication |
foreach ($this->storage_path as $value) { |
|
|
|
|
62
|
|
|
$logsPath = $value . '/' . $folder; |
63
|
|
|
if (app('files')->exists($logsPath)) { |
64
|
|
|
$this->folder = $folder; |
65
|
|
|
break; |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
} |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @param string $file |
73
|
|
|
* @throws \Exception |
74
|
|
|
*/ |
75
|
|
|
public function setFile($file) |
76
|
|
|
{ |
77
|
|
|
$file = $this->pathToLogFile($file); |
78
|
|
|
|
79
|
|
|
if (app('files')->exists($file)) { |
80
|
|
|
$this->file = $file; |
81
|
|
|
} |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @param string $file |
86
|
|
|
* @return string |
87
|
|
|
* @throws \Exception |
88
|
|
|
*/ |
89
|
|
|
public function pathToLogFile($file) |
90
|
|
|
{ |
91
|
|
|
|
92
|
|
|
if (app('files')->exists($file)) { // try the absolute path |
93
|
|
|
return $file; |
94
|
|
|
} |
95
|
|
|
if (is_array($this->storage_path)) { |
96
|
|
View Code Duplication |
foreach ($this->storage_path as $folder) { |
|
|
|
|
97
|
|
|
if (app('files')->exists($folder . '/' . $file)) { // try the absolute path |
98
|
|
|
$file = $folder . '/' . $file; |
99
|
|
|
break; |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
return $file; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
$logsPath = $this->storage_path; |
106
|
|
|
$logsPath .= ($this->folder) ? '/' . $this->folder : ''; |
107
|
|
|
$file = $logsPath . '/' . $file; |
108
|
|
|
// check if requested file is really in the logs directory |
109
|
|
|
if (dirname($file) !== $logsPath) { |
110
|
|
|
throw new \Exception('No such log file'); |
111
|
|
|
} |
112
|
|
|
return $file; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @return string |
117
|
|
|
*/ |
118
|
|
|
public function getFolderName() |
119
|
|
|
{ |
120
|
|
|
return $this->folder; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @return string |
125
|
|
|
*/ |
126
|
|
|
public function getFileName() |
127
|
|
|
{ |
128
|
|
|
return basename($this->file); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* @return array |
133
|
|
|
*/ |
134
|
|
|
public function all() |
135
|
|
|
{ |
136
|
|
|
$log = array(); |
137
|
|
|
|
138
|
|
|
if (!$this->file) { |
139
|
|
|
$log_file = (!$this->folder) ? $this->getFiles() : $this->getFolderFiles(); |
140
|
|
|
if (!count($log_file)) { |
141
|
|
|
return []; |
142
|
|
|
} |
143
|
|
|
$this->file = $log_file[0]; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
if (app('files')->size($this->file) > self::MAX_FILE_SIZE) { |
147
|
|
|
return null; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
$file = app('files')->get($this->file); |
151
|
|
|
|
152
|
|
|
preg_match_all($this->pattern->getPattern('logs'), $file, $headings); |
153
|
|
|
|
154
|
|
|
if (!is_array($headings)) { |
155
|
|
|
return $log; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$log_data = preg_split($this->pattern->getPattern('logs'), $file); |
159
|
|
|
|
160
|
|
|
if ($log_data[0] < 1) { |
161
|
|
|
array_shift($log_data); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
foreach ($headings as $h) { |
165
|
|
|
for ($i = 0, $j = count($h); $i < $j; $i++) { |
166
|
|
|
foreach ($this->level->all() as $level) { |
167
|
|
|
if (strpos(strtolower($h[$i]), '.' . $level) || strpos(strtolower($h[$i]), $level . ':')) { |
168
|
|
|
|
169
|
|
|
preg_match($this->pattern->getPattern('current_log', 0) . $level . $this->pattern->getPattern('current_log', 1), $h[$i], $current); |
170
|
|
|
if (!isset($current[4])) { |
171
|
|
|
continue; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
$log[] = array( |
175
|
|
|
'context' => $current[3], |
176
|
|
|
'level' => $level, |
177
|
|
|
'folder' => $this->folder, |
178
|
|
|
'level_class' => $this->level->cssClass($level), |
179
|
|
|
'level_img' => $this->level->img($level), |
180
|
|
|
'date' => $current[1], |
181
|
|
|
'text' => $current[4], |
182
|
|
|
'in_file' => isset($current[5]) ? $current[5] : null, |
183
|
|
|
'stack' => preg_replace("/^\n*/", '', $log_data[$i]) |
184
|
|
|
); |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
if (empty($log)) { |
191
|
|
|
|
192
|
|
|
$lines = explode(PHP_EOL, $file); |
193
|
|
|
$log = []; |
194
|
|
|
|
195
|
|
|
foreach ($lines as $key => $line) { |
196
|
|
|
$log[] = [ |
197
|
|
|
'context' => '', |
198
|
|
|
'level' => '', |
199
|
|
|
'folder' => '', |
200
|
|
|
'level_class' => '', |
201
|
|
|
'level_img' => '', |
202
|
|
|
'date' => $key + 1, |
203
|
|
|
'text' => $line, |
204
|
|
|
'in_file' => null, |
205
|
|
|
'stack' => '', |
206
|
|
|
]; |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
return array_reverse($log); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* @return array |
215
|
|
|
*/ |
216
|
|
|
public function getFolders() |
217
|
|
|
{ |
218
|
|
|
$folders = glob($this->storage_path . '/*', GLOB_ONLYDIR); |
219
|
|
|
if (is_array($this->storage_path)) { |
220
|
|
|
foreach ($this->storage_path as $value) { |
221
|
|
|
$folders = array_merge( |
222
|
|
|
$folders, |
223
|
|
|
glob($value . '/*', GLOB_ONLYDIR) |
224
|
|
|
); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
if (is_array($folders)) { |
229
|
|
|
foreach ($folders as $k => $folder) { |
230
|
|
|
$folders[$k] = basename($folder); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
return array_values($folders); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param bool $basename |
238
|
|
|
* @return array |
239
|
|
|
*/ |
240
|
|
|
public function getFolderFiles($basename = false) |
241
|
|
|
{ |
242
|
|
|
return $this->getFiles($basename, $this->folder); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* @param bool $basename |
247
|
|
|
* @param string $folder |
248
|
|
|
* @return array |
249
|
|
|
*/ |
250
|
|
|
public function getFiles($basename = false, $folder = '') |
251
|
|
|
{ |
252
|
|
|
$pattern = function_exists('config') ? config('logviewer.pattern', '*.log') : '*.log'; |
253
|
|
|
$files = glob( |
254
|
|
|
$this->storage_path . '/' . $folder . '/' . $pattern, |
255
|
|
|
preg_match($this->pattern->getPattern('files'), $pattern) ? GLOB_BRACE : 0 |
256
|
|
|
); |
257
|
|
|
if (is_array($this->storage_path)) { |
258
|
|
|
foreach ($this->storage_path as $value) { |
259
|
|
|
$files = array_merge( |
260
|
|
|
$files, |
261
|
|
|
glob( |
262
|
|
|
$value . '/' . $folder . '/' . $pattern, |
263
|
|
|
preg_match($this->pattern->getPattern('files'), $pattern) ? GLOB_BRACE : 0 |
264
|
|
|
) |
265
|
|
|
); |
266
|
|
|
} |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
$files = array_reverse($files); |
270
|
|
|
$files = array_filter($files, 'is_file'); |
271
|
|
|
if ($basename && is_array($files)) { |
272
|
|
|
foreach ($files as $k => $file) { |
273
|
|
|
$files[$k] = basename($file); |
274
|
|
|
} |
275
|
|
|
} |
276
|
|
|
return array_values($files); |
277
|
|
|
} |
278
|
|
|
} |
279
|
|
|
|
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.