Completed
Pull Request — master (#58)
by Oliver
01:51
created

LaravelLogViewer   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 19
Bugs 1 Features 2
Metric Value
wmc 29
c 19
b 1
f 2
lcom 1
cbo 0
dl 0
loc 188
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A setFile() 0 8 2
A pathToLogFile() 0 15 3
A getFileName() 0 4 1
C all() 0 55 12
A getFiles() 0 19 4
A getLogLevels() 0 5 1
A getIgnoredFileNames() 0 8 2
A isIgnoredFileName() 0 16 4
1
<?php
2
namespace Rap2hpoutre\LaravelLogViewer;
3
4
use Illuminate\Support\Facades\File;
5
use Psr\Log\LogLevel;
6
use ReflectionClass;
7
8
/**
9
 * Class LaravelLogViewer
10
 * @package Rap2hpoutre\LaravelLogViewer
11
 */
12
class LaravelLogViewer
13
{
14
15
    /**
16
     * @var string file
17
     */
18
    private static $file;
19
20
    private static $levels_classes = [
21
        'debug' => 'info',
22
        'info' => 'info',
23
        'notice' => 'info',
24
        'warning' => 'warning',
25
        'error' => 'danger',
26
        'critical' => 'danger',
27
        'alert' => 'danger',
28
        'emergency' => 'danger',
29
    ];
30
31
    private static $levels_imgs = [
32
        'debug' => 'info',
33
        'info' => 'info',
34
        'notice' => 'info',
35
        'warning' => 'warning',
36
        'error' => 'warning',
37
        'critical' => 'warning',
38
        'alert' => 'warning',
39
        'emergency' => 'warning',
40
    ];
41
42
    private static $ignoredFileNames;
43
44
    const MAX_FILE_SIZE = 52428800; // Why? Uh... Sorry
45
46
    /**
47
     * @param string $file
48
     */
49
    public static function setFile($file)
50
    {
51
        $file = self::pathToLogFile($file);
52
53
        if (File::exists($file)) {
54
            self::$file = $file;
55
        }
56
    }
57
58
    public static function pathToLogFile($file)
59
    {
60
        $logsPath = storage_path('logs');
61
62
        if (! File::exists($file)) { // try the absolute path
63
            $file = $logsPath . '/' . $file;
64
        }
65
66
        // check if requested file is really in the logs directory
67
        if (dirname($file) !== $logsPath) {
68
            throw new \Exception('No such log file');
69
        }
70
71
        return $file;
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    public static function getFileName()
78
    {
79
        return basename(self::$file);
80
    }
81
82
    /**
83
     * @return array
84
     */
85
    public static function all()
86
    {
87
        $log = array();
88
89
        $log_levels = self::getLogLevels();
90
91
        $pattern = '/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\].*/';
92
93
        if (!self::$file) {
94
            $log_file = self::getFiles();
95
            if(!count($log_file)) {
96
                return [];
97
            }
98
            self::$file = $log_file[0];
99
        }
100
101
        if (File::size(self::$file) > self::MAX_FILE_SIZE) return null;
102
103
        $file = File::get(self::$file);
104
105
        preg_match_all($pattern, $file, $headings);
106
107
        if (!is_array($headings)) return $log;
108
109
        $log_data = preg_split($pattern, $file);
110
111
        if ($log_data[0] < 1) {
112
            array_shift($log_data);
113
        }
114
115
        foreach ($headings as $h) {
116
            for ($i=0, $j = count($h); $i < $j; $i++) {
117
                foreach ($log_levels as $level_key => $level_value) {
118
                    if (strpos(strtolower($h[$i]), '.' . $level_value)) {
119
120
                        preg_match('/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\].*?\.' . $level_key . ': (.*?)( in .*?:[0-9]+)?$/', $h[$i], $current);
121
122
                        if (!isset($current[2])) continue;
123
124
                        $log[] = array(
125
                            'level' => $level_value,
126
                            'level_class' => self::$levels_classes[$level_value],
127
                            'level_img' => self::$levels_imgs[$level_value],
128
                            'date' => $current[1],
129
                            'text' => $current[2],
130
                            'in_file' => isset($current[3]) ? $current[3] : null,
131
                            'stack' => preg_replace("/^\n*/", '', $log_data[$i])
132
                        );
133
                    }
134
                }
135
            }
136
        }
137
138
        return array_reverse($log);
139
    }
140
141
    /**
142
     * @param bool $basename
143
     * @return array
144
     */
145
    public static function getFiles($basename = false)
146
    {
147
        $files = glob(storage_path() . '/logs/*');
148
        $files = array_reverse($files);
149
        $files = array_filter($files, 'is_file');
150
151
        $files = array_filter($files, function ($var) {
152
            $ignore = ! self::isIgnoredFileName($var);
153
154
            return $ignore;
155
        });
156
157
        if ($basename && is_array($files)) {
158
            foreach ($files as $k => $file) {
159
                $files[$k] = basename($file);
160
            }
161
        }
162
        return array_values($files);
163
    }
164
165
    /**
166
     * @return array
167
     */
168
    private static function getLogLevels()
169
    {
170
        $class = new ReflectionClass(new LogLevel);
171
        return $class->getConstants();
172
    }
173
174
    private static function getIgnoredFileNames()
175
    {
176
        if (! is_array(self::$ignoredFileNames)) {
177
            self::$ignoredFileNames = config('logviewer.ignore');
178
        }
179
180
        return self::$ignoredFileNames;
181
    }
182
183
    private static function isIgnoredFileName($filePath)
184
    {
185
        $ignoredFileNames = self::getIgnoredFileNames();
186
187
        foreach ($ignoredFileNames as $fileName) {
188
            if (str_is($fileName, $filePath)) {
189
                return true;
190
            }
191
192
            if (str_contains($filePath, $fileName)) {
193
                return true;
194
            }
195
        }
196
197
        return false;
198
    }
199
}
200