Restructure Logger to new paradigm

This commit is contained in:
Philipp 2021-10-23 12:22:27 +02:00
parent 0fe545ab17
commit 184f6cc255
No known key found for this signature in database
GPG Key ID: 24A7501396EB5432
28 changed files with 219 additions and 169 deletions

View File

@ -22,7 +22,7 @@
namespace Friendica\Core; namespace Friendica\Core;
use Friendica\DI; use Friendica\DI;
use Friendica\Util\Logger\WorkerLogger; use Friendica\Core\Logger\Type\WorkerLogger;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -19,20 +19,20 @@
* *
*/ */
namespace Friendica\Factory; namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger; use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Core;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Util\FileSystem; use Friendica\Util\FileSystem;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
use Friendica\Util\Logger\Monolog\DevelopHandler; use Friendica\Core\Logger\Type\Monolog\DevelopHandler;
use Friendica\Util\Logger\Monolog\IntrospectionProcessor; use Friendica\Core\Logger\Type\Monolog\IntrospectionProcessor;
use Friendica\Util\Logger\ProfilerLogger; use Friendica\Core\Logger\Type\ProfilerLogger;
use Friendica\Util\Logger\StreamLogger; use Friendica\Core\Logger\Type\StreamLogger;
use Friendica\Util\Logger\SyslogLogger; use Friendica\Core\Logger\Type\SyslogLogger;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Monolog; use Monolog;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -40,24 +40,24 @@ use Psr\Log\LogLevel;
/** /**
* A logger factory * A logger factory
*
* Currently only Monolog is supported
*/ */
class LoggerFactory class Logger
{ {
const DEV_CHANNEL = 'dev'; const DEV_CHANNEL = 'dev';
/** /**
* A list of classes, which shouldn't get logged * A list of classes, which shouldn't get logged
* *
* @var array * @var string[]
*/ */
private static $ignoreClassList = [ private static $ignoreClassList = [
Logger::class, Core\Logger::class,
Profiler::class, Profiler::class,
'Friendica\\Util\\Logger', 'Friendica\\Core\\Logger\\Type',
'Friendica\\Core\\Logger\\Type\\Monolog',
]; ];
/** @var string The log-channel (app, worker, ...) */
private $channel; private $channel;
public function __construct(string $channel) public function __construct(string $channel)
@ -75,7 +75,7 @@ class LoggerFactory
* *
* @return LoggerInterface The PSR-3 compliant logger instance * @return LoggerInterface The PSR-3 compliant logger instance
*/ */
public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem) public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem): LoggerInterface
{ {
if (empty($config->get('system', 'debugging', false))) { if (empty($config->get('system', 'debugging', false))) {
$logger = new VoidLogger(); $logger = new VoidLogger();
@ -106,6 +106,7 @@ class LoggerFactory
static::addStreamHandler($logger, $stream, $loglevel); static::addStreamHandler($logger, $stream, $loglevel);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// No Logger .. // No Logger ..
/// @todo isn't it possible to give the admin any hint about this wrong configuration?
$logger = new VoidLogger(); $logger = new VoidLogger();
} }
} }
@ -116,6 +117,7 @@ class LoggerFactory
$logger = new SyslogLogger($this->channel, $introspection, $loglevel); $logger = new SyslogLogger($this->channel, $introspection, $loglevel);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// No logger ... // No logger ...
/// @todo isn't it possible to give the admin any hint about this wrong configuration?
$logger = new VoidLogger(); $logger = new VoidLogger();
} }
break; break;
@ -129,9 +131,11 @@ class LoggerFactory
$logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel); $logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel);
} catch (\Throwable $t) { } catch (\Throwable $t) {
// No logger ... // No logger ...
/// @todo isn't it possible to give the admin any hint about this wrong configuration?
$logger = new VoidLogger(); $logger = new VoidLogger();
} }
} else { } else {
/// @todo isn't it possible to give the admin any hint about this wrong configuration?
$logger = new VoidLogger(); $logger = new VoidLogger();
} }
break; break;
@ -161,8 +165,6 @@ class LoggerFactory
* @param FileSystem $fileSystem FileSystem utils * @param FileSystem $fileSystem FileSystem utils
* *
* @return LoggerInterface The PSR-3 compliant logger instance * @return LoggerInterface The PSR-3 compliant logger instance
*
* @throws InternalServerErrorException
* @throws \Exception * @throws \Exception
*/ */
public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem) public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem)
@ -172,9 +174,8 @@ class LoggerFactory
$developerIp = $config->get('system', 'dlogip'); $developerIp = $config->get('system', 'dlogip');
if ((!isset($developerIp) || !$debugging) && if ((!isset($developerIp) || !$debugging) &&
(!is_file($stream) || is_writable($stream))) { (!is_file($stream) || is_writable($stream))) {
$logger = new VoidLogger(); return new VoidLogger();
return $logger;
} }
$loggerTimeZone = new \DateTimeZone('UTC'); $loggerTimeZone = new \DateTimeZone('UTC');
@ -228,7 +229,7 @@ class LoggerFactory
* *
* @return string the PSR-3 compliant level * @return string the PSR-3 compliant level
*/ */
private static function mapLegacyConfigDebugLevel($level) private static function mapLegacyConfigDebugLevel(string $level): string
{ {
switch ($level) { switch ($level) {
// legacy WARNING // legacy WARNING
@ -263,9 +264,9 @@ class LoggerFactory
* *
* @return void * @return void
* *
* @throws \Exception in case of general failures * @throws LoggerException
*/ */
public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE) public static function addStreamHandler(LoggerInterface $logger, $stream, string $level = LogLevel::NOTICE)
{ {
if ($logger instanceof Monolog\Logger) { if ($logger instanceof Monolog\Logger) {
$loglevel = Monolog\Logger::toMonologLevel($level); $loglevel = Monolog\Logger::toMonologLevel($level);
@ -275,19 +276,16 @@ class LoggerFactory
$loglevel = LogLevel::NOTICE; $loglevel = LogLevel::NOTICE;
} }
$fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel); try {
$fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
$formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n"); $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
$fileHandler->setFormatter($formatter); $fileHandler->setFormatter($formatter);
$logger->pushHandler($fileHandler); $logger->pushHandler($fileHandler);
} } catch (\Exception $exception) {
} throw new LoggerException('Cannot create Monolog Logger.', $exception);
}
public static function addVoidHandler($logger)
{
if ($logger instanceof Monolog\Logger) {
$logger->pushHandler(new Monolog\Handler\NullHandler());
} }
} }
} }

