mirror of
https://github.com/friendica/friendica
synced 2025-04-26 03:50:12 +00:00
Merge pull request #12012 from nupplaphil/feat/move_monolog
Move Monolog to Addons
This commit is contained in:
commit
abf52c0c11
13 changed files with 92 additions and 338 deletions
|
@ -22,19 +22,16 @@
|
|||
namespace Friendica\Core\Logger\Factory;
|
||||
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Logger\Exception\LoggerException;
|
||||
use Friendica\Core;
|
||||
use Friendica\Core\Logger\Exception\LogLevelException;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Util\FileSystem;
|
||||
use Friendica\Core\Logger\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\Util\Profiler;
|
||||
use Monolog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\NullLogger;
|
||||
|
@ -60,9 +57,15 @@ class Logger
|
|||
/** @var string The log-channel (app, worker, ...) */
|
||||
private $channel;
|
||||
|
||||
public function __construct(string $channel)
|
||||
public function __construct(string $channel, bool $includeAddon = true)
|
||||
{
|
||||
$this->channel = $channel;
|
||||
|
||||
/// @fixme clean solution = Making Addon & Hook dynamic and load them inside the constructor, so there's no custom load logic necessary anymore
|
||||
if ($includeAddon) {
|
||||
Core\Addon::loadAddons();
|
||||
Core\Hook::loadHooks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,35 +91,9 @@ class Logger
|
|||
$minLevel = $minLevel ?? $config->get('system', 'loglevel');
|
||||
$loglevel = self::mapLegacyConfigDebugLevel((string)$minLevel);
|
||||
|
||||
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 ..
|
||||
try {
|
||||
$logger = new SyslogLogger($this->channel, $introspection, $loglevel);
|
||||
} catch (\Throwable $e) {
|
||||
// No logger ...
|
||||
$logger = new NullLogger();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
$name = $config->get('system', 'logger_config', 'stream');
|
||||
|
||||
switch ($name) {
|
||||
case 'syslog':
|
||||
try {
|
||||
$logger = new SyslogLogger($this->channel, $introspection, $loglevel, $config->get('system', 'syslog_flags', SyslogLogger::DEFAULT_FLAGS), $config->get('system', 'syslog_facility', SyslogLogger::DEFAULT_FACILITY));
|
||||
|
@ -132,29 +109,48 @@ class Logger
|
|||
|
||||
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 (LogLevelException $exception) {
|
||||
// If there's a wrong config value for loglevel, try again with standard
|
||||
$logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE);
|
||||
$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]);
|
||||
} catch (\Throwable $t) {
|
||||
// No logger ...
|
||||
$logger = new NullLogger();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$logger = new SyslogLogger($this->channel, $introspection, $loglevel);
|
||||
} catch (LogLevelException $exception) {
|
||||
// If there's a wrong config value for loglevel, try again with standard
|
||||
$logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE);
|
||||
$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]);
|
||||
} catch (\Throwable $e) {
|
||||
// No logger ...
|
||||
$logger = new NullLogger();
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'channel' => $this->channel,
|
||||
'introspection' => $introspection,
|
||||
'loglevel' => $loglevel,
|
||||
'logger' => null,
|
||||
];
|
||||
try {
|
||||
Core\Hook::callAll('logger_instance', $data);
|
||||
} catch (InternalServerErrorException $exception) {
|
||||
$data['logger'] = null;
|
||||
}
|
||||
|
||||
if (($data['logger'] ?? null) instanceof LoggerInterface) {
|
||||
$logger = $data['logger'];
|
||||
}
|
||||
|
||||
if (empty($logger)) {
|
||||
$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 (LogLevelException $exception) {
|
||||
// If there's a wrong config value for loglevel, try again with standard
|
||||
$logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE);
|
||||
$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]);
|
||||
} catch (\Throwable $t) {
|
||||
// No logger ...
|
||||
$logger = new NullLogger();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$logger = new SyslogLogger($this->channel, $introspection, $loglevel);
|
||||
} catch (LogLevelException $exception) {
|
||||
// If there's a wrong config value for loglevel, try again with standard
|
||||
$logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE);
|
||||
$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]);
|
||||
} catch (\Throwable $e) {
|
||||
// No logger ...
|
||||
$logger = new NullLogger();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -197,27 +193,11 @@ class Logger
|
|||
return new NullLogger();
|
||||
}
|
||||
|
||||
$loggerTimeZone = new \DateTimeZone('UTC');
|
||||
Monolog\Logger::setTimezone($loggerTimeZone);
|
||||
|
||||
$introspection = new Introspection(self::$ignoreClassList);
|
||||
|
||||
switch ($config->get('system', 'logger_config', 'stream')) {
|
||||
$name = $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;
|
||||
switch ($name) {
|
||||
|
||||
case 'syslog':
|
||||
$logger = new SyslogLogger(self::DEV_CHANNEL, $introspection, LogLevel::DEBUG);
|
||||
|
@ -225,6 +205,23 @@ class Logger
|
|||
|
||||
case 'stream':
|
||||
default:
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'channel' => self::DEV_CHANNEL,
|
||||
'introspection' => $introspection,
|
||||
'loglevel' => LogLevel::DEBUG,
|
||||
'logger' => null,
|
||||
];
|
||||
try {
|
||||
Core\Hook::callAll('logger_instance', $data);
|
||||
} catch (InternalServerErrorException $exception) {
|
||||
$data['logger'] = null;
|
||||
}
|
||||
|
||||
if (($data['logger'] ?? null) instanceof LoggerInterface) {
|
||||
return $data['logger'];
|
||||
}
|
||||
|
||||
$logger = new StreamLogger(self::DEV_CHANNEL, $stream, $introspection, $fileSystem, LogLevel::DEBUG);
|
||||
break;
|
||||
}
|
||||
|
@ -273,38 +270,4 @@ class Logger
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\App\Request;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @var string The IP of the current request
|
||||
*/
|
||||
private $remoteAddress;
|
||||
|
||||
/**
|
||||
* @param Request $request The current http request
|
||||
* @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(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->developerIp = $developerIp;
|
||||
$this->remoteAddress = $request->getRemoteAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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) && $this->remoteAddress != $this->developerIp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Core\Logger\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;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ 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
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ use PDO;
|
|||
use PDOException;
|
||||
use PDOStatement;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* This class is for the low level database stuff that does driver specific things.
|
||||
|
@ -80,15 +81,17 @@ class Database
|
|||
/** @var ViewDefinition */
|
||||
protected $viewDefinition;
|
||||
|
||||
public function __construct(Cache $configCache, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger)
|
||||
public function __construct(Cache $configCache, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
|
||||
{
|
||||
// We are storing these values for being able to perform a reconnect
|
||||
$this->configCache = $configCache;
|
||||
$this->profiler = $profiler;
|
||||
$this->logger = $logger;
|
||||
$this->dbaDefinition = $dbaDefinition;
|
||||
$this->viewDefinition = $viewDefinition;
|
||||
|
||||
// Temporary NullLogger until we can fetch the logger class from the config
|
||||
$this->logger = new NullLogger();
|
||||
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue