Commit 00c62ae6 authored by Xander Miller's avatar Xander Miller
Browse files

Merge branch 'goal/error-log' into 'master'

PSR-3 Error logging (Monolog)

Closes #555

See merge request !428
parents 3efa2421 4be4fe75
Loading
Loading
Loading
Loading

Core/Log/Logger.php

0 → 100644
+88 −0
Original line number Original line Diff line number Diff line
<?php
/**
 * Logger
 *
 * @author edgebal
 */

namespace Minds\Core\Log;

use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\ChromePHPHandler;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Handler\PHPConsoleHandler;
use Monolog\Logger as MonologLogger;
use Sentry\Monolog\Handler as SentryHandler;
use Sentry\SentrySdk;

/**
 * A PSR-3 logger tailored for Minds. Based off Monolog.
 *
 * @package Minds\Core\Log
 * @see \Monolog\Logger
 * @see \Psr\Log\LoggerInterface
 */
class Logger extends MonologLogger
{
    /**
     * Logger constructor.
     * @param string $channel
     * @param array $options
     */
    public function __construct(string $channel = 'Minds', array $options = [])
    {
        $options = array_merge([
            'isProduction' => true,
            'devToolsLogger' => '',
        ], $options);

        $handlers = [];

        $errorLogHandler = new ErrorLogHandler(
            ErrorLogHandler::OPERATING_SYSTEM,
            $options['isProduction'] ? MonologLogger::INFO : MonologLogger::DEBUG,
            true,
            true
        );

        $errorLogHandler
            ->setFormatter(new LineFormatter(
                "%channel%.%level_name%: %message% %context% %extra%\n",
                'c',
                !$options['isProduction'], // Allow newlines on dev mode
                true
            ));

        $handlers[] = $errorLogHandler;

        if ($options['isProduction']) {
            $handlers[] = new SentryHandler(SentrySdk::getCurrentHub());
        } else {
            // Extra handlers for Development Mode

            switch ($options['devToolsLogger']) {
                case 'firephp':
                    $handlers[] = new FirePHPHandler();
                    break;

                case 'chromelogger':
                    $handlers[] = new ChromePHPHandler();
                    break;

                case 'phpconsole':
                    try {
                        $handlers[] = new PHPConsoleHandler();
                    } catch (Exception $exception) {
                        // If the server-side vendor package is not installed, ignore any warnings.
                    }
                    break;
            }
        }

        // Create Monolog instance

        parent::__construct($channel, $handlers);
    }
}

Core/Log/Module.php

0 → 100644
+26 −0
Original line number Original line Diff line number Diff line
<?php
/**
 * Module
 *
 * @author edgebal
 */

namespace Minds\Core\Log;

use Minds\Interfaces\ModuleInterface;

/**
 * Module class
 *
 * @package Minds\Core\Log
 */
class Module implements ModuleInterface
{
    /**
     * @inheritDoc
     */
    public function onInit(): void
    {
        (new Provider())->register();
    }
}

Core/Log/Provider.php

0 → 100644
+42 −0
Original line number Original line Diff line number Diff line
<?php
/**
 * Provider
 *
 * @author edgebal
 */

namespace Minds\Core\Log;

use Minds\Core\Config;
use Minds\Core\Di\Di;
use Minds\Core\Di\Provider as DiProvider;

/**
 * DI Provider bindings
 *
 * @package Minds\Core\Log
 */
class Provider extends DiProvider
{
    public function register()
    {
        $this->di->bind('Logger', function ($di) {
            /** @var Di $di */

            /** @var Config|false $config */
            $config = $di->get('Config');

            $options = [
                'isProduction' => $config ? !$config->get('development_mode') : true,
                'devToolsLogger' => $config ? $config->get('devtools_logger') : '',
            ];

            return new Logger('Minds', $options);
        }, [ 'useFactory' => false ]);

        $this->di->bind('Logger\Singleton', function ($di) {
            /** @var Di $di */
            return $di->get('Logger');
        }, [ 'useFactory' => true ]);
    }
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@ class Minds extends base
    public static $booted = false;
    public static $booted = false;


    private $modules = [
    private $modules = [
        Log\Module::class,
        Events\Module::class,
        Events\Module::class,
        SSO\Module::class,
        SSO\Module::class,
        Email\Module::class,
        Email\Module::class,
+11 −18
Original line number Original line Diff line number Diff line
@@ -7,6 +7,8 @@
namespace Minds\Core\Router\Middleware\Kernel;
namespace Minds\Core\Router\Middleware\Kernel;


use Exception;
use Exception;
use Minds\Core\Di\Di;
use Minds\Core\Log\Logger;
use Minds\Core\Router\Exceptions\ForbiddenException;
use Minds\Core\Router\Exceptions\ForbiddenException;
use Minds\Core\Router\Exceptions\UnauthorizedException;
use Minds\Core\Router\Exceptions\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ResponseInterface;
@@ -15,21 +17,20 @@ use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Diactoros\Response\JsonResponse;
use function Sentry\captureException;


class ErrorHandlerMiddleware implements MiddlewareInterface
class ErrorHandlerMiddleware implements MiddlewareInterface
{
{
    /** @var bool */
    /** @var Logger */
    protected $sentryEnabled = true;
    protected $logger;


    /**
    /**
     * @param bool $sentryEnabled
     * ErrorHandlerMiddleware constructor.
     * @return ErrorHandlerMiddleware
     * @param Logger $logger
     */
     */
    public function setSentryEnabled(bool $sentryEnabled): ErrorHandlerMiddleware
    public function __construct(
    {
        $logger = null
        $this->sentryEnabled = $sentryEnabled;
    ) {
        return $this;
        $this->logger = $logger ?: Di::_()->get('Logger');
    }
    }


    /**
    /**
@@ -58,15 +59,7 @@ class ErrorHandlerMiddleware implements MiddlewareInterface
            $status = 403;
            $status = 403;
        } catch (Exception $e) {
        } catch (Exception $e) {
            // Log
            // Log

            $this->logger->critical($e, ['exception' => $e]);
            // TODO: Monolog
            error_log((string) $e);

            // Sentry

            if ($this->sentryEnabled) {
                captureException($e);
            }
        }
        }


        switch ($request->getAttribute('accept')) {
        switch ($request->getAttribute('accept')) {
Loading