Skip to content

Commit 162c36a

Browse files
authored
Merge pull request #1021 from nextcloud/feat/add-setup-check-for-errors-in-log
Add a setupcheck for errors and warnings in log file
2 parents df9ce9f + ac41cde commit 162c36a

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

lib/AppInfo/Application.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
use OCA\LogReader\Listener\LogListener;
2727
use OCA\LogReader\Log\Formatter;
28+
use OCA\LogReader\SetupChecks\LogErrors;
2829
use OCP\AppFramework\App;
2930
use OCP\AppFramework\Bootstrap\IBootContext;
3031
use OCP\AppFramework\Bootstrap\IBootstrap;
@@ -42,6 +43,8 @@ public function register(IRegistrationContext $context): void {
4243
$context->registerService(Formatter::class, function (ContainerInterface $c) {
4344
return new Formatter(\OC::$SERVERROOT);
4445
});
46+
47+
$context->registerSetupCheck(LogErrors::class);
4548
}
4649

4750
public function boot(IBootContext $context): void {

lib/SetupChecks/LogErrors.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2023 Côme Chilliet <[email protected]>
7+
*
8+
* @author Côme Chilliet <[email protected]>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
namespace OCA\LogReader\SetupChecks;
27+
28+
use OCA\LogReader\Log\LogIteratorFactory;
29+
use OCP\IConfig;
30+
use OCP\IDateTimeFormatter;
31+
use OCP\IL10N;
32+
use OCP\SetupCheck\ISetupCheck;
33+
use OCP\SetupCheck\SetupResult;
34+
35+
class LogErrors implements ISetupCheck {
36+
private const LEVEL_WARNING = 2;
37+
private const LEVEL_ERROR = 3;
38+
private const LEVEL_FATAL = 4;
39+
40+
public function __construct(
41+
private IL10N $l10n,
42+
private IConfig $config,
43+
private IDateTimeFormatter $dateFormatter,
44+
private LogIteratorFactory $logIteratorFactory,
45+
) {
46+
}
47+
48+
public function getName(): string {
49+
return $this->l10n->t('Errors in the log');
50+
}
51+
52+
public function getCategory(): string {
53+
return 'system';
54+
}
55+
56+
public function run(): SetupResult {
57+
$logIterator = $this->logIteratorFactory->getLogIterator([self::LEVEL_WARNING,self::LEVEL_ERROR,self::LEVEL_FATAL]);
58+
$count = [
59+
self::LEVEL_WARNING => 0,
60+
self::LEVEL_ERROR => 0,
61+
self::LEVEL_FATAL => 0,
62+
];
63+
$limit = new \DateTime('7 days ago');
64+
foreach ($logIterator as $logItem) {
65+
if (!isset($logItem['time'])) {
66+
continue;
67+
}
68+
$time = \DateTime::createFromFormat(\DateTime::ATOM, $logItem['time']);
69+
if ($time < $limit) {
70+
break;
71+
}
72+
$count[$logItem['level']]++;
73+
}
74+
if (array_sum($count) === 0) {
75+
return SetupResult::success($this->l10n->t('No errors in the logs since %s', $this->dateFormatter->formatDate($limit)));
76+
} elseif ($count[self::LEVEL_ERROR] + $count[self::LEVEL_FATAL] > 0) {
77+
return SetupResult::error(
78+
$this->l10n->n(
79+
'%n error in the logs since %s',
80+
'%n errors in the logs since %s',
81+
$count[self::LEVEL_ERROR] + $count[self::LEVEL_FATAL],
82+
[$this->dateFormatter->formatDate($limit)],
83+
)
84+
);
85+
} else {
86+
return SetupResult::warning(
87+
$this->l10n->n(
88+
'%n warning in the logs since %s',
89+
'%n warnings in the logs since %s'.json_encode($count),
90+
$count[self::LEVEL_WARNING],
91+
[$this->dateFormatter->formatDate($limit)],
92+
)
93+
);
94+
}
95+
}
96+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2023 Côme Chilliet <[email protected]>
7+
*
8+
* @author Côme Chilliet <[email protected]>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
27+
namespace OCA\LogReader\Tests\Unit\SetupChecks;
28+
29+
use OCA\LogReader\Log\LogIteratorFactory;
30+
use OCA\LogReader\SetupChecks\LogErrors;
31+
use OCP\IConfig;
32+
use OCP\IDateTimeFormatter;
33+
use OCP\IL10N;
34+
use Test\TestCase;
35+
36+
class LogErrorsTest extends TestCase {
37+
private IL10N $l10n;
38+
private IConfig $config;
39+
private IDateTimeFormatter $dateFormatter;
40+
private LogIteratorFactory $logIteratorFactory;
41+
private LogErrors $logErrorsCheck;
42+
43+
protected function setUp(): void {
44+
parent::setUp();
45+
46+
$this->l10n = $this->createMock(IL10N::class);
47+
$this->config = $this->createMock(IConfig::class);
48+
$this->dateFormatter = $this->createMock(IDateTimeFormatter::class);
49+
$this->logIteratorFactory = $this->createMock(LogIteratorFactory::class);
50+
$this->logErrorsCheck = new LogErrors(
51+
$this->l10n,
52+
$this->config,
53+
$this->dateFormatter,
54+
$this->logIteratorFactory,
55+
);
56+
}
57+
58+
public function logProvider(): array {
59+
$now = (new \DateTime())->format(\DateTime::ATOM);
60+
$tooOld = (new \DateTime('1 month ago'))->format(\DateTime::ATOM);
61+
return [
62+
[[], 'success'],
63+
[[['level' => 2, 'time' => $now]], 'warning'],
64+
[[['level' => 3, 'time' => $now]], 'error'],
65+
[[['level' => 2, 'time' => $now],['level' => 3, 'time' => $now]], 'error'],
66+
[[['level' => 2, 'time' => $now],['level' => 3, 'time' => $tooOld]], 'warning'],
67+
[[['level' => 2, 'time' => $tooOld],['level' => 3, 'time' => $tooOld]], 'success'],
68+
];
69+
}
70+
71+
/**
72+
* @dataProvider logProvider
73+
*/
74+
public function testSetupCheck(array $logContent, string $severity): void {
75+
$logIterator = new \ArrayIterator($logContent);
76+
$this->logIteratorFactory
77+
->expects(self::once())
78+
->method('getLogIterator')
79+
->willReturn($logIterator);
80+
81+
$result = $this->logErrorsCheck->run();
82+
83+
$this->assertEquals($severity, $result->getSeverity());
84+
}
85+
}

0 commit comments

Comments
 (0)