]> git.mxchange.org Git - friendica.git/commitdiff
Restructure Logger to new paradigm
authorPhilipp <admin@philipp.info>
Sat, 23 Oct 2021 10:22:27 +0000 (12:22 +0200)
committerPhilipp <admin@philipp.info>
Thu, 28 Oct 2021 18:01:02 +0000 (20:01 +0200)
46 files changed:
src/Core/Logger.php
src/Core/Logger/Exception/LoggerArgumentException.php [new file with mode: 0644]
src/Core/Logger/Exception/LoggerException.php [new file with mode: 0644]
src/Core/Logger/Factory/Logger.php [new file with mode: 0644]
src/Core/Logger/Type/AbstractLogger.php [new file with mode: 0644]
src/Core/Logger/Type/Monolog/DevelopHandler.php [new file with mode: 0644]
src/Core/Logger/Type/Monolog/IntrospectionProcessor.php [new file with mode: 0644]
src/Core/Logger/Type/ProfilerLogger.php [new file with mode: 0644]
src/Core/Logger/Type/README.md [new file with mode: 0644]
src/Core/Logger/Type/StreamLogger.php [new file with mode: 0644]
src/Core/Logger/Type/SyslogLogger.php [new file with mode: 0644]
src/Core/Logger/Type/VoidLogger.php [new file with mode: 0644]
src/Core/Logger/Type/WorkerLogger.php [new file with mode: 0644]
src/DI.php
src/Factory/LoggerFactory.php [deleted file]
src/Util/FileSystem.php
src/Util/Logger/AbstractLogger.php [deleted file]
src/Util/Logger/Monolog/DevelopHandler.php [deleted file]
src/Util/Logger/Monolog/IntrospectionProcessor.php [deleted file]
src/Util/Logger/ProfilerLogger.php [deleted file]
src/Util/Logger/README.md [deleted file]
src/Util/Logger/StreamLogger.php [deleted file]
src/Util/Logger/SyslogLogger.php [deleted file]
src/Util/Logger/VoidLogger.php [deleted file]
src/Util/Logger/WorkerLogger.php [deleted file]
static/dependencies.config.php
tests/src/Console/AutomaticInstallationConsoleTest.php
tests/src/Contact/FriendSuggest/Factory/FriendSuggestTest.php
tests/src/Core/Logger/AbstractLoggerTest.php [new file with mode: 0644]
tests/src/Core/Logger/LoggerDataTrait.php [new file with mode: 0644]
tests/src/Core/Logger/ProfilerLoggerTest.php [new file with mode: 0644]
tests/src/Core/Logger/StreamLoggerTest.php [new file with mode: 0644]
tests/src/Core/Logger/SyslogLoggerTest.php [new file with mode: 0644]
tests/src/Core/Logger/SyslogLoggerWrapper.php [new file with mode: 0644]
tests/src/Core/Logger/VoidLoggerTest.php [new file with mode: 0644]
tests/src/Core/Logger/WorkerLoggerTest.php [new file with mode: 0644]
tests/src/Profile/ProfileField/Entity/ProfileFieldTest.php
tests/src/Security/TwoFactor/Factory/TrustedBrowserTest.php
tests/src/Util/Logger/AbstractLoggerTest.php [deleted file]
tests/src/Util/Logger/LoggerDataTrait.php [deleted file]
tests/src/Util/Logger/ProfilerLoggerTest.php [deleted file]
tests/src/Util/Logger/StreamLoggerTest.php [deleted file]
tests/src/Util/Logger/SyslogLoggerTest.php [deleted file]
tests/src/Util/Logger/SyslogLoggerWrapper.php [deleted file]
tests/src/Util/Logger/VoidLoggerTest.php [deleted file]
tests/src/Util/Logger/WorkerLoggerTest.php [deleted file]

index 6dde142cc953f3feae67ec1c39d1d882d009909d..4e2575d1b99cf667f36e8e6edb5c269f8f45029e 100644 (file)
@@ -22,7 +22,7 @@
 namespace Friendica\Core;
 
 use Friendica\DI;
-use Friendica\Util\Logger\WorkerLogger;
+use Friendica\Core\Logger\Type\WorkerLogger;
 use Psr\Log\LoggerInterface;
 use Psr\Log\LogLevel;
 
