first commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "wpdesk\/wp-logs",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Krzysiek",
|
||||
"email": "krzysiek@wpdesk.pl"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.0.19"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"dealerdirect\/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0|^8",
|
||||
"psr\/log": "^1",
|
||||
"monolog\/monolog": "^1.23",
|
||||
"wpdesk\/wp-notice": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit\/phpunit": "^5",
|
||||
"squizlabs\/php_codesniffer": "^3.0.2",
|
||||
"wpdesk\/wp-code-sniffer": "^1.2.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FcfVendor\\WPDesk\\Logger\\": "src\/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
|
||||
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
|
||||
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
|
||||
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
|
||||
},
|
||||
"extra": {
|
||||
"text-domain": "wp-logs",
|
||||
"translations-folder": "lang",
|
||||
"po-files": {
|
||||
"pl_PL": "pl_PL.po",
|
||||
"en_AU": "en_AU.po",
|
||||
"en_CA": "en_CA.po",
|
||||
"en_GB": "en_GB.po",
|
||||
"es_ES": "es_ES.po",
|
||||
"de_DE": "de_DE.po"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use FcfVendor\Monolog\Handler\HandlerInterface;
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use FcfVendor\Monolog\Registry;
|
||||
/**
|
||||
* Manages and facilitates creation of logger
|
||||
*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
class BasicLoggerFactory implements \FcfVendor\WPDesk\Logger\LoggerFactory
|
||||
{
|
||||
/** @var string Last created logger name/channel */
|
||||
private static $lastLoggerChannel;
|
||||
/**
|
||||
* Creates logger for plugin
|
||||
*
|
||||
* @param string $name The logging channel/name of logger
|
||||
* @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
|
||||
* @param callable[] $processors Optional array of processors
|
||||
* @return Logger
|
||||
*/
|
||||
public function createLogger($name, $handlers = array(), array $processors = array())
|
||||
{
|
||||
if (\FcfVendor\Monolog\Registry::hasLogger($name)) {
|
||||
return \FcfVendor\Monolog\Registry::getInstance($name);
|
||||
}
|
||||
self::$lastLoggerChannel = $name;
|
||||
$logger = new \FcfVendor\Monolog\Logger($name, $handlers, $processors);
|
||||
\FcfVendor\Monolog\Registry::addLogger($logger);
|
||||
return $logger;
|
||||
}
|
||||
/**
|
||||
* Returns created Logger by name or last created logger
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
*
|
||||
* @return Logger
|
||||
*/
|
||||
public function getLogger($name = null)
|
||||
{
|
||||
if ($name === null) {
|
||||
$name = self::$lastLoggerChannel;
|
||||
}
|
||||
return \FcfVendor\Monolog\Registry::getInstance($name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
use WP_Error;
|
||||
use Exception;
|
||||
/**
|
||||
* Facilitates creation of logger with default WPDesk settings
|
||||
*
|
||||
* @deprecated Only for backward compatibility. Please use injected Logger compatible with PSR
|
||||
*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
class LoggerFacade
|
||||
{
|
||||
const BACKTRACE_FILENAME_KEY = 'file';
|
||||
/** @var WPDeskLoggerFactory */
|
||||
private static $factory;
|
||||
/**
|
||||
* Get logger by name. If not exists create one.
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
* @return Logger
|
||||
*/
|
||||
public static function getLogger($name = \FcfVendor\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
if (self::$factory === null) {
|
||||
self::$factory = new \FcfVendor\WPDesk\Logger\WPDeskLoggerFactory();
|
||||
}
|
||||
return self::$factory->createWPDeskLogger($name);
|
||||
}
|
||||
/**
|
||||
* Snake case alias for getLogger
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Logger
|
||||
*/
|
||||
public static function get_logger($name = \FcfVendor\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
return self::getLogger($name);
|
||||
}
|
||||
/**
|
||||
* If set, logs are disabled
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
*/
|
||||
public static function set_disable_log($name = \FcfVendor\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
self::$factory->disableLog($name);
|
||||
}
|
||||
/**
|
||||
* Log this exception into WPDesk logger
|
||||
*
|
||||
* @param WP_Error $e Error to log.
|
||||
* @param array $backtrace Backtrace information with snapshot of error env.
|
||||
* @param array $context Context to log
|
||||
* @param string $level Level of error.
|
||||
*
|
||||
* @see http://php.net/manual/en/function.debug-backtrace.php
|
||||
*/
|
||||
public static function log_wp_error(\WP_Error $e, array $backtrace, array $context = array(), $level = \Psr\Log\LogLevel::ERROR)
|
||||
{
|
||||
$message = 'Error: ' . \get_class($e) . ' Code: ' . $e->get_error_code() . ' Message: ' . $e->get_error_message();
|
||||
self::log_message_backtrace($message, $backtrace, $context, $level);
|
||||
}
|
||||
/**
|
||||
* Log this exception into WPDesk logger
|
||||
*
|
||||
* @param Exception $e Exception to log.
|
||||
* @param array $context Context to log
|
||||
* @param string $level Level of error.
|
||||
*/
|
||||
public static function log_exception(\Exception $e, array $context = array(), $level = \Psr\Log\LogLevel::ERROR)
|
||||
{
|
||||
$message = 'Exception: ' . \get_class($e) . ' Code: ' . $e->getCode() . ' Message: ' . $e->getMessage() . ' Stack: ' . $e->getTraceAsString();
|
||||
self::log_message($message, \array_merge($context, ['exception' => $e]), $e->getFile(), $level);
|
||||
}
|
||||
/**
|
||||
* Log message into WPDesk logger
|
||||
*
|
||||
* @param string $message Message to log.
|
||||
* @param array $context Context to log
|
||||
* @param string $source Source of the message - can be file name, class name or whatever.
|
||||
* @param string $level Level of error.
|
||||
*/
|
||||
public static function log_message($message, array $context = array(), $source = null, $level = \Psr\Log\LogLevel::DEBUG)
|
||||
{
|
||||
$logger = self::getLogger();
|
||||
if ($source !== null) {
|
||||
$context = \array_merge($context, ['source' => $source]);
|
||||
}
|
||||
$logger->log($level, $message, $context);
|
||||
}
|
||||
/**
|
||||
* Log message into WPDesk logger
|
||||
*
|
||||
* @param string $message Message to log.
|
||||
* @param array $backtrace Backtrace information with snapshot of error env.
|
||||
* @param array $context Context to log
|
||||
* @param string $level Level of error.
|
||||
*/
|
||||
public static function log_message_backtrace($message, array $backtrace, array $context = array(), $level = \Psr\Log\LogLevel::DEBUG)
|
||||
{
|
||||
$message .= ' Backtrace: ' . \json_encode($backtrace);
|
||||
$source = null;
|
||||
if (isset($backtrace[self::BACKTRACE_FILENAME_KEY])) {
|
||||
$source = $backtrace[self::BACKTRACE_FILENAME_KEY];
|
||||
}
|
||||
self::log_message($message, $context, $source, $level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use FcfVendor\Monolog\Logger;
|
||||
/*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
interface LoggerFactory
|
||||
{
|
||||
/**
|
||||
* Returns created Logger
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Logger
|
||||
*/
|
||||
public function getLogger($name);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
final class Settings
|
||||
{
|
||||
/** @var string */
|
||||
public $level = \Psr\Log\LogLevel::DEBUG;
|
||||
/** @var bool */
|
||||
public $use_wc_log = \true;
|
||||
/** @var bool */
|
||||
public $use_wp_log = \true;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use FcfVendor\Monolog\Handler\HandlerInterface;
|
||||
use FcfVendor\Monolog\Handler\NullHandler;
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use FcfVendor\Monolog\Handler\ErrorLogHandler;
|
||||
use FcfVendor\WPDesk\Logger\WC\WooCommerceHandler;
|
||||
final class SimpleLoggerFactory implements \FcfVendor\WPDesk\Logger\LoggerFactory
|
||||
{
|
||||
/** @var Settings */
|
||||
private $options;
|
||||
/** @var string */
|
||||
private $channel;
|
||||
/** @var Logger */
|
||||
private $logger;
|
||||
public function __construct(string $channel, \FcfVendor\WPDesk\Logger\Settings $options = null)
|
||||
{
|
||||
$this->channel = $channel;
|
||||
$this->options = $options ?? new \FcfVendor\WPDesk\Logger\Settings();
|
||||
}
|
||||
public function getLogger($name = null) : \FcfVendor\Monolog\Logger
|
||||
{
|
||||
if ($this->logger) {
|
||||
return $this->logger;
|
||||
}
|
||||
$logger = new \FcfVendor\Monolog\Logger($this->channel);
|
||||
if ($this->options->use_wc_log && \function_exists('wc_get_logger')) {
|
||||
$logger->pushHandler(new \FcfVendor\WPDesk\Logger\WC\WooCommerceHandler(\wc_get_logger(), $this->channel));
|
||||
}
|
||||
// Adding WooCommerce logger may have failed, if so add WP by default.
|
||||
if ($this->options->use_wp_log || empty($logger->getHandlers())) {
|
||||
$logger->pushHandler($this->get_wp_handler());
|
||||
}
|
||||
return $this->logger = $logger;
|
||||
}
|
||||
private function get_wp_handler() : \FcfVendor\Monolog\Handler\HandlerInterface
|
||||
{
|
||||
if (\defined('FcfVendor\\WP_DEBUG_LOG') && WP_DEBUG_LOG) {
|
||||
return new \FcfVendor\Monolog\Handler\ErrorLogHandler(\FcfVendor\Monolog\Handler\ErrorLogHandler::OPERATING_SYSTEM, $this->options->level);
|
||||
}
|
||||
return new \FcfVendor\Monolog\Handler\NullHandler();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger\WC\Exception;
|
||||
|
||||
class WCLoggerAlreadyCaptured extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger\WC;
|
||||
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use FcfVendor\WPDesk\Logger\WC\Exception\WCLoggerAlreadyCaptured;
|
||||
/**
|
||||
* Can capture default WooCommerce logger
|
||||
*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
class WooCommerceCapture
|
||||
{
|
||||
const WOOCOMMERCE_LOGGER_FILTER = 'woocommerce_logging_class';
|
||||
const WOOCOMMERCE_AFTER_IS_LOADED_ACTION = 'woocommerce_loaded';
|
||||
/** @var string Minimal version of WooCommerce supported by logger capture */
|
||||
const SUPPORTED_WC_VERSION = '3.5.0';
|
||||
/**
|
||||
* Is logger filter captured by library.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isCaptured = \false;
|
||||
/**
|
||||
* Our monolog
|
||||
*
|
||||
* @var Logger
|
||||
*/
|
||||
private $monolog;
|
||||
/**
|
||||
* Original WC Logger
|
||||
*
|
||||
* @var \WC_Logger_Interface
|
||||
*/
|
||||
private $originalWCLogger;
|
||||
/**
|
||||
* WordPress hook function to return our logger
|
||||
*
|
||||
* @var ?callable
|
||||
*/
|
||||
private $captureHookFunction;
|
||||
/**
|
||||
* WordPress hook function to return original wc logger
|
||||
*
|
||||
* @var ?callable
|
||||
*/
|
||||
private $freeHookFunction;
|
||||
public function __construct(\FcfVendor\Monolog\Logger $monolog)
|
||||
{
|
||||
$this->monolog = $monolog;
|
||||
}
|
||||
/**
|
||||
* Prepares callable property captureHookFunction.
|
||||
* For it to work WC have to be loaded
|
||||
*/
|
||||
private function prepareCaptureHookCallable()
|
||||
{
|
||||
$monolog = $this->monolog;
|
||||
if ($this->captureHookFunction === null) {
|
||||
$this->captureHookFunction = function () use($monolog) {
|
||||
return new \FcfVendor\WPDesk\Logger\WC\WooCommerceMonologPlugin($monolog, $this->originalWCLogger);
|
||||
};
|
||||
$this->monolog->pushHandler(new \FcfVendor\WPDesk\Logger\WC\WooCommerceHandler($this->originalWCLogger));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Is this version of WooCommerce is supported by logger capture
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupportedWCVersion()
|
||||
{
|
||||
return \class_exists(\WooCommerce::class) && \version_compare(\WooCommerce::instance()->version, self::SUPPORTED_WC_VERSION, '>=');
|
||||
}
|
||||
/**
|
||||
* Capture WooCommerce logger and inject our decorated Logger
|
||||
*/
|
||||
public function captureWcLogger()
|
||||
{
|
||||
if (self::isSupportedWCVersion()) {
|
||||
if ($this->isCaptured) {
|
||||
throw new \FcfVendor\WPDesk\Logger\WC\Exception\WCLoggerAlreadyCaptured('Try to free wc logger first.');
|
||||
}
|
||||
if ($this->isWooCommerceLoggerAvailable()) {
|
||||
$this->prepareFreeHookCallable();
|
||||
$this->prepareCaptureHookCallable();
|
||||
\remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
|
||||
\add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
|
||||
$this->isCaptured = \true;
|
||||
} elseif (\function_exists('add_action')) {
|
||||
\add_action(self::WOOCOMMERCE_AFTER_IS_LOADED_ACTION, [$this, 'captureWcLogger']);
|
||||
} else {
|
||||
$this->monolog->alert('Cannot capture WC - WordPress is not available.');
|
||||
}
|
||||
} else {
|
||||
$this->monolog->alert('Cannot capture WC - WooCommerce version is not supported.');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Can i fetch WC Logger?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isWooCommerceLoggerAvailable()
|
||||
{
|
||||
return \function_exists('wc_get_logger');
|
||||
}
|
||||
/**
|
||||
* Prepares callable property freeHookFunction.
|
||||
* For it to work WC have to be loaded
|
||||
*/
|
||||
private function prepareFreeHookCallable()
|
||||
{
|
||||
if ($this->freeHookFunction === null) {
|
||||
$this->originalWCLogger = $logger = \wc_get_logger();
|
||||
$this->freeHookFunction = function () use($logger) {
|
||||
return $logger;
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove WooCommerce logger injection
|
||||
*/
|
||||
public function freeWcLogger()
|
||||
{
|
||||
if ($this->isCaptured) {
|
||||
\remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
|
||||
\add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
|
||||
$this->isCaptured = \false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger\WC;
|
||||
|
||||
use FcfVendor\Monolog\Handler\AbstractProcessingHandler;
|
||||
use FcfVendor\Monolog\Logger;
|
||||
/**
|
||||
* Class WooCommerceFactory
|
||||
*/
|
||||
class WooCommerceHandler extends \FcfVendor\Monolog\Handler\AbstractProcessingHandler
|
||||
{
|
||||
const DEFAULT_WC_SOURCE = 'wpdesk-logger';
|
||||
/** @var \WC_Logger_Interface */
|
||||
private $wc_logger;
|
||||
/** @var string */
|
||||
private $channel;
|
||||
/**
|
||||
* Writes the record down to the log of the implementing handler
|
||||
*
|
||||
* @param array $record
|
||||
* @return void
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$context = \array_merge(['source' => $this->channel], $record['extra'], $record['context']);
|
||||
$this->wc_logger->log($this->convertMonologLevelToWC($record['level']), $record['message'], $context);
|
||||
}
|
||||
/**
|
||||
* @param int $level
|
||||
* @return string
|
||||
*/
|
||||
private function convertMonologLevelToWC($level)
|
||||
{
|
||||
return \FcfVendor\Monolog\Logger::getLevelName($level);
|
||||
}
|
||||
public function __construct(\WC_Logger_Interface $originalWcLogger, string $channel = self::DEFAULT_WC_SOURCE)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->wc_logger = $originalWcLogger;
|
||||
$this->channel = $channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger\WC;
|
||||
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
use WC_Log_Levels;
|
||||
/**
|
||||
* Can decorate monolog with WC_Logger_Interface
|
||||
*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
class WooCommerceMonologPlugin implements \WC_Logger_Interface
|
||||
{
|
||||
/** @var Logger */
|
||||
private $monolog;
|
||||
/** @var \WC_Logger */
|
||||
private $originalWCLogger;
|
||||
public function __construct(\FcfVendor\Monolog\Logger $monolog, \WC_Logger_Interface $originalLogger)
|
||||
{
|
||||
$this->monolog = $monolog;
|
||||
$this->originalWCLogger = $originalLogger;
|
||||
}
|
||||
/**
|
||||
* Method added for compatibility with \WC_Logger
|
||||
*
|
||||
* @param string $source
|
||||
*/
|
||||
public function clear($source = '')
|
||||
{
|
||||
$this->originalWCLogger->clear($source);
|
||||
}
|
||||
/**
|
||||
* Method added for compatibility with \WC_Logger
|
||||
*/
|
||||
public function clear_expired_logs()
|
||||
{
|
||||
$this->originalWCLogger->clear_expired_logs();
|
||||
}
|
||||
/**
|
||||
* Method for compatibility reason. Do not use.
|
||||
*
|
||||
* @param string $handle
|
||||
* @param string $message
|
||||
* @param string $level
|
||||
* @return bool|void
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function add($handle, $message, $level = \WC_Log_Levels::NOTICE)
|
||||
{
|
||||
$this->log($message, $level);
|
||||
}
|
||||
/**
|
||||
* System is unusable.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function emergency($message, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::EMERGENCY, $message, $context);
|
||||
}
|
||||
public function log($level, $message, $context = [])
|
||||
{
|
||||
$this->monolog->log($level, $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, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::ALERT, $message, $context);
|
||||
}
|
||||
/**
|
||||
* Critical conditions.
|
||||
*
|
||||
* Example: Application component unavailable, unexpected exception.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function critical($message, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::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, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::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, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::WARNING, $message, $context);
|
||||
}
|
||||
/**
|
||||
* Normal but significant events.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function notice($message, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::NOTICE, $message, $context);
|
||||
}
|
||||
/**
|
||||
* Interesting events.
|
||||
*
|
||||
* Example: User logs in, SQL logs.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function info($message, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::INFO, $message, $context);
|
||||
}
|
||||
/**
|
||||
* Detailed debug information.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function debug($message, $context = array())
|
||||
{
|
||||
$this->log(\Psr\Log\LogLevel::DEBUG, $message, $context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger\WP;
|
||||
|
||||
class WPCapture
|
||||
{
|
||||
/** @var string */
|
||||
private $filename;
|
||||
const LOG_DIR = 'wpdesk-logs';
|
||||
public function __construct($filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
}
|
||||
/**
|
||||
* Add notice for directory.
|
||||
*
|
||||
* @param string $dir Directory.
|
||||
*/
|
||||
private function add_notice_for_dir($dir)
|
||||
{
|
||||
new \FcfVendor\WPDesk\Notice\Notice(\sprintf(
|
||||
// Translators: directory.
|
||||
\__('Can not enable WP Desk Debug log! Cannot create directory %s or this directory is not writeable!', 'flexible-checkout-fields'),
|
||||
$dir
|
||||
), \FcfVendor\WPDesk\Notice\Notice::NOTICE_TYPE_ERROR);
|
||||
}
|
||||
/**
|
||||
* Add notice for file.
|
||||
*
|
||||
* @param string $file File..
|
||||
*/
|
||||
private function add_notice_for_file($file)
|
||||
{
|
||||
new \FcfVendor\WPDesk\Notice\Notice(\sprintf(
|
||||
// Translators: directory.
|
||||
\__('Can not enable WP Desk Debug log! Cannot create file %s!', 'flexible-checkout-fields'),
|
||||
$file
|
||||
), \FcfVendor\WPDesk\Notice\Notice::NOTICE_TYPE_ERROR);
|
||||
}
|
||||
/**
|
||||
* Is debug log writable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_debug_log_writable_or_show_notice()
|
||||
{
|
||||
$log_dir = $this->get_log_dir();
|
||||
$log_file = $this->get_log_file();
|
||||
$index_file = $this->get_index_file();
|
||||
if (!\file_exists($log_dir)) {
|
||||
if (!\mkdir($log_dir, 0777, \true)) {
|
||||
$this->add_notice_for_dir($log_dir);
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
if (!\file_exists($index_file)) {
|
||||
$index_html = \fopen($index_file, 'w');
|
||||
if (\false === $index_html) {
|
||||
$this->add_notice_for_file($index_file);
|
||||
return \false;
|
||||
} else {
|
||||
\fclose($index_html);
|
||||
}
|
||||
}
|
||||
if (!\file_exists($log_file)) {
|
||||
$log = \fopen($log_file, 'w');
|
||||
if (\false === $log) {
|
||||
$this->add_notice_for_file($log_file);
|
||||
return \false;
|
||||
} else {
|
||||
\fclose($log);
|
||||
}
|
||||
}
|
||||
if (!\is_writable($log_file)) {
|
||||
$this->add_notice_for_file($log_file);
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Init debug log file.
|
||||
*/
|
||||
public function init_debug_log_file()
|
||||
{
|
||||
if ($this->is_debug_log_writable_or_show_notice()) {
|
||||
\ini_set('log_errors', 1);
|
||||
\ini_set('error_log', $this->get_log_file());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get uploads dir.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_uploads_dir()
|
||||
{
|
||||
$upload_dir = \wp_upload_dir();
|
||||
return \untrailingslashit($upload_dir['basedir']);
|
||||
}
|
||||
/**
|
||||
* Get log dir.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_log_dir()
|
||||
{
|
||||
return \trailingslashit($this->get_uploads_dir()) . self::LOG_DIR;
|
||||
}
|
||||
/**
|
||||
* Get log file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_log_file()
|
||||
{
|
||||
return \trailingslashit($this->get_log_dir()) . $this->filename;
|
||||
}
|
||||
/**
|
||||
* Get log file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_index_file()
|
||||
{
|
||||
return \trailingslashit($this->get_log_dir()) . 'index.html';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor\WPDesk\Logger;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use FcfVendor\Monolog\Handler\NullHandler;
|
||||
use FcfVendor\Monolog\Logger;
|
||||
use FcfVendor\Monolog\Registry;
|
||||
use FcfVendor\Monolog\Handler\StreamHandler;
|
||||
use Psr\Log\LogLevel;
|
||||
use FcfVendor\WPDesk\Logger\WC\WooCommerceCapture;
|
||||
use FcfVendor\WPDesk\Logger\WP\WPCapture;
|
||||
/**
|
||||
* Manages and facilitates creation of logger
|
||||
*
|
||||
* @package WPDesk\Logger
|
||||
*/
|
||||
class WPDeskLoggerFactory extends \FcfVendor\WPDesk\Logger\BasicLoggerFactory
|
||||
{
|
||||
const DEFAULT_LOGGER_CHANNEL_NAME = 'wpdesk';
|
||||
/** @var string Log to file when level is */
|
||||
const LEVEL_WPDESK_FILE = \Psr\Log\LogLevel::DEBUG;
|
||||
/** @var string Log to wc logger when level is */
|
||||
const LEVEL_WC = \Psr\Log\LogLevel::ERROR;
|
||||
/** @var bool Will factory return null logger or not */
|
||||
public static $shouldLoggerBeActivated = \true;
|
||||
/**
|
||||
* Remove static instances. In general should be use only testing purposes.
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
*/
|
||||
public static function tearDown($name = self::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
if (\FcfVendor\Monolog\Registry::hasLogger($name)) {
|
||||
\FcfVendor\Monolog\Registry::removeLogger($name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Disable logger. Still exists but logs won't be saved
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
*/
|
||||
public function disableLog($name = self::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
if (!\FcfVendor\Monolog\Registry::hasLogger($name)) {
|
||||
$this->createWPDeskLogger($name);
|
||||
}
|
||||
if (\FcfVendor\Monolog\Registry::hasLogger($name)) {
|
||||
/** @var Logger $logger */
|
||||
$logger = \FcfVendor\Monolog\Registry::getInstance($name);
|
||||
$this->removeAllHandlers($logger);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates default WPDesk logger.
|
||||
*
|
||||
* Requirements:
|
||||
* - get_option, add/remove_action, add/remove filter and WP_CONTENT_DIR should be available for logger.
|
||||
*
|
||||
* Assumptions:
|
||||
* - logger is actively working when 'wpdesk_helper_options' has 'debug_log' set to '1';
|
||||
* - fatal errors, exception and standard errors are recorded but in a transparent way;
|
||||
* - WooCommerce logger is captured and returns this logger; That is true of default logger is instantiated.
|
||||
* - logs are still correctly written to WooCommerce subsystem in a transparent way;
|
||||
* - all recorded errors are written to WPDesk file.
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
* @return Logger
|
||||
*/
|
||||
public function createWPDeskLogger($name = self::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
if (!self::$shouldLoggerBeActivated) {
|
||||
return new \FcfVendor\Monolog\Logger($name);
|
||||
}
|
||||
if (\FcfVendor\Monolog\Registry::hasLogger($name)) {
|
||||
return \FcfVendor\Monolog\Registry::getInstance($name);
|
||||
}
|
||||
$logger = $this->createLogger($name);
|
||||
if (self::isWPLogPermitted()) {
|
||||
$this->appendMainLog($logger);
|
||||
}
|
||||
if ($name !== self::DEFAULT_LOGGER_CHANNEL_NAME) {
|
||||
$this->appendFileLog($logger, $this->getFileName($name));
|
||||
} else {
|
||||
$this->captureWooCommerce($logger);
|
||||
}
|
||||
return $logger;
|
||||
}
|
||||
/**
|
||||
* Is capturing the php log is permitted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isWPLogPermitted()
|
||||
{
|
||||
return \apply_filters('wpdesk_is_wp_log_capture_permitted', \true);
|
||||
}
|
||||
/**
|
||||
* @param $logger
|
||||
*/
|
||||
private function appendMainLog($logger)
|
||||
{
|
||||
$wpCapture = $this->captureWPLog();
|
||||
if (\is_writable($wpCapture->get_log_file())) {
|
||||
$this->appendFileLog($logger, $wpCapture->get_log_file());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Logger $logger
|
||||
*/
|
||||
private function appendFileLog($logger, $filename)
|
||||
{
|
||||
try {
|
||||
$this->pushFileHandle($filename, $logger);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$logger->emergency('Main log file could not be created - invalid filename.');
|
||||
} catch (\Exception $e) {
|
||||
$logger->emergency('Main log file could not be written.');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return WPCapture
|
||||
*/
|
||||
private function captureWPLog()
|
||||
{
|
||||
static $wpCapture;
|
||||
if (!$wpCapture) {
|
||||
$wpCapture = new \FcfVendor\WPDesk\Logger\WP\WPCapture(\basename($this->getFileName()));
|
||||
$wpCapture->init_debug_log_file();
|
||||
}
|
||||
return $wpCapture;
|
||||
}
|
||||
/**
|
||||
* Capture WooCommerce and add handle
|
||||
*
|
||||
* @param Logger $logger
|
||||
*/
|
||||
private function captureWooCommerce(\FcfVendor\Monolog\Logger $logger)
|
||||
{
|
||||
if (!\defined('FcfVendor\\WC_LOG_THRESHOLD')) {
|
||||
\define('FcfVendor\\WC_LOG_THRESHOLD', self::LEVEL_WC);
|
||||
}
|
||||
$wcIntegration = new \FcfVendor\WPDesk\Logger\WC\WooCommerceCapture($logger);
|
||||
$wcIntegration->captureWcLogger();
|
||||
}
|
||||
/**
|
||||
* Add WPDesk log file handle
|
||||
*
|
||||
* @param Logger $logger
|
||||
* @param string $filename Name of file with path
|
||||
*
|
||||
* @throws Exception If a missing directory is not buildable
|
||||
* @throws InvalidArgumentException If stream is not a resource or string
|
||||
*/
|
||||
private function pushFileHandle($filename, \FcfVendor\Monolog\Logger $logger)
|
||||
{
|
||||
$logger->pushHandler(new \FcfVendor\Monolog\Handler\StreamHandler($filename, self::LEVEL_WPDESK_FILE));
|
||||
}
|
||||
/**
|
||||
* Get filename old way
|
||||
*
|
||||
* @deprecated not sure if can remove
|
||||
*/
|
||||
public function getWPDeskFileName()
|
||||
{
|
||||
return $this->getFileName();
|
||||
}
|
||||
/**
|
||||
* Returns WPDesk filename.
|
||||
*
|
||||
* @param string $name Name of the logger
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileName($name = self::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
$upload_dir = \wp_upload_dir();
|
||||
return \trailingslashit(\untrailingslashit($upload_dir['basedir'])) . \FcfVendor\WPDesk\Logger\WP\WPCapture::LOG_DIR . \DIRECTORY_SEPARATOR . $name . '_debug.log';
|
||||
}
|
||||
/**
|
||||
* Removes all handlers from logger
|
||||
*
|
||||
* @param Logger $logger
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function removeAllHandlers(\FcfVendor\Monolog\Logger $logger)
|
||||
{
|
||||
try {
|
||||
while (\true) {
|
||||
$logger->popHandler();
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
$logger->pushHandler(new \FcfVendor\Monolog\Handler\NullHandler());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* is WPDesk file log is working(writable, exists, connected).
|
||||
* @param string $name Name of the logger
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLogWorking($name = self::DEFAULT_LOGGER_CHANNEL_NAME)
|
||||
{
|
||||
return \FcfVendor\Monolog\Registry::hasLogger($name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor;
|
||||
|
||||
if (!\defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
if (!\class_exists('FcfVendor\\WPDesk_Logger_Factory')) {
|
||||
/**
|
||||
* @deprecated Only for backward compatibility. Please use injected Logger compatible with PSR
|
||||
*/
|
||||
class WPDesk_Logger_Factory
|
||||
{
|
||||
/**
|
||||
* Static logger storage
|
||||
*
|
||||
* @var WPDesk_Logger
|
||||
*/
|
||||
private static $logger = null;
|
||||
const BACKTRACE_FILENAME_KEY = 'file';
|
||||
const WPDESK_LOG_ACTION_NAME = 'wpdesk_log';
|
||||
/**
|
||||
* Creates and returns a logger
|
||||
*
|
||||
* @return WPDesk_Logger
|
||||
*/
|
||||
public static function create_logger()
|
||||
{
|
||||
if (empty(self::$logger)) {
|
||||
$logger = new \FcfVendor\WPDesk_Logger();
|
||||
$logger->attach_hooks();
|
||||
self::$logger = $logger;
|
||||
}
|
||||
return self::$logger;
|
||||
}
|
||||
/**
|
||||
* Log this exception into wpdesk logger
|
||||
*
|
||||
* @param WP_Error $e Error to log.
|
||||
* @param array $backtrace Backtrace information with snapshot of error env.
|
||||
*
|
||||
* @see http://php.net/manual/en/function.debug-backtrace.php
|
||||
*/
|
||||
public static function log_wp_error(\WP_Error $e, array $backtrace)
|
||||
{
|
||||
$message = 'Error: ' . \get_class($e) . ' Code: ' . $e->get_error_code() . ' Message: ' . $e->get_error_message();
|
||||
self::log_message_backtrace($message, \FcfVendor\WPDesk_Logger::ERROR, $backtrace);
|
||||
}
|
||||
/**
|
||||
* Log this exception into WPDesk logger
|
||||
*
|
||||
* @param Exception $e Exception to log.
|
||||
*/
|
||||
public static function log_exception(\Exception $e)
|
||||
{
|
||||
$message = 'Exception: ' . \get_class($e) . ' Code: ' . $e->getCode() . ' Message: ' . $e->getMessage() . ' Stack: ' . $e->getTraceAsString();
|
||||
self::log_message($message, $e->getFile(), \FcfVendor\WPDesk_Logger::ERROR);
|
||||
}
|
||||
/**
|
||||
* Log message into WPDesk logger
|
||||
*
|
||||
* @param string $message Message to log.
|
||||
* @param string $source Source of the message - can be file name, class name or whatever.
|
||||
* @param string $level Level of error.
|
||||
*/
|
||||
public static function log_message($message, $source = 'unknown', $level = \FcfVendor\WPDesk_Logger::DEBUG)
|
||||
{
|
||||
self::create_logger();
|
||||
\do_action(self::WPDESK_LOG_ACTION_NAME, $level, $source, $message);
|
||||
self::$logger->wpdesk_log($level, $source, $message);
|
||||
}
|
||||
/**
|
||||
* Log message into WPDesk logger
|
||||
*
|
||||
* @param string $message Message to log.
|
||||
* @param string $level Level of error.
|
||||
* @param array $backtrace Backtrace information with snapshot of error env.
|
||||
*/
|
||||
public static function log_message_backtrace($message, $level = \FcfVendor\WPDesk_Logger::DEBUG, array $backtrace)
|
||||
{
|
||||
$message .= ' Backtrace: ' . \json_encode($backtrace);
|
||||
if (isset($backtrace[self::BACKTRACE_FILENAME_KEY])) {
|
||||
$filename = $backtrace[self::BACKTRACE_FILENAME_KEY];
|
||||
} else {
|
||||
$filename = 'unknown';
|
||||
}
|
||||
self::log_message($message, $filename, $level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace FcfVendor;
|
||||
|
||||
if (!\defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
if (!\class_exists('FcfVendor\\WPDesk_Logger')) {
|
||||
/**
|
||||
* @deprecated Only for backward compatibility. Please use injected Logger compatible with PSR
|
||||
*/
|
||||
class WPDesk_Logger
|
||||
{
|
||||
/** @var \Psr\Log\LoggerInterface */
|
||||
static $logger;
|
||||
const EMERGENCY = 'emergency';
|
||||
const ALERT = 'alert';
|
||||
const CRITICAL = 'critical';
|
||||
const ERROR = 'error';
|
||||
const WARNING = 'warning';
|
||||
const NOTICE = 'notice';
|
||||
const INFO = 'info';
|
||||
const DEBUG = 'debug';
|
||||
public function __construct()
|
||||
{
|
||||
if (!self::$logger) {
|
||||
$loggerFactroy = new \FcfVendor\WPDesk\Logger\WPDeskLoggerFactory();
|
||||
self::$logger = $loggerFactroy->createWPDeskLogger();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Level strings mapped to integer severity.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $level_to_severity = [self::EMERGENCY => 800, self::ALERT => 700, self::CRITICAL => 600, self::ERROR => 500, self::WARNING => 400, self::NOTICE => 300, self::INFO => 200, self::DEBUG => 100];
|
||||
/**
|
||||
* Attach hooks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function attach_hooks()
|
||||
{
|
||||
\add_action('plugins_loaded', [$this, 'plugins_loaded']);
|
||||
\add_filter('wpdesk_logger_level_options', [$this, 'wpdesk_logger_level_options']);
|
||||
}
|
||||
public function plugins_loaded()
|
||||
{
|
||||
if (\defined('WC_VERSION')) {
|
||||
if (\version_compare(\WC_VERSION, '3.0', '<')) {
|
||||
\add_action('wpdesk_log', [$this, 'wpdesk_log'], 10, 4);
|
||||
} else {
|
||||
\add_action('wpdesk_log', [$this, 'wpdesk_log_30'], 10, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function wpdesk_logger_level_options(array $options)
|
||||
{
|
||||
return ['disabled' => \__('Disabled', 'flexible-checkout-fields'), 'emergency' => \__('Emergency', 'flexible-checkout-fields'), 'alert' => \__('Alert', 'flexible-checkout-fields'), 'critical' => \__('Critical', 'flexible-checkout-fields'), 'error' => \__('Error', 'flexible-checkout-fields'), 'warning' => \__('Warning', 'flexible-checkout-fields'), 'notice' => \__('Notice', 'flexible-checkout-fields'), 'info' => \__('Info', 'flexible-checkout-fields'), 'debug' => \__('Debug', 'flexible-checkout-fields')];
|
||||
}
|
||||
/**
|
||||
* @param string $level
|
||||
* @param string $source
|
||||
* @param string $message
|
||||
* @param string $settings_level
|
||||
*/
|
||||
public function wpdesk_log($level, $source, $message, $settings_level = 'debug')
|
||||
{
|
||||
if (!isset($this->level_to_severity[$settings_level]) || !isset($this->level_to_severity[$level])) {
|
||||
return;
|
||||
}
|
||||
if ($this->level_to_severity[$settings_level] > $this->level_to_severity[$level]) {
|
||||
return;
|
||||
}
|
||||
if (\is_array($message) || \is_object($message)) {
|
||||
$message = \print_r($message, \true);
|
||||
}
|
||||
self::$logger->log($level, $message, ['source' => $source]);
|
||||
}
|
||||
public function wpdesk_log_30($level, $source, $message, $settings_level = 'debug')
|
||||
{
|
||||
if (!isset($this->level_to_severity[$settings_level]) || !isset($this->level_to_severity[$level])) {
|
||||
return;
|
||||
}
|
||||
if ($this->level_to_severity[$settings_level] > $this->level_to_severity[$level]) {
|
||||
return;
|
||||
}
|
||||
if (\is_array($message) || \is_object($message)) {
|
||||
$message = \print_r($message, \true);
|
||||
}
|
||||
self::$logger->log($level, $message, ['source' => $source]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user