• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eliashaeussler / cache-warmup / 28539802234

01 Jul 2026 06:40PM UTC coverage: 89.739% (-0.4%) from 90.11%
28539802234

Pull #676

github

eliashaeussler
[!!!][FEATURE] Introduce profiler to measure duration and memory usage
Pull Request #676: [!!!][FEATURE] Introduce profiler to measure duration and memory usage

60 of 70 new or added lines in 7 files covered. (85.71%)

12 existing lines in 2 files now uncovered.

1819 of 2027 relevant lines covered (89.74%)

10.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.19
/src/Formatter/JsonFormatter.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "eliashaeussler/cache-warmup".
7
 *
8
 * Copyright (C) 2020-2026 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\CacheWarmup\Formatter;
25

26
use EliasHaeussler\CacheWarmup\Helper;
27
use EliasHaeussler\CacheWarmup\Profiler;
28
use EliasHaeussler\CacheWarmup\Result;
29
use Stringable;
30
use Symfony\Component\Console;
31

32
use function array_map;
33
use function is_array;
34
use function is_scalar;
35
use function json_encode;
36

37
/**
38
 * JsonFormatter.
39
 *
40
 * @author Elias Häußler <elias@haeussler.dev>
41
 * @license GPL-3.0-or-later
42
 *
43
 * @phpstan-type JsonArray array{
44
 *     parserResult?: array{
45
 *         success?: array{
46
 *             sitemaps: list<string>,
47
 *             urls: list<string>,
48
 *         },
49
 *         failure?: array{
50
 *             sitemaps: list<string>,
51
 *         },
52
 *         excluded?: array{
53
 *             sitemaps: list<string>,
54
 *             urls: list<string>,
55
 *         },
56
 *     },
57
 *     parserStatistics?: array{
58
 *         duration: float,
59
 *         memoryUsage: int,
60
 *     },
61
 *     cacheWarmupResult?: array{
62
 *         success?: list<string>,
63
 *         failure?: list<string>,
64
 *         cancelled?: bool,
65
 *     },
66
 *     cacheWarmupStatistics?: array{
67
 *         duration: float,
68
 *         memoryUsage: int,
69
 *     },
70
 *     messages?: array<value-of<MessageSeverity>, list<string>>,
71
 * }
72
 */
73
final class JsonFormatter implements Formatter
74
{
75
    /**
76
     * @phpstan-var JsonArray
77
     */
78
    private array $json = [];
79

80
    public function __construct(
14✔
81
        private readonly Console\Style\SymfonyStyle $io,
82
    ) {}
14✔
83

84
    public function formatParserResult(
5✔
85
        Result\ParserResult $successful,
86
        Result\ParserResult $failed,
87
        Result\ParserResult $excluded,
88
        ?Profiler\MeasurementSpan $measurement = null,
89
    ): void {
90
        // Add successful result
91
        if ($this->io->isVeryVerbose()) {
5✔
92
            $this->addToJson('parserResult/success/sitemaps', $successful->getSitemaps());
1✔
93
            $this->addToJson('parserResult/success/urls', $successful->getUrls());
1✔
94
        }
95

96
        // Add failed result
97
        $this->addToJson('parserResult/failure/sitemaps', $failed->getSitemaps());
5✔
98

99
        // Add excluded result
100
        $this->addToJson('parserResult/excluded/sitemaps', $excluded->getSitemaps());
5✔
101
        $this->addToJson('parserResult/excluded/urls', $excluded->getUrls());
5✔
102

103
        // Add statistics
104
        if (null !== $measurement) {
5✔
105
            $this->addToJson('parserStatistics/duration', $measurement->duration);
1✔
106
            $this->addToJson('parserStatistics/memoryUsage', $measurement->memoryUsage);
1✔
107
        }
108
    }
109

110
    public function formatCacheWarmupResult(
5✔
111
        Result\CacheWarmupResult $result,
112
        ?Profiler\MeasurementSpan $measurement = null,
113
    ): void {
114
        $this->addToJson('cacheWarmupResult/success', $result->getSuccessful());
5✔
115
        $this->addToJson('cacheWarmupResult/failure', $result->getFailed());
5✔
116

117
        if ($result->wasCancelled()) {
5✔
118
            $this->addToJson('cacheWarmupResult/cancelled', true);
1✔
119
        }
120

121
        // Add statistics
122
        if (null !== $measurement) {
5✔
123
            $this->addToJson('cacheWarmupStatistics/duration', $measurement->duration);
1✔
124
            $this->addToJson('cacheWarmupStatistics/memoryUsage', $measurement->memoryUsage);
1✔
125
        }
126
    }
127

128
    public function logMessage(string $message, MessageSeverity $severity = MessageSeverity::Info): void
4✔
129
    {
130
        if (!is_array($this->json['messages'] ?? null)) {
4✔
131
            $this->json['messages'] = [];
4✔
132
        }
133

134
        if (!is_array($this->json['messages'][$severity->value] ?? null)) {
4✔
135
            $this->json['messages'][$severity->value] = [];
4✔
136
        }
137

138
        $this->json['messages'][$severity->value][] = $message;
4✔
139
    }
140

141
    public function isVerbose(): bool
×
142
    {
143
        return false;
×
144
    }
145

146
    /**
147
     * @phpstan-return JsonArray
148
     */
149
    public function getJson(): array
14✔
150
    {
151
        return $this->json;
14✔
152
    }
153

UNCOV
154
    public static function getType(): string
×
155
    {
UNCOV
156
        return 'json';
×
157
    }
158

159
    /**
160
     * @param string|float|int|bool|list<bool|float|int|resource|string|Stringable|null> $value
161
     */
162
    private function addToJson(string $path, string|float|int|bool|array $value): void
10✔
163
    {
164
        if (is_scalar($value) && '' !== $value) {
10✔
165
            Helper\ArrayHelper::setValueByPath($this->json, $path, $value);
3✔
166
        }
167
        if (is_array($value) && [] !== $value) {
10✔
168
            Helper\ArrayHelper::setValueByPath($this->json, $path, array_map(strval(...), $value));
5✔
169
        }
170
    }
171

172
    /**
173
     * @codeCoverageIgnore
174
     */
175
    public function __destruct()
176
    {
177
        // Early return if no JSON data was added
178
        if ([] === $this->json) {
179
            return;
180
        }
181

182
        // Early return if output is quiet
183
        if ($this->io->isQuiet()) {
184
            return;
185
        }
186

187
        $flags = JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR;
188

189
        // Pretty-print JSON on verbose output
190
        if ($this->io->isVerbose()) {
191
            $flags |= JSON_PRETTY_PRINT;
192
        }
193

194
        $this->io->writeln(json_encode($this->json, $flags));
195
    }
196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc