Passed
Push — v1 ( 65d641...7780c4 )
by Andrew
02:59
created

ProfileTarget::calculateTimings()   B

Complexity

Conditions 7
Paths 11

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 28
rs 8.6666
c 0
b 0
f 0
cc 7
nc 11
nop 1
1
<?php
2
/**
3
 * Webperf plugin for Craft CMS 3.x
4
 *
5
 * Monitor the performance of your webpages through real-world user timing data
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2018 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\webperf\log;
12
13
use nystudio107\webperf\Webperf;
14
15
use yii\log\Target;
0 ignored issues
show
Bug introduced by
The type yii\log\Target was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use yii\log\Logger;
0 ignored issues
show
Bug introduced by
The type yii\log\Logger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
18
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
19
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 4
Loading history...
20
 * @package   Webperf
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
21
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 3 spaces but found 5
Loading history...
22
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
23
class ProfileTarget extends Target
24
{
25
26
    const PROFILE_CATEGORIES = [
27
        'database' => [
28
            'prefix' => 'yii\db',
29
        ],
30
        'twig' => [
31
            'prefix' => 'craft\web\twig\Template',
32
        ],
33
        'other' => [
34
            'prefix' => 'webperf-other',
35
        ],
36
    ];
37
38
    // Public Properties
39
    // =========================================================================
40
41
    public $stats = [];
42
43
    // Public Methods
44
    // =========================================================================
45
46
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
47
     * @inheritdoc
48
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
49
    public function init()
50
    {
51
        parent::init();
52
        foreach (self::PROFILE_CATEGORIES as $key => $value) {
53
            $this->stats[$key] = [
54
                'count' => 0,
55
                'duration' => 0.0,
56
                'memory' => 0,
57
            ];
58
        }
59
    }
60
61
    /**
62
     * Processes the given log messages.
63
     * This method will filter the given messages with [[levels]] and [[categories]].
64
     * And if requested, it will also export the filtering result to specific medium (e.g. email).
65
     * @param array $messages log messages to be processed. See [[Logger::messages]] for the structure
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
66
     * of each message.
0 ignored issues
show
Coding Style introduced by
Parameter comment not aligned correctly; expected 24 spaces but found 1
Loading history...
67
     * @param bool $final whether this method is called at the end of the current application
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
68
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
69
    public function collect($messages, $final)
70
    {
71
        // Merge in any messages intended for us
72
        $this->messages = array_merge(
0 ignored issues
show
Bug Best Practice introduced by
The property messages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
73
            $this->messages,
74
            static::filterMessages($messages, $this->getLevels(), $this->categories, $this->except)
75
        );
76
        // Calculate the timings from the messages, and then reset them
77
        $timings = $this->calculateTimings($this->messages);
78
        $this->messages = [];
79
        // Loop through and tally up all of the timings
80
        foreach ($timings as $timing) {
81
            $cat = 'other';
82
            foreach (self::PROFILE_CATEGORIES as $key => $value) {
83
                if (strpos($timing['category'], $value['prefix']) === 0) {
84
                    $cat = $key;
85
                }
86
            }
87
            $this->stats[$cat]['count']++;
88
            $this->stats[$cat]['duration'] += (float)$timing['duration'] * 1000;
89
            $this->stats[$cat]['memory'] += (int)$timing['memoryDiff'];
90
        }
91
        if ($final) {
92
            $this->export();
93
            Webperf::$plugin->beacons->includeCraftBeacon();
94
        }
95
    }
96
97
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
98
     * @inheritdoc
99
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
100
    public function export()
101
    {
102
    }
103
104
    // Protected Methods
105
    // =========================================================================
106
107
    /**
108
     * Calculates the elapsed time for the given log messages.
109
     * @param array $messages the log messages obtained from profiling
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
110
     * @return array timings. Each element is an array consisting of these elements:
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
111
     * `info`, `category`, `timestamp`, `trace`, `level`, `duration`, `memory`, `memoryDiff`.
112
     * The `memory` and `memoryDiff` values are available since version 2.0.11.
113
     */
114
    protected function calculateTimings($messages): array
115
    {
116
        $timings = [];
117
        $stack = [];
118
119
        foreach ($messages as $i => $log) {
120
            list($token, $level, $category, $timestamp, $traces) = $log;
121
            $memory = isset($log[5]) ? $log[5] : 0;
122
            $log[6] = $i;
123
            $hash = md5(json_encode($token));
124
            if ($level == Logger::LEVEL_PROFILE_BEGIN) {
125
                $stack[$hash] = $log;
126
            } elseif ($level == Logger::LEVEL_PROFILE_END) {
127
                if (isset($stack[$hash])) {
128
                    $timings[$stack[$hash][6]] = [
129
                        'category' => $stack[$hash][2],
130
                        'timestamp' => $stack[$hash][3],
131
                        'level' => count($stack) - 1,
132
                        'duration' => $timestamp - $stack[$hash][3],
133
                        'memory' => $memory,
134
                        'memoryDiff' => $memory - (isset($stack[$hash][5]) ? $stack[$hash][5] : 0),
135
                    ];
136
                    unset($stack[$hash]);
137
                }
138
            }
139
        }
140
141
        return array_values($timings);
142
    }
143
}
144