Logging: Add settings UI to configure the logger (#42979)
* Centralize log level labels * Fire an action specific to loading the Logs tab * Functional settings screen (no way to navigate to it yet) * Deprecate wc_register_default_log_handler * Hook up the settings * Add section nav * Add an action hook to the settings form * Rename render_page method to render_form * Scaffold the unit tests * Remove logging enabled check from WC_Logger construct Caching the enabled setting value turns out to not be a great idea, it breaks some tests, and could cause issues if the setting value changes, and then a logging event happens later in the same request. WP has its own caching layer for options anyway, but one that will update if the value of the option changes. So this just makes the enabled check directly from the should_handle method. * Add most unit tests. Still needs a couple more * Add remaining unit tests * Update since values on new hooks to 8.6.0 * phpcs cleanup * Change deprecated tag from 8.5.0 to 8.6.0 * Add missing return types to unit tests * Add changelog file * Add missing clear method to new log file handler * Change level_threshold default value to 'none' * Ensure logger has a valid level threshold set, regardless of level given * Update legacy unit test * Ensure settings only saved on settings view * Add settings sections for filesystem and database Also add a filesystem setting for collapsing log entry lines. * Add public LoggingUtil class for external usage, and use in WC_Logger * Remove unused import * Deprecate wc_get_log_file_path and wc_get_log_file_name * Preserve white space in log file lines It turns out that several extensions add log entries that are just a print_r of an array. Preserving the white space is important for making this data legible (ideally they'd switch to adding this data within the context parameter) * More legacy unit test fixes * Remove entry collapse option and functionality It's unclear right now that entry collapsing provides much real benefit, while it clearly does have some potential drawbacks if extensions are in use that add print_r output to the log files. * phpcs cleanup * Yet more unit test tweaks * Remove unused code * Don't wrap extra handler options in <code>, it gets excaped * Attempt fix for WC_Tests_Logger::test_clear This is only failing on GH CI, not when running locally. Maybe ensuring all the created log files are deleted will help. * Improve logging of fatal errors This improves the formatting of error messages caught and logged during shutdown to be more legible and to take advantage of the logging method's context parameter. With this change, the log entry will be a simple message on one line, and any stack trace will be available but hidden in an "Additional context" details element. * Tweaks to some settings' wording * Update webooks link to logs, undeprecate * Remove `realpath` usage since it deos not work if log directory does not already exists. --------- Co-authored-by: Vedanshu Jain <vedanshu.jain.2012@gmail.com>
This commit is contained in:
parent
a38c7bcccf
commit
4ecbaf573c
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Make the new log file handler the default logging handler and add a settings screen for configuring the logging system
|
|
@ -1392,6 +1392,7 @@ table.wc_status_table--tools {
|
|||
display: block;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
white-space: pre-wrap;
|
||||
|
||||
&:before {
|
||||
counter-increment: line;
|
||||
|
@ -1422,8 +1423,7 @@ table.wc_status_table--tools {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
details {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
@ -1493,6 +1493,14 @@ table.wc_status_table--tools {
|
|||
}
|
||||
}
|
||||
|
||||
.wc-logs-settings {
|
||||
.wc-settings-row-logs-retention-period-days {
|
||||
td {
|
||||
line-height: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log severity level colors.
|
||||
*
|
||||
|
|
|
@ -43,40 +43,19 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
|
|||
* @global wpdb $wpdb
|
||||
*/
|
||||
public function level_dropdown() {
|
||||
$labels = WC_Log_Levels::get_all_level_labels();
|
||||
|
||||
$levels = array(
|
||||
array(
|
||||
'value' => WC_Log_Levels::EMERGENCY,
|
||||
'label' => __( 'Emergency', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::ALERT,
|
||||
'label' => __( 'Alert', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::CRITICAL,
|
||||
'label' => __( 'Critical', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::ERROR,
|
||||
'label' => __( 'Error', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::WARNING,
|
||||
'label' => __( 'Warning', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::NOTICE,
|
||||
'label' => __( 'Notice', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::INFO,
|
||||
'label' => __( 'Info', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'value' => WC_Log_Levels::DEBUG,
|
||||
'label' => __( 'Debug', 'woocommerce' ),
|
||||
),
|
||||
$levels = array_reduce(
|
||||
array_keys( $labels ),
|
||||
function( $carry, $item ) use ( $labels ) {
|
||||
$carry[] = array(
|
||||
'value' => $item,
|
||||
'label' => $labels[ $item ],
|
||||
);
|
||||
|
||||
return $carry;
|
||||
},
|
||||
array()
|
||||
);
|
||||
|
||||
$selected_level = isset( $_REQUEST['level'] ) ? $_REQUEST['level'] : '';
|
||||
|
@ -181,16 +160,7 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
|
|||
*/
|
||||
public function column_level( $log ) {
|
||||
$level_key = WC_Log_Levels::get_severity_level( $log['level'] );
|
||||
$levels = array(
|
||||
'emergency' => __( 'Emergency', 'woocommerce' ),
|
||||
'alert' => __( 'Alert', 'woocommerce' ),
|
||||
'critical' => __( 'Critical', 'woocommerce' ),
|
||||
'error' => __( 'Error', 'woocommerce' ),
|
||||
'warning' => __( 'Warning', 'woocommerce' ),
|
||||
'notice' => __( 'Notice', 'woocommerce' ),
|
||||
'info' => __( 'Info', 'woocommerce' ),
|
||||
'debug' => __( 'Debug', 'woocommerce' ),
|
||||
);
|
||||
$levels = WC_Log_Levels::get_all_level_labels();
|
||||
|
||||
if ( ! isset( $levels[ $level_key ] ) ) {
|
||||
return '';
|
||||
|
|
|
@ -12,7 +12,6 @@ defined( 'ABSPATH' ) || exit;
|
|||
* Log levels class.
|
||||
*/
|
||||
abstract class WC_Log_Levels {
|
||||
|
||||
/**
|
||||
* Log Levels
|
||||
*
|
||||
|
@ -122,4 +121,39 @@ abstract class WC_Log_Levels {
|
|||
public static function get_all_severity_levels() {
|
||||
return self::$severity_to_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UI label for a log level.
|
||||
*
|
||||
* @param string $level Log level, options: emergency|alert|critical|error|warning|notice|info|debug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_level_label( $level ) {
|
||||
$labels = self::get_all_level_labels();
|
||||
|
||||
if ( ! array_key_exists( $level, $labels ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $labels[ $level ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UI labels for all log levels.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_all_level_labels() {
|
||||
return array(
|
||||
self::EMERGENCY => __( 'Emergency', 'woocommerce' ),
|
||||
self::ALERT => __( 'Alert', 'woocommerce' ),
|
||||
self::CRITICAL => __( 'Critical', 'woocommerce' ),
|
||||
self::ERROR => __( 'Error', 'woocommerce' ),
|
||||
self::WARNING => __( 'Warning', 'woocommerce' ),
|
||||
self::NOTICE => __( 'Notice', 'woocommerce' ),
|
||||
self::INFO => __( 'Info', 'woocommerce' ),
|
||||
self::DEBUG => __( 'Debug', 'woocommerce' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @package WooCommerce\Classes
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\LoggingUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -15,7 +15,6 @@ defined( 'ABSPATH' ) || exit;
|
|||
* WC_Logger class.
|
||||
*/
|
||||
class WC_Logger implements WC_Logger_Interface {
|
||||
|
||||
/**
|
||||
* Stores registered log handlers.
|
||||
*
|
||||
|
@ -38,15 +37,24 @@ class WC_Logger implements WC_Logger_Interface {
|
|||
*/
|
||||
public function __construct( $handlers = null, $threshold = null ) {
|
||||
if ( null === $handlers ) {
|
||||
$handlers = apply_filters( 'woocommerce_register_log_handlers', array() );
|
||||
$default_handler = LoggingUtil::get_default_handler();
|
||||
$handler_instance = new $default_handler();
|
||||
|
||||
/**
|
||||
* Filter the list of log handler class instances that will run whenever a log entry is added.
|
||||
*
|
||||
* @param WC_Log_Handler_Interface[]
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
$handlers = apply_filters( 'woocommerce_register_log_handlers', array( $handler_instance ) );
|
||||
}
|
||||
|
||||
$register_handlers = array();
|
||||
|
||||
if ( ! empty( $handlers ) && is_array( $handlers ) ) {
|
||||
foreach ( $handlers as $handler ) {
|
||||
$implements = class_implements( $handler );
|
||||
if ( is_object( $handler ) && is_array( $implements ) && in_array( 'WC_Log_Handler_Interface', $implements, true ) ) {
|
||||
if ( $handler instanceof WC_Log_Handler_Interface ) {
|
||||
$register_handlers[] = $handler;
|
||||
} else {
|
||||
wc_doing_it_wrong(
|
||||
|
@ -63,20 +71,12 @@ class WC_Logger implements WC_Logger_Interface {
|
|||
}
|
||||
}
|
||||
|
||||
// Support the constant as long as a valid log level has been set for it.
|
||||
if ( null === $threshold ) {
|
||||
$threshold = Constants::get_constant( 'WC_LOG_THRESHOLD' );
|
||||
if ( null !== $threshold && ! WC_Log_Levels::is_valid_level( $threshold ) ) {
|
||||
$threshold = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( null !== $threshold ) {
|
||||
$threshold = WC_Log_Levels::get_level_severity( $threshold );
|
||||
if ( ! WC_Log_Levels::is_valid_level( $threshold ) ) {
|
||||
$threshold = LoggingUtil::get_level_threshold();
|
||||
}
|
||||
|
||||
$this->handlers = $register_handlers;
|
||||
$this->threshold = $threshold;
|
||||
$this->threshold = WC_Log_Levels::get_level_severity( $threshold );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,9 +86,14 @@ class WC_Logger implements WC_Logger_Interface {
|
|||
* @return bool True if the log should be handled.
|
||||
*/
|
||||
protected function should_handle( $level ) {
|
||||
if ( ! LoggingUtil::logging_is_enabled() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( null === $this->threshold ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->threshold <= WC_Log_Levels::get_level_severity( $level );
|
||||
}
|
||||
|
||||
|
@ -131,6 +136,8 @@ class WC_Logger implements WC_Logger_Interface {
|
|||
* 'debug': Debug-level messages.
|
||||
* @param string $message Log message.
|
||||
* @param array $context Optional. Additional information for log handlers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log( $level, $message, $context = array() ) {
|
||||
if ( ! WC_Log_Levels::is_valid_level( $level ) ) {
|
||||
|
@ -300,15 +307,10 @@ class WC_Logger implements WC_Logger_Interface {
|
|||
/**
|
||||
* Clear all logs older than a defined number of days. Defaults to 30 days.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @return void
|
||||
*/
|
||||
public function clear_expired_logs() {
|
||||
/**
|
||||
* Filter the retention period of log entries.
|
||||
*
|
||||
* @param int $days The number of days to retain log entries.
|
||||
*/
|
||||
$days = absint( apply_filters( 'woocommerce_logger_days_to_retain_logs', 30 ) );
|
||||
$days = LoggingUtil::get_retention_period();
|
||||
$timestamp = strtotime( "-{$days} days" );
|
||||
|
||||
foreach ( $this->handlers as $handler ) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil };
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -614,7 +614,7 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
* @return string
|
||||
*/
|
||||
public function get_delivery_logs() {
|
||||
return esc_url( add_query_arg( 'log_file', wc_get_log_file_name( 'webhooks-delivery' ), admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
|
||||
return add_query_arg( 'source', 'webhooks-delivery', LoggingUtil::get_logs_tab_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -298,13 +298,32 @@ final class WooCommerce {
|
|||
public function log_errors() {
|
||||
$error = error_get_last();
|
||||
if ( $error && in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) {
|
||||
$error_copy = $error;
|
||||
$message = $error_copy['message'];
|
||||
unset( $error_copy['message'] );
|
||||
|
||||
$context = array(
|
||||
'source' => 'fatal-errors',
|
||||
'error' => $error_copy,
|
||||
);
|
||||
|
||||
if ( false !== strpos( $message, 'Stack trace:' ) ) {
|
||||
$segments = explode( 'Stack trace:', $message );
|
||||
$message = str_replace( PHP_EOL, ' ', trim( $segments[0] ) );
|
||||
$backtrace = array_map(
|
||||
'trim',
|
||||
explode( PHP_EOL, $segments[1] )
|
||||
);
|
||||
|
||||
$context['backtrace'] = $backtrace;
|
||||
} else {
|
||||
$context['backtrace'] = true;
|
||||
}
|
||||
|
||||
$logger = wc_get_logger();
|
||||
$logger->critical(
|
||||
/* translators: 1: error message 2: file name and path 3: line number */
|
||||
sprintf( __( '%1$s in %2$s on line %3$s', 'woocommerce' ), $error['message'], $error['file'], $error['line'] ) . PHP_EOL,
|
||||
array(
|
||||
'source' => 'fatal-errors',
|
||||
)
|
||||
$message,
|
||||
$context
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -1124,30 +1124,6 @@ function get_woocommerce_api_url( $path ) {
|
|||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file path.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $handle name.
|
||||
* @return string the log file path.
|
||||
*/
|
||||
function wc_get_log_file_path( $handle ) {
|
||||
return WC_Log_Handler_File::get_log_file_path( $handle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file name.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @param string $handle Name.
|
||||
* @return string The log file name.
|
||||
*/
|
||||
function wc_get_log_file_name( $handle ) {
|
||||
return WC_Log_Handler_File::get_log_file_name( $handle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get page children.
|
||||
*
|
||||
|
@ -2101,25 +2077,6 @@ function wc_print_r( $expression, $return = false ) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default log handler.
|
||||
*
|
||||
* @since 3.0
|
||||
* @param array $handlers Handlers.
|
||||
* @return array
|
||||
*/
|
||||
function wc_register_default_log_handler( $handlers ) {
|
||||
$handler_class = Constants::get_constant( 'WC_LOG_HANDLER' );
|
||||
if ( is_null( $handler_class ) || ! class_exists( $handler_class ) ) {
|
||||
$handler_class = WC_Log_Handler_File::class;
|
||||
}
|
||||
|
||||
array_push( $handlers, new $handler_class() );
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
add_filter( 'woocommerce_register_log_handlers', 'wc_register_default_log_handler' );
|
||||
|
||||
/**
|
||||
* Based on wp_list_pluck, this calls a method instead of returning a property.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
|
||||
use Automattic\WooCommerce\Utilities\LoggingUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -1123,3 +1125,57 @@ function get_woocommerce_term_meta( $term_id, $key, $single = true ) {
|
|||
wc_deprecated_function( 'get_woocommerce_term_meta', '3.6', 'get_term_meta' );
|
||||
return function_exists( 'get_term_meta' ) ? get_term_meta( $term_id, $key, $single ) : get_metadata( 'woocommerce_term', $term_id, $key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default log handler.
|
||||
*
|
||||
* @deprecated 8.6.0
|
||||
* @since 3.0
|
||||
* @param array $handlers Handlers.
|
||||
* @return array
|
||||
*/
|
||||
function wc_register_default_log_handler( $handlers = array() ) {
|
||||
wc_deprecated_function( 'wc_register_default_log_handler', '8.6.0' );
|
||||
|
||||
$default_handler = wc_get_container()->get( Settings::class )->get_default_handler();
|
||||
|
||||
array_push( $handlers, new $default_handler() );
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file path.
|
||||
*
|
||||
* @deprecated 8.6.0
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $handle name.
|
||||
* @return string the log file path.
|
||||
*/
|
||||
function wc_get_log_file_path( $handle ) {
|
||||
wc_deprecated_function( 'wc_get_log_file_path', '8.6.0' );
|
||||
|
||||
$directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
|
||||
$file_id = LoggingUtil::generate_log_file_id( $handle, null, time() );
|
||||
$hash = LoggingUtil::generate_log_file_hash( $file_id );
|
||||
|
||||
return "{$directory}{$file_id}-{$hash}.log";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file name.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @param string $handle Name.
|
||||
* @return string The log file name.
|
||||
*/
|
||||
function wc_get_log_file_name( $handle ) {
|
||||
wc_deprecated_function( 'wc_get_log_file_name', '8.6.0' );
|
||||
|
||||
$file_id = LoggingUtil::generate_log_file_id( $handle, null, time() );
|
||||
$hash = LoggingUtil::generate_log_file_hash( $file_id );
|
||||
|
||||
return "{$file_id}-{$hash}";
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ class FileController {
|
|||
* Class FileController
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->log_directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
|
||||
$this->log_directory = trailingslashit( Constants::get_constant( 'WC_LOG_DIR' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
|
||||
use WC_Log_Handler;
|
||||
|
||||
/**
|
||||
|
@ -18,11 +17,19 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
|||
*/
|
||||
private $file_controller;
|
||||
|
||||
/**
|
||||
* Instance of the Settings class.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* LogHandlerFileV2 class.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->file_controller = wc_get_container()->get( FileController::class );
|
||||
$this->settings = wc_get_container()->get( Settings::class );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,20 +80,17 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
|||
$time_string = static::format_time( $timestamp );
|
||||
$level_string = strtoupper( $level );
|
||||
|
||||
// Remove line breaks so the whole entry is on one line in the file.
|
||||
$formatted_message = str_replace( PHP_EOL, ' ', $message );
|
||||
|
||||
unset( $context['source'] );
|
||||
if ( ! empty( $context ) ) {
|
||||
if ( isset( $context['backtrace'] ) && true === filter_var( $context['backtrace'], FILTER_VALIDATE_BOOLEAN ) ) {
|
||||
$context['backtrace'] = static::get_backtrace();
|
||||
}
|
||||
|
||||
$formatted_context = wp_json_encode( $context );
|
||||
$formatted_message .= " CONTEXT: $formatted_context";
|
||||
$formatted_context = wp_json_encode( $context );
|
||||
$message .= " CONTEXT: $formatted_context";
|
||||
}
|
||||
|
||||
$entry = "$time_string $level_string $formatted_message";
|
||||
$entry = "$time_string $level_string $message";
|
||||
|
||||
// phpcs:disable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
/** This filter is documented in includes/abstracts/abstract-wc-log-handler.php */
|
||||
|
@ -152,6 +156,63 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
|||
return sanitize_title( $source );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all logs from a specific source.
|
||||
*
|
||||
* @param string $source The source of the log entries.
|
||||
*
|
||||
* @return int The number of files that were deleted.
|
||||
*/
|
||||
public function clear( string $source ): int {
|
||||
$source = File::sanitize_source( $source );
|
||||
|
||||
$files = $this->file_controller->get_files(
|
||||
array(
|
||||
'source' => $source,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $files ) || count( $files ) < 1 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$file_ids = array_map(
|
||||
fn( $file ) => $file->get_file_id(),
|
||||
$files
|
||||
);
|
||||
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
|
||||
if ( $deleted > 0 ) {
|
||||
$this->handle(
|
||||
time(),
|
||||
'info',
|
||||
sprintf(
|
||||
esc_html(
|
||||
// translators: %1$s is a number of log files, %2$s is a slug-style name for a file.
|
||||
_n(
|
||||
'%1$s log file from source %2$s was deleted.',
|
||||
'%1$s log files from source %2$s were deleted.',
|
||||
$deleted,
|
||||
'woocommerce'
|
||||
)
|
||||
),
|
||||
number_format_i18n( $deleted ),
|
||||
sprintf(
|
||||
'<code>%s</code>',
|
||||
esc_html( $source )
|
||||
)
|
||||
),
|
||||
array(
|
||||
'source' => 'wc_logger',
|
||||
'backtrace' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all logs older than a specified timestamp.
|
||||
*
|
||||
|
@ -172,7 +233,7 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
|||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $files ) ) {
|
||||
if ( is_wp_error( $files ) || count( $files ) < 1 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -181,12 +242,8 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
|||
$files
|
||||
);
|
||||
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
|
||||
// phpcs:disable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
/** This filter is documented in includes/class-wc-logger.php. */
|
||||
$retention_days = absint( apply_filters( 'woocommerce_logger_days_to_retain_logs', 30 ) );
|
||||
// phpcs:enable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
$retention_days = $this->settings->get_retention_period();
|
||||
|
||||
if ( $deleted > 0 ) {
|
||||
$this->handle(
|
||||
|
|
|
@ -4,7 +4,7 @@ declare( strict_types = 1 );
|
|||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController, FileListTable, SearchListTable };
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use WC_Admin_Status;
|
||||
|
@ -26,6 +26,13 @@ class PageController {
|
|||
*/
|
||||
private $file_controller;
|
||||
|
||||
/**
|
||||
* Instance of Settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Instance of FileListTable or SearchListTable.
|
||||
*
|
||||
|
@ -39,13 +46,16 @@ class PageController {
|
|||
* @internal
|
||||
*
|
||||
* @param FileController $file_controller Instance of FileController.
|
||||
* @param Settings $settings Instance of Settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function init(
|
||||
FileController $file_controller
|
||||
FileController $file_controller,
|
||||
Settings $settings
|
||||
): void {
|
||||
$this->file_controller = $file_controller;
|
||||
$this->settings = $settings;
|
||||
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
@ -56,8 +66,61 @@ class PageController {
|
|||
* @return void
|
||||
*/
|
||||
private function init_hooks(): void {
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'setup_screen_options' ) );
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'handle_list_table_bulk_actions' ) );
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'maybe_do_logs_tab_action' ), 2 );
|
||||
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'setup_screen_options' ) );
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'handle_list_table_bulk_actions' ) );
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'notices' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current tab on the Status page is Logs, and if so, fire an action.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_do_logs_tab_action(): void {
|
||||
$is_logs_tab = 'logs' === filter_input( INPUT_GET, 'tab' );
|
||||
|
||||
if ( $is_logs_tab ) {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
|
||||
/**
|
||||
* Action fires when the Logs tab starts loading.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_load_tab', $params['view'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notices to display on Logs screens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function notices() {
|
||||
if ( ! $this->settings->logging_is_enabled() ) {
|
||||
add_action(
|
||||
'admin_notices',
|
||||
function() {
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %s is a URL to another admin screen.
|
||||
wp_kses_post( __( 'Logging is disabled. It can be enabled in <a href="%s">Logs Settings</a>.', 'woocommerce' ) ),
|
||||
esc_url( add_query_arg( 'view', 'settings', $this->get_logs_tab_url() ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,40 +138,83 @@ class PageController {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the default log handler.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_default_handler(): string {
|
||||
$handler = Constants::get_constant( 'WC_LOG_HANDLER' );
|
||||
|
||||
if ( is_null( $handler ) || ! class_exists( $handler ) ) {
|
||||
$handler = WC_Log_Handler_File::class;
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the "Logs" tab, depending on the current default log handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(): void {
|
||||
$handler = $this->get_default_handler();
|
||||
$handler = $this->settings->get_default_handler();
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
|
||||
$this->render_section_nav();
|
||||
|
||||
if ( 'settings' === $params['view'] ) {
|
||||
$this->settings->render_form();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( $handler ) {
|
||||
case LogHandlerFileV2::class:
|
||||
$this->render_filev2();
|
||||
break;
|
||||
case 'WC_Log_Handler_DB':
|
||||
return;
|
||||
case WC_Log_Handler_DB::class:
|
||||
WC_Admin_Status::status_logs_db();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
case WC_Log_Handler_File::class:
|
||||
WC_Admin_Status::status_logs_file();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action fires only if there is not a built-in rendering method for the current default log handler.
|
||||
*
|
||||
* This is intended as a way for extensions to render log views for custom handlers.
|
||||
*
|
||||
* @param string $handler
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_render_page', $handler );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render navigation to switch between logs browsing and settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_section_nav(): void {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$browse_url = $this->get_logs_tab_url();
|
||||
$settings_url = add_query_arg( 'view', 'settings', $this->get_logs_tab_url() );
|
||||
|
||||
?>
|
||||
<ul class="subsubsub">
|
||||
<li>
|
||||
<?php
|
||||
printf(
|
||||
'<a href="%1$s"%2$s>%3$s</a>',
|
||||
esc_url( $browse_url ),
|
||||
'settings' !== $params['view'] ? ' class="current"' : '',
|
||||
esc_html__( 'Browse', 'woocommerce' )
|
||||
);
|
||||
?>
|
||||
|
|
||||
</li>
|
||||
<li>
|
||||
<?php
|
||||
printf(
|
||||
'<a href="%1$s"%2$s>%3$s</a>',
|
||||
esc_url( $settings_url ),
|
||||
'settings' === $params['view'] ? ' class="current"' : '',
|
||||
esc_html__( 'Settings', 'woocommerce' )
|
||||
);
|
||||
?>
|
||||
</li>
|
||||
</ul>
|
||||
<br class="clear">
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,7 +420,7 @@ class PageController {
|
|||
* @return void
|
||||
*/
|
||||
private function render_search_results_view(): void {
|
||||
$params = $this->get_query_params( array( 'order', 'orderby', 'search', 'source', 'view' ) );
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$list_table = $this->get_list_table( $params['view'] );
|
||||
|
||||
$list_table->prepare_items();
|
||||
|
@ -391,7 +497,7 @@ class PageController {
|
|||
'view' => array(
|
||||
'filter' => FILTER_VALIDATE_REGEXP,
|
||||
'options' => array(
|
||||
'regexp' => '/^(list_files|single_file|search_results)$/',
|
||||
'regexp' => '/^(list_files|single_file|search_results|settings)$/',
|
||||
'default' => $defaults['view'],
|
||||
),
|
||||
),
|
||||
|
@ -434,17 +540,18 @@ class PageController {
|
|||
/**
|
||||
* Register screen options for the logging views.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setup_screen_options(): void {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$handler = $this->get_default_handler();
|
||||
private function setup_screen_options( string $view ): void {
|
||||
$handler = $this->settings->get_default_handler();
|
||||
$list_table = null;
|
||||
|
||||
switch ( $handler ) {
|
||||
case LogHandlerFileV2::class:
|
||||
if ( in_array( $params['view'], array( 'list_files', 'search_results' ), true ) ) {
|
||||
$list_table = $this->get_list_table( $params['view'] );
|
||||
if ( in_array( $view, array( 'list_files', 'search_results' ), true ) ) {
|
||||
$list_table = $this->get_list_table( $view );
|
||||
}
|
||||
break;
|
||||
case 'WC_Log_Handler_DB':
|
||||
|
@ -469,22 +576,24 @@ class PageController {
|
|||
/**
|
||||
* Process bulk actions initiated from the log file list table.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handle_list_table_bulk_actions(): void {
|
||||
private function handle_list_table_bulk_actions( string $view ): void {
|
||||
// Bail if we're not using the file handler.
|
||||
if ( LogHandlerFileV2::class !== $this->get_default_handler() ) {
|
||||
if ( LogHandlerFileV2::class !== $this->settings->get_default_handler() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$params = $this->get_query_params( array( 'file_id', 'view' ) );
|
||||
$params = $this->get_query_params( array( 'file_id' ) );
|
||||
|
||||
// Bail if this is not the list table view.
|
||||
if ( 'list_files' !== $params['view'] ) {
|
||||
if ( 'list_files' !== $view ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$action = $this->get_list_table( $params['view'] )->current_action();
|
||||
$action = $this->get_list_table( $view )->current_action();
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : $this->get_logs_tab_url();
|
||||
|
@ -573,10 +682,9 @@ class PageController {
|
|||
* @return string
|
||||
*/
|
||||
private function format_line( string $line, int $line_number ): string {
|
||||
$severity_levels = WC_Log_Levels::get_all_severity_levels();
|
||||
$classes = array( 'line' );
|
||||
$classes = array( 'line' );
|
||||
|
||||
$line = esc_html( trim( $line ) );
|
||||
$line = esc_html( $line );
|
||||
if ( empty( $line ) ) {
|
||||
$line = ' ';
|
||||
}
|
||||
|
@ -594,11 +702,11 @@ class PageController {
|
|||
$has_timestamp = true;
|
||||
}
|
||||
|
||||
if ( isset( $segments[1] ) && in_array( strtolower( $segments[1] ), $severity_levels, true ) ) {
|
||||
if ( isset( $segments[1] ) && WC_Log_Levels::is_valid_level( strtolower( $segments[1] ) ) ) {
|
||||
$segments[1] = sprintf(
|
||||
'<span class="%1$s">%2$s</span>',
|
||||
esc_attr( 'log-level log-level--' . strtolower( $segments[1] ) ),
|
||||
esc_html( $segments[1] )
|
||||
esc_html( WC_Log_Levels::get_level_label( strtolower( $segments[1] ) ) )
|
||||
);
|
||||
$has_level = true;
|
||||
}
|
||||
|
@ -611,7 +719,7 @@ class PageController {
|
|||
$context = json_decode( $maybe_json, false, 512, JSON_THROW_ON_ERROR );
|
||||
|
||||
$message_chunks[1] = sprintf(
|
||||
'<details><summary>%1$s</summary><pre>%2$s</pre></details>',
|
||||
'<details><summary>%1$s</summary>%2$s</details>',
|
||||
esc_html__( 'Additional context', 'woocommerce' ),
|
||||
wp_json_encode( $context, JSON_PRETTY_PRINT )
|
||||
);
|
||||
|
|
|
@ -0,0 +1,449 @@
|
|||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use WC_Admin_Settings;
|
||||
use WC_Log_Handler, WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
|
||||
|
||||
/**
|
||||
* Settings class.
|
||||
*/
|
||||
class Settings {
|
||||
|
||||
use AccessiblePrivateMethods;
|
||||
|
||||
/**
|
||||
* Default values for logging settings.
|
||||
*
|
||||
* @const array
|
||||
*/
|
||||
private const DEFAULTS = array(
|
||||
'logging_enabled' => true,
|
||||
'default_handler' => LogHandlerFileV2::class,
|
||||
'retention_period_days' => 30,
|
||||
'level_threshold' => 'none',
|
||||
'file_entry_collapse_lines' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* The prefix for settings keys used in the options table.
|
||||
*
|
||||
* @const string
|
||||
*/
|
||||
private const PREFIX = 'woocommerce_logs_';
|
||||
|
||||
/**
|
||||
* Class Settings.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'save_settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render and save settings controls.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_settings_definitions(): array {
|
||||
$settings = array(
|
||||
'start' => array(
|
||||
'title' => __( 'Logs settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'logging_enabled' => array(
|
||||
'title' => __( 'Logger', 'woocommerce' ),
|
||||
'desc' => __( 'Enable logging', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'logging_enabled',
|
||||
'type' => 'checkbox',
|
||||
'value' => $this->logging_is_enabled() ? 'yes' : 'no',
|
||||
'default' => self::DEFAULTS['logging_enabled'] ? 'yes' : 'no',
|
||||
'autoload' => false,
|
||||
),
|
||||
'default_handler' => array(),
|
||||
'retention_period_days' => array(),
|
||||
'level_threshold' => array(),
|
||||
'end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
|
||||
if ( true === $this->logging_is_enabled() ) {
|
||||
$settings['default_handler'] = $this->get_default_handler_setting_definition();
|
||||
$settings['retention_period_days'] = $this->get_retention_period_days_setting_definition();
|
||||
$settings['level_threshold'] = $this->get_level_threshold_setting_definition();
|
||||
}
|
||||
|
||||
$default_handler = $this->get_default_handler();
|
||||
if ( in_array( $default_handler, array( LogHandlerFileV2::class, WC_Log_Handler_File::class ), true ) ) {
|
||||
$settings += $this->get_filesystem_settings_definitions();
|
||||
} elseif ( WC_Log_Handler_DB::class === $default_handler ) {
|
||||
$settings += $this->get_database_settings_definitions();
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the default_handler setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_default_handler_setting_definition(): array {
|
||||
$handler_options = array(
|
||||
LogHandlerFileV2::class => __( 'File system (default)', 'woocommerce' ),
|
||||
WC_Log_Handler_DB::class => __( 'Database (not recommended on live sites)', 'woocommerce' ),
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter the list of logging handlers that can be set as the default handler.
|
||||
*
|
||||
* @param array $handler_options An associative array of class_name => description.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
$handler_options = apply_filters( 'woocommerce_logger_handler_options', $handler_options );
|
||||
|
||||
$current_value = $this->get_default_handler();
|
||||
if ( ! array_key_exists( $current_value, $handler_options ) ) {
|
||||
$handler_options[ $current_value ] = $current_value;
|
||||
}
|
||||
|
||||
$desc = array();
|
||||
|
||||
$desc[] = __( 'Note that if this setting is changed, any log entries that have already been recorded will remain stored in their current location, but will not migrate.', 'woocommerce' );
|
||||
|
||||
$hardcoded = ! is_null( Constants::get_constant( 'WC_LOG_HANDLER' ) );
|
||||
if ( $hardcoded ) {
|
||||
$desc[] = sprintf(
|
||||
// translators: %s is the name of a code variable.
|
||||
__( 'This setting cannot be changed here because it is defined in the %s constant.', 'woocommerce' ),
|
||||
'<code>WC_LOG_HANDLER</code>'
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Log storage', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This determines where log entries are saved.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'default_handler',
|
||||
'type' => 'radio',
|
||||
'value' => $current_value,
|
||||
'default' => self::DEFAULTS['default_handler'],
|
||||
'autoload' => false,
|
||||
'options' => $handler_options,
|
||||
'disabled' => $hardcoded ? array_keys( $handler_options ) : array(),
|
||||
'desc' => implode( '<br><br>', $desc ),
|
||||
'desc_at_end' => true,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the retention_period_days setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_retention_period_days_setting_definition(): array {
|
||||
$custom_attributes = array(
|
||||
'min' => 1,
|
||||
'step' => 1,
|
||||
);
|
||||
|
||||
$hardcoded = has_filter( 'woocommerce_logger_days_to_retain_logs' );
|
||||
$desc = '';
|
||||
if ( $hardcoded ) {
|
||||
$custom_attributes['disabled'] = 'true';
|
||||
|
||||
$desc = sprintf(
|
||||
// translators: %s is the name of a filter hook.
|
||||
__( 'This setting cannot be changed here because it is being set by a filter on the %s hook.', 'woocommerce' ),
|
||||
'<code>woocommerce_logger_days_to_retain_logs</code>'
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Retention period', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This sets how many days log entries will be kept before being auto-deleted.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'retention_period_days',
|
||||
'type' => 'number',
|
||||
'value' => $this->get_retention_period(),
|
||||
'default' => self::DEFAULTS['retention_period_days'],
|
||||
'autoload' => false,
|
||||
'custom_attributes' => $custom_attributes,
|
||||
'css' => 'width:70px;',
|
||||
'row_class' => 'logs-retention-period-days',
|
||||
'suffix' => sprintf(
|
||||
' %s',
|
||||
__( 'days', 'woocommerce' ),
|
||||
),
|
||||
'desc' => $desc,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the level_threshold setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_level_threshold_setting_definition(): array {
|
||||
$hardcoded = ! is_null( Constants::get_constant( 'WC_LOG_THRESHOLD' ) );
|
||||
$desc = '';
|
||||
if ( $hardcoded ) {
|
||||
$desc = sprintf(
|
||||
// translators: %1$s is the name of a code variable. %2$s is the name of a file.
|
||||
__( 'This setting cannot be changed here because it is defined in the %1$s constant, probably in your %2$s file.', 'woocommerce' ),
|
||||
'<code>WC_LOG_THRESHOLD</code>',
|
||||
'<b>wp-config.php</b>'
|
||||
);
|
||||
}
|
||||
|
||||
$labels = WC_Log_Levels::get_all_level_labels();
|
||||
$labels['none'] = __( 'None', 'woocommerce' );
|
||||
|
||||
$custom_attributes = array();
|
||||
if ( $hardcoded ) {
|
||||
$custom_attributes['disabled'] = 'true';
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Level threshold', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This sets the minimum severity level of logs that will be stored. Lower severity levels will be ignored. "None" means all logs will be stored.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'level_threshold',
|
||||
'type' => 'select',
|
||||
'value' => $this->get_level_threshold(),
|
||||
'default' => self::DEFAULTS['level_threshold'],
|
||||
'autoload' => false,
|
||||
'options' => $labels,
|
||||
'custom_attributes' => $custom_attributes,
|
||||
'css' => 'width:auto;',
|
||||
'desc' => $desc,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render settings related to filesystem log handlers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_filesystem_settings_definitions(): array {
|
||||
$location_info = array();
|
||||
$directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
|
||||
|
||||
$location_info[] = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
__( 'Log files are stored in this directory: %s', 'woocommerce' ),
|
||||
sprintf(
|
||||
'<code>%s</code>',
|
||||
esc_html( $directory )
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! wp_is_writable( $directory ) ) {
|
||||
$location_info[] = __( '⚠️ This directory does not appear to be writable.', 'woocommerce' );
|
||||
}
|
||||
|
||||
$location_info[] = sprintf(
|
||||
// translators: %1$s is a code variable. %2$s is the name of a file.
|
||||
__( 'Change the location by defining the %1$s constant in your %2$s file with a new path.', 'woocommerce' ),
|
||||
'<code>WC_LOG_DIR</code>',
|
||||
'<code>wp-config.php</code>'
|
||||
);
|
||||
|
||||
return array(
|
||||
'file_start' => array(
|
||||
'title' => __( 'File system settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'log_directory' => array(
|
||||
'type' => 'info',
|
||||
'text' => implode( "\n\n", $location_info ),
|
||||
),
|
||||
'entry_format' => array(),
|
||||
'file_end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render settings related to database log handlers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_database_settings_definitions(): array {
|
||||
global $wpdb;
|
||||
$table = "{$wpdb->prefix}woocommerce_log";
|
||||
|
||||
$location_info = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
__( 'Log entries are stored in this database table: %s', 'woocommerce' ),
|
||||
"<code>$table</code>"
|
||||
);
|
||||
|
||||
return array(
|
||||
'file_start' => array(
|
||||
'title' => __( 'Database settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'database_table' => array(
|
||||
'type' => 'info',
|
||||
'text' => $location_info,
|
||||
),
|
||||
'file_end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the submission of the settings form and update the settings values.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_settings( string $view ): void {
|
||||
$is_saving = 'settings' === $view && isset( $_POST['save_settings'] );
|
||||
|
||||
if ( $is_saving ) {
|
||||
check_admin_referer( self::PREFIX . 'settings' );
|
||||
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to manage logging settings.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
$settings = $this->get_settings_definitions();
|
||||
|
||||
WC_Admin_Settings::save_fields( $settings );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the settings page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_form(): void {
|
||||
$settings = $this->get_settings_definitions();
|
||||
|
||||
?>
|
||||
<form id="mainform" class="wc-logs-settings" method="post">
|
||||
<?php WC_Admin_Settings::output_fields( $settings ); ?>
|
||||
<?php
|
||||
/**
|
||||
* Action fires after the built-in logging settings controls have been rendered.
|
||||
*
|
||||
* This is intended as a way to allow other logging settings controls to be added by extensions.
|
||||
*
|
||||
* @param bool $enabled True if logging is currently enabled.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_settings_form_fields', $this->logging_is_enabled() );
|
||||
?>
|
||||
<?php wp_nonce_field( self::PREFIX . 'settings' ); ?>
|
||||
<?php submit_button( __( 'Save changes', 'woocommerce' ), 'primary', 'save_settings' ); ?>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the logging_enabled setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function logging_is_enabled(): bool {
|
||||
$key = self::PREFIX . 'logging_enabled';
|
||||
|
||||
$enabled = WC_Admin_Settings::get_option( $key, self::DEFAULTS['logging_enabled'] );
|
||||
$enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ( is_null( $enabled ) ) {
|
||||
$enabled = self::DEFAULTS['logging_enabled'];
|
||||
}
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the default_handler setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_default_handler(): string {
|
||||
$key = self::PREFIX . 'default_handler';
|
||||
|
||||
$handler = Constants::get_constant( 'WC_LOG_HANDLER' );
|
||||
|
||||
if ( is_null( $handler ) ) {
|
||||
$handler = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
if ( ! class_exists( $handler ) || ! is_a( $handler, 'WC_Log_Handler_Interface', true ) ) {
|
||||
$handler = self::DEFAULTS['default_handler'];
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the retention_period_days setting.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_retention_period(): int {
|
||||
$key = self::PREFIX . 'retention_period_days';
|
||||
|
||||
$retention_period = self::DEFAULTS['retention_period_days'];
|
||||
|
||||
if ( has_filter( 'woocommerce_logger_days_to_retain_logs' ) ) {
|
||||
/**
|
||||
* Filter the retention period of log entries.
|
||||
*
|
||||
* @param int $days The number of days to retain log entries.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*/
|
||||
$retention_period = apply_filters( 'woocommerce_logger_days_to_retain_logs', $retention_period );
|
||||
} else {
|
||||
$retention_period = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
$retention_period = absint( $retention_period );
|
||||
|
||||
if ( $retention_period < 1 ) {
|
||||
$retention_period = self::DEFAULTS['retention_period_days'];
|
||||
}
|
||||
|
||||
return $retention_period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the level_threshold setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_level_threshold(): string {
|
||||
$key = self::PREFIX . 'level_threshold';
|
||||
|
||||
$threshold = Constants::get_constant( 'WC_LOG_THRESHOLD' );
|
||||
|
||||
if ( is_null( $threshold ) ) {
|
||||
$threshold = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
if ( ! WC_Log_Levels::is_valid_level( $threshold ) ) {
|
||||
$threshold = self::DEFAULTS['level_threshold'];
|
||||
}
|
||||
|
||||
return $threshold;
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\PageController;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ FileController, ListTable };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@ class LoggingServiceProvider extends AbstractServiceProvider {
|
|||
protected $provides = array(
|
||||
FileController::class,
|
||||
PageController::class,
|
||||
Settings::class,
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -31,7 +32,10 @@ class LoggingServiceProvider extends AbstractServiceProvider {
|
|||
$this->share( PageController::class )->addArguments(
|
||||
array(
|
||||
FileController::class,
|
||||
Settings::class,
|
||||
)
|
||||
);
|
||||
|
||||
$this->share( Settings::class );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with logging.
|
||||
*/
|
||||
final class LoggingUtil {
|
||||
/**
|
||||
* Get the canonical URL for the Logs tab of the Status admin page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_logs_tab_url(): string {
|
||||
return wc_get_container()->get( PageController::class )->get_logs_tab_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the logging_enabled setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function logging_is_enabled(): bool {
|
||||
return wc_get_container()->get( Settings::class )->logging_is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the default_handler setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_handler(): string {
|
||||
return wc_get_container()->get( Settings::class )->get_default_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the retention_period_days setting.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_retention_period(): int {
|
||||
return wc_get_container()->get( Settings::class )->get_retention_period();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the level_threshold setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_level_threshold(): string {
|
||||
return wc_get_container()->get( Settings::class )->get_level_threshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a public ID for a log file based on its properties.
|
||||
*
|
||||
* The file ID is the basename of the file without the hash part. It allows us to identify a file without revealing
|
||||
* its full name in the filesystem, so that it's difficult to access the file directly with an HTTP request.
|
||||
*
|
||||
* @param string $source The source of the log entries contained in the file.
|
||||
* @param int|null $rotation Optional. The 0-based incremental rotation marker, if the file has been rotated.
|
||||
* Should only be a single digit.
|
||||
* @param int $created Optional. The date the file was created, as a Unix timestamp.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generate_log_file_id( string $source, ?int $rotation = null, int $created = 0 ): string {
|
||||
return File::generate_file_id( $source, $rotation, $created );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a hash to use as the suffix on a log filename.
|
||||
*
|
||||
* @param string $file_id A file ID (file basename without the hash).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generate_log_file_hash( string $file_id ): string {
|
||||
return File::generate_hash( $file_id );
|
||||
}
|
||||
}
|
|
@ -98,10 +98,10 @@ class WC_Tests_Log_Handler_File extends WC_Unit_Test_Case {
|
|||
*/
|
||||
public function test_remove() {
|
||||
$handler = new WC_Log_Handler_File();
|
||||
$log_name = '_test_remove';
|
||||
$log_name = 'test_remove';
|
||||
$handler->handle( time(), 'debug', 'debug', array( 'source' => $log_name ) );
|
||||
$handler->remove( wc_get_log_file_name( $log_name ) );
|
||||
$this->assertFileDoesNotExist( WC_Log_Handler_File::get_log_file_path( $log_name ) );
|
||||
$handler->remove( $handler::get_log_file_name( $log_name ) );
|
||||
$this->assertFileDoesNotExist( $handler::get_log_file_path( $log_name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,12 +5,45 @@
|
|||
* @package WooCommerce\Tests
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
/**
|
||||
* Class WC_Tests_Logger
|
||||
* @package WooCommerce\Tests\Log
|
||||
* @since 2.3
|
||||
*/
|
||||
class WC_Tests_Logger extends WC_Unit_Test_Case {
|
||||
/**
|
||||
* Set up to do before running any of these tests.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
self::delete_all_log_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down after each test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown(): void {
|
||||
self::delete_all_log_files();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all existing log files.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function delete_all_log_files(): void {
|
||||
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
|
||||
foreach ( $files as $file ) {
|
||||
unlink( $file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test add().
|
||||
|
@ -48,13 +81,13 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
|
|||
* @since 2.4
|
||||
*/
|
||||
public function test_clear() {
|
||||
// phpcs:disable WordPress.WP.AlternativeFunctions
|
||||
$file = wc_get_log_file_path( 'unit-tests' );
|
||||
file_put_contents( $file, 'Test file content.' );
|
||||
$path = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . 'unit-tests.log';
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
|
||||
file_put_contents( $path, 'Test file content.' );
|
||||
$this->assertFileExists( $path );
|
||||
$log = new WC_Logger();
|
||||
$log->clear( 'unit-tests' );
|
||||
$this->assertEquals( '', file_get_contents( $file ) );
|
||||
// phpcs:enable WordPress.WP.AlternativeFunctions
|
||||
$this->assertFileDoesNotExist( $path );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\LoggingUtil;
|
||||
|
||||
/**
|
||||
* Core function unit tests.
|
||||
|
@ -281,11 +282,14 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case {
|
|||
* @since 2.4
|
||||
*/
|
||||
public function test_wc_get_log_file_path() {
|
||||
$log_dir = trailingslashit( WC_LOG_DIR );
|
||||
$hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) );
|
||||
$date_suffix = date( 'Y-m-d', time() ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
|
||||
$this->setExpectedDeprecated( 'wc_get_log_file_path' );
|
||||
|
||||
$this->assertEquals( $log_dir . 'unit-tests-' . $date_suffix . '-' . $hash_name . '.log', wc_get_log_file_path( 'unit-tests' ) );
|
||||
$log_dir = trailingslashit( WC_LOG_DIR );
|
||||
$hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) );
|
||||
$file_id = LoggingUtil::generate_log_file_id( 'unit-tests', null, time() );
|
||||
$hash = LoggingUtil::generate_log_file_hash( $file_id );
|
||||
|
||||
$this->assertEquals( $log_dir . $file_id . '-' . $hash . '.log', wc_get_log_file_path( 'unit-tests' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -744,6 +748,7 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case {
|
|||
* @return void
|
||||
*/
|
||||
public function test_wc_get_log_file_name() {
|
||||
$this->setExpectedDeprecated( 'wc_get_log_file_name' );
|
||||
$this->assertNotEmpty( wc_get_log_file_name( 'test' ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ MESSAGE;
|
|||
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$actual_content = file_get_contents( reset( $paths ) );
|
||||
$expected_content = gmdate( 'c', $time ) . ' DEBUG How to win 1. Bake cookies 2. ??? 3. Profit' . "\n";
|
||||
$expected_content = gmdate( 'c', $time ) . ' DEBUG ' . $message . "\n";
|
||||
|
||||
$this->assertEquals( $expected_content, $actual_content );
|
||||
}
|
||||
|
@ -252,7 +252,34 @@ MESSAGE;
|
|||
/**
|
||||
* @testdox Check that the delete_logs_before_timestamp method deletes files based on their created date.
|
||||
*/
|
||||
public function test_delete_logs() {
|
||||
public function test_clear() {
|
||||
$this->sut->handle( time(), 'debug', 'duck', array( 'source' => 'duck' ) );
|
||||
$this->sut->handle( strtotime( '-2 days' ), 'debug', 'duck', array( 'source' => 'duck' ) );
|
||||
$this->sut->handle( strtotime( '-4 days' ), 'debug', 'duck', array( 'source' => 'duck' ) );
|
||||
$this->sut->handle( time(), 'debug', 'goose', array( 'source' => 'goose' ) );
|
||||
|
||||
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
|
||||
$this->assertCount( 4, $paths );
|
||||
|
||||
$result = $this->sut->clear( 'duck' );
|
||||
$this->assertEquals( 3, $result );
|
||||
|
||||
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
|
||||
$this->assertCount( 2, $paths ); // New log gets created when old logs are deleted!
|
||||
|
||||
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . 'wc_logger*.log' );
|
||||
$this->assertCount( 1, $paths );
|
||||
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$actual_content = file_get_contents( reset( $paths ) );
|
||||
$expected_string = '3 log files from source <code>duck</code> were deleted.';
|
||||
$this->assertStringContainsString( $expected_string, $actual_content );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the delete_logs_before_timestamp method deletes files based on their created date.
|
||||
*/
|
||||
public function test_delete_logs_before_timestamp() {
|
||||
$current_time = time();
|
||||
$past_time = strtotime( '-5 days' );
|
||||
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
<?php
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Tests\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
|
||||
use WC_Logger;
|
||||
use WC_Log_Handler_DB, WC_Log_Handler_Email;
|
||||
use WC_Unit_Test_Case;
|
||||
|
||||
/**
|
||||
* SettingsTest class.
|
||||
*/
|
||||
class SettingsTest extends WC_Unit_Test_Case {
|
||||
/**
|
||||
* "System Under Test", an instance of the class to be tested.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $sut;
|
||||
|
||||
/**
|
||||
* Instance of the WC_Logger class.
|
||||
*
|
||||
* @var WC_Logger
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Instance of the FileController class.
|
||||
*
|
||||
* @var FileController
|
||||
*/
|
||||
private $file_controller;
|
||||
|
||||
/**
|
||||
* Set up to do before running any of these tests.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
self::delete_all_log_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up before each test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->sut = new Settings();
|
||||
$this->logger = new WC_Logger();
|
||||
$this->file_controller = new FileController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down after each test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown(): void {
|
||||
self::delete_all_log_files();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all existing log files.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function delete_all_log_files(): void {
|
||||
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
|
||||
foreach ( $files as $file ) {
|
||||
unlink( $file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that log entries can be recorded while logging is enabled.
|
||||
*/
|
||||
public function test_logs_created_while_logging_enabled(): void {
|
||||
$this->assertTrue( $this->sut->logging_is_enabled() );
|
||||
|
||||
$files = $this->file_controller->get_files();
|
||||
$this->assertCount( 0, $files );
|
||||
|
||||
$this->logger->debug( 'Test' );
|
||||
|
||||
$files = $this->file_controller->get_files();
|
||||
$this->assertCount( 1, $files );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that log entries cannot be recorded while logging is disabled.
|
||||
*/
|
||||
public function test_logs_not_created_while_logging_disabled(): void {
|
||||
update_option( 'woocommerce_logs_logging_enabled', 'no' );
|
||||
$this->assertFalse( $this->sut->logging_is_enabled() );
|
||||
|
||||
$files = $this->file_controller->get_files();
|
||||
$this->assertCount( 0, $files );
|
||||
|
||||
$this->logger->debug( 'Test' );
|
||||
|
||||
$files = $this->file_controller->get_files();
|
||||
$this->assertCount( 0, $files );
|
||||
|
||||
delete_option( 'woocommerce_logs_logging_enabled' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_default_handler method returns the default value when nothing else has been set.
|
||||
*/
|
||||
public function test_default_handler_setting_default_value(): void {
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( LogHandlerFileV2::class, $handler );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_default_handler method returns the value set in WC_LOG_HANDLER as long as it's a
|
||||
* valid handler class.
|
||||
*/
|
||||
public function test_default_handler_setting_with_constant(): void {
|
||||
Constants::set_constant( 'WC_LOG_HANDLER', WC_Log_Handler_DB::class );
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( WC_Log_Handler_DB::class, $handler );
|
||||
|
||||
// Invalid handler.
|
||||
Constants::set_constant( 'WC_LOG_HANDLER', 'Fluffernutter' );
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( LogHandlerFileV2::class, $handler );
|
||||
|
||||
Constants::clear_single_constant( 'WC_LOG_HANDLER' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_default_handler method returns the value set in the options table as long as it's a
|
||||
* valid handler class.
|
||||
*/
|
||||
public function test_default_handler_setting_with_option_value(): void {
|
||||
update_option( 'woocommerce_logs_default_handler', WC_Log_Handler_Email::class );
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( WC_Log_Handler_Email::class, $handler );
|
||||
|
||||
// Constant overrides option.
|
||||
Constants::set_constant( 'WC_LOG_HANDLER', WC_Log_Handler_DB::class );
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( WC_Log_Handler_DB::class, $handler );
|
||||
Constants::clear_single_constant( 'WC_LOG_HANDLER' );
|
||||
|
||||
// Invalid handler.
|
||||
update_option( 'woocommerce_logs_default_handler', 'Smorgasbord' );
|
||||
$handler = $this->sut->get_default_handler();
|
||||
$this->assertEquals( LogHandlerFileV2::class, $handler );
|
||||
|
||||
delete_option( 'woocommerce_logs_default_handler' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_retention_period method returns the default value when nothing else has been set.
|
||||
*/
|
||||
public function test_retention_period_setting_default_value(): void {
|
||||
$retention = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 30, $retention );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_retention_period method returns the value set by the filter callback as long as
|
||||
* it's a valid value.
|
||||
*/
|
||||
public function test_retention_period_setting_with_filter(): void {
|
||||
add_filter( 'woocommerce_logger_days_to_retain_logs', fn() => 45 );
|
||||
$retention = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 45, $retention );
|
||||
remove_all_filters( 'woocommerce_logger_days_to_retain_logs' );
|
||||
|
||||
// Invalid number.
|
||||
add_filter( 'woocommerce_logger_days_to_retain_logs', '__return_zero' );
|
||||
$retention = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 30, $retention );
|
||||
remove_all_filters( 'woocommerce_logger_days_to_retain_logs' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_retention_period method returns the value set in the options table as long as it's a
|
||||
* valid value.
|
||||
*/
|
||||
public function test_retention_period_setting_with_option_value(): void {
|
||||
update_option( 'woocommerce_logs_retention_period_days', 53 );
|
||||
$handler = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 53, $handler );
|
||||
|
||||
// Filter overrides option.
|
||||
add_filter( 'woocommerce_logger_days_to_retain_logs', fn() => 45 );
|
||||
$retention = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 45, $retention );
|
||||
remove_all_filters( 'woocommerce_logger_days_to_retain_logs' );
|
||||
|
||||
// Invalid number.
|
||||
update_option( 'woocommerce_logs_retention_period_days', 'french toast' );
|
||||
$handler = $this->sut->get_retention_period();
|
||||
$this->assertEquals( 30, $handler );
|
||||
|
||||
delete_option( 'woocommerce_logs_retention_period_days' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_level_threshold method returns the default value when nothing else has been set.
|
||||
*/
|
||||
public function test_level_threshold_setting_default_value(): void {
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'none', $level );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_level_threshold method returns the value set in WC_LOG_THRESHOLD as long as it's a
|
||||
* valid level.
|
||||
*/
|
||||
public function test_level_threshold_setting_with_constant(): void {
|
||||
Constants::set_constant( 'WC_LOG_THRESHOLD', 'alert' );
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'alert', $level );
|
||||
|
||||
// Invalid level.
|
||||
Constants::set_constant( 'WC_LOG_THRESHOLD', 'mascarpone' );
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'none', $level );
|
||||
|
||||
Constants::clear_single_constant( 'WC_LOG_THRESHOLD' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the get_level_threshold method returns the value set in the options table as long as it's a
|
||||
* valid level.
|
||||
*/
|
||||
public function test_level_threshold_setting_with_option_value(): void {
|
||||
update_option( 'woocommerce_logs_level_threshold', 'warning' );
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'warning', $level );
|
||||
|
||||
// Constant overrides option.
|
||||
Constants::set_constant( 'WC_LOG_THRESHOLD', 'info' );
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'info', $level );
|
||||
Constants::clear_single_constant( 'WC_LOG_THRESHOLD' );
|
||||
|
||||
// Invalid level.
|
||||
update_option( 'woocommerce_logs_level_threshold', 123 );
|
||||
$level = $this->sut->get_level_threshold();
|
||||
$this->assertEquals( 'none', $level );
|
||||
|
||||
delete_option( 'woocommerce_logs_level_threshold' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the settings form does not contain other settings controls when logging is disabled.
|
||||
*/
|
||||
public function test_render_form_logging_disabled_no_other_settings(): void {
|
||||
update_option( 'woocommerce_logs_logging_enabled', 'no' );
|
||||
|
||||
ob_start();
|
||||
$this->sut->render_form();
|
||||
$content = ob_get_clean();
|
||||
|
||||
$this->assertStringNotContainsString( 'Log storage', $content );
|
||||
$this->assertStringNotContainsString( 'Retention period', $content );
|
||||
$this->assertStringNotContainsString( 'Level threshold', $content );
|
||||
|
||||
delete_option( 'woocommerce_logs_logging_enabled' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the settings form default handler control is disabled when the WC_LOG_HANDLER constant is set.
|
||||
*/
|
||||
public function test_render_form_default_handler_input_disabled_with_constant(): void {
|
||||
Constants::set_constant( 'WC_LOG_HANDLER', WC_Log_Handler_DB::class );
|
||||
|
||||
ob_start();
|
||||
$this->sut->render_form();
|
||||
$content = ob_get_clean();
|
||||
|
||||
$this->assertMatchesRegularExpression(
|
||||
'/name="woocommerce_logs_default_handler"[^>]+disabled/',
|
||||
$content
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'This setting cannot be changed here because it is defined in the <code>WC_LOG_HANDLER</code> constant',
|
||||
$content
|
||||
);
|
||||
|
||||
Constants::clear_single_constant( 'WC_LOG_HANDLER' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the settings form retention period control is disabled when the
|
||||
* woocommerce_logger_days_to_retain_logs hook has a filter.
|
||||
*/
|
||||
public function test_render_form_retention_period_input_disabled_with_filter(): void {
|
||||
add_filter( 'woocommerce_logger_days_to_retain_logs', fn() => 45 );
|
||||
|
||||
ob_start();
|
||||
$this->sut->render_form();
|
||||
$content = ob_get_clean();
|
||||
|
||||
$this->assertMatchesRegularExpression(
|
||||
'/name="woocommerce_logs_retention_period_days"[^>]+disabled/',
|
||||
$content
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'This setting cannot be changed here because it is being set by a filter on the <code>woocommerce_logger_days_to_retain_logs</code> hook',
|
||||
$content
|
||||
);
|
||||
|
||||
remove_all_filters( 'woocommerce_logger_days_to_retain_logs' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Check that the settings form level threshold control is disabled when the WC_LOG_THRESHOLD constant is set.
|
||||
*/
|
||||
public function test_render_form_level_threshold_input_disabled_with_constant(): void {
|
||||
Constants::set_constant( 'WC_LOG_THRESHOLD', 'error' );
|
||||
|
||||
ob_start();
|
||||
$this->sut->render_form();
|
||||
$content = ob_get_clean();
|
||||
|
||||
$this->assertMatchesRegularExpression(
|
||||
'/name="woocommerce_logs_level_threshold"[^>]+disabled/',
|
||||
$content
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'This setting cannot be changed here because it is defined in the <code>WC_LOG_THRESHOLD</code> constant',
|
||||
$content
|
||||
);
|
||||
|
||||
Constants::clear_single_constant( 'WC_LOG_THRESHOLD' );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue