Passed
Push — MODEL_LIB_240928 ( d6fbb6...55f3e4 )
by Rafael
49:14
created

DolLogsCollector   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 79
dl 0
loc 198
rs 10
c 0
b 0
f 0
wmc 25

8 Methods

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