diff --git a/.github/workflows/psalm-matrix.yml b/.github/workflows/psalm-matrix.yml
index 192fcc13..c3fa781d 100644
--- a/.github/workflows/psalm-matrix.yml
+++ b/.github/workflows/psalm-matrix.yml
@@ -24,7 +24,7 @@ jobs:
# do not stop on another job's failure
fail-fast: false
matrix:
- ocp-version: [ 'dev-master', 'dev-stable27', 'dev-stable26', 'dev-stable25']
+ ocp-version: [ 'dev-master' ]
name: Nextcloud ${{ matrix.ocp-version }}
steps:
diff --git a/appinfo/info.xml b/appinfo/info.xml
index a2e2e0af..f80b2869 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -12,6 +12,10 @@
LogReader
+
+
+
+
tools
https://github.com/nextcloud/logreader
https://github.com/nextcloud/logreader/issues
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 87a415d4..5f46c8c5 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -23,11 +23,13 @@
namespace OCA\LogReader\AppInfo;
+use OCA\LogReader\Listener\LogListener;
use OCA\LogReader\Log\Formatter;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\Log\BeforeMessageLoggedEvent;
use Psr\Container\ContainerInterface;
class Application extends App implements IBootstrap {
@@ -36,6 +38,7 @@ public function __construct(array $urlParams = []) {
}
public function register(IRegistrationContext $context): void {
+ $context->registerEventListener(BeforeMessageLoggedEvent::class, LogListener::class);
$context->registerService(Formatter::class, function (ContainerInterface $c) {
return new Formatter(\OC::$SERVERROOT);
});
diff --git a/lib/Listener/LogListener.php b/lib/Listener/LogListener.php
new file mode 100644
index 00000000..6017082b
--- /dev/null
+++ b/lib/Listener/LogListener.php
@@ -0,0 +1,61 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\LogReader\Listener;
+
+use OC\SystemConfig;
+use OCA\LogReader\Log\Console;
+use OCA\LogReader\Log\Formatter;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Log\BeforeMessageLoggedEvent;
+use Symfony\Component\Console\Terminal;
+
+class LogListener implements IEventListener {
+ private ?Console $console;
+
+ public function __construct(Formatter $formatter, SystemConfig $config) {
+ if (defined('OC_CONSOLE') && \OC_CONSOLE) {
+ $level = getenv('OCC_LOG');
+ if ($level) {
+ $terminal = new Terminal();
+ $this->console = new Console($formatter, $config, $level, $terminal->getWidth());
+ } else {
+ $this->console = null;
+ }
+ } else {
+ $this->console = null;
+ }
+ }
+
+
+ public function handle(Event $event): void {
+ if (!$event instanceof BeforeMessageLoggedEvent) {
+ return;
+ }
+
+ if ($this->console) {
+ $this->console->log($event->getLevel(), $event->getApp(), $event->getMessage());
+ }
+ }
+}
diff --git a/lib/Log/Console.php b/lib/Log/Console.php
new file mode 100644
index 00000000..7e6a544c
--- /dev/null
+++ b/lib/Log/Console.php
@@ -0,0 +1,87 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\LogReader\Log;
+
+use OC\Log\LogDetails;
+use OC\SystemConfig;
+use OCA\LogReader\Command\Tail;
+
+/**
+ * Utility to write log messages to the console as they are emitted
+ */
+class Console extends LogDetails {
+ private int $level;
+ private int $terminalWidth;
+ private Formatter $formatter;
+
+ public function __construct(Formatter $formatter, SystemConfig $config, string $level, int $terminalWidth) {
+ parent::__construct($config);
+ $this->formatter = $formatter;
+ $this->level = self::parseLogLevel($level);
+ $this->terminalWidth = $terminalWidth;
+ }
+
+ public function log(int $level, string $app, array $entry) {
+ if ($level >= $this->level) {
+ $messageWidth = $this->terminalWidth - 8 - 18 - 6;
+
+ $entry = $this->logDetails($app, $entry, $level);
+
+ $lines = explode("\n", $this->formatter->formatMessage($entry, $messageWidth));
+ $lines[0] = str_pad(Tail::LEVELS[$level], 8) . ' ' .
+ str_pad(wordwrap($app, 18), 18) . ' ' .
+ str_pad($lines[0], $messageWidth);
+
+ for ($i = 1; $i < count($lines); $i++) {
+ $lines[$i] = str_repeat(' ', 8 + 18 + 2) . $lines[$i];
+ }
+
+ foreach ($lines as $line) {
+ fwrite(STDERR, $line . "\n");
+ }
+ fwrite(STDERR, "\n");
+ }
+ }
+
+ private static function parseLogLevel(string $level): int {
+ if (is_numeric($level)) {
+ return (int)$level;
+ }
+
+ switch (strtoupper($level)) {
+ case "DEBUG":
+ return 0;
+ case "INFO":
+ return 1;
+ case "WARN":
+ return 2;
+ case "ERROR":
+ return 3;
+ case "FATAL":
+ return 4;
+ default:
+ throw new \Exception("Unknown log level $level");
+ }
+ }
+}
diff --git a/tests/stubs/stub.phpstub b/tests/stubs/stub.phpstub
index f57424fa..5a7d0120 100644
--- a/tests/stubs/stub.phpstub
+++ b/tests/stubs/stub.phpstub
@@ -32,3 +32,18 @@ namespace OC\Core\Command {
class InterruptedException extends \Exception {
}
}
+
+namespace OC {
+ class SystemConfig {
+ }
+}
+
+namespace OC\Log {
+ use OC\SystemConfig;
+ class LogDetails {
+ public function __construct(SystemConfig $config) {
+ }
+ public function logDetails(string $app, $message, int $level): array {
+ }
+ }
+}