Passed
Push — master ( c9e4eb...edd92f )
by Nils
02:54
created

MetricThresholdCollector   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 49
c 1
b 0
f 0
dl 0
loc 87
rs 10
wmc 13

2 Methods

Rating   Name   Duplication   Size   Complexity  
B countStandardDeviationOutliers() 0 35 7
A collect() 0 22 6
1
<?php
2
3
namespace Startwind\Inventorio\Collector\Metrics;
4
5
use Startwind\Inventorio\Collector\BasicCollector;
6
use Startwind\Inventorio\Metrics\Collector\Metric\Webserver\ApacheAccessLogMetric;
7
use Startwind\Inventorio\Metrics\Collector\Metric\Webserver\ApacheErrorLogMetric;
8
use Startwind\Inventorio\Metrics\Memory\Memory;
9
10
class MetricThresholdCollector extends BasicCollector
11
{
12
    const THRESHOLD_ABSOLUTE = 'absolute';
13
    const THRESHOLD_STANDARD_DEVIATION = 'standardDeviation';
14
15
    protected string $identifier = 'MetricsThreshold';
16
17
    private array $thresholds = [
18
        'cpu-usage' => [
19
            'type' => self::THRESHOLD_ABSOLUTE,
20
            'threshold' => 80
21
        ],
22
        'memory-usage' => [
23
            'type' => self::THRESHOLD_ABSOLUTE,
24
            'threshold' => 80
25
        ],
26
        ApacheErrorLogMetric::IDENTIFIER => [
27
            'type' => self::THRESHOLD_STANDARD_DEVIATION,
28
            'factor' => 3,
29
            'outlinerMinLimit' => 10
30
        ],
31
        ApacheAccessLogMetric::IDENTIFIER => [
32
            'type' => self::THRESHOLD_STANDARD_DEVIATION,
33
            'factor' => 3,
34
            'outlinerMinLimit' => 10
35
        ]
36
    ];
37
38
    public function collect(): array
39
    {
40
        $memory = Memory::getInstance();
41
42
        $result = [];
43
44
        foreach ($this->thresholds as $metric => $threshold) {
45
            switch ($threshold['type']) {
46
                case self::THRESHOLD_ABSOLUTE:
47
                    if ($memory->hasData($metric)) {
48
                        $result[$metric] = $memory->getNumberOfGreaterThan($metric, $threshold['threshold']);
49
                    }
50
                    break;
51
                case self::THRESHOLD_STANDARD_DEVIATION:
52
                    if ($memory->hasData($metric)) {
53
                        $data = $memory->getData($metric);
54
                        $result[$metric] = $this->countStandardDeviationOutliers($data, $threshold['factor'], $threshold['outlinerMinLimit']);
55
                    }
56
            }
57
        }
58
59
        return $result;
60
    }
61
62
    private function countStandardDeviationOutliers(array $values, float $factor = 3.0, $outlinerMinLimit = 10): int
63
    {
64
        $n = count($values);
65
66
        // we wait until we have enough data
67
        if ($n < 5) {
68
            return 0;
69
        }
70
71
        $sum = array_sum($values);
72
        $mean = $sum / $n;
73
74
        // Calculate standard deviation
75
        $sumOfSquares = 0.0;
76
        foreach ($values as $value) {
77
            $sumOfSquares += pow($value - $mean, 2);
78
        }
79
80
        $stdDev = sqrt($sumOfSquares / $n);
81
82
        if ($stdDev == 0.0) {
83
            return 0;
84
        }
85
86
        // Count outliers
87
        $threshold = $factor * $stdDev;
88
        $outliers = 0;
89
90
        foreach ($values as $value) {
91
            if (abs($value - $mean) > $threshold && $value > $outlinerMinLimit) {
92
                $outliers++;
93
            }
94
        }
95
96
        return $outliers;
97
    }
98
}
99