diff --git a/src/Core/Logger/Exception/LoggerArgumentException.php b/src/Core/Logger/Exception/LoggerArgumentException.php
new file mode 100644 (file)
index 0000000..1b5f653
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+namespace Friendica\Core\Logger\Exception;
+
+use Throwable;
+
+class LoggerArgumentException extends \InvalidArgumentException
+{
+       public function __construct($message = "", Throwable $previous = null)
+       {
+               parent::__construct($message, 500, $previous);
+       }
+}
diff --git a/src/Core/Logger/Exception/LoggerException.php b/src/Core/Logger/Exception/LoggerException.php
new file mode 100644 (file)
index 0000000..665dc21
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+namespace Friendica\Core\Logger\Exception;
+
+use Throwable;
+
+class LoggerException extends \Exception
+{
+       public function __construct($message = "", Throwable $previous = null)
+       {
+               parent::__construct($message, 500, $previous);
+       }
+}
diff --git a/src/Core/Logger/Factory/Logger.php b/src/Core/Logger/Factory/Logger.php
new file mode 100644 (file)
index 0000000..4ca4f05
--- /dev/null
@@ -0,0 +1,291 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Factory;
+
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Core;
+use Friendica\Database\Database;
+use Friendica\Util\FileSystem;
+use Friendica\Util\Introspection;
+use Friendica\Core\Logger\Type\Monolog\DevelopHandler;
+use Friendica\Core\Logger\Type\Monolog\IntrospectionProcessor;
+use Friendica\Core\Logger\Type\ProfilerLogger;
+use Friendica\Core\Logger\Type\StreamLogger;
+use Friendica\Core\Logger\Type\SyslogLogger;
+use Friendica\Core\Logger\Type\VoidLogger;
+use Friendica\Util\Profiler;
+use Monolog;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * A logger factory
+ */
+class Logger
+{
+       const DEV_CHANNEL = 'dev';
+
+       /**
+        * A list of classes, which shouldn't get logged
+        *
+        * @var string[]
+        */
+       private static $ignoreClassList = [
+               Core\Logger::class,
+               Profiler::class,
+               'Friendica\\Core\\Logger\\Type',
+               'Friendica\\Core\\Logger\\Type\\Monolog',
+       ];
+
+       /** @var string The log-channel (app, worker, ...) */
+       private $channel;
+
+       public function __construct(string $channel)
+       {
+               $this->channel = $channel;
+       }
+
+       /**
+        * Creates a new PSR-3 compliant logger instances
+        *
+        * @param Database            $database   The Friendica Database instance
+        * @param IManageConfigValues $config     The config
+        * @param Profiler            $profiler   The profiler of the app
+        * @param FileSystem          $fileSystem FileSystem utils
+        *
+        * @return LoggerInterface The PSR-3 compliant logger instance
+        */
+       public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem): LoggerInterface
+       {
+               if (empty($config->get('system', 'debugging', false))) {
+                       $logger = new VoidLogger();
+                       $database->setLogger($logger);
+                       return $logger;
+               }
+
+               $introspection = new Introspection(self::$ignoreClassList);
+               $level         = $config->get('system', 'loglevel');
+               $loglevel      = self::mapLegacyConfigDebugLevel((string)$level);
+
+               switch ($config->get('system', 'logger_config', 'stream')) {
+                       case 'monolog':
+                               $loggerTimeZone = new \DateTimeZone('UTC');
+                               Monolog\Logger::setTimezone($loggerTimeZone);
+
+                               $logger = new Monolog\Logger($this->channel);
+                               $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
+                               $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
+                               $logger->pushProcessor(new Monolog\Processor\UidProcessor());
+                               $logger->pushProcessor(new IntrospectionProcessor($introspection, LogLevel::DEBUG));
+
+                               $stream = $config->get('system', 'logfile');
+
+                               // just add a stream in case it's either writable or not file
+                               if (!is_file($stream) || is_writable($stream)) {
+                                       try {
+                                               static::addStreamHandler($logger, $stream, $loglevel);
+                                       } catch (\Throwable $e) {
+                                               // No Logger ..
+                                               /// @todo isn't it possible to give the admin any hint about this wrong configuration?
+                                               $logger = new VoidLogger();
+                                       }
+                               }
+                               break;
+
+                       case 'syslog':
+                               try {
+                                       $logger = new SyslogLogger($this->channel, $introspection, $loglevel);
+                               } catch (\Throwable $e) {
+                                       // No logger ...
+                                       /// @todo isn't it possible to give the admin any hint about this wrong configuration?
+                                       $logger = new VoidLogger();
+                               }
+                               break;
+
+                       case 'stream':
+                       default:
+                               $stream = $config->get('system', 'logfile');
+                               // just add a stream in case it's either writable or not file
+                               if (!is_file($stream) || is_writable($stream)) {
+                                       try {
+                                               $logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel);
+                                       } catch (\Throwable $t) {
+                                               // No logger ...
+                                               /// @todo isn't it possible to give the admin any hint about this wrong configuration?
+                                               $logger = new VoidLogger();
+                                       }
+                               } else {
+                                       /// @todo isn't it possible to give the admin any hint about this wrong configuration?
+                                       $logger = new VoidLogger();
+                               }
+                               break;
+               }
+
+               $profiling = $config->get('system', 'profiling', false);
+
+               // In case profiling is enabled, wrap the ProfilerLogger around the current logger
+               if (isset($profiling) && $profiling !== false) {
+                       $logger = new ProfilerLogger($logger, $profiler);
+               }
+
+               $database->setLogger($logger);
+               return $logger;
+       }
+
+       /**
+        * Creates a new PSR-3 compliant develop logger
+        *
+        * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
+        * you'll use this logger instance for the duration of your work.
+        *
+        * It should never get filled during normal usage of Friendica
+        *
+        * @param IManageConfigValues $config     The config
+        * @param Profiler            $profiler   The profiler of the app
+        * @param FileSystem          $fileSystem FileSystem utils
+        *
+        * @return LoggerInterface The PSR-3 compliant logger instance
+        * @throws \Exception
+        */
+       public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem)
+       {
+               $debugging   = $config->get('system', 'debugging');
+               $stream      = $config->get('system', 'dlogfile');
+               $developerIp = $config->get('system', 'dlogip');
+
+               if ((!isset($developerIp) || !$debugging) &&
+                       (!is_file($stream) || is_writable($stream))) {
+                       return new VoidLogger();
+               }
+
+               $loggerTimeZone = new \DateTimeZone('UTC');
+               Monolog\Logger::setTimezone($loggerTimeZone);
+
+               $introspection = new Introspection(self::$ignoreClassList);
+
+               switch ($config->get('system', 'logger_config', 'stream')) {
+
+                       case 'monolog':
+                               $loggerTimeZone = new \DateTimeZone('UTC');
+                               Monolog\Logger::setTimezone($loggerTimeZone);
+
+                               $logger = new Monolog\Logger(self::DEV_CHANNEL);
+                               $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
+                               $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
+                               $logger->pushProcessor(new Monolog\Processor\UidProcessor());
+                               $logger->pushProcessor(new IntrospectionProcessor($introspection, LogLevel::DEBUG));
+
+                               $logger->pushHandler(new DevelopHandler($developerIp));
+
+                               static::addStreamHandler($logger, $stream, LogLevel::DEBUG);
+                               break;
+
+                       case 'syslog':
+                               $logger = new SyslogLogger(self::DEV_CHANNEL, $introspection, LogLevel::DEBUG);
+                               break;
+
+                       case 'stream':
+                       default:
+                               $logger = new StreamLogger(self::DEV_CHANNEL, $stream, $introspection, $fileSystem, LogLevel::DEBUG);
+                               break;
+               }
+
+               $profiling = $config->get('system', 'profiling', false);
+
+               // In case profiling is enabled, wrap the ProfilerLogger around the current logger
+               if (isset($profiling) && $profiling !== false) {
+                       $logger = new ProfilerLogger($logger, $profiler);
+               }
+
+               return $logger;
+       }
+
+       /**
+        * Mapping a legacy level to the PSR-3 compliant levels
+        *
+        * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
+        *
+        * @param string $level the level to be mapped
+        *
+        * @return string the PSR-3 compliant level
+        */
+       private static function mapLegacyConfigDebugLevel(string $level): string
+       {
+               switch ($level) {
+                       // legacy WARNING
+                       case "0":
+                               return LogLevel::ERROR;
+                       // legacy INFO
+                       case "1":
+                               return LogLevel::WARNING;
+                       // legacy TRACE
+                       case "2":
+                               return LogLevel::NOTICE;
+                       // legacy DEBUG
+                       case "3":
+                               return LogLevel::INFO;
+                       // legacy DATA
+                       case "4":
+                       // legacy ALL
+                       case "5":
+                               return LogLevel::DEBUG;
+                       // default if nothing set
+                       default:
+                               return $level;
+               }
+       }
+
+       /**
+        * Adding a handler to a given logger instance
+        *
+        * @param LoggerInterface $logger The logger instance
+        * @param mixed           $stream The stream which handles the logger output
+        * @param string          $level  The level, for which this handler at least should handle logging
+        *
+        * @return void
+        *
+        * @throws LoggerException
+        */
+       public static function addStreamHandler(LoggerInterface $logger, $stream, string $level = LogLevel::NOTICE)
+       {
+               if ($logger instanceof Monolog\Logger) {
+                       $loglevel = Monolog\Logger::toMonologLevel($level);
+
+                       // fallback to notice if an invalid loglevel is set
+                       if (!is_int($loglevel)) {
+                               $loglevel = LogLevel::NOTICE;
+                       }
+
+                       try {
+                               $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
+
+                               $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
+                               $fileHandler->setFormatter($formatter);
+
+                               $logger->pushHandler($fileHandler);
+                       } catch (\Exception $exception) {
+                               throw new LoggerException('Cannot create Monolog Logger.', $exception);
+                       }
+               }
+       }
+}
diff --git a/src/Core/Logger/Type/AbstractLogger.php b/src/Core/Logger/Type/AbstractLogger.php
new file mode 100644 (file)
index 0000000..0b6d9f3
--- /dev/null
@@ -0,0 +1,206 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Util\Introspection;
+use Friendica\Util\Strings;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * This class contains all necessary dependencies and calls for Friendica
+ * Every new Logger should extend this class and define, how addEntry() works
+ *
+ * Additional information for each Logger, who extends this class:
+ * - Introspection
+ * - UID for each call
+ * - Channel of the current call (i.e. index, worker, daemon, ...)
+ */
+abstract class AbstractLogger implements LoggerInterface
+{
+       /**
+        * The output channel of this logger
+        * @var string
+        */
+       protected $channel;
+
+       /**
+        * The Introspection for the current call
+        * @var Introspection
+        */
+       protected $introspection;
+
+       /**
+        * The UID of the current call
+        * @var string
+        */
+       protected $logUid;
+
+       /**
+        * Adds a new entry to the log
+        *
+        * @param mixed  $level
+        * @param string $message
+        * @param array  $context
+        *
+        * @return void
+        */
+       abstract protected function addEntry($level, string $message, array $context = []);
+
+       /**
+        * @param string        $channel       The output channel
+        * @param Introspection $introspection The introspection of the current call
+        *
+        * @throws LoggerException
+        */
+       public function __construct(string $channel, Introspection $introspection)
+       {
+               $this->channel       = $channel;
+               $this->introspection = $introspection;
+
+               try {
+                       $this->logUid = Strings::getRandomHex(6);
+               } catch (\Exception $exception) {
+                       throw new LoggerException('Cannot generate log Id', $exception);
+               }
+       }
+
+       /**
+        * Simple interpolation of PSR-3 compliant replacements ( variables between '{' and '}' )
+        *
+        * @see https://www.php-fig.org/psr/psr-3/#12-message
+        *
+        * @param string $message
+        * @param array  $context
+        *
+        * @return string the interpolated message
+        */
+       protected function psrInterpolate(string $message, array $context = []): string
+       {
+               $replace = [];
+               foreach ($context as $key => $value) {
+                       // check that the value can be casted to string
+                       if (!is_array($value) && (!is_object($value) || method_exists($value, '__toString'))) {
+                               $replace['{' . $key . '}'] = $value;
+                       } elseif (is_array($value)) {
+                               $replace['{' . $key . '}'] = @json_encode($value);
+                       }
+               }
+
+               return strtr($message, $replace);
+       }
+
+       /**
+        * JSON Encodes a complete array including objects with "__toString()" methods
+        *
+        * @param array $input an Input Array to encode
+        *
+        * @return false|string The json encoded output of the array
+        */
+       protected function jsonEncodeArray(array $input)
+       {
+               $output = [];
+
+               foreach ($input as $key => $value) {
+                       if (is_object($value) && method_exists($value, '__toString')) {
+                               $output[$key] = $value->__toString();
+                       } else {
+                               $output[$key] = $value;
+                       }
+               }
+
+               return @json_encode($output);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function emergency($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::EMERGENCY, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function alert($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::ALERT, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function critical($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::CRITICAL, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function error($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::ERROR, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function warning($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::WARNING, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function notice($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::NOTICE, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function info($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::INFO, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function debug($message, array $context = [])
+       {
+               $this->addEntry(LogLevel::DEBUG, (string) $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function log($level, $message, array $context = [])
+       {
+               $this->addEntry($level, (string) $message, $context);
+       }
+}
diff --git a/src/Core/Logger/Type/Monolog/DevelopHandler.php b/src/Core/Logger/Type/Monolog/DevelopHandler.php
new file mode 100644 (file)
index 0000000..5d2a844
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type\Monolog;
+
+use Monolog\Handler;
+use Monolog\Logger;
+
+/**
+ * Simple handler for Friendica developers to use for deeper logging
+ *
+ * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
+ * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
+ */
+class DevelopHandler extends Handler\AbstractHandler
+{
+       /**
+        * @var string The IP of the developer who wants to debug
+        */
+       private $developerIp;
+
+       /**
+        * @param string $developerIp  The IP of the developer who wants to debug
+        * @param int    $level        The minimum logging level at which this handler will be triggered
+        * @param bool   $bubble       Whether the messages that are handled can bubble up the stack or not
+        */
+       public function __construct($developerIp, $level = Logger::DEBUG, bool $bubble = true)
+       {
+               parent::__construct($level, $bubble);
+
+               $this->developerIp = $developerIp;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function handle(array $record): bool
+       {
+               if (!$this->isHandling($record)) {
+                       return false;
+               }
+
+               /// Just in case the remote IP is the same as the developer IP log the output
+               if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp) {
+                       return false;
+               }
+
+               return false === $this->bubble;
+       }
+}
diff --git a/src/Core/Logger/Type/Monolog/IntrospectionProcessor.php b/src/Core/Logger/Type/Monolog/IntrospectionProcessor.php
new file mode 100644 (file)
index 0000000..756331b
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type\Monolog;
+
+use Friendica\Util\Introspection;
+use Monolog\Logger;
+use Monolog\Processor\ProcessorInterface;
+
+/**
+ * Injects line/file//function where the log message came from
+ */
+class IntrospectionProcessor implements ProcessorInterface
+{
+       private $level;
+
+       private $introspection;
+
+       /**
+        * @param Introspection $introspection Holds the Introspection of the current call
+        * @param string|int    $level         The minimum logging level at which this Processor will be triggered
+        */
+       public function __construct(Introspection $introspection, $level = Logger::DEBUG)
+       {
+               $this->level = Logger::toMonologLevel($level);
+               $introspection->addClasses(['Monolog\\']);
+               $this->introspection = $introspection;
+       }
+
+       public function __invoke(array $record): array
+       {
+               // return if the level is not high enough
+               if ($record['level'] < $this->level) {
+                       return $record;
+               }
+               // we should have the call source now
+               $record['extra'] = array_merge(
+                       $record['extra'],
+                       $this->introspection->getRecord()
+               );
+
+               return $record;
+       }
+}
diff --git a/src/Core/Logger/Type/ProfilerLogger.php b/src/Core/Logger/Type/ProfilerLogger.php
new file mode 100644 (file)
index 0000000..2333dd5
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * This Logger adds additional profiling data in case profiling is enabled.
+ * It uses a predefined logger.
+ */
+class ProfilerLogger implements LoggerInterface
+{
+       /**
+        * The Logger of the current call
+        * @var LoggerInterface
+        */
+       private $logger;
+
+       /**
+        * The Profiler for the current call
+        * @var Profiler
+        */
+       protected $profiler;
+
+       /**
+        * ProfilerLogger constructor.
+        * @param LoggerInterface $logger   The Logger of the current call
+        * @param Profiler        $profiler The profiler of the current call
+        */
+       public function __construct(LoggerInterface $logger, Profiler $profiler)
+       {
+               $this->logger   = $logger;
+               $this->profiler = $profiler;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function emergency($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->emergency($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function alert($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->alert($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function critical($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->critical($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function error($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->error($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function warning($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->warning($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function notice($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->notice($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function info($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->info($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function debug($message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->debug($message, $context);
+               $this->profiler->stopRecording();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function log($level, $message, array $context = [])
+       {
+               $this->profiler->startRecording('file');
+               $this->logger->log($level, $message, $context);
+               $this->profiler->stopRecording();
+       }
+}
diff --git a/src/Core/Logger/Type/README.md b/src/Core/Logger/Type/README.md
new file mode 100644 (file)
index 0000000..4494031
--- /dev/null
@@ -0,0 +1,27 @@
+## Friendica\Util\Logger
+
+This namespace contains the different implementations of a Logger.
+
+### Configuration guideline
+
+The following settings are possible for `logger_config`:
+-      `monolog`: A Logging framework with lots of additions (see [Monolog](https://github.com/Seldaek/monolog/)). There are just Friendica additions inside the Monolog directory
+-      [`stream`](StreamLogger.php): A small logger for files or streams
+-      [`syslog`](SyslogLogger.php): Prints the logging output into the syslog
+
+[`VoidLogger`](VoidLogger.php) is a fallback logger without any function if no debugging is enabled.
+
+[`ProfilerLogger`](ProfilerLogger.php) is a wrapper around an existing logger in case profiling is enabled for Friendica.
+Every log call will be saved to the `Profiler` with a timestamp.
+
+### Implementation guideline
+
+Each logging implementation should pe capable of printing at least the following information:
+-      An unique ID for each Request/Call
+-      The process ID (PID)
+-      A timestamp of the logging entry
+-      The critically of the log entry
+-      A log message
+-      A context of the log message (f.e which user)
+
+If possible, a Logger should extend [`AbstractLogger`](AbstractLogger.php), because it contains additional, Friendica specific business logic for each logging call.
diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php
new file mode 100644 (file)
index 0000000..be0283d
--- /dev/null
@@ -0,0 +1,203 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Friendica\Core\Logger\Exception\LoggerArgumentException;
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Util\DateTimeFormat;
+use Friendica\Util\FileSystem;
+use Friendica\Util\Introspection;
+use Psr\Log\LogLevel;
+
+/**
+ * A Logger instance for logging into a stream (file, stdout, stderr)
+ */
+class StreamLogger extends AbstractLogger
+{
+       /**
+        * The minimum loglevel at which this logger will be triggered
+        * @var string
+        */
+       private $logLevel;
+
+       /**
+        * The file URL of the stream (if needed)
+        * @var string
+        */
+       private $url;
+
+       /**
+        * The stream, where the current logger is writing into
+        * @var resource
+        */
+       private $stream;
+
+       /**
+        * The current process ID
+        * @var int
+        */
+       private $pid;
+
+       /**
+        * @var FileSystem
+        */
+       private $fileSystem;
+
+       /**
+        * Translates LogLevel log levels to integer values
+        * @var array
+        */
+       private $levelToInt = [
+               LogLevel::EMERGENCY => 0,
+               LogLevel::ALERT     => 1,
+               LogLevel::CRITICAL  => 2,
+               LogLevel::ERROR     => 3,
+               LogLevel::WARNING   => 4,
+               LogLevel::NOTICE    => 5,
+               LogLevel::INFO      => 6,
+               LogLevel::DEBUG     => 7,
+       ];
+
+       /**
+        * {@inheritdoc}
+        * @param string|resource $stream The stream to write with this logger (either a file or a stream, i.e. stdout)
+        * @param string          $level  The minimum loglevel at which this logger will be triggered
+        *
+        * @throws LoggerArgumentException
+        */
+       public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG)
+       {
+               $this->fileSystem = $fileSystem;
+
+               parent::__construct($channel, $introspection);
+
+               if (is_resource($stream)) {
+                       $this->stream = $stream;
+               } elseif (is_string($stream)) {
+                       $this->url = $stream;
+               } else {
+                       throw new LoggerArgumentException('A stream must either be a resource or a string.');
+               }
+
+               $this->pid = getmypid();
+               if (array_key_exists($level, $this->levelToInt)) {
+                       $this->logLevel = $this->levelToInt[$level];
+               } else {
+                       throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
+               }
+
+               $this->checkStream();
+       }
+
+       public function close()
+       {
+               if ($this->url && is_resource($this->stream)) {
+                       fclose($this->stream);
+               }
+
+               $this->stream = null;
+       }
+
+       /**
+        * Adds a new entry to the log
+        *
+        * @param mixed  $level
+        * @param string $message
+        * @param array  $context
+        *
+        * @return void
+        *
+        * @throws LoggerException
+        * @throws LoggerArgumentException
+        */
+       protected function addEntry($level, string $message, array $context = [])
+       {
+               if (!array_key_exists($level, $this->levelToInt)) {
+                       throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
+               }
+
+               $logLevel = $this->levelToInt[$level];
+
+               if ($logLevel > $this->logLevel) {
+                       return;
+               }
+
+               $this->checkStream();
+
+               $formattedLog = $this->formatLog($level, $message, $context);
+               fwrite($this->stream, $formattedLog);
+       }
+
+       /**
+        * Formats a log record for the syslog output
+        *
+        * @param mixed  $level   The loglevel/priority
+        * @param string $message The message
+        * @param array  $context The context of this call
+        *
+        * @return string the formatted syslog output
+        *
+        * @throws LoggerException
+        */
+       private function formatLog($level, string $message, array $context = []): string
+       {
+               $record = $this->introspection->getRecord();
+               $record = array_merge($record, ['uid' => $this->logUid, 'process_id' => $this->pid]);
+
+               try {
+                       $logMessage = DateTimeFormat::utcNow(DateTimeFormat::ATOM) . ' ';
+               } catch (\Exception $exception) {
+                       throw new LoggerException('Cannot get current datetime.', $exception);
+               }
+               $logMessage .= $this->channel . ' ';
+               $logMessage .= '[' . strtoupper($level) . ']: ';
+               $logMessage .= $this->psrInterpolate($message, $context) . ' ';
+               $logMessage .= $this->jsonEncodeArray($context) . ' - ';
+               $logMessage .= $this->jsonEncodeArray($record);
+               $logMessage .= PHP_EOL;
+
+               return $logMessage;
+       }
+
+       /**
+        * Checks the current stream
+        *
+        * @throws LoggerException
+        * @throws LoggerArgumentException
+        */
+       private function checkStream()
+       {
+               if (is_resource($this->stream)) {
+                       return;
+               }
+
+               if (empty($this->url)) {
+                       throw new LoggerArgumentException('Missing stream URL.');
+               }
+
+               try {
+                       $this->stream = $this->fileSystem->createStream($this->url);
+               } catch (\UnexpectedValueException $exception) {
+                       throw new LoggerException('Cannot create stream.', $exception);
+               }
+       }
+}
diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php
new file mode 100644 (file)
index 0000000..667b44c
--- /dev/null
@@ -0,0 +1,230 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Friendica\Core\Logger\Exception\LoggerArgumentException;
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Util\Introspection;
+use Psr\Log\InvalidArgumentException;
+use Psr\Log\LogLevel;
+
+/**
+ * A Logger instance for syslogging (fast, but simple)
+ * @see http://php.net/manual/en/function.syslog.php
+ */
+class SyslogLogger extends AbstractLogger
+{
+       const IDENT = 'Friendica';
+
+       /**
+        * Translates LogLevel log levels to syslog log priorities.
+        * @var array
+        */
+       private $logLevels = [
+               LogLevel::DEBUG     => LOG_DEBUG,
+               LogLevel::INFO      => LOG_INFO,
+               LogLevel::NOTICE    => LOG_NOTICE,
+               LogLevel::WARNING   => LOG_WARNING,
+               LogLevel::ERROR     => LOG_ERR,
+               LogLevel::CRITICAL  => LOG_CRIT,
+               LogLevel::ALERT     => LOG_ALERT,
+               LogLevel::EMERGENCY => LOG_EMERG,
+       ];
+
+       /**
+        * Translates log priorities to string outputs
+        * @var array
+        */
+       private $logToString = [
+               LOG_DEBUG   => 'DEBUG',
+               LOG_INFO    => 'INFO',
+               LOG_NOTICE  => 'NOTICE',
+               LOG_WARNING => 'WARNING',
+               LOG_ERR     => 'ERROR',
+               LOG_CRIT    => 'CRITICAL',
+               LOG_ALERT   => 'ALERT',
+               LOG_EMERG   => 'EMERGENCY'
+       ];
+
+       /**
+        * Indicates what logging options will be used when generating a log message
+        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
+        *
+        * @var int
+        */
+       private $logOpts;
+
+       /**
+        * Used to specify what type of program is logging the message
+        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
+        *
+        * @var int
+        */
+       private $logFacility;
+
+       /**
+        * The minimum loglevel at which this logger will be triggered
+        * @var int
+        */
+       private $logLevel;
+
+       /**
+        * A error message of the current operation
+        * @var string
+        */
+       private $errorMessage;
+
+       /**
+        * {@inheritdoc}
+        * @param string $level       The minimum loglevel at which this logger will be triggered
+        * @param int    $logOpts     Indicates what logging options will be used when generating a log message
+        * @param int    $logFacility Used to specify what type of program is logging the message
+        *
+        * @throws LoggerArgumentException
+        */
+       public function __construct($channel, Introspection $introspection, string $level = LogLevel::NOTICE, int $logOpts = LOG_PID, int $logFacility = LOG_USER)
+       {
+               parent::__construct($channel, $introspection);
+               $this->logOpts     = $logOpts;
+               $this->logFacility = $logFacility;
+               $this->logLevel    = $this->mapLevelToPriority($level);
+               $this->introspection->addClasses([self::class]);
+       }
+
+       /**
+        * Adds a new entry to the syslog
+        *
+        * @param mixed  $level
+        * @param string $message
+        * @param array  $context
+        *
+        * @throws LoggerArgumentException in case the level isn't valid
+        * @throws LoggerException In case the syslog cannot be opened for writing
+        */
+       protected function addEntry($level, string $message, array $context = [])
+       {
+               $logLevel = $this->mapLevelToPriority($level);
+
+               if ($logLevel > $this->logLevel) {
+                       return;
+               }
+
+               $formattedLog = $this->formatLog($logLevel, $message, $context);
+               $this->write($logLevel, $formattedLog);
+       }
+
+       /**
+        * Maps the LogLevel (@see LogLevel) to a SysLog priority (@see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters)
+        *
+        * @param string $level A LogLevel
+        *
+        * @return int The SysLog priority
+        *
+        * @throws LoggerArgumentException If the loglevel isn't valid
+        */
+       public function mapLevelToPriority(string $level): int
+       {
+               if (!array_key_exists($level, $this->logLevels)) {
+                       throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
+               }
+
+               return $this->logLevels[$level];
+       }
+
+       /**
+        * Closes the Syslog
+        */
+       public function close()
+       {
+               closelog();
+       }
+
+       /**
+        * Writes a message to the syslog
+        *
+        * @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters
+        *
+        * @param int    $priority The Priority
+        * @param string $message  The message of the log
+        *
+        * @throws LoggerException In case the syslog cannot be opened/written
+        */
+       private function write(int $priority, string $message)
+       {
+               set_error_handler([$this, 'customErrorHandler']);
+               $opened = openlog(self::IDENT, $this->logOpts, $this->logFacility);
+               restore_error_handler();
+
+               if (!$opened) {
+                       throw new LoggerException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
+               }
+
+               $this->syslogWrapper($priority, $message);
+       }
+
+       /**
+        * Formats a log record for the syslog output
+        *
+        * @param int    $level   The loglevel/priority
+        * @param string $message The message
+        * @param array  $context The context of this call
+        *
+        * @return string the formatted syslog output
+        */
+       private function formatLog(int $level, string $message, array $context = []): string
+       {
+               $record = $this->introspection->getRecord();
+               $record = array_merge($record, ['uid' => $this->logUid]);
+
+               $logMessage = $this->channel . ' ';
+               $logMessage .= '[' . $this->logToString[$level] . ']: ';
+               $logMessage .= $this->psrInterpolate($message, $context) . ' ';
+               $logMessage .= $this->jsonEncodeArray($context) . ' - ';
+               $logMessage .= $this->jsonEncodeArray($record);
+
+               return $logMessage;
+       }
+
+       private function customErrorHandler($code, $msg)
+       {
+               $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
+       }
+
+       /**
+        * A syslog wrapper to make syslog functionality testable
+        *
+        * @param int    $level The syslog priority
+        * @param string $entry The message to send to the syslog function
+        *
+        * @throws LoggerException
+        */
+       protected function syslogWrapper(int $level, string $entry)
+       {
+               set_error_handler([$this, 'customErrorHandler']);
+               $written = syslog($level, $entry);
+               restore_error_handler();
+
+               if (!$written) {
+                       throw new LoggerException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
+               }
+       }
+}
diff --git a/src/Core/Logger/Type/VoidLogger.php b/src/Core/Logger/Type/VoidLogger.php
new file mode 100644 (file)
index 0000000..5cd2cac
--- /dev/null
@@ -0,0 +1,159 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Psr\Log\LoggerInterface;
+
+/**
+ * A Logger instance to not log
+ */
+class VoidLogger implements LoggerInterface
+{
+       /**
+        * System is unusable.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function emergency($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Action must be taken immediately.
+        *
+        * Example: Entire website down, database unavailable, etc. This should
+        * trigger the SMS alerts and wake you up.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function alert($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Critical conditions.
+        *
+        * Example: Application component unavailable, unexpected exception.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function critical($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Runtime errors that do not require immediate action but should typically
+        * be logged and monitored.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function error($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Exceptional occurrences that are not errors.
+        *
+        * Example: Use of deprecated APIs, poor use of an API, undesirable things
+        * that are not necessarily wrong.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function warning($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Normal but significant events.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function notice($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Interesting events.
+        *
+        * Example: User logs in, SQL logs.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function info($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Detailed debug information.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function debug($message, array $context = array())
+       {
+               return;
+       }
+
+       /**
+        * Logs with an arbitrary level.
+        *
+        * @param mixed $level
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function log($level, $message, array $context = array())
+       {
+               return;
+       }
+}
diff --git a/src/Core/Logger/Type/WorkerLogger.php b/src/Core/Logger/Type/WorkerLogger.php
new file mode 100644 (file)
index 0000000..fcbe128
--- /dev/null
@@ -0,0 +1,235 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Type;
+
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Util\Strings;
+use Psr\Log\LoggerInterface;
+
+/**
+ * A Logger for specific worker tasks, which adds a worker id to it.
+ * Uses the decorator pattern (https://en.wikipedia.org/wiki/Decorator_pattern)
+ */
+class WorkerLogger implements LoggerInterface
+{
+       /**
+        * @var LoggerInterface The original Logger instance
+        */
+       private $logger;
+
+       /**
+        * @var string the current worker ID
+        */
+       private $workerId;
+
+       /**
+        * @var string The called function name
+        */
+       private $functionName;
+
+       /**
+        * @param LoggerInterface $logger       The logger for worker entries
+        * @param string          $functionName The current function name of the worker
+        * @param int             $idLength     The length of the generated worker ID
+        *
+        * @throws LoggerException
+        */
+       public function __construct(LoggerInterface $logger, string $functionName = '', int $idLength = 7)
+       {
+               $this->logger       = $logger;
+               $this->functionName = $functionName;
+               try {
+                       $this->workerId = Strings::getRandomHex($idLength);
+               } catch (\Exception $exception) {
+                       throw new LoggerException('Cannot generate random Hex.', $exception);
+               }
+       }
+
+       /**
+        * Sets the function name for additional logging
+        *
+        * @param string $functionName
+        */
+       public function setFunctionName(string $functionName)
+       {
+               $this->functionName = $functionName;
+       }
+
+       /**
+        * Adds the worker context for each log entry
+        *
+        * @param array $context
+        */
+       private function addContext(array &$context)
+       {
+               $context['worker_id']  = $this->workerId;
+               $context['worker_cmd'] = $this->functionName;
+       }
+
+       /**
+        * Returns the worker ID
+        *
+        * @return string
+        */
+       public function getWorkerId(): string
+       {
+               return $this->workerId;
+       }
+
+       /**
+        * System is unusable.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function emergency($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->emergency($message, $context);
+       }
+
+       /**
+        * Action must be taken immediately.
+        *
+        * Example: Entire website down, database unavailable, etc. This should
+        * trigger the SMS alerts and wake you up.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function alert($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->alert($message, $context);
+       }
+
+       /**
+        * Critical conditions.
+        *
+        * Example: Application component unavailable, unexpected exception.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function critical($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->critical($message, $context);
+       }
+
+       /**
+        * Runtime errors that do not require immediate action but should typically
+        * be logged and monitored.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function error($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->error($message, $context);
+       }
+
+       /**
+        * Exceptional occurrences that are not errors.
+        *
+        * Example: Use of deprecated APIs, poor use of an API, undesirable things
+        * that are not necessarily wrong.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function warning($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->warning($message, $context);
+       }
+
+       /**
+        * Normal but significant events.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function notice($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->notice($message, $context);
+       }
+
+       /**
+        * Interesting events.
+        *
+        * Example: User logs in, SQL logs.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function info($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->info($message, $context);
+       }
+
+       /**
+        * Detailed debug information.
+        *
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function debug($message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->debug($message, $context);
+       }
+
+       /**
+        * Logs with an arbitrary level.
+        *
+        * @param mixed $level
+        * @param string $message
+        * @param array $context
+        *
+        * @return void
+        */
+       public function log($level, $message, array $context = [])
+       {
+               $this->addContext($context);
+               $this->logger->log($level, $message, $context);
+       }
+}
index 5ba7e88db1f00379891b1e97d33d7352a81cbd01..8ee7004408aecb828941f9db927aba1715678ac4 100644 (file)
@@ -243,7 +243,7 @@ abstract class DI
         */
        public static function workerLogger()
        {
-               return self::$dice->create(Util\Logger\WorkerLogger::class);
+               return self::$dice->create(Core\Logger\Type\WorkerLogger::class);
        }
 
        //
diff --git a/src/Factory/LoggerFactory.php b/src/Factory/LoggerFactory.php
deleted file mode 100644 (file)
index d01b477..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Factory;
-
-use Friendica\Core\Config\Capability\IManageConfigValues;
-use Friendica\Core\Logger;
-use Friendica\Database\Database;
-use Friendica\Network\HTTPException\InternalServerErrorException;
-use Friendica\Util\FileSystem;
-use Friendica\Util\Introspection;
-use Friendica\Util\Logger\Monolog\DevelopHandler;
-use Friendica\Util\Logger\Monolog\IntrospectionProcessor;
-use Friendica\Util\Logger\ProfilerLogger;
-use Friendica\Util\Logger\StreamLogger;
-use Friendica\Util\Logger\SyslogLogger;
-use Friendica\Util\Logger\VoidLogger;
-use Friendica\Util\Profiler;
-use Monolog;
-use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
-
-/**
- * A logger factory
- *
- * Currently only Monolog is supported
- */
-class LoggerFactory
-{
-       const DEV_CHANNEL = 'dev';
-
-       /**
-        * A list of classes, which shouldn't get logged
-        *
-        * @var array
-        */
-       private static $ignoreClassList = [
-               Logger::class,
-               Profiler::class,
-               'Friendica\\Util\\Logger',
-       ];
-
-       private $channel;
-
-       public function __construct(string $channel)
-       {
-               $this->channel = $channel;
-       }
-
-       /**
-        * Creates a new PSR-3 compliant logger instances
-        *
-        * @param Database            $database   The Friendica Database instance
-        * @param IManageConfigValues $config     The config
-        * @param Profiler            $profiler   The profiler of the app
-        * @param FileSystem          $fileSystem FileSystem utils
-        *
-        * @return LoggerInterface The PSR-3 compliant logger instance
-        */
-       public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem)
-       {
-               if (empty($config->get('system', 'debugging', false))) {
-                       $logger = new VoidLogger();
-                       $database->setLogger($logger);
-                       return $logger;
-               }
-
-               $introspection = new Introspection(self::$ignoreClassList);
-               $level         = $config->get('system', 'loglevel');
-               $loglevel      = self::mapLegacyConfigDebugLevel((string)$level);
-
-               switch ($config->get('system', 'logger_config', 'stream')) {
-                       case 'monolog':
-                               $loggerTimeZone = new \DateTimeZone('UTC');
-                               Monolog\Logger::setTimezone($loggerTimeZone);
-
-                               $logger = new Monolog\Logger($this->channel);
-                               $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
-                               $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
-                               $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-                               $logger->pushProcessor(new IntrospectionProcessor($introspection, LogLevel::DEBUG));
-
-                               $stream = $config->get('system', 'logfile');
-
-                               // just add a stream in case it's either writable or not file
-                               if (!is_file($stream) || is_writable($stream)) {
-                                       try {
-                                               static::addStreamHandler($logger, $stream, $loglevel);
-                                       } catch (\Throwable $e) {
-                                               // No Logger ..
-                                               $logger = new VoidLogger();
-                                       }
-                               }
-                               break;
-
-                       case 'syslog':
-                               try {
-                                       $logger = new SyslogLogger($this->channel, $introspection, $loglevel);
-                               } catch (\Throwable $e) {
-                                       // No logger ...
-                                       $logger = new VoidLogger();
-                               }
-                               break;
-
-                       case 'stream':
-                       default:
-                               $stream = $config->get('system', 'logfile');
-                               // just add a stream in case it's either writable or not file
-                               if (!is_file($stream) || is_writable($stream)) {
-                                       try {
-                                               $logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel);
-                                       } catch (\Throwable $t) {
-                                               // No logger ...
-                                               $logger = new VoidLogger();
-                                       }
-                               } else {
-                                       $logger = new VoidLogger();
-                               }
-                               break;
-               }
-
-               $profiling = $config->get('system', 'profiling', false);
-
-               // In case profiling is enabled, wrap the ProfilerLogger around the current logger
-               if (isset($profiling) && $profiling !== false) {
-                       $logger = new ProfilerLogger($logger, $profiler);
-               }
-
-               $database->setLogger($logger);
-               return $logger;
-       }
-
-       /**
-        * Creates a new PSR-3 compliant develop logger
-        *
-        * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
-        * you'll use this logger instance for the duration of your work.
-        *
-        * It should never get filled during normal usage of Friendica
-        *
-        * @param IManageConfigValues $config     The config
-        * @param Profiler            $profiler   The profiler of the app
-        * @param FileSystem          $fileSystem FileSystem utils
-        *
-        * @return LoggerInterface The PSR-3 compliant logger instance
-        *
-        * @throws InternalServerErrorException
-        * @throws \Exception
-        */
-       public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem)
-       {
-               $debugging   = $config->get('system', 'debugging');
-               $stream      = $config->get('system', 'dlogfile');
-               $developerIp = $config->get('system', 'dlogip');
-
-               if ((!isset($developerIp) || !$debugging) &&
-                   (!is_file($stream) || is_writable($stream))) {
-                       $logger = new VoidLogger();
-                       return $logger;
-               }
-
-               $loggerTimeZone = new \DateTimeZone('UTC');
-               Monolog\Logger::setTimezone($loggerTimeZone);
-
-               $introspection = new Introspection(self::$ignoreClassList);
-
-               switch ($config->get('system', 'logger_config', 'stream')) {
-
-                       case 'monolog':
-                               $loggerTimeZone = new \DateTimeZone('UTC');
-                               Monolog\Logger::setTimezone($loggerTimeZone);
-
-                               $logger = new Monolog\Logger(self::DEV_CHANNEL);
-                               $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
-                               $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
-                               $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-                               $logger->pushProcessor(new IntrospectionProcessor($introspection, LogLevel::DEBUG));
-
-                               $logger->pushHandler(new DevelopHandler($developerIp));
-
-                               static::addStreamHandler($logger, $stream, LogLevel::DEBUG);
-                               break;
-
-                       case 'syslog':
-                               $logger = new SyslogLogger(self::DEV_CHANNEL, $introspection, LogLevel::DEBUG);
-                               break;
-
-                       case 'stream':
-                       default:
-                               $logger = new StreamLogger(self::DEV_CHANNEL, $stream, $introspection, $fileSystem, LogLevel::DEBUG);
-                               break;
-               }
-
-               $profiling = $config->get('system', 'profiling', false);
-
-               // In case profiling is enabled, wrap the ProfilerLogger around the current logger
-               if (isset($profiling) && $profiling !== false) {
-                       $logger = new ProfilerLogger($logger, $profiler);
-               }
-
-               return $logger;
-       }
-
-       /**
-        * Mapping a legacy level to the PSR-3 compliant levels
-        *
-        * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
-        *
-        * @param string $level the level to be mapped
-        *
-        * @return string the PSR-3 compliant level
-        */
-       private static function mapLegacyConfigDebugLevel($level)
-       {
-               switch ($level) {
-                       // legacy WARNING
-                       case "0":
-                               return LogLevel::ERROR;
-                       // legacy INFO
-                       case "1":
-                               return LogLevel::WARNING;
-                       // legacy TRACE
-                       case "2":
-                               return LogLevel::NOTICE;
-                       // legacy DEBUG
-                       case "3":
-                               return LogLevel::INFO;
-                       // legacy DATA
-                       case "4":
-                       // legacy ALL
-                       case "5":
-                               return LogLevel::DEBUG;
-                       // default if nothing set
-                       default:
-                               return $level;
-               }
-       }
-
-       /**
-        * Adding a handler to a given logger instance
-        *
-        * @param LoggerInterface $logger The logger instance
-        * @param mixed           $stream The stream which handles the logger output
-        * @param string          $level  The level, for which this handler at least should handle logging
-        *
-        * @return void
-        *
-        * @throws \Exception in case of general failures
-        */
-       public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE)
-       {
-               if ($logger instanceof Monolog\Logger) {
-                       $loglevel = Monolog\Logger::toMonologLevel($level);
-
-                       // fallback to notice if an invalid loglevel is set
-                       if (!is_int($loglevel)) {
-                               $loglevel = LogLevel::NOTICE;
-                       }
-
-                       $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
-
-                       $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
-                       $fileHandler->setFormatter($formatter);
-
-                       $logger->pushHandler($fileHandler);
-               }
-       }
-
-       public static function addVoidHandler($logger)
-       {
-               if ($logger instanceof Monolog\Logger) {
-                       $logger->pushHandler(new Monolog\Handler\NullHandler());
-               }
-       }
-}
index 4fa5c31c8a5c4a24d2bba63a88a446a7752e3582..1a86f43be716486cb223ac61c21da8f6cf445625 100644 (file)
@@ -73,7 +73,9 @@ class FileSystem
         *
         * @param string $url The file/url
         *
-        * @return false|resource the open stream ressource
+        * @return resource the open stream rssource
+        *
+        * @throws \UnexpectedValueException
         */
        public function createStream(string $url)
        {
diff --git a/src/Util/Logger/AbstractLogger.php b/src/Util/Logger/AbstractLogger.php
deleted file mode 100644 (file)
index a8aba34..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Friendica\Util\Introspection;
-use Friendica\Util\Strings;
-use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
-
-/**
- * This class contains all necessary dependencies and calls for Friendica
- * Every new Logger should extend this class and define, how addEntry() works
- *
- * Additional information for each Logger, who extends this class:
- * - Introspection
- * - UID for each call
- * - Channel of the current call (i.e. index, worker, daemon, ...)
- */
-abstract class AbstractLogger implements LoggerInterface
-{
-       /**
-        * The output channel of this logger
-        * @var string
-        */
-       protected $channel;
-
-       /**
-        * The Introspection for the current call
-        * @var Introspection
-        */
-       protected $introspection;
-
-       /**
-        * The UID of the current call
-        * @var string
-        */
-       protected $logUid;
-
-       /**
-        * Adds a new entry to the log
-        *
-        * @param int    $level
-        * @param string $message
-        * @param array  $context
-        *
-        * @return void
-        */
-       abstract protected function addEntry($level, $message, $context = []);
-
-       /**
-        * @param string        $channel       The output channel
-        * @param Introspection $introspection The introspection of the current call
-        *
-        * @throws \Exception
-        */
-       public function __construct($channel, Introspection $introspection)
-       {
-               $this->channel       = $channel;
-               $this->introspection = $introspection;
-               $this->logUid        = Strings::getRandomHex(6);
-       }
-
-       /**
-        * Simple interpolation of PSR-3 compliant replacements ( variables between '{' and '}' )
-        * @see https://www.php-fig.org/psr/psr-3/#12-message
-        *
-        * @param string $message
-        * @param array  $context
-        *
-        * @return string the interpolated message
-        */
-       protected function psrInterpolate($message, array $context = array())
-       {
-               $replace = [];
-               foreach ($context as $key => $value) {
-                       // check that the value can be casted to string
-                       if (!is_array($value) && (!is_object($value) || method_exists($value, '__toString'))) {
-                               $replace['{' . $key . '}'] = $value;
-                       } elseif (is_array($value)) {
-                               $replace['{' . $key . '}'] = @json_encode($value);
-                       }
-               }
-
-               return strtr($message, $replace);
-       }
-
-       /**
-        * JSON Encodes an complete array including objects with "__toString()" methods
-        *
-        * @param array $input an Input Array to encode
-        *
-        * @return false|string The json encoded output of the array
-        */
-       protected function jsonEncodeArray(array $input)
-       {
-               $output = [];
-
-               foreach ($input as $key => $value) {
-                       if (is_object($value) && method_exists($value, '__toString')) {
-                               $output[$key] = $value->__toString();
-                       } else {
-                               $output[$key] = $value;
-                       }
-               }
-
-               return @json_encode($output);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function emergency($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::EMERGENCY, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function alert($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::ALERT, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function critical($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::CRITICAL, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function error($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::ERROR, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function warning($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::WARNING, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function notice($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::NOTICE, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function info($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::INFO, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function debug($message, array $context = array())
-       {
-               $this->addEntry(LogLevel::DEBUG, (string) $message, $context);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function log($level, $message, array $context = array())
-       {
-               $this->addEntry($level, (string) $message, $context);
-       }
-}
diff --git a/src/Util/Logger/Monolog/DevelopHandler.php b/src/Util/Logger/Monolog/DevelopHandler.php
deleted file mode 100644 (file)
index a55ac37..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger\Monolog;
-
-use Monolog\Handler;
-use Monolog\Logger;
-
-/**
- * Simple handler for Friendica developers to use for deeper logging
- *
- * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
- * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
- */
-class DevelopHandler extends Handler\AbstractHandler
-{
-       /**
-        * @var string The IP of the developer who wants to debug
-        */
-       private $developerIp;
-
-       /**
-        * @param string $developerIp  The IP of the developer who wants to debug
-        * @param int    $level        The minimum logging level at which this handler will be triggered
-        * @param bool   $bubble       Whether the messages that are handled can bubble up the stack or not
-        */
-       public function __construct($developerIp, $level = Logger::DEBUG, $bubble = true)
-       {
-               parent::__construct($level, $bubble);
-
-               $this->developerIp = $developerIp;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function handle(array $record)
-       {
-               if (!$this->isHandling($record)) {
-                       return false;
-               }
-
-               /// Just in case the remote IP is the same as the developer IP log the output
-               if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp)
-               {
-                       return false;
-               }
-
-               return false === $this->bubble;
-       }
-}
diff --git a/src/Util/Logger/Monolog/IntrospectionProcessor.php b/src/Util/Logger/Monolog/IntrospectionProcessor.php
deleted file mode 100644 (file)
index ceb0e31..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger\Monolog;
-
-use Friendica\Util\Introspection;
-use Monolog\Logger;
-use Monolog\Processor\ProcessorInterface;
-
-/**
- * Injects line/file//function where the log message came from
- */
-class IntrospectionProcessor implements ProcessorInterface
-{
-       private $level;
-
-       private $introspection;
-
-       /**
-        * @param Introspection $introspection Holds the Introspection of the current call
-        * @param string|int    $level         The minimum logging level at which this Processor will be triggered
-        */
-       public function __construct(Introspection $introspection, $level = Logger::DEBUG)
-       {
-               $this->level = Logger::toMonologLevel($level);
-               $introspection->addClasses(array('Monolog\\'));
-               $this->introspection = $introspection;
-       }
-
-       public function __invoke(array $record)
-       {
-               // return if the level is not high enough
-               if ($record['level'] < $this->level) {
-                       return $record;
-               }
-               // we should have the call source now
-               $record['extra'] = array_merge(
-                       $record['extra'],
-                       $this->introspection->getRecord()
-               );
-
-               return $record;
-       }
-}
diff --git a/src/Util/Logger/ProfilerLogger.php b/src/Util/Logger/ProfilerLogger.php
deleted file mode 100644 (file)
index 1c190d4..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Friendica\Core\System;
-use Friendica\Util\Profiler;
-use Psr\Log\LoggerInterface;
-
-/**
- * This Logger adds additional profiling data in case profiling is enabled.
- * It uses a predefined logger.
- */
-class ProfilerLogger implements LoggerInterface
-{
-       /**
-        * The Logger of the current call
-        * @var LoggerInterface
-        */
-       private $logger;
-
-       /**
-        * The Profiler for the current call
-        * @var Profiler
-        */
-       protected $profiler;
-
-       /**
-        * ProfilerLogger constructor.
-        * @param LoggerInterface $logger   The Logger of the current call
-        * @param Profiler        $profiler The profiler of the current call
-        */
-       public function __construct(LoggerInterface $logger, Profiler $profiler)
-       {
-               $this->logger = $logger;
-               $this->profiler = $profiler;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function emergency($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->emergency($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function alert($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->alert($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function critical($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->critical($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function error($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->error($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function warning($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->warning($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function notice($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->notice($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function info($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->info($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function debug($message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->debug($message, $context);
-               $this->profiler->stopRecording();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function log($level, $message, array $context = array())
-       {
-               $this->profiler->startRecording('file');
-               $this->logger->log($level, $message, $context);
-               $this->profiler->stopRecording();
-       }
-}
diff --git a/src/Util/Logger/README.md b/src/Util/Logger/README.md
deleted file mode 100644 (file)
index 4494031..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-## Friendica\Util\Logger
-
-This namespace contains the different implementations of a Logger.
-
-### Configuration guideline
-
-The following settings are possible for `logger_config`:
--      `monolog`: A Logging framework with lots of additions (see [Monolog](https://github.com/Seldaek/monolog/)). There are just Friendica additions inside the Monolog directory
--      [`stream`](StreamLogger.php): A small logger for files or streams
--      [`syslog`](SyslogLogger.php): Prints the logging output into the syslog
-
-[`VoidLogger`](VoidLogger.php) is a fallback logger without any function if no debugging is enabled.
-
-[`ProfilerLogger`](ProfilerLogger.php) is a wrapper around an existing logger in case profiling is enabled for Friendica.
-Every log call will be saved to the `Profiler` with a timestamp.
-
-### Implementation guideline
-
-Each logging implementation should pe capable of printing at least the following information:
--      An unique ID for each Request/Call
--      The process ID (PID)
--      A timestamp of the logging entry
--      The critically of the log entry
--      A log message
--      A context of the log message (f.e which user)
-
-If possible, a Logger should extend [`AbstractLogger`](AbstractLogger.php), because it contains additional, Friendica specific business logic for each logging call.
diff --git a/src/Util/Logger/StreamLogger.php b/src/Util/Logger/StreamLogger.php
deleted file mode 100644 (file)
index 752f486..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Friendica\Util\DateTimeFormat;
-use Friendica\Util\FileSystem;
-use Friendica\Util\Introspection;
-use Psr\Log\LogLevel;
-
-/**
- * A Logger instance for logging into a stream (file, stdout, stderr)
- */
-class StreamLogger extends AbstractLogger
-{
-       /**
-        * The minimum loglevel at which this logger will be triggered
-        * @var string
-        */
-       private $logLevel;
-
-       /**
-        * The file URL of the stream (if needed)
-        * @var string
-        */
-       private $url;
-
-       /**
-        * The stream, where the current logger is writing into
-        * @var resource
-        */
-       private $stream;
-
-       /**
-        * The current process ID
-        * @var int
-        */
-       private $pid;
-
-       /**
-        * @var FileSystem
-        */
-       private $fileSystem;
-
-       /**
-        * Translates LogLevel log levels to integer values
-        * @var array
-        */
-       private $levelToInt = [
-               LogLevel::EMERGENCY => 0,
-               LogLevel::ALERT     => 1,
-               LogLevel::CRITICAL  => 2,
-               LogLevel::ERROR     => 3,
-               LogLevel::WARNING   => 4,
-               LogLevel::NOTICE    => 5,
-               LogLevel::INFO      => 6,
-               LogLevel::DEBUG     => 7,
-       ];
-
-       /**
-        * {@inheritdoc}
-        * @param string|resource $stream The stream to write with this logger (either a file or a stream, i.e. stdout)
-        * @param string          $level  The minimum loglevel at which this logger will be triggered
-        *
-        * @throws \Exception
-        */
-       public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, $level = LogLevel::DEBUG)
-       {
-               $this->fileSystem = $fileSystem;
-
-               parent::__construct($channel, $introspection);
-
-               if (is_resource($stream)) {
-                       $this->stream = $stream;
-               } elseif (is_string($stream)) {
-                       $this->url = $stream;
-               } else {
-                       throw new \InvalidArgumentException('A stream must either be a resource or a string.');
-               }
-
-               $this->pid = getmypid();
-               if (array_key_exists($level, $this->levelToInt)) {
-                       $this->logLevel = $this->levelToInt[$level];
-               } else {
-                       throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level));
-               }
-
-               $this->checkStream();
-       }
-
-       public function close()
-       {
-               if ($this->url && is_resource($this->stream)) {
-                       fclose($this->stream);
-               }
-
-               $this->stream = null;
-       }
-
-       /**
-        * Adds a new entry to the log
-        *
-        * @param int $level
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       protected function addEntry($level, $message, $context = [])
-       {
-               if (!array_key_exists($level, $this->levelToInt)) {
-                       throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level));
-               }
-
-               $logLevel = $this->levelToInt[$level];
-
-               if ($logLevel > $this->logLevel) {
-                       return;
-               }
-
-               $this->checkStream();
-
-               $formattedLog = $this->formatLog($level, $message, $context);
-               fwrite($this->stream, $formattedLog);
-       }
-
-       /**
-        * Formats a log record for the syslog output
-        *
-        * @param int    $level   The loglevel/priority
-        * @param string $message The message
-        * @param array  $context The context of this call
-        *
-        * @return string the formatted syslog output
-        */
-       private function formatLog($level, $message, $context = [])
-       {
-               $record = $this->introspection->getRecord();
-               $record = array_merge($record, ['uid' => $this->logUid, 'process_id' => $this->pid]);
-               $logMessage = '';
-
-               $logMessage .= DateTimeFormat::utcNow(DateTimeFormat::ATOM) . ' ';
-               $logMessage .= $this->channel . ' ';
-               $logMessage .= '[' . strtoupper($level) . ']: ';
-               $logMessage .= $this->psrInterpolate($message, $context) . ' ';
-               $logMessage .= $this->jsonEncodeArray($context) . ' - ';
-               $logMessage .= $this->jsonEncodeArray($record);
-               $logMessage .= PHP_EOL;
-
-               return $logMessage;
-       }
-
-       private function checkStream()
-       {
-               if (is_resource($this->stream)) {
-                       return;
-               }
-
-               if (empty($this->url)) {
-                       throw new \LogicException('Missing stream URL.');
-               }
-
-               $this->stream = $this->fileSystem->createStream($this->url);
-       }
-}
diff --git a/src/Util/Logger/SyslogLogger.php b/src/Util/Logger/SyslogLogger.php
deleted file mode 100644 (file)
index f33e2d6..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Friendica\Network\HTTPException\InternalServerErrorException;
-use Friendica\Util\Introspection;
-use Psr\Log\LogLevel;
-
-/**
- * A Logger instance for syslogging (fast, but simple)
- * @see http://php.net/manual/en/function.syslog.php
- */
-class SyslogLogger extends AbstractLogger
-{
-       const IDENT = 'Friendica';
-
-       /**
-        * Translates LogLevel log levels to syslog log priorities.
-        * @var array
-        */
-       private $logLevels = [
-               LogLevel::DEBUG     => LOG_DEBUG,
-               LogLevel::INFO      => LOG_INFO,
-               LogLevel::NOTICE    => LOG_NOTICE,
-               LogLevel::WARNING   => LOG_WARNING,
-               LogLevel::ERROR     => LOG_ERR,
-               LogLevel::CRITICAL  => LOG_CRIT,
-               LogLevel::ALERT     => LOG_ALERT,
-               LogLevel::EMERGENCY => LOG_EMERG,
-       ];
-
-       /**
-        * Translates log priorities to string outputs
-        * @var array
-        */
-       private $logToString = [
-               LOG_DEBUG   => 'DEBUG',
-               LOG_INFO    => 'INFO',
-               LOG_NOTICE  => 'NOTICE',
-               LOG_WARNING => 'WARNING',
-               LOG_ERR     => 'ERROR',
-               LOG_CRIT    => 'CRITICAL',
-               LOG_ALERT   => 'ALERT',
-               LOG_EMERG   => 'EMERGENCY'
-       ];
-
-       /**
-        * Indicates what logging options will be used when generating a log message
-        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
-        *
-        * @var int
-        */
-       private $logOpts;
-
-       /**
-        * Used to specify what type of program is logging the message
-        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
-        *
-        * @var int
-        */
-       private $logFacility;
-
-       /**
-        * The minimum loglevel at which this logger will be triggered
-        * @var int
-        */
-       private $logLevel;
-
-       /**
-        * A error message of the current operation
-        * @var string
-        */
-       private $errorMessage;
-
-       /**
-        * {@inheritdoc}
-        * @param string $level       The minimum loglevel at which this logger will be triggered
-        * @param int    $logOpts     Indicates what logging options will be used when generating a log message
-        * @param int    $logFacility Used to specify what type of program is logging the message
-        *
-        * @throws \Exception
-        */
-       public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
-       {
-               parent::__construct($channel, $introspection);
-               $this->logOpts = $logOpts;
-               $this->logFacility = $logFacility;
-               $this->logLevel = $this->mapLevelToPriority($level);
-               $this->introspection->addClasses(array(self::class));
-       }
-
-       /**
-        * Adds a new entry to the syslog
-        *
-        * @param int    $level
-        * @param string $message
-        * @param array  $context
-        *
-        * @throws InternalServerErrorException if the syslog isn't available
-        */
-       protected function addEntry($level, $message, $context = [])
-       {
-               $logLevel = $this->mapLevelToPriority($level);
-
-               if ($logLevel > $this->logLevel) {
-                       return;
-               }
-
-               $formattedLog = $this->formatLog($logLevel, $message, $context);
-               $this->write($logLevel, $formattedLog);
-       }
-
-       /**
-        * Maps the LogLevel (@see LogLevel) to a SysLog priority (@see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters)
-        *
-        * @param string $level A LogLevel
-        *
-        * @return int The SysLog priority
-        *
-        * @throws \Psr\Log\InvalidArgumentException If the loglevel isn't valid
-        */
-       public function mapLevelToPriority($level)
-       {
-               if (!array_key_exists($level, $this->logLevels)) {
-                       throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level));
-               }
-
-               return $this->logLevels[$level];
-       }
-
-       /**
-        * Closes the Syslog
-        */
-       public function close()
-       {
-               closelog();
-       }
-
-       /**
-        * Writes a message to the syslog
-        * @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters
-        *
-        * @param int    $priority The Priority
-        * @param string $message  The message of the log
-        *
-        * @throws InternalServerErrorException if syslog cannot be used
-        */
-       private function write($priority, $message)
-       {
-               set_error_handler([$this, 'customErrorHandler']);
-               $opened = openlog(self::IDENT, $this->logOpts, $this->logFacility);
-               restore_error_handler();
-
-               if (!$opened) {
-                       throw new \UnexpectedValueException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
-               }
-
-               $this->syslogWrapper($priority, $message);
-       }
-
-       /**
-        * Formats a log record for the syslog output
-        *
-        * @param int    $level   The loglevel/priority
-        * @param string $message The message
-        * @param array  $context The context of this call
-        *
-        * @return string the formatted syslog output
-        */
-       private function formatLog($level, $message, $context = [])
-       {
-               $record = $this->introspection->getRecord();
-               $record = array_merge($record, ['uid' => $this->logUid]);
-               $logMessage = '';
-
-               $logMessage .= $this->channel . ' ';
-               $logMessage .= '[' . $this->logToString[$level] . ']: ';
-               $logMessage .= $this->psrInterpolate($message, $context) . ' ';
-               $logMessage .= $this->jsonEncodeArray($context) . ' - ';
-               $logMessage .= $this->jsonEncodeArray($record);
-
-               return $logMessage;
-       }
-
-       private function customErrorHandler($code, $msg)
-       {
-               $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
-       }
-
-       /**
-        * A syslog wrapper to make syslog functionality testable
-        *
-        * @param int    $level The syslog priority
-        * @param string $entry The message to send to the syslog function
-        */
-       protected function syslogWrapper($level, $entry)
-       {
-               set_error_handler([$this, 'customErrorHandler']);
-               $written = syslog($level, $entry);
-               restore_error_handler();
-
-               if (!$written) {
-                       throw new \UnexpectedValueException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
-               }
-       }
-}
diff --git a/src/Util/Logger/VoidLogger.php b/src/Util/Logger/VoidLogger.php
deleted file mode 100644 (file)
index 6c47601..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Psr\Log\LoggerInterface;
-
-/**
- * A Logger instance to not log
- */
-class VoidLogger implements LoggerInterface
-{
-       /**
-        * System is unusable.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function emergency($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Action must be taken immediately.
-        *
-        * Example: Entire website down, database unavailable, etc. This should
-        * trigger the SMS alerts and wake you up.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function alert($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Critical conditions.
-        *
-        * Example: Application component unavailable, unexpected exception.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function critical($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Runtime errors that do not require immediate action but should typically
-        * be logged and monitored.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function error($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Exceptional occurrences that are not errors.
-        *
-        * Example: Use of deprecated APIs, poor use of an API, undesirable things
-        * that are not necessarily wrong.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function warning($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Normal but significant events.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function notice($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Interesting events.
-        *
-        * Example: User logs in, SQL logs.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function info($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Detailed debug information.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function debug($message, array $context = array())
-       {
-               return;
-       }
-
-       /**
-        * Logs with an arbitrary level.
-        *
-        * @param mixed $level
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function log($level, $message, array $context = array())
-       {
-               return;
-       }
-}
diff --git a/src/Util/Logger/WorkerLogger.php b/src/Util/Logger/WorkerLogger.php
deleted file mode 100644 (file)
index fdda6c9..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util\Logger;
-
-use Friendica\Util\Strings;
-use Psr\Log\LoggerInterface;
-
-/**
- * A Logger for specific worker tasks, which adds an additional woker-id to it.
- * Uses the decorator pattern (https://en.wikipedia.org/wiki/Decorator_pattern)
- */
-class WorkerLogger implements LoggerInterface
-{
-       /**
-        * @var LoggerInterface The original Logger instance
-        */
-       private $logger;
-
-       /**
-        * @var string the current worker ID
-        */
-       private $workerId;
-
-       /**
-        * @var string The called function name
-        */
-       private $functionName;
-
-       /**
-        * @param LoggerInterface $logger The logger for worker entries
-        * @param string $functionName The current function name of the worker
-        * @param int $idLength The length of the generated worker ID
-        */
-       public function __construct(LoggerInterface $logger, $functionName = '', $idLength = 7)
-       {
-               $this->logger = $logger;
-               $this->functionName = $functionName;
-               $this->workerId = Strings::getRandomHex($idLength);
-       }
-
-       /**
-        * Sets the function name for additional logging
-        *
-        * @param string $functionName
-        */
-       public function setFunctionName(string $functionName)
-       {
-               $this->functionName = $functionName;
-       }
-
-       /**
-        * Adds the worker context for each log entry
-        *
-        * @param array $context
-        */
-       private function addContext(array &$context)
-       {
-               $context['worker_id'] = $this->workerId;
-               $context['worker_cmd'] = $this->functionName;
-       }
-
-       /**
-        * Returns the worker ID
-        *
-        * @return string
-        */
-       public function getWorkerId()
-       {
-               return $this->workerId;
-       }
-
-       /**
-        * System is unusable.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function emergency($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->emergency($message, $context);
-       }
-
-       /**
-        * Action must be taken immediately.
-        *
-        * Example: Entire website down, database unavailable, etc. This should
-        * trigger the SMS alerts and wake you up.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function alert($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->alert($message, $context);
-       }
-
-       /**
-        * Critical conditions.
-        *
-        * Example: Application component unavailable, unexpected exception.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function critical($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->critical($message, $context);
-       }
-
-       /**
-        * Runtime errors that do not require immediate action but should typically
-        * be logged and monitored.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function error($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->error($message, $context);
-       }
-
-       /**
-        * Exceptional occurrences that are not errors.
-        *
-        * Example: Use of deprecated APIs, poor use of an API, undesirable things
-        * that are not necessarily wrong.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function warning($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->warning($message, $context);
-       }
-
-       /**
-        * Normal but significant events.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function notice($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->notice($message, $context);
-       }
-
-       /**
-        * Interesting events.
-        *
-        * Example: User logs in, SQL logs.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function info($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->info($message, $context);
-       }
-
-       /**
-        * Detailed debug information.
-        *
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function debug($message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->debug($message, $context);
-       }
-
-       /**
-        * Logs with an arbitrary level.
-        *
-        * @param mixed $level
-        * @param string $message
-        * @param array $context
-        *
-        * @return void
-        */
-       public function log($level, $message, array $context = [])
-       {
-               $this->addContext($context);
-               $this->logger->log($level, $message, $context);
-       }
-}
index bbf8c5599c1d65e6769b34b62ff859db150eea2d..042949e60e62496b2df83731f27b1067b88cb2ab 100644 (file)
@@ -141,7 +141,7 @@ return [
         *    and is automatically passed as an argument with the same name
         */
        LoggerInterface::class          => [
-               'instanceOf' => Factory\LoggerFactory::class,
+               'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class,
                'constructParams' => [
                        'index',
                ],
@@ -150,7 +150,7 @@ return [
                ],
        ],
        '$devLogger'                    => [
-               'instanceOf' => Factory\LoggerFactory::class,
+               'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class,
                'constructParams' => [
                        'dev',
                ],
index 760a732d670fe96fc60553fdb1593332d2a45722..3f4f8c03c9ef0770968d298ea4a6b1d07ba2b2ea 100644 (file)
@@ -32,7 +32,7 @@ use Friendica\Database\Database;
 use Friendica\DI;
 use Friendica\Test\Util\RendererMockTrait;
 use Friendica\Test\Util\VFSTrait;
-use Friendica\Util\Logger\VoidLogger;
+use Friendica\Core\Logger\Type\VoidLogger;
 use Mockery;
 use Mockery\MockInterface;
 use org\bovigo\vfs\vfsStream;
index afa0711ae0a7f2c813f441f43aa047d2c3ae3178..969107316850068cc0cea2bdcaac8aa32fe09b91 100644 (file)
@@ -5,7 +5,7 @@ namespace Friendica\Test\src\Contact\FriendSuggest\Factory;
 use Friendica\Contact\FriendSuggest\Factory\FriendSuggest;
 use Friendica\Contact\FriendSuggest\Entity;
 use Friendica\Test\MockedTest;
-use Friendica\Util\Logger\VoidLogger;
+use Friendica\Core\Logger\Type\VoidLogger;
 
 class FriendSuggestTest extends MockedTest
 {
diff --git a/tests/src/Core/Logger/AbstractLoggerTest.php b/tests/src/Core/Logger/AbstractLoggerTest.php
new file mode 100644 (file)
index 0000000..f1a0553
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Test\MockedTest;
+use Friendica\Util\Introspection;
+use Mockery\MockInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+abstract class AbstractLoggerTest extends MockedTest
+{
+       use LoggerDataTrait;
+
+       const LOGLINE = '/.* \[.*\]: .* \{.*\"file\":\".*\".*,.*\"line\":\d*,.*\"function\":\".*\".*,.*\"uid\":\".*\".*}/';
+
+       const FILE = 'test';
+       const LINE = 666;
+       const FUNC = 'myfunction';
+
+       /**
+        * @var Introspection|MockInterface
+        */
+       protected $introspection;
+
+       /**
+        * Returns the content of the current logger instance
+        *
+        * @return string
+        */
+       abstract protected function getContent();
+
+       /**
+        * Returns the current logger instance
+        *
+        * @param string $level the default loglevel
+        *
+        * @return LoggerInterface
+        */
+       abstract protected function getInstance($level = LogLevel::DEBUG);
+
+       protected function setUp(): void
+       {
+               parent::setUp();
+
+               $this->introspection = \Mockery::mock(Introspection::class);
+               $this->introspection->shouldReceive('getRecord')->andReturn([
+                       'file'     => self::FILE,
+                       'line'     => self::LINE,
+                       'function' => self::FUNC
+               ]);
+       }
+
+       public function assertLogline($string)
+       {
+               self::assertRegExp(self::LOGLINE, $string);
+       }
+
+       public function assertLoglineNums($assertNum, $string)
+       {
+               self::assertEquals($assertNum, preg_match_all(self::LOGLINE, $string));
+       }
+
+       /**
+        * Test if the logger works correctly
+        */
+       public function testNormal()
+       {
+               $logger = $this->getInstance();
+               $logger->emergency('working!');
+               $logger->alert('working too!');
+               $logger->debug('and now?');
+               $logger->notice('message', ['an' => 'context']);
+
+               $text = $this->getContent();
+               self::assertLogline($text);
+               self::assertLoglineNums(4, $text);
+       }
+
+       /**
+        * Test if a log entry is correctly interpolated
+        */
+       public function testPsrInterpolate()
+       {
+               $logger = $this->getInstance();
+
+               $logger->emergency('A {psr} test', ['psr' => 'working']);
+               $logger->alert('An {array} test', ['array' => ['it', 'is', 'working']]);
+               $text = $this->getContent();
+               self::assertStringContainsString('A working test', $text);
+               self::assertStringContainsString('An ["it","is","working"] test', $text);
+       }
+
+       /**
+        * Test if a log entry contains all necessary information
+        */
+       public function testContainsInformation()
+       {
+               $logger = $this->getInstance();
+               $logger->emergency('A test');
+
+               $text = $this->getContent();
+               self::assertStringContainsString('"file":"' . self::FILE . '"', $text);
+               self::assertStringContainsString('"line":' . self::LINE, $text);
+               self::assertStringContainsString('"function":"' . self::FUNC . '"', $text);
+       }
+
+       /**
+        * Test if the minimum level is working
+        */
+       public function testMinimumLevel()
+       {
+               $logger = $this->getInstance(LogLevel::NOTICE);
+
+               $logger->emergency('working');
+               $logger->alert('working');
+               $logger->error('working');
+               $logger->warning('working');
+               $logger->notice('working');
+               $logger->info('not working');
+               $logger->debug('not working');
+
+               $text = $this->getContent();
+
+               self::assertLoglineNums(5, $text);
+       }
+
+       /**
+        * Test with different logging data
+        * @dataProvider dataTests
+        */
+       public function testDifferentTypes($function, $message, array $context)
+       {
+               $logger = $this->getInstance();
+               $logger->$function($message, $context);
+
+               $text = $this->getContent();
+
+               self::assertLogline($text);
+
+               self::assertStringContainsString(@json_encode($context), $text);
+       }
+
+       /**
+        * Test a message with an exception
+        */
+       public function testExceptionHandling()
+       {
+               $e = new \Exception("Test String", 123);
+               $eFollowUp = new \Exception("FollowUp", 456, $e);
+
+               $assertion = $eFollowUp->__toString();
+
+               $logger = $this->getInstance();
+               $logger->alert('test', ['e' => $eFollowUp]);
+               $text = $this->getContent();
+
+               self::assertLogline($text);
+
+               self::assertStringContainsString(@json_encode($assertion), $this->getContent());
+       }
+
+       public function testNoObjectHandling()
+       {
+               $logger = $this->getInstance();
+               $logger->alert('test', ['e' => ['test' => 'test']]);
+               $text = $this->getContent();
+
+               self::assertLogline($text);
+
+               self::assertStringContainsString('test', $this->getContent());
+       }
+}
diff --git a/tests/src/Core/Logger/LoggerDataTrait.php b/tests/src/Core/Logger/LoggerDataTrait.php
new file mode 100644 (file)
index 0000000..0d6b004
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+trait LoggerDataTrait
+{
+       public function dataTests()
+       {
+               return [
+                       'emergency' => [
+                               'function' => 'emergency',
+                               'message' => 'test',
+                               'context' => ['a' => 'context'],
+                       ],
+                       'alert' => [
+                               'function' => 'alert',
+                               'message' => 'test {test}',
+                               'context' => ['a' => 'context', 2 => 'so', 'test' => 'works'],
+                       ],
+                       'critical' => [
+                               'function' => 'critical',
+                               'message' => 'test crit 2345',
+                               'context' => ['a' => 'context', 'wit' => ['more', 'array']],
+                       ],
+                       'error' => [
+                               'function' => 'error',
+                               'message' => 2.554,
+                               'context' => [],
+                       ],
+                       'warning' => [
+                               'function' => 'warning',
+                               'message' => 'test warn',
+                               'context' => ['a' => 'context'],
+                       ],
+                       'notice' => [
+                               'function' => 'notice',
+                               'message' => 2346,
+                               'context' => ['a' => 'context'],
+                       ],
+                       'info' => [
+                               'function' => 'info',
+                               'message' => null,
+                               'context' => ['a' => 'context'],
+                       ],
+                       'debug' => [
+                               'function' => 'debug',
+                               'message' => true,
+                               'context' => ['a' => false],
+                       ],
+               ];
+       }
+}
diff --git a/tests/src/Core/Logger/ProfilerLoggerTest.php b/tests/src/Core/Logger/ProfilerLoggerTest.php
new file mode 100644 (file)
index 0000000..3b8e771
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Test\MockedTest;
+use Friendica\Core\Logger\Type\ProfilerLogger;
+use Friendica\Util\Profiler;
+use Mockery\MockInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+class ProfilerLoggerTest extends MockedTest
+{
+       use LoggerDataTrait;
+
+       /**
+        * @var LoggerInterface|MockInterface
+        */
+       private $logger;
+       /**
+        * @var Profiler|MockInterface
+        */
+       private $profiler;
+
+       protected function setUp(): void
+       {
+               parent::setUp();
+
+               $this->logger = \Mockery::mock(LoggerInterface::class);
+               $this->profiler = \Mockery::mock(Profiler::class);
+       }
+
+       /**
+        * Test if the profiler is profiling data
+        * @dataProvider dataTests
+        * @doesNotPerformAssertions
+        */
+       public function testProfiling($function, $message, array $context)
+       {
+               $logger = new ProfilerLogger($this->logger, $this->profiler);
+
+               $this->logger->shouldReceive($function)->with($message, $context)->once();
+               $this->profiler->shouldReceive('startRecording')->with('file')->once();
+               $this->profiler->shouldReceive('stopRecording');
+               $this->profiler->shouldReceive('saveTimestamp');
+               $logger->$function($message, $context);
+       }
+
+       /**
+        * Test the log() function
+        * @doesNotPerformAssertions
+        */
+       public function testProfilingLog()
+       {
+               $logger = new ProfilerLogger($this->logger, $this->profiler);
+
+               $this->logger->shouldReceive('log')->with(LogLevel::WARNING, 'test', ['a' => 'context'])->once();
+               $this->profiler->shouldReceive('startRecording')->with('file')->once();
+               $this->profiler->shouldReceive('stopRecording');
+               $this->profiler->shouldReceive('saveTimestamp');
+
+               $logger->log(LogLevel::WARNING, 'test', ['a' => 'context']);
+       }
+}
diff --git a/tests/src/Core/Logger/StreamLoggerTest.php b/tests/src/Core/Logger/StreamLoggerTest.php
new file mode 100644 (file)
index 0000000..65ef76e
--- /dev/null
@@ -0,0 +1,213 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Core\Logger\Exception\LoggerArgumentException;
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Util\FileSystem;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Core\Logger\Type\StreamLogger;
+use org\bovigo\vfs\vfsStream;
+use org\bovigo\vfs\vfsStreamFile;
+use Psr\Log\LogLevel;
+
+class StreamLoggerTest extends AbstractLoggerTest
+{
+       use VFSTrait;
+
+       /**
+        * @var vfsStreamFile
+        */
+       private $logfile;
+
+       /**
+        * @var Filesystem
+        */
+       private $fileSystem;
+
+       protected function setUp(): void
+       {
+               parent::setUp();
+
+               $this->setUpVfsDir();
+
+               $this->fileSystem = new FileSystem();
+       }
+
+       /**
+        * {@@inheritdoc}
+        */
+       protected function getInstance($level = LogLevel::DEBUG)
+       {
+               $this->logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $this->logfile->url(), $this->introspection, $this->fileSystem, $level);
+
+               return $logger;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       protected function getContent()
+       {
+               return $this->logfile->getContent();
+       }
+
+       /**
+        * Test if a stream is working
+        */
+       public function testStream()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $filehandler = fopen($logfile->url(), 'ab');
+
+               $logger = new \Friendica\Core\Logger\Type\StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem);
+               $logger->emergency('working');
+
+               $text = $logfile->getContent();
+
+               self::assertLogline($text);
+       }
+
+       /**
+        * Test if the close statement is working
+        */
+       public function testClose()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
+               $logger->emergency('working');
+               $logger->close();
+               // close doesn't affect
+               $logger->emergency('working too');
+
+               $text = $logfile->getContent();
+
+               self::assertLoglineNums(2, $text);
+       }
+
+       /**
+        * Test when a file isn't set
+        */
+       public function testNoUrl()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessage("Missing stream URL.");
+
+               $logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when a file cannot be opened
+        */
+       public function testWrongUrl()
+       {
+               $this->expectException(LoggerException::class);
+               $this->expectExceptionMessage("Cannot create stream.");
+
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root)->chmod(0);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when the directory cannot get created
+        */
+       public function testWrongDir()
+       {
+               $this->expectException(\UnexpectedValueException::class);
+               $this->expectExceptionMessageMatches("/Directory .* cannot get created: .* /");
+
+               static::markTestIncomplete('We need a platform independent way to set directory to readonly');
+
+               $logger = new StreamLogger('test', '/$%/wrong/directory/file.txt', $this->introspection, $this->fileSystem);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when the minimum level is not valid
+        */
+       public function testWrongMinimumLevel()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
+
+               $logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE');
+       }
+
+       /**
+        * Test when the minimum level is not valid
+        */
+       public function testWrongLogLevel()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
+
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
+
+               $logger->log('NOPE', 'a test');
+       }
+
+       /**
+        * Test when the file is null
+        */
+       public function testWrongFile()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessage("A stream must either be a resource or a string.");
+
+               $logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem);
+       }
+
+       /**
+        * Test a relative path
+        * @doesNotPerformAssertions
+        */
+       public function testRealPath()
+       {
+               static::markTestSkipped('vfsStream isn\'t compatible with chdir, so not testable.');
+
+               $logfile = vfsStream::newFile('friendica.log')
+                                   ->at($this->root);
+
+               chdir($this->root->getChild('logs')->url());
+
+               $logger = new StreamLogger('test', '../friendica.log' , $this->introspection, $this->fileSystem);
+
+               $logger->info('Test');
+       }
+}
diff --git a/tests/src/Core/Logger/SyslogLoggerTest.php b/tests/src/Core/Logger/SyslogLoggerTest.php
new file mode 100644 (file)
index 0000000..8ba2ebc
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Core\Logger\Exception\LoggerArgumentException;
+use Friendica\Core\Logger\Exception\LoggerException;
+use Friendica\Core\Logger\Type\SyslogLogger;
+use Psr\Log\LogLevel;
+
+class SyslogLoggerTest extends AbstractLoggerTest
+{
+       /**
+        * @var SyslogLoggerWrapper
+        */
+       private $logger;
+
+       protected function setUp(): void
+       {
+               parent::setUp();
+
+               $this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       protected function getContent()
+       {
+               return $this->logger->getContent();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       protected function getInstance($level = LogLevel::DEBUG)
+       {
+               $this->logger = new SyslogLoggerWrapper('test', $this->introspection, $level);
+
+               return $this->logger;
+       }
+
+
+       /**
+        * Test when the minimum level is not valid
+        */
+       public function testWrongMinimumLevel()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
+               
+               $logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE');
+       }
+
+       /**
+        * Test when the minimum level is not valid
+        */
+       public function testWrongLogLevel()
+       {
+               $this->expectException(LoggerArgumentException::class);
+               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
+
+               $logger = new SyslogLoggerWrapper('test', $this->introspection);
+
+               $logger->log('NOPE', 'a test');
+       }
+
+       /**
+        * Test the close() method
+        * @doesNotPerformAssertions
+        */
+       public function testClose()
+       {
+               $logger = new SyslogLoggerWrapper('test', $this->introspection);
+               $logger->emergency('test');
+               $logger->close();
+               // Reopened itself
+               $logger->emergency('test');
+       }
+}
diff --git a/tests/src/Core/Logger/SyslogLoggerWrapper.php b/tests/src/Core/Logger/SyslogLoggerWrapper.php
new file mode 100644 (file)
index 0000000..05dcbd6
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Core\Logger\Type\SyslogLogger;
+use Friendica\Util\Introspection;
+use Psr\Log\LogLevel;
+
+/**
+ * Wraps the SyslogLogger for replacing the syslog call with a string field.
+ */
+class SyslogLoggerWrapper extends SyslogLogger
+{
+       private $content;
+
+       public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
+       {
+               parent::__construct($channel, $introspection, $level, $logOpts, $logFacility);
+
+               $this->content = '';
+       }
+
+       /**
+        * Gets the content from the wrapped Syslog
+        *
+        * @return string
+        */
+       public function getContent()
+       {
+               return $this->content;
+       }
+
+       /**
+        * {@inheritdoc}
+        * @noinspection PhpMissingParentCallCommonInspection
+        */
+       protected function syslogWrapper(int $level, string $entry)
+       {
+               $this->content .= $entry . PHP_EOL;
+       }
+}
diff --git a/tests/src/Core/Logger/VoidLoggerTest.php b/tests/src/Core/Logger/VoidLoggerTest.php
new file mode 100644 (file)
index 0000000..a2134ce
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Test\MockedTest;
+use Friendica\Core\Logger\Type\VoidLogger;
+use Psr\Log\LogLevel;
+
+class VoidLoggerTest extends MockedTest
+{
+       use LoggerDataTrait;
+
+       /**
+        * Test if the profiler is profiling data
+        * @dataProvider dataTests
+        * @doesNotPerformAssertions
+        */
+       public function testNormal($function, $message, array $context)
+       {
+               $logger = new VoidLogger();
+               $logger->$function($message, $context);
+       }
+
+       /**
+        * Test the log() function
+        * @doesNotPerformAssertions
+        */
+       public function testProfilingLog()
+       {
+               $logger = new VoidLogger();
+               $logger->log(LogLevel::WARNING, 'test', ['a' => 'context']);
+       }
+}
diff --git a/tests/src/Core/Logger/WorkerLoggerTest.php b/tests/src/Core/Logger/WorkerLoggerTest.php
new file mode 100644 (file)
index 0000000..0f751f2
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Core\Logger;
+
+use Friendica\Core\Logger\Type\WorkerLogger;
+use Friendica\Test\MockedTest;
+use Psr\Log\LoggerInterface;
+
+class WorkerLoggerTest extends MockedTest
+{
+       private function assertUid($uid, $length = 7)
+       {
+               self::assertRegExp('/^[a-zA-Z0-9]{' . $length . '}+$/', $uid);
+       }
+
+       /**
+        * Test the a id with length zero
+        *
+        */
+       public function testGetWorkerIdZero()
+       {
+               $this->expectException(\Error::class);
+               
+               $logger = \Mockery::mock(LoggerInterface::class);
+               new WorkerLogger($logger, 'test', 0);
+       }
+
+       /**
+        * Test the generated Uid
+        */
+       public function testGetWorkerId()
+       {
+               $logger = \Mockery::mock(LoggerInterface::class);
+               for ($i = 1; $i < 14; $i++) {
+                       $workLogger = new WorkerLogger($logger, 'test', $i);
+                       $uid = $workLogger->getWorkerId();
+                       self::assertUid($uid, $i);
+               }
+       }
+
+       public function dataTest()
+       {
+               return [
+                       'info' => [
+                               'func' => 'info',
+                               'msg' => 'the alert',
+                               'context' => [],
+                       ],
+                       'alert' => [
+                               'func' => 'alert',
+                               'msg' => 'another alert',
+                               'context' => ['test' => 'it'],
+                       ],
+                       'critical' => [
+                               'func' => 'critical',
+                               'msg' => 'Critical msg used',
+                               'context' => ['test' => 'it', 'more' => 0.24545],
+                       ],
+                       'error' => [
+                               'func' => 'error',
+                               'msg' => 21345623,
+                               'context' => ['test' => 'it', 'yet' => true],
+                       ],
+                       'warning' => [
+                               'func' => 'warning',
+                               'msg' => 'another alert' . 123523 . 324.54534 . 'test',
+                               'context' => ['test' => 'it', 2 => 'nope'],
+                       ],
+                       'notice' => [
+                               'func' => 'notice',
+                               'msg' => 'Notice' . ' alert' . true . 'with' . '\'strange\'' . 1.24. 'behavior',
+                               'context' => ['test' => 'it'],
+                       ],
+                       'debug' => [
+                               'func' => 'debug',
+                               'msg' => 'at last a debug',
+                               'context' => ['test' => 'it'],
+                       ],
+               ];
+       }
+
+       /**
+        * Test the WorkerLogger with different log calls
+        * @dataProvider dataTest
+        */
+       public function testEmergency($func, $msg, $context = [])
+       {
+               $logger = \Mockery::mock(LoggerInterface::class);
+               $workLogger = new WorkerLogger($logger, 'test');
+               $testContext = $context;
+               $testContext['worker_id'] = $workLogger->getWorkerId();
+               $testContext['worker_cmd'] = 'test';
+               self::assertUid($testContext['worker_id']);
+               $logger
+                       ->shouldReceive($func)
+                       ->with($msg, $testContext)
+                       ->once();
+               $workLogger->$func($msg, $context);
+       }
+
+       /**
+        * Test the WorkerLogger with
+        */
+       public function testLog()
+       {
+               $logger = \Mockery::mock(LoggerInterface::class);
+               $workLogger = new WorkerLogger($logger, 'test');
+               $context = $testContext = ['test' => 'it'];
+               $testContext['worker_id'] = $workLogger->getWorkerId();
+               $testContext['worker_cmd'] = 'test';
+               self::assertUid($testContext['worker_id']);
+               $logger
+                       ->shouldReceive('log')
+                       ->with('debug', 'a test', $testContext)
+                       ->once();
+               $workLogger->log('debug', 'a test', $context);
+       }
+}
index 275a1d59721f6f399d31a1e4846efa7ea8ebea18..6e054428d88d60d001d9e95e5823d4cb15570406 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFacto
 use Friendica\Test\MockedTest;
 use Friendica\Util\ACLFormatter;
 use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Logger\VoidLogger;
+use Friendica\Core\Logger\Type\VoidLogger;
 use Mockery\MockInterface;
 
 class ProfileFieldTest extends MockedTest
index 0a093db5a1d92a6843c407868a2f00fd5fad4fa6..e27445d32bd871c3342d8cf60c25fc1b3d005e3c 100644 (file)
@@ -5,7 +5,7 @@ namespace Friendica\Test\src\Security\TwoFactor\Factory;
 use Friendica\Security\TwoFactor\Factory\TrustedBrowser;
 use Friendica\Test\MockedTest;
 use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Logger\VoidLogger;
+use Friendica\Core\Logger\Type\VoidLogger;
 use Friendica\Util\Strings;
 
 class TrustedBrowserTest extends MockedTest
diff --git a/tests/src/Util/Logger/AbstractLoggerTest.php b/tests/src/Util/Logger/AbstractLoggerTest.php
deleted file mode 100644 (file)
index d008f4d..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Test\MockedTest;
-use Friendica\Util\Introspection;
-use Mockery\MockInterface;
-use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
-
-abstract class AbstractLoggerTest extends MockedTest
-{
-       use LoggerDataTrait;
-
-       const LOGLINE = '/.* \[.*\]: .* \{.*\"file\":\".*\".*,.*\"line\":\d*,.*\"function\":\".*\".*,.*\"uid\":\".*\".*}/';
-
-       const FILE = 'test';
-       const LINE = 666;
-       const FUNC = 'myfunction';
-
-       /**
-        * @var Introspection|MockInterface
-        */
-       protected $introspection;
-
-       /**
-        * Returns the content of the current logger instance
-        *
-        * @return string
-        */
-       abstract protected function getContent();
-
-       /**
-        * Returns the current logger instance
-        *
-        * @param string $level the default loglevel
-        *
-        * @return LoggerInterface
-        */
-       abstract protected function getInstance($level = LogLevel::DEBUG);
-
-       protected function setUp(): void
-       {
-               parent::setUp();
-
-               $this->introspection = \Mockery::mock(Introspection::class);
-               $this->introspection->shouldReceive('getRecord')->andReturn([
-                       'file'     => self::FILE,
-                       'line'     => self::LINE,
-                       'function' => self::FUNC
-               ]);
-       }
-
-       public function assertLogline($string)
-       {
-               self::assertRegExp(self::LOGLINE, $string);
-       }
-
-       public function assertLoglineNums($assertNum, $string)
-       {
-               self::assertEquals($assertNum, preg_match_all(self::LOGLINE, $string));
-       }
-
-       /**
-        * Test if the logger works correctly
-        */
-       public function testNormal()
-       {
-               $logger = $this->getInstance();
-               $logger->emergency('working!');
-               $logger->alert('working too!');
-               $logger->debug('and now?');
-               $logger->notice('message', ['an' => 'context']);
-
-               $text = $this->getContent();
-               self::assertLogline($text);
-               self::assertLoglineNums(4, $text);
-       }
-
-       /**
-        * Test if a log entry is correctly interpolated
-        */
-       public function testPsrInterpolate()
-       {
-               $logger = $this->getInstance();
-
-               $logger->emergency('A {psr} test', ['psr' => 'working']);
-               $logger->alert('An {array} test', ['array' => ['it', 'is', 'working']]);
-               $text = $this->getContent();
-               self::assertStringContainsString('A working test', $text);
-               self::assertStringContainsString('An ["it","is","working"] test', $text);
-       }
-
-       /**
-        * Test if a log entry contains all necessary information
-        */
-       public function testContainsInformation()
-       {
-               $logger = $this->getInstance();
-               $logger->emergency('A test');
-
-               $text = $this->getContent();
-               self::assertStringContainsString('"file":"' . self::FILE . '"', $text);
-               self::assertStringContainsString('"line":' . self::LINE, $text);
-               self::assertStringContainsString('"function":"' . self::FUNC . '"', $text);
-       }
-
-       /**
-        * Test if the minimum level is working
-        */
-       public function testMinimumLevel()
-       {
-               $logger = $this->getInstance(LogLevel::NOTICE);
-
-               $logger->emergency('working');
-               $logger->alert('working');
-               $logger->error('working');
-               $logger->warning('working');
-               $logger->notice('working');
-               $logger->info('not working');
-               $logger->debug('not working');
-
-               $text = $this->getContent();
-
-               self::assertLoglineNums(5, $text);
-       }
-
-       /**
-        * Test with different logging data
-        * @dataProvider dataTests
-        */
-       public function testDifferentTypes($function, $message, array $context)
-       {
-               $logger = $this->getInstance();
-               $logger->$function($message, $context);
-
-               $text = $this->getContent();
-
-               self::assertLogline($text);
-
-               self::assertStringContainsString(@json_encode($context), $text);
-       }
-
-       /**
-        * Test a message with an exception
-        */
-       public function testExceptionHandling()
-       {
-               $e = new \Exception("Test String", 123);
-               $eFollowUp = new \Exception("FollowUp", 456, $e);
-
-               $assertion = $eFollowUp->__toString();
-
-               $logger = $this->getInstance();
-               $logger->alert('test', ['e' => $eFollowUp]);
-               $text = $this->getContent();
-
-               self::assertLogline($text);
-
-               self::assertStringContainsString(@json_encode($assertion), $this->getContent());
-       }
-
-       public function testNoObjectHandling()
-       {
-               $logger = $this->getInstance();
-               $logger->alert('test', ['e' => ['test' => 'test']]);
-               $text = $this->getContent();
-
-               self::assertLogline($text);
-
-               self::assertStringContainsString('test', $this->getContent());
-       }
-}
diff --git a/tests/src/Util/Logger/LoggerDataTrait.php b/tests/src/Util/Logger/LoggerDataTrait.php
deleted file mode 100644 (file)
index 0bebe7d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-trait LoggerDataTrait
-{
-       public function dataTests()
-       {
-               return [
-                       'emergency' => [
-                               'function' => 'emergency',
-                               'message' => 'test',
-                               'context' => ['a' => 'context'],
-                       ],
-                       'alert' => [
-                               'function' => 'alert',
-                               'message' => 'test {test}',
-                               'context' => ['a' => 'context', 2 => 'so', 'test' => 'works'],
-                       ],
-                       'critical' => [
-                               'function' => 'critical',
-                               'message' => 'test crit 2345',
-                               'context' => ['a' => 'context', 'wit' => ['more', 'array']],
-                       ],
-                       'error' => [
-                               'function' => 'error',
-                               'message' => 2.554,
-                               'context' => [],
-                       ],
-                       'warning' => [
-                               'function' => 'warning',
-                               'message' => 'test warn',
-                               'context' => ['a' => 'context'],
-                       ],
-                       'notice' => [
-                               'function' => 'notice',
-                               'message' => 2346,
-                               'context' => ['a' => 'context'],
-                       ],
-                       'info' => [
-                               'function' => 'info',
-                               'message' => null,
-                               'context' => ['a' => 'context'],
-                       ],
-                       'debug' => [
-                               'function' => 'debug',
-                               'message' => true,
-                               'context' => ['a' => false],
-                       ],
-               ];
-       }
-}
diff --git a/tests/src/Util/Logger/ProfilerLoggerTest.php b/tests/src/Util/Logger/ProfilerLoggerTest.php
deleted file mode 100644 (file)
index 7b62446..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Test\MockedTest;
-use Friendica\Util\Logger\ProfilerLogger;
-use Friendica\Util\Profiler;
-use Mockery\MockInterface;
-use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
-
-class ProfilerLoggerTest extends MockedTest
-{
-       use LoggerDataTrait;
-
-       /**
-        * @var LoggerInterface|MockInterface
-        */
-       private $logger;
-       /**
-        * @var Profiler|MockInterface
-        */
-       private $profiler;
-
-       protected function setUp(): void
-       {
-               parent::setUp();
-
-               $this->logger = \Mockery::mock(LoggerInterface::class);
-               $this->profiler = \Mockery::mock(Profiler::class);
-       }
-
-       /**
-        * Test if the profiler is profiling data
-        * @dataProvider dataTests
-        * @doesNotPerformAssertions
-        */
-       public function testProfiling($function, $message, array $context)
-       {
-               $logger = new ProfilerLogger($this->logger, $this->profiler);
-
-               $this->logger->shouldReceive($function)->with($message, $context)->once();
-               $this->profiler->shouldReceive('startRecording')->with('file')->once();
-               $this->profiler->shouldReceive('stopRecording');
-               $this->profiler->shouldReceive('saveTimestamp');
-               $logger->$function($message, $context);
-       }
-
-       /**
-        * Test the log() function
-        * @doesNotPerformAssertions
-        */
-       public function testProfilingLog()
-       {
-               $logger = new ProfilerLogger($this->logger, $this->profiler);
-
-               $this->logger->shouldReceive('log')->with(LogLevel::WARNING, 'test', ['a' => 'context'])->once();
-               $this->profiler->shouldReceive('startRecording')->with('file')->once();
-               $this->profiler->shouldReceive('stopRecording');
-               $this->profiler->shouldReceive('saveTimestamp');
-
-               $logger->log(LogLevel::WARNING, 'test', ['a' => 'context']);
-       }
-}
diff --git a/tests/src/Util/Logger/StreamLoggerTest.php b/tests/src/Util/Logger/StreamLoggerTest.php
deleted file mode 100644 (file)
index 8599e08..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Util\FileSystem;
-use Friendica\Test\Util\VFSTrait;
-use Friendica\Util\Logger\StreamLogger;
-use org\bovigo\vfs\vfsStream;
-use org\bovigo\vfs\vfsStreamFile;
-use Psr\Log\LogLevel;
-
-class StreamLoggerTest extends AbstractLoggerTest
-{
-       use VFSTrait;
-
-       /**
-        * @var vfsStreamFile
-        */
-       private $logfile;
-
-       /**
-        * @var Filesystem
-        */
-       private $fileSystem;
-
-       protected function setUp(): void
-       {
-               parent::setUp();
-
-               $this->setUpVfsDir();
-
-               $this->fileSystem = new FileSystem();
-       }
-
-       /**
-        * {@@inheritdoc}
-        */
-       protected function getInstance($level = LogLevel::DEBUG)
-       {
-               $this->logfile = vfsStream::newFile('friendica.log')
-                       ->at($this->root);
-
-               $logger = new StreamLogger('test', $this->logfile->url(), $this->introspection, $this->fileSystem, $level);
-
-               return $logger;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       protected function getContent()
-       {
-               return $this->logfile->getContent();
-       }
-
-       /**
-        * Test if a stream is working
-        */
-       public function testStream()
-       {
-               $logfile = vfsStream::newFile('friendica.log')
-                       ->at($this->root);
-
-               $filehandler = fopen($logfile->url(), 'ab');
-
-               $logger = new StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem);
-               $logger->emergency('working');
-
-               $text = $logfile->getContent();
-
-               self::assertLogline($text);
-       }
-
-       /**
-        * Test if the close statement is working
-        */
-       public function testClose()
-       {
-               $logfile = vfsStream::newFile('friendica.log')
-                       ->at($this->root);
-
-               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
-               $logger->emergency('working');
-               $logger->close();
-               // close doesn't affect
-               $logger->emergency('working too');
-
-               $text = $logfile->getContent();
-
-               self::assertLoglineNums(2, $text);
-       }
-
-       /**
-        * Test when a file isn't set
-        */
-       public function testNoUrl()
-       {
-               $this->expectException(\LogicException::class);
-               $this->expectExceptionMessage("Missing stream URL.");
-
-               $logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem);
-
-               $logger->emergency('not working');
-       }
-
-       /**
-        * Test when a file cannot be opened
-        */
-       public function testWrongUrl()
-       {
-               $this->expectException(\UnexpectedValueException::class);
-               $this->expectExceptionMessageMatches("/The stream or file .* could not be opened: .* /");
-
-               $logfile = vfsStream::newFile('friendica.log')
-                       ->at($this->root)->chmod(0);
-
-               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
-
-               $logger->emergency('not working');
-       }
-
-       /**
-        * Test when the directory cannot get created
-        */
-       public function testWrongDir()
-       {
-               $this->expectException(\UnexpectedValueException::class);
-               $this->expectExceptionMessageMatches("/Directory .* cannot get created: .* /");
-
-               static::markTestIncomplete('We need a platform independent way to set directory to readonly');
-
-               $logger = new StreamLogger('test', '/$%/wrong/directory/file.txt', $this->introspection, $this->fileSystem);
-
-               $logger->emergency('not working');
-       }
-
-       /**
-        * Test when the minimum level is not valid
-        */
-       public function testWrongMinimumLevel()
-       {
-               $this->expectException(\InvalidArgumentException::class);
-               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
-
-               $logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE');
-       }
-
-       /**
-        * Test when the minimum level is not valid
-        */
-       public function testWrongLogLevel()
-       {
-               $this->expectException(\InvalidArgumentException::class);
-               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
-
-               $logfile = vfsStream::newFile('friendica.log')
-                       ->at($this->root);
-
-               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem);
-
-               $logger->log('NOPE', 'a test');
-       }
-
-       /**
-        * Test when the file is null
-        */
-       public function testWrongFile()
-       {
-               $this->expectException(\InvalidArgumentException::class);
-               $this->expectExceptionMessage("A stream must either be a resource or a string.");
-
-               $logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem);
-       }
-
-       /**
-        * Test a relative path
-        * @doesNotPerformAssertions
-        */
-       public function testRealPath()
-       {
-               static::markTestSkipped('vfsStream isn\'t compatible with chdir, so not testable.');
-
-               $logfile = vfsStream::newFile('friendica.log')
-                                   ->at($this->root);
-
-               chdir($this->root->getChild('logs')->url());
-
-               $logger = new StreamLogger('test', '../friendica.log' , $this->introspection, $this->fileSystem);
-
-               $logger->info('Test');
-       }
-}
diff --git a/tests/src/Util/Logger/SyslogLoggerTest.php b/tests/src/Util/Logger/SyslogLoggerTest.php
deleted file mode 100644 (file)
index e93e43d..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Util\Logger\SyslogLogger;
-use Psr\Log\LogLevel;
-
-class SyslogLoggerTest extends AbstractLoggerTest
-{
-       /**
-        * @var SyslogLoggerWrapper
-        */
-       private $logger;
-
-       protected function setUp(): void
-       {
-               parent::setUp();
-
-               $this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       protected function getContent()
-       {
-               return $this->logger->getContent();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       protected function getInstance($level = LogLevel::DEBUG)
-       {
-               $this->logger = new SyslogLoggerWrapper('test', $this->introspection, $level);
-
-               return $this->logger;
-       }
-
-
-       /**
-        * Test when the minimum level is not valid
-        */
-       public function testWrongMinimumLevel()
-       {
-               $this->expectException(\InvalidArgumentException::class);
-               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
-               
-               $logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE');
-       }
-
-       /**
-        * Test when the minimum level is not valid
-        */
-       public function testWrongLogLevel()
-       {
-               $this->expectException(\InvalidArgumentException::class);
-               $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
-
-               $logger = new SyslogLoggerWrapper('test', $this->introspection);
-
-               $logger->log('NOPE', 'a test');
-       }
-
-       /**
-        * Test when the logfacility is wrong (string)
-        */
-       public function testServerException()
-       {
-               if (PHP_MAJOR_VERSION < 8) {
-                       $this->expectException(\UnexpectedValueException::class);
-                       $this->expectExceptionMessageMatches("/Can\'t open syslog for ident \".*\" and facility \".*\": .* /");
-               } else {
-                       $this->expectException(\TypeError::class);
-                       $this->expectExceptionMessage("openlog(): Argument #3 (\$facility) must be of type int, string given");
-               }
-
-               $logger = new SyslogLoggerWrapper('test', $this->introspection, LogLevel::DEBUG, null, 'a string');
-               $logger->emergency('not working');
-       }
-
-       /**
-        * Test the close() method
-        * @doesNotPerformAssertions
-        */
-       public function testClose()
-       {
-               $logger = new SyslogLoggerWrapper('test', $this->introspection);
-               $logger->emergency('test');
-               $logger->close();
-               // Reopened itself
-               $logger->emergency('test');
-       }
-}
diff --git a/tests/src/Util/Logger/SyslogLoggerWrapper.php b/tests/src/Util/Logger/SyslogLoggerWrapper.php
deleted file mode 100644 (file)
index 710899c..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Util\Introspection;
-use Friendica\Util\Logger\SyslogLogger;
-use Psr\Log\LogLevel;
-
-/**
- * Wraps the SyslogLogger for replacing the syslog call with a string field.
- */
-class SyslogLoggerWrapper extends SyslogLogger
-{
-       private $content;
-
-       public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
-       {
-               parent::__construct($channel, $introspection, $level, $logOpts, $logFacility);
-
-               $this->content = '';
-       }
-
-       /**
-        * Gets the content from the wrapped Syslog
-        *
-        * @return string
-        */
-       public function getContent()
-       {
-               return $this->content;
-       }
-
-       /**
-        * {@inheritdoc}
-        * @noinspection PhpMissingParentCallCommonInspection
-        */
-       protected function syslogWrapper($level, $entry)
-       {
-               $this->content .= $entry . PHP_EOL;
-       }
-}
diff --git a/tests/src/Util/Logger/VoidLoggerTest.php b/tests/src/Util/Logger/VoidLoggerTest.php
deleted file mode 100644 (file)
index 75b2d1a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Test\MockedTest;
-use Friendica\Util\Logger\VoidLogger;
-use Psr\Log\LogLevel;
-
-class VoidLoggerTest extends MockedTest
-{
-       use LoggerDataTrait;
-
-       /**
-        * Test if the profiler is profiling data
-        * @dataProvider dataTests
-        * @doesNotPerformAssertions
-        */
-       public function testNormal($function, $message, array $context)
-       {
-               $logger = new VoidLogger();
-               $logger->$function($message, $context);
-       }
-
-       /**
-        * Test the log() function
-        * @doesNotPerformAssertions
-        */
-       public function testProfilingLog()
-       {
-               $logger = new VoidLogger();
-               $logger->log(LogLevel::WARNING, 'test', ['a' => 'context']);
-       }
-}
diff --git a/tests/src/Util/Logger/WorkerLoggerTest.php b/tests/src/Util/Logger/WorkerLoggerTest.php
deleted file mode 100644 (file)
index 06fae3c..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @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 <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Test\src\Util\Logger;
-
-use Friendica\Test\MockedTest;
-use Friendica\Util\Logger\WorkerLogger;
-use Psr\Log\LoggerInterface;
-
-class WorkerLoggerTest extends MockedTest
-{
-       private function assertUid($uid, $length = 7)
-       {
-               self::assertRegExp('/^[a-zA-Z0-9]{' . $length . '}+$/', $uid);
-       }
-
-       /**
-        * Test the a id with length zero
-        *
-        */
-       public function testGetWorkerIdZero()
-       {
-               $this->expectException(\Error::class);
-               
-               $logger = \Mockery::mock(LoggerInterface::class);
-               new WorkerLogger($logger, 'test', 0);
-       }
-
-       /**
-        * Test the generated Uid
-        */
-       public function testGetWorkerId()
-       {
-               $logger = \Mockery::mock(LoggerInterface::class);
-               for ($i = 1; $i < 14; $i++) {
-                       $workLogger = new WorkerLogger($logger, 'test', $i);
-                       $uid = $workLogger->getWorkerId();
-                       self::assertUid($uid, $i);
-               }
-       }
-
-       public function dataTest()
-       {
-               return [
-                       'info' => [
-                               'func' => 'info',
-                               'msg' => 'the alert',
-                               'context' => [],
-                       ],
-                       'alert' => [
-                               'func' => 'alert',
-                               'msg' => 'another alert',
-                               'context' => ['test' => 'it'],
-                       ],
-                       'critical' => [
-                               'func' => 'critical',
-                               'msg' => 'Critical msg used',
-                               'context' => ['test' => 'it', 'more' => 0.24545],
-                       ],
-                       'error' => [
-                               'func' => 'error',
-                               'msg' => 21345623,
-                               'context' => ['test' => 'it', 'yet' => true],
-                       ],
-                       'warning' => [
-                               'func' => 'warning',
-                               'msg' => 'another alert' . 123523 . 324.54534 . 'test',
-                               'context' => ['test' => 'it', 2 => 'nope'],
-                       ],
-                       'notice' => [
-                               'func' => 'notice',
-                               'msg' => 'Notice' . ' alert' . true . 'with' . '\'strange\'' . 1.24. 'behavior',
-                               'context' => ['test' => 'it'],
-                       ],
-                       'debug' => [
-                               'func' => 'debug',
-                               'msg' => 'at last a debug',
-                               'context' => ['test' => 'it'],
-                       ],
-               ];
-       }
-
-       /**
-        * Test the WorkerLogger with different log calls
-        * @dataProvider dataTest
-        */
-       public function testEmergency($func, $msg, $context = [])
-       {
-               $logger = \Mockery::mock(LoggerInterface::class);
-               $workLogger = new WorkerLogger($logger, 'test');
-               $testContext = $context;
-               $testContext['worker_id'] = $workLogger->getWorkerId();
-               $testContext['worker_cmd'] = 'test';
-               self::assertUid($testContext['worker_id']);
-               $logger
-                       ->shouldReceive($func)
-                       ->with($msg, $testContext)
-                       ->once();
-               $workLogger->$func($msg, $context);
-       }
-
-       /**
-        * Test the WorkerLogger with
-        */
-       public function testLog()
-       {
-               $logger = \Mockery::mock(LoggerInterface::class);
-               $workLogger = new WorkerLogger($logger, 'test');
-               $context = $testContext = ['test' => 'it'];
-               $testContext['worker_id'] = $workLogger->getWorkerId();
-               $testContext['worker_cmd'] = 'test';
-               self::assertUid($testContext['worker_id']);
-               $logger
-                       ->shouldReceive('log')
-                       ->with('debug', 'a test', $testContext)
-                       ->once();
-               $workLogger->log('debug', 'a test', $context);
-       }
-}