LogrotateCollector   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 70
c 6
b 0
f 0
dl 0
loc 134
rs 10
wmc 22

4 Methods

Rating   Name   Duplication   Size   Complexity  
A collect() 0 4 1
C getLogFileStatus() 0 85 15
A getIdentifier() 0 3 1
A getLogFilesWithStats() 0 33 5
1
<?php
2
3
namespace Startwind\Inventorio\Collector\System\Logs;
4
5
use Startwind\Inventorio\Collector\Collector;
6
use Startwind\Inventorio\Exec\File;
7
use Startwind\Inventorio\Exec\Runner;
8
use Startwind\Inventorio\Exec\System;
9
10
class LogrotateCollector implements Collector
11
{
12
    public function getIdentifier(): string
13
    {
14
        return 'SystemLogLogrotate';
15
    }
16
17
    public function collect(): array
18
    {
19
        return [
20
            'logfiles' => $this->getLogFileStatus()
21
        ];
22
    }
23
24
    private function getLogFileStatus(): array
25
    {
26
        $fileHandler = File::getInstance();
27
28
        $searchPath = '/var/log';
29
30
        $logrotateConfigurations = ['/etc/logrotate.conf'];
31
32
        if ($fileHandler->isDir('/etc/logrotate.d')) {
33
            $entries = $fileHandler->scanDir('/etc/logrotate.d');
34
            foreach ($entries as $entry) {
35
                if ($entry === '.' || $entry === '..') continue;
36
                $fullPath = '/etc/logrotate.d/' . $entry;
37
                $logrotateConfigurations[] = $fullPath;
38
            }
39
        }
40
41
        $allLogs = $this->getLogFilesWithStats($searchPath);
42
43
        // Step 2: Extract managed log paths from logrotate config files
44
        $explicitManaged = [];
45
        foreach ($logrotateConfigurations as $confFile) {
46
            $lines = $fileHandler->getContents($confFile, true);
47
            foreach ($lines as $line) {
48
                if (preg_match('#^\s*/[^\s{}]+\.log#', $line, $matches)) {
49
                    // $path = $fileHandler->realPath($matches[0]);
50
                    $path = $matches[0];
51
                    $explicitManaged[] = $path;
52
                }
53
            }
54
        }
55
56
        $explicitManaged = array_unique($explicitManaged);
57
58
        // Step 3: Check for rotated versions (*.log.1, *.log.2.gz, etc.)
59
        $rotatedManaged = [];
60
61
        foreach (array_keys($allLogs) as $logFile) {
62
            $dir = dirname($logFile);
63
            $base = basename($logFile);
64
65
            $entries = $fileHandler->scanDir($dir);
66
            $found = false;
67
68
            foreach ($entries as $entry) {
69
                if (
70
                    str_starts_with($entry, $base . '.') &&
71
                    $fileHandler->isFile($dir . '/' . $entry)
72
                ) {
73
                    $found = true;
74
                    break;
75
                }
76
            }
77
78
            if ($found) {
79
                $rotatedManaged[] = $logFile;
80
            }
81
        }
82
83
        // Combine explicit config-based and detected rotated logs
84
        $allManaged = array_unique(array_merge($explicitManaged, $rotatedManaged));
85
86
        // Step 4: Build result
87
        $result = [
88
            'managed' => [],
89
            'unmanaged' => []
90
        ];
91
92
        foreach ($allLogs as $path => $info) {
93
            $entry = [
94
                'path' => $path,
95
                'size' => $info['size'],
96
                'last_modified' => date('c', $info['last_modified'])
97
            ];
98
99
            $index = str_replace('/', '-', $path);
100
101
            if (in_array($path, $allManaged)) {
102
                $result['managed'][$index] = $entry;
103
            } else {
104
                $result['unmanaged'][$index] = $entry;
105
            }
106
        }
107
108
        return $result;
109
    }
110
111
    function getLogFilesWithStats(string $dir): array
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
112
    {
113
        $result = [];
114
115
        $os = strtolower(System::getInstance()->getPlatform());
116
117
        if ($os === 'linux') {
118
            $cmd = "find " . escapeshellarg($dir) . " -type f -name '*.log' -exec stat --format='%n\t%s\t%Y' {} + 2>/dev/null";
119
        } elseif ($os === 'darwin') {
120
            $cmd = "find " . escapeshellarg($dir) . " -type f -name '*.log' -exec stat -f '%N\t%z\t%m' {} + 2>/dev/null";
121
        } else {
122
            return [];
123
        }
124
125
        $output = Runner::getInstance()->run($cmd)->getOutput();
126
        $output = explode("\n", $output);
127
128
        foreach ($output as $line) {
129
            $parts = preg_split('/\s+/', $line, 3);
130
131
            if (count($parts) !== 3) {
132
                continue;
133
            }
134
135
            [$file, $size, $mtime] = $parts;
136
137
            $result[$file] = [
138
                'size' => (int)$size,
139
                'last_modified' => (int)$mtime,
140
            ];
141
        }
142
143
        return $result;
144
    }
145
}
146