}
use Dice\Dice;
+use Friendica\DI;
use Psr\Log\LoggerInterface;
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
+/// @fixme Necessary until Hooks inside the Logger can get loaded without the DI-class
+DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
(new Friendica\Core\Console($dice, $argv))->execute();
"michelf/php-markdown": "^1.7",
"minishlink/web-push": "^6.0",
"mobiledetect/mobiledetectlib": "^2.8",
- "monolog/monolog": "^1.25",
"nikic/fast-route": "^1.3",
"paragonie/hidden-string": "^1.0",
"patrickschur/language-detection": "^5.0.0",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.2",
"psr/container": "^1.0",
+ "psr/log": "^1.1",
"seld/cli-prompt": "^1.0",
"smarty/smarty": "^4",
"ua-parser/uap-php": "^3.9",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f5922f03b367e68a5930df6ed80c5c2f",
+ "content-hash": "c851fbba46ed090d0fbaf68e9b3b94df",
"packages": [
{
"name": "asika/simple-console",
],
"time": "2022-02-17T19:24:25+00:00"
},
- {
- "name": "monolog/monolog",
- "version": "1.27.1",
- "source": {
- "type": "git",
- "url": "https://github.com/Seldaek/monolog.git",
- "reference": "904713c5929655dc9b97288b69cfeedad610c9a1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1",
- "reference": "904713c5929655dc9b97288b69cfeedad610c9a1",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0",
- "psr/log": "~1.0"
- },
- "provide": {
- "psr/log-implementation": "1.0.0"
- },
- "require-dev": {
- "aws/aws-sdk-php": "^2.4.9 || ^3.0",
- "doctrine/couchdb": "~1.0@dev",
- "graylog2/gelf-php": "~1.0",
- "php-amqplib/php-amqplib": "~2.4",
- "php-console/php-console": "^3.1.3",
- "phpstan/phpstan": "^0.12.59",
- "phpunit/phpunit": "~4.5",
- "ruflin/elastica": ">=0.90 <3.0",
- "sentry/sentry": "^0.13",
- "swiftmailer/swiftmailer": "^5.3|^6.0"
- },
- "suggest": {
- "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
- "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
- "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
- "ext-mongo": "Allow sending log messages to a MongoDB server",
- "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
- "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
- "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
- "php-console/php-console": "Allow sending log messages to Google Chrome",
- "rollbar/rollbar": "Allow sending log messages to Rollbar",
- "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
- "sentry/sentry": "Allow sending log messages to a Sentry server"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Monolog\\": "src/Monolog"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- }
- ],
- "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
- "homepage": "http://github.com/Seldaek/monolog",
- "keywords": [
- "log",
- "logging",
- "psr-3"
- ],
- "funding": [
- {
- "url": "https://github.com/Seldaek",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
- "type": "tidelift"
- }
- ],
- "time": "2022-06-09T08:53:42+00:00"
- },
{
"name": "nikic/fast-route",
"version": "v1.3.0",
Hook::callAll('block', $hook_data);
Hook::callAll('unblock', $hook_data);
+### src/Core/Logger/Factory.php
+
+ Hook::callAll('logger_instance', $data);
+
### src/Core/StorageManager
Hook::callAll('storage_instance', $data);
Hook::callAll('block', $hook_data);
Hook::callAll('unblock', $hook_data);
+### src/Core/Logger/Factory.php
+
+ Hook::callAll('logger_instance', $data);
+
### src/Core/StorageManager
Hook::callAll('storage_instance', $data);
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;
/** @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();
+ }
}
/**
$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));
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;
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);
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;
}
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);
- }
- }
- }
}
+++ /dev/null
-<?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;
- }
-}
+++ /dev/null
-<?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;
- }
-}
### 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
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.
/** @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();
}
protected function getInstance()
{
- $logger = new NullLogger();
$profiler = Mockery::mock(Profiler::class);
$profiler->shouldReceive('startRecording');
$profiler->shouldReceive('stopRecording');
$dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load();
$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load();
- $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $logger);
+ $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition);
$this->cache = new Cache\Type\DatabaseCache('database', $dba);
return $this->cache;
protected function getInstance()
{
- $logger = new NullLogger();
$profiler = \Mockery::mock(Profiler::class);
$profiler->shouldReceive('startRecording');
$profiler->shouldReceive('stopRecording');
$dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load();
$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load();
- $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $logger);
+ $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition);
return new Database($dba);
}
$dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load();
$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load();
- $this->dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $this->logger);
+ $this->dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition);
$configModel = new Repository\Config($this->dba, new Mode(Mode::DBCONFIGAVAILABLE));
$this->config = new PreloadConfig($configCache, $configModel);