Test Failed
Push — main ( fac5ed...59bfee )
by Rafael
50:50
created

DolLogsCollector::collect()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 25
rs 9.2222
1
<?php
2
3
/* Copyright (C) 2023   Laurent Destailleur     <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
/**
20
 *  \file       htdocs/debugbar/class/DataCollector/DolLogsCollector.php
21
 *  \brief      Class for debugbar collection
22
 *  \ingroup    debugbar
23
 */
24
25
namespace DoliCore\Tools\DebugBarCollector;
26
27
use DebugBar\DataCollector\MessagesCollector;
28
use Psr\Log\LogLevel;
29
use ReflectionClass;
30
31
//use ReflectionClass;
32
33
/**
34
 * DolLogsCollector class
35
 *
36
 * Delete when fully migrated to Monolog
37
 * This class is only needed for compatibility with Dolibarr.
38
 *
39
 * @package DoliCore\Tools\DebugBarCollector
40
 */
41
class DolLogsCollector extends MessagesCollector
42
{
43
    /**
44
     * @var string default logs file path
45
     */
46
    protected $path;
47
    /**
48
     * @var int number of lines to show
49
     */
50
    protected $maxnboflines;
51
52
    /**
53
     * @var int number of lines
54
     */
55
    protected $nboflines;
56
57
    /**
58
     * Constructor
59
     *
60
     * @param string $path Path
61
     * @param string $name Name
62
     */
63
    public function __construct($path = null, $name = 'logs')
64
    {
65
        global $conf;
66
67
        parent::__construct($name);
68
69
        $this->nboflines = 0;
70
        $this->maxnboflines = getDolGlobalInt('DEBUGBAR_LOGS_LINES_NUMBER', 250); // High number slows seriously output
71
72
        $this->path = $path ?: $this->getLogsFile();
73
    }
74
75
    /**
76
     * Get the path to the logs file
77
     *
78
     * @return string
79
     */
80
    public function getLogsFile()
81
    {
82
        // default dolibarr log file
83
        $path = DOL_DATA_ROOT . '/dolibarr.log';
84
        return $path;
85
    }
86
87
    /**
88
     *  Return widget settings
89
     *
90
     * @return array  Array
91
     */
92
    public function getWidgets()
93
    {
94
        global $langs;
95
96
        $title = $langs->transnoentities('DolLogs');
97
        $name = $this->getName();
98
99
        return [
100
            "$title" => [
101
                "icon" => "list-alt",
102
                "widget" => "PhpDebugBar.Widgets.MessagesWidget",
103
                "map" => "$name.messages",
104
                "default" => "[]",
105
            ],
106
            "$title:badge" => [
107
                "map" => "$name.count",
108
                "default" => "null",
109
            ],
110
        ];
111
    }
112
113
    /**
114
     *  Return collected data
115
     *
116
     * @return array  Array
117
     */
118
    public function collect()
119
    {
120
        global $conf;
121
122
        $uselogfile = getDolGlobalInt('DEBUGBAR_USE_LOG_FILE');
123
124
        if ($uselogfile) {
125
            $this->getStorageLogs($this->path);
126
        } else {
127
            $log_levels = $this->getLevels();
128
129
            foreach ($conf->logbuffer as $line) {
130
                if ($this->nboflines >= $this->maxnboflines) {
131
                    break;
132
                }
133
                foreach ($log_levels as $level_key => $level) {
134
                    if (strpos(strtolower($line), strtolower($level_key)) == 20) {
135
                        $this->nboflines++;
136
                        $this->addMessage($line, $level, false);
137
                    }
138
                }
139
            }
140
        }
141
142
        return parent::collect();
143
    }
144
145
    /**
146
     * Get logs
147
     *
148
     * @param string $path Path
149
     *
150
     * @return  void
151
     */
152
    public function getStorageLogs($path)
153
    {
154
        if (!file_exists($path)) {
155
            return;
156
        }
157
158
        // Load the latest lines
159
        $file = implode("", $this->tailFile($path, $this->maxnboflines));
160
161
        foreach ($this->getLogs($file) as $log) {
162
            $this->addMessage($log['line'], $log['level'], false);
163
        }
164
    }
165
166
    /**
167
     * Get latest file lines
168
     *
169
     * @param string $file  File
170
     * @param int    $lines Lines
171
     *
172
     * @return array       Array
173
     */
174
    protected function tailFile($file, $lines)
175
    {
176
        $handle = fopen($file, "r");
177
        $linecounter = $lines;
178
        $pos = -2;
179
        $beginning = false;
180
        $text = [];
181
        while ($linecounter > 0) {
182
            $t = " ";
183
            while ($t != "\n") {
184
                if (fseek($handle, $pos, SEEK_END) == -1) {
185
                    $beginning = true;
186
                    break;
187
                }
188
                $t = fgetc($handle);
189
                $pos--;
190
            }
191
            $linecounter--;
192
            if ($beginning) {
193
                rewind($handle);
194
            }
195
            $text[$lines - $linecounter - 1] = fgets($handle);
196
            if ($beginning) {
197
                break;
198
            }
199
        }
200
        fclose($handle);
201
        return array_reverse($text);
202
    }
203
204
    /**
205
     * Search a string for log entries
206
     *
207
     * @param string $file File
208
     *
209
     * @return array               Lines of logs
210
     */
211
    public function getLogs($file)
212
    {
213
        $pattern = "/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*/";
214
        $log_levels = $this->getLevels();
215
        preg_match_all($pattern, $file, $matches);
216
        $log = [];
217
        foreach ($matches as $lines) {
218
            foreach ($lines as $line) {
219
                foreach ($log_levels as $level_key => $level) {
220
                    if (strpos(strtolower($line), strtolower($level_key)) == 20) {
221
                        $log[] = ['level' => $level, 'line' => $line];
222
                    }
223
                }
224
            }
225
        }
226
        $log = array_reverse($log);
227
        return $log;
228
    }
229
230
    /**
231
     * Get the log levels from psr/log.
232
     *
233
     * @return array       Array of log level
234
     */
235
    public function getLevels()
236
    {
237
        $class = new ReflectionClass(new LogLevel());
238
        $levels = $class->getConstants();
239
        $levels['ERR'] = 'error';
240
        $levels['WARN'] = 'warning';
241
242
        return $levels;
243
    }
244
}
245