LogrotateCollector::getLogFileStatus()   C
last analyzed

Complexity

Conditions 15
Paths 168

Size

Total Lines 85
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 15
eloc 47
c 5
b 0
f 0
nc 168
nop 0
dl 0
loc 85
rs 5.35

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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