View File

@ -19,8 +19,9 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -58,29 +59,35 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* Adds a new entry to the log * Adds a new entry to the log
* *
* @param int $level * @param mixed $level
* @param string $message * @param string $message
* @param array $context * @param array $context
* *
* @return void * @return void
*/ */
abstract protected function addEntry($level, $message, $context = []); abstract protected function addEntry($level, string $message, array $context = []);
/** /**
* @param string $channel The output channel * @param string $channel The output channel
* @param Introspection $introspection The introspection of the current call * @param Introspection $introspection The introspection of the current call
* *
* @throws \Exception * @throws LoggerException
*/ */
public function __construct($channel, Introspection $introspection) public function __construct(string $channel, Introspection $introspection)
{ {
$this->channel = $channel; $this->channel = $channel;
$this->introspection = $introspection; $this->introspection = $introspection;
$this->logUid = Strings::getRandomHex(6);
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 '}' ) * Simple interpolation of PSR-3 compliant replacements ( variables between '{' and '}' )
*
* @see https://www.php-fig.org/psr/psr-3/#12-message * @see https://www.php-fig.org/psr/psr-3/#12-message
* *
* @param string $message * @param string $message
@ -88,7 +95,7 @@ abstract class AbstractLogger implements LoggerInterface
* *
* @return string the interpolated message * @return string the interpolated message
*/ */
protected function psrInterpolate($message, array $context = array()) protected function psrInterpolate(string $message, array $context = []): string
{ {
$replace = []; $replace = [];
foreach ($context as $key => $value) { foreach ($context as $key => $value) {
@ -104,7 +111,7 @@ abstract class AbstractLogger implements LoggerInterface
} }
/** /**
* JSON Encodes an complete array including objects with "__toString()" methods * JSON Encodes a complete array including objects with "__toString()" methods
* *
* @param array $input an Input Array to encode * @param array $input an Input Array to encode
* *
@ -128,7 +135,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function emergency($message, array $context = array()) public function emergency($message, array $context = [])
{ {
$this->addEntry(LogLevel::EMERGENCY, (string) $message, $context); $this->addEntry(LogLevel::EMERGENCY, (string) $message, $context);
} }
@ -136,7 +143,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function alert($message, array $context = array()) public function alert($message, array $context = [])
{ {
$this->addEntry(LogLevel::ALERT, (string) $message, $context); $this->addEntry(LogLevel::ALERT, (string) $message, $context);
} }
@ -144,7 +151,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function critical($message, array $context = array()) public function critical($message, array $context = [])
{ {
$this->addEntry(LogLevel::CRITICAL, (string) $message, $context); $this->addEntry(LogLevel::CRITICAL, (string) $message, $context);
} }
@ -152,7 +159,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function error($message, array $context = array()) public function error($message, array $context = [])
{ {
$this->addEntry(LogLevel::ERROR, (string) $message, $context); $this->addEntry(LogLevel::ERROR, (string) $message, $context);
} }
@ -160,7 +167,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function warning($message, array $context = array()) public function warning($message, array $context = [])
{ {
$this->addEntry(LogLevel::WARNING, (string) $message, $context); $this->addEntry(LogLevel::WARNING, (string) $message, $context);
} }
@ -168,7 +175,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function notice($message, array $context = array()) public function notice($message, array $context = [])
{ {
$this->addEntry(LogLevel::NOTICE, (string) $message, $context); $this->addEntry(LogLevel::NOTICE, (string) $message, $context);
} }
@ -176,7 +183,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function info($message, array $context = array()) public function info($message, array $context = [])
{ {
$this->addEntry(LogLevel::INFO, (string) $message, $context); $this->addEntry(LogLevel::INFO, (string) $message, $context);
} }
@ -184,7 +191,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function debug($message, array $context = array()) public function debug($message, array $context = [])
{ {
$this->addEntry(LogLevel::DEBUG, (string) $message, $context); $this->addEntry(LogLevel::DEBUG, (string) $message, $context);
} }
@ -192,7 +199,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = [])
{ {
$this->addEntry($level, (string) $message, $context); $this->addEntry($level, (string) $message, $context);
} }

View File

@ -19,7 +19,7 @@
* *
*/ */
namespace Friendica\Util\Logger\Monolog; namespace Friendica\Core\Logger\Type\Monolog;
use Monolog\Handler; use Monolog\Handler;
use Monolog\Logger; use Monolog\Logger;
@ -42,7 +42,7 @@ class DevelopHandler extends Handler\AbstractHandler
* @param int $level The minimum logging level at which this handler will be triggered * @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 * @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) public function __construct($developerIp, $level = Logger::DEBUG, bool $bubble = true)
{ {
parent::__construct($level, $bubble); parent::__construct($level, $bubble);
@ -52,15 +52,14 @@ class DevelopHandler extends Handler\AbstractHandler
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function handle(array $record) public function handle(array $record): bool
{ {
if (!$this->isHandling($record)) { if (!$this->isHandling($record)) {
return false; return false;
} }
/// Just in case the remote IP is the same as the developer IP log the output /// 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) if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp) {
{
return false; return false;
} }

View File

@ -19,7 +19,7 @@
* *
*/ */
namespace Friendica\Util\Logger\Monolog; namespace Friendica\Core\Logger\Type\Monolog;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
use Monolog\Logger; use Monolog\Logger;
@ -41,11 +41,11 @@ class IntrospectionProcessor implements ProcessorInterface
public function __construct(Introspection $introspection, $level = Logger::DEBUG) public function __construct(Introspection $introspection, $level = Logger::DEBUG)
{ {
$this->level = Logger::toMonologLevel($level); $this->level = Logger::toMonologLevel($level);
$introspection->addClasses(array('Monolog\\')); $introspection->addClasses(['Monolog\\']);
$this->introspection = $introspection; $this->introspection = $introspection;
} }
public function __invoke(array $record) public function __invoke(array $record): array
{ {
// return if the level is not high enough // return if the level is not high enough
if ($record['level'] < $this->level) { if ($record['level'] < $this->level) {

View File

@ -19,9 +19,8 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Friendica\Core\System;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -50,14 +49,14 @@ class ProfilerLogger implements LoggerInterface
*/ */
public function __construct(LoggerInterface $logger, Profiler $profiler) public function __construct(LoggerInterface $logger, Profiler $profiler)
{ {
$this->logger = $logger; $this->logger = $logger;
$this->profiler = $profiler; $this->profiler = $profiler;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function emergency($message, array $context = array()) public function emergency($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->emergency($message, $context); $this->logger->emergency($message, $context);
@ -67,7 +66,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function alert($message, array $context = array()) public function alert($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->alert($message, $context); $this->logger->alert($message, $context);
@ -77,7 +76,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function critical($message, array $context = array()) public function critical($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->critical($message, $context); $this->logger->critical($message, $context);
@ -87,7 +86,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function error($message, array $context = array()) public function error($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->error($message, $context); $this->logger->error($message, $context);
@ -97,7 +96,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function warning($message, array $context = array()) public function warning($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->warning($message, $context); $this->logger->warning($message, $context);
@ -107,7 +106,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function notice($message, array $context = array()) public function notice($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->notice($message, $context); $this->logger->notice($message, $context);
@ -117,7 +116,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function info($message, array $context = array()) public function info($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->info($message, $context); $this->logger->info($message, $context);
@ -127,7 +126,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function debug($message, array $context = array()) public function debug($message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->debug($message, $context); $this->logger->debug($message, $context);
@ -137,7 +136,7 @@ class ProfilerLogger implements LoggerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = [])
{ {
$this->profiler->startRecording('file'); $this->profiler->startRecording('file');
$this->logger->log($level, $message, $context); $this->logger->log($level, $message, $context);

View File

@ -19,8 +19,10 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\FileSystem; use Friendica\Util\FileSystem;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
@ -80,9 +82,9 @@ class StreamLogger extends AbstractLogger
* @param string|resource $stream The stream to write with this logger (either a file or a stream, i.e. stdout) * @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 * @param string $level The minimum loglevel at which this logger will be triggered
* *
* @throws \Exception * @throws LoggerArgumentException
*/ */
public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, $level = LogLevel::DEBUG) public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG)
{ {
$this->fileSystem = $fileSystem; $this->fileSystem = $fileSystem;
@ -93,14 +95,14 @@ class StreamLogger extends AbstractLogger
} elseif (is_string($stream)) { } elseif (is_string($stream)) {
$this->url = $stream; $this->url = $stream;
} else { } else {
throw new \InvalidArgumentException('A stream must either be a resource or a string.'); throw new LoggerArgumentException('A stream must either be a resource or a string.');
} }
$this->pid = getmypid(); $this->pid = getmypid();
if (array_key_exists($level, $this->levelToInt)) { if (array_key_exists($level, $this->levelToInt)) {
$this->logLevel = $this->levelToInt[$level]; $this->logLevel = $this->levelToInt[$level];
} else { } else {
throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level)); throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
} }
$this->checkStream(); $this->checkStream();
@ -118,16 +120,19 @@ class StreamLogger extends AbstractLogger
/** /**
* Adds a new entry to the log * Adds a new entry to the log
* *
* @param int $level * @param mixed $level
* @param string $message * @param string $message
* @param array $context * @param array $context
* *
* @return void * @return void
*
* @throws LoggerException
* @throws LoggerArgumentException
*/ */
protected function addEntry($level, $message, $context = []) protected function addEntry($level, string $message, array $context = [])
{ {
if (!array_key_exists($level, $this->levelToInt)) { if (!array_key_exists($level, $this->levelToInt)) {
throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level)); throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
} }
$logLevel = $this->levelToInt[$level]; $logLevel = $this->levelToInt[$level];
@ -145,19 +150,24 @@ class StreamLogger extends AbstractLogger
/** /**
* Formats a log record for the syslog output * Formats a log record for the syslog output
* *
* @param int $level The loglevel/priority * @param mixed $level The loglevel/priority
* @param string $message The message * @param string $message The message
* @param array $context The context of this call * @param array $context The context of this call
* *
* @return string the formatted syslog output * @return string the formatted syslog output
*
* @throws LoggerException
*/ */
private function formatLog($level, $message, $context = []) private function formatLog($level, string $message, array $context = []): string
{ {
$record = $this->introspection->getRecord(); $record = $this->introspection->getRecord();
$record = array_merge($record, ['uid' => $this->logUid, 'process_id' => $this->pid]); $record = array_merge($record, ['uid' => $this->logUid, 'process_id' => $this->pid]);
$logMessage = '';
$logMessage .= DateTimeFormat::utcNow(DateTimeFormat::ATOM) . ' '; try {
$logMessage = DateTimeFormat::utcNow(DateTimeFormat::ATOM) . ' ';
} catch (\Exception $exception) {
throw new LoggerException('Cannot get current datetime.', $exception);
}
$logMessage .= $this->channel . ' '; $logMessage .= $this->channel . ' ';
$logMessage .= '[' . strtoupper($level) . ']: '; $logMessage .= '[' . strtoupper($level) . ']: ';
$logMessage .= $this->psrInterpolate($message, $context) . ' '; $logMessage .= $this->psrInterpolate($message, $context) . ' ';
@ -168,6 +178,12 @@ class StreamLogger extends AbstractLogger
return $logMessage; return $logMessage;
} }
/**
* Checks the current stream
*
* @throws LoggerException
* @throws LoggerArgumentException
*/
private function checkStream() private function checkStream()
{ {
if (is_resource($this->stream)) { if (is_resource($this->stream)) {
@ -175,9 +191,13 @@ class StreamLogger extends AbstractLogger
} }
if (empty($this->url)) { if (empty($this->url)) {
throw new \LogicException('Missing stream URL.'); throw new LoggerArgumentException('Missing stream URL.');
} }
$this->stream = $this->fileSystem->createStream($this->url); try {
$this->stream = $this->fileSystem->createStream($this->url);
} catch (\UnexpectedValueException $exception) {
throw new LoggerException('Cannot create stream.', $exception);
}
} }
} }

View File

@ -19,10 +19,12 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
/** /**
@ -97,27 +99,28 @@ class SyslogLogger extends AbstractLogger
* @param int $logOpts Indicates what logging options will be used when generating a log message * @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 * @param int $logFacility Used to specify what type of program is logging the message
* *
* @throws \Exception * @throws LoggerArgumentException
*/ */
public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER) public function __construct($channel, Introspection $introspection, string $level = LogLevel::NOTICE, int $logOpts = LOG_PID, int $logFacility = LOG_USER)
{ {
parent::__construct($channel, $introspection); parent::__construct($channel, $introspection);
$this->logOpts = $logOpts; $this->logOpts = $logOpts;
$this->logFacility = $logFacility; $this->logFacility = $logFacility;
$this->logLevel = $this->mapLevelToPriority($level); $this->logLevel = $this->mapLevelToPriority($level);
$this->introspection->addClasses(array(self::class)); $this->introspection->addClasses([self::class]);
} }
/** /**
* Adds a new entry to the syslog * Adds a new entry to the syslog
* *
* @param int $level * @param mixed $level
* @param string $message * @param string $message
* @param array $context * @param array $context
* *
* @throws InternalServerErrorException if the syslog isn't available * @throws LoggerArgumentException in case the level isn't valid
* @throws LoggerException In case the syslog cannot be opened for writing
*/ */
protected function addEntry($level, $message, $context = []) protected function addEntry($level, string $message, array $context = [])
{ {
$logLevel = $this->mapLevelToPriority($level); $logLevel = $this->mapLevelToPriority($level);
@ -136,12 +139,12 @@ class SyslogLogger extends AbstractLogger
* *
* @return int The SysLog priority * @return int The SysLog priority
* *
* @throws \Psr\Log\InvalidArgumentException If the loglevel isn't valid * @throws LoggerArgumentException If the loglevel isn't valid
*/ */
public function mapLevelToPriority($level) public function mapLevelToPriority(string $level): int
{ {
if (!array_key_exists($level, $this->logLevels)) { if (!array_key_exists($level, $this->logLevels)) {
throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level)); throw new LoggerArgumentException(sprintf('The level "%s" is not valid.', $level));
} }
return $this->logLevels[$level]; return $this->logLevels[$level];
@ -157,21 +160,22 @@ class SyslogLogger extends AbstractLogger
/** /**
* Writes a message to the syslog * Writes a message to the syslog
*
* @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters * @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters
* *
* @param int $priority The Priority * @param int $priority The Priority
* @param string $message The message of the log * @param string $message The message of the log
* *
* @throws InternalServerErrorException if syslog cannot be used * @throws LoggerException In case the syslog cannot be opened/written
*/ */
private function write($priority, $message) private function write(int $priority, string $message)
{ {
set_error_handler([$this, 'customErrorHandler']); set_error_handler([$this, 'customErrorHandler']);
$opened = openlog(self::IDENT, $this->logOpts, $this->logFacility); $opened = openlog(self::IDENT, $this->logOpts, $this->logFacility);
restore_error_handler(); restore_error_handler();
if (!$opened) { if (!$opened) {
throw new \UnexpectedValueException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility)); throw new LoggerException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
} }
$this->syslogWrapper($priority, $message); $this->syslogWrapper($priority, $message);
@ -186,13 +190,12 @@ class SyslogLogger extends AbstractLogger
* *
* @return string the formatted syslog output * @return string the formatted syslog output
*/ */
private function formatLog($level, $message, $context = []) private function formatLog(int $level, string $message, array $context = []): string
{ {
$record = $this->introspection->getRecord(); $record = $this->introspection->getRecord();
$record = array_merge($record, ['uid' => $this->logUid]); $record = array_merge($record, ['uid' => $this->logUid]);
$logMessage = '';
$logMessage .= $this->channel . ' '; $logMessage = $this->channel . ' ';
$logMessage .= '[' . $this->logToString[$level] . ']: '; $logMessage .= '[' . $this->logToString[$level] . ']: ';
$logMessage .= $this->psrInterpolate($message, $context) . ' '; $logMessage .= $this->psrInterpolate($message, $context) . ' ';
$logMessage .= $this->jsonEncodeArray($context) . ' - '; $logMessage .= $this->jsonEncodeArray($context) . ' - ';
@ -211,15 +214,17 @@ class SyslogLogger extends AbstractLogger
* *
* @param int $level The syslog priority * @param int $level The syslog priority
* @param string $entry The message to send to the syslog function * @param string $entry The message to send to the syslog function
*
* @throws LoggerException
*/ */
protected function syslogWrapper($level, $entry) protected function syslogWrapper(int $level, string $entry)
{ {
set_error_handler([$this, 'customErrorHandler']); set_error_handler([$this, 'customErrorHandler']);
$written = syslog($level, $entry); $written = syslog($level, $entry);
restore_error_handler(); restore_error_handler();
if (!$written) { if (!$written) {
throw new \UnexpectedValueException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility)); throw new LoggerException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility));
} }
} }
} }

View File

@ -19,7 +19,7 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;

View File

@ -19,13 +19,14 @@
* *
*/ */
namespace Friendica\Util\Logger; namespace Friendica\Core\Logger\Type;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
* A Logger for specific worker tasks, which adds an additional woker-id to it. * A Logger for specific worker tasks, which adds a worker id to it.
* Uses the decorator pattern (https://en.wikipedia.org/wiki/Decorator_pattern) * Uses the decorator pattern (https://en.wikipedia.org/wiki/Decorator_pattern)
*/ */
class WorkerLogger implements LoggerInterface class WorkerLogger implements LoggerInterface
@ -46,15 +47,21 @@ class WorkerLogger implements LoggerInterface
private $functionName; private $functionName;
/** /**
* @param LoggerInterface $logger The logger for worker entries * @param LoggerInterface $logger The logger for worker entries
* @param string $functionName The current function name of the worker * @param string $functionName The current function name of the worker
* @param int $idLength The length of the generated worker ID * @param int $idLength The length of the generated worker ID
*
* @throws LoggerException
*/ */
public function __construct(LoggerInterface $logger, $functionName = '', $idLength = 7) public function __construct(LoggerInterface $logger, string $functionName = '', int $idLength = 7)
{ {
$this->logger = $logger; $this->logger = $logger;
$this->functionName = $functionName; $this->functionName = $functionName;
$this->workerId = Strings::getRandomHex($idLength); try {
$this->workerId = Strings::getRandomHex($idLength);
} catch (\Exception $exception) {
throw new LoggerException('Cannot generate random Hex.', $exception);
}
} }
/** /**
@ -74,7 +81,7 @@ class WorkerLogger implements LoggerInterface
*/ */
private function addContext(array &$context) private function addContext(array &$context)
{ {
$context['worker_id'] = $this->workerId; $context['worker_id'] = $this->workerId;
$context['worker_cmd'] = $this->functionName; $context['worker_cmd'] = $this->functionName;
} }
@ -83,7 +90,7 @@ class WorkerLogger implements LoggerInterface
* *
* @return string * @return string
*/ */
public function getWorkerId() public function getWorkerId(): string
{ {
return $this->workerId; return $this->workerId;
} }

View File

@ -243,7 +243,7 @@ abstract class DI
*/ */
public static function workerLogger() public static function workerLogger()
{ {
return self::$dice->create(Util\Logger\WorkerLogger::class); return self::$dice->create(Core\Logger\Type\WorkerLogger::class);
} }
// //

View File

@ -73,7 +73,9 @@ class FileSystem
* *
* @param string $url The file/url * @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) public function createStream(string $url)
{ {

View File

@ -141,7 +141,7 @@ return [
* and is automatically passed as an argument with the same name * and is automatically passed as an argument with the same name
*/ */
LoggerInterface::class => [ LoggerInterface::class => [
'instanceOf' => Factory\LoggerFactory::class, 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class,
'constructParams' => [ 'constructParams' => [
'index', 'index',
], ],
@ -150,7 +150,7 @@ return [
], ],
], ],
'$devLogger' => [ '$devLogger' => [
'instanceOf' => Factory\LoggerFactory::class, 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class,
'constructParams' => [ 'constructParams' => [
'dev', 'dev',
], ],

View File

@ -32,7 +32,7 @@ use Friendica\Database\Database;
use Friendica\DI; use Friendica\DI;
use Friendica\Test\Util\RendererMockTrait; use Friendica\Test\Util\RendererMockTrait;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
use Mockery; use Mockery;
use Mockery\MockInterface; use Mockery\MockInterface;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;

View File

@ -5,7 +5,7 @@ namespace Friendica\Test\src\Contact\FriendSuggest\Factory;
use Friendica\Contact\FriendSuggest\Factory\FriendSuggest; use Friendica\Contact\FriendSuggest\Factory\FriendSuggest;
use Friendica\Contact\FriendSuggest\Entity; use Friendica\Contact\FriendSuggest\Entity;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
class FriendSuggestTest extends MockedTest class FriendSuggestTest extends MockedTest
{ {

View File

@ -19,7 +19,7 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;

View File

@ -19,7 +19,7 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
trait LoggerDataTrait trait LoggerDataTrait
{ {

View File

@ -19,10 +19,10 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\Logger\ProfilerLogger; use Friendica\Core\Logger\Type\ProfilerLogger;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Mockery\MockInterface; use Mockery\MockInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;

View File

@ -19,11 +19,13 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Util\FileSystem; use Friendica\Util\FileSystem;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Logger\StreamLogger; use Friendica\Core\Logger\Type\StreamLogger;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamFile; use org\bovigo\vfs\vfsStreamFile;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
@ -82,7 +84,7 @@ class StreamLoggerTest extends AbstractLoggerTest
$filehandler = fopen($logfile->url(), 'ab'); $filehandler = fopen($logfile->url(), 'ab');
$logger = new StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem); $logger = new \Friendica\Core\Logger\Type\StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem);
$logger->emergency('working'); $logger->emergency('working');
$text = $logfile->getContent(); $text = $logfile->getContent();
@ -114,7 +116,7 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testNoUrl() public function testNoUrl()
{ {
$this->expectException(\LogicException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage("Missing stream URL."); $this->expectExceptionMessage("Missing stream URL.");
$logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem); $logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem);
@ -127,8 +129,8 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongUrl() public function testWrongUrl()
{ {
$this->expectException(\UnexpectedValueException::class); $this->expectException(LoggerException::class);
$this->expectExceptionMessageMatches("/The stream or file .* could not be opened: .* /"); $this->expectExceptionMessage("Cannot create stream.");
$logfile = vfsStream::newFile('friendica.log') $logfile = vfsStream::newFile('friendica.log')
->at($this->root)->chmod(0); ->at($this->root)->chmod(0);
@ -158,7 +160,7 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongMinimumLevel() public function testWrongMinimumLevel()
{ {
$this->expectException(\InvalidArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
$logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE'); $logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE');
@ -169,7 +171,7 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongLogLevel() public function testWrongLogLevel()
{ {
$this->expectException(\InvalidArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
$logfile = vfsStream::newFile('friendica.log') $logfile = vfsStream::newFile('friendica.log')
@ -185,7 +187,7 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongFile() public function testWrongFile()
{ {
$this->expectException(\InvalidArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage("A stream must either be a resource or a string."); $this->expectExceptionMessage("A stream must either be a resource or a string.");
$logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem); $logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem);

View File

@ -19,9 +19,11 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Util\Logger\SyslogLogger; use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Core\Logger\Type\SyslogLogger;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
class SyslogLoggerTest extends AbstractLoggerTest class SyslogLoggerTest extends AbstractLoggerTest
@ -62,7 +64,7 @@ class SyslogLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongMinimumLevel() public function testWrongMinimumLevel()
{ {
$this->expectException(\InvalidArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
$logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE'); $logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE');
@ -73,7 +75,7 @@ class SyslogLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongLogLevel() public function testWrongLogLevel()
{ {
$this->expectException(\InvalidArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./");
$logger = new SyslogLoggerWrapper('test', $this->introspection); $logger = new SyslogLoggerWrapper('test', $this->introspection);
@ -81,23 +83,6 @@ class SyslogLoggerTest extends AbstractLoggerTest
$logger->log('NOPE', 'a test'); $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 * Test the close() method
* @doesNotPerformAssertions * @doesNotPerformAssertions

View File

@ -19,10 +19,10 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Core\Logger\Type\SyslogLogger;
use Friendica\Util\Introspection; use Friendica\Util\Introspection;
use Friendica\Util\Logger\SyslogLogger;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
/** /**
@ -53,7 +53,7 @@ class SyslogLoggerWrapper extends SyslogLogger
* {@inheritdoc} * {@inheritdoc}
* @noinspection PhpMissingParentCallCommonInspection * @noinspection PhpMissingParentCallCommonInspection
*/ */
protected function syslogWrapper($level, $entry) protected function syslogWrapper(int $level, string $entry)
{ {
$this->content .= $entry . PHP_EOL; $this->content .= $entry . PHP_EOL;
} }

View File

@ -19,10 +19,10 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
class VoidLoggerTest extends MockedTest class VoidLoggerTest extends MockedTest

View File

@ -19,10 +19,10 @@
* *
*/ */
namespace Friendica\Test\src\Util\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Core\Logger\Type\WorkerLogger;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\Logger\WorkerLogger;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class WorkerLoggerTest extends MockedTest class WorkerLoggerTest extends MockedTest

View File

@ -11,7 +11,7 @@ use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFacto
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\ACLFormatter; use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
use Mockery\MockInterface; use Mockery\MockInterface;
class ProfileFieldTest extends MockedTest class ProfileFieldTest extends MockedTest

View File

@ -5,7 +5,7 @@ namespace Friendica\Test\src\Security\TwoFactor\Factory;
use Friendica\Security\TwoFactor\Factory\TrustedBrowser; use Friendica\Security\TwoFactor\Factory\TrustedBrowser;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Logger\VoidLogger; use Friendica\Core\Logger\Type\VoidLogger;
use Friendica\Util\Strings; use Friendica\Util\Strings;
class TrustedBrowserTest extends MockedTest class TrustedBrowserTest extends MockedTest