Commit 40283950 authored by Michael Iseard's avatar Michael Iseard
Browse files

Switch logging from file to database

parent b356b7d7
......@@ -438,10 +438,6 @@ class Admin {
switch ( $action ) {
case 'kudos_log_download':
LoggerService::download();
break;
case 'kudos_log_clear':
if ( LoggerService::clear() === 0 ) {
new AdminNotice( __( 'Log cleared', 'kudos-donations' ) );
......@@ -590,23 +586,6 @@ class Admin {
return false;
}
/**
* Clear the log file when over certain size.
*
* @return bool|int
*/
public function clear_log() {
$file = LoggerService::LOG_FILE;
$size = filesize( $file );
if ( $size >= LoggerService::LOG_SIZE ) {
return LoggerService::clear();
}
return false;
}
/**
* Register the kudos settings.
*/
......
......@@ -225,7 +225,7 @@ class Utils {
}
/**
* Returns human readable filesize from given bytes.
* Returns human-readable filesize from given bytes.
*
* @param int $bytes Size of file in bytes. Usually the value returned from filesize().
* @param int $decimals Number of decimal places to return.
......
......@@ -90,7 +90,6 @@ class KudosDonations {
add_action( 'admin_init', [ $plugin_admin, 'admin_actions' ] );
add_action( 'rest_api_init', [ $plugin_admin, 'register_settings' ] );
add_action( 'kudos_remove_secret_action', [ $plugin_admin, 'remove_secret_action' ], 10, 2 );
add_action( 'kudos_check_log', [ $plugin_admin, 'clear_log' ] );
add_action( 'enqueue_block_editor_assets', [ $plugin_admin, 'register_block_editor_assets' ] );
}
......
......@@ -6,7 +6,6 @@ use Kudos\Entity\DonorEntity;
use Kudos\Entity\SubscriptionEntity;
use Kudos\Entity\TransactionEntity;
use Kudos\Helpers\Settings;
use Kudos\Helpers\Utils;
use Kudos\Helpers\WpDb;
/**
......@@ -39,8 +38,8 @@ class ActivatorService {
public function __construct() {
$this->logger = new LoggerService();
$this->wpdb = new WpDb();
$this->logger = new LoggerService($this->wpdb);
$this->twig = new TwigService($this->logger);
$this->mapper = new MapperService($this->logger, $this->wpdb);
$this->settings = new Settings($this->mapper);
......@@ -54,8 +53,12 @@ class ActivatorService {
*/
public function activate( string $old_version = null ) {
self::create_log_table();
self::create_donors_table();
self::create_transactions_table();
self::create_subscriptions_table();
$logger = $this->logger;
$logger->init();
$twig = $this->twig;
$twig->init();
$settings = $this->settings;
......@@ -66,16 +69,10 @@ class ActivatorService {
}
$settings->add_defaults();
self::create_donors_table();
self::create_transactions_table();
self::create_subscriptions_table();
update_option( '_kudos_donations_version', KUDOS_VERSION );
$logger->info( 'Kudos Donations plugin activated', ['version' => KUDOS_VERSION] );
// Schedule log file clearing.
Utils::schedule_recurring_action( strtotime( 'today midnight' ), DAY_IN_SECONDS, 'kudos_check_log' );
}
/**
......@@ -106,29 +103,6 @@ class ActivatorService {
}
}
if ( version_compare( $old_version, '2.3.0', '<' ) ) {
// Rename setting
$transaction_table = TransactionEntity::get_table_name();
$wpdb->query( "ALTER TABLE $transaction_table RENAME COLUMN `campaign_label` TO `campaign_id`" );
$settings::update_setting( 'show_intro', 1 );
// Apply mode to Donors
$donor_table = DonorEntity::get_table_name();
$wpdb->query( "ALTER TABLE $donor_table ADD `mode` VARCHAR(45) NOT NULL" );
$donors = $this->mapper
->get_repository(DonorEntity::class)
->get_all_by();
/** @var DonorEntity $donor */
foreach ( $donors as $donor ) {
$transactions = $donor->get_transactions();
if ( $transactions ) {
$donor->set_fields( [ 'mode' => $transactions[0]->mode ] );
}
$this->mapper->save( $donor );
}
}
if ( version_compare( $old_version, '2.3.2', '<' ) ) {
// Setting now replaced by 'theme_colors'
$old_color = $settings::get_setting( 'theme_color' );
......@@ -186,6 +160,9 @@ class ActivatorService {
// Remove unused settings.
$settings::remove_setting('return_message_enable');
$settings::remove_setting('custom_return_enable');
// Disable log file clearing
as_unschedule_all_actions('kudos_check_log');
}
}
......@@ -288,4 +265,28 @@ class ActivatorService {
dbDelta( $sql );
}
/**
* Creates the subscription table
*/
private function create_log_table() {
$wpdb = $this->wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = LoggerService::get_table_name();
$sql = "CREATE TABLE $table_name (
id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
date DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL,
level VARCHAR(255) NOT NULL,
message VARCHAR(255) NOT NULL,
context VARCHAR(255),
PRIMARY KEY (id)
) $charset_collate";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
}
<?php
namespace Kudos\Service\LogHandlers;
use Kudos\Helpers\WpDb;
use Kudos\Service\LoggerService;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
class DatabaseHandler extends AbstractProcessingHandler {
/**
* @var \Kudos\Helpers\WpDb|\wpdb
*/
private $wpdb;
public function __construct( WpDb $wpdb, $level = Logger::DEBUG, bool $bubble = true ) {
$this->wpdb = $wpdb;
parent::__construct( $level, $bubble );
}
protected function write( array $record ): void {
$wpdb = $this->wpdb;
$wpdb->insert( $wpdb->prefix . LoggerService::TABLE, [
'level' => $record['level'],
'message' => $record['message'],
'context' => $record['context'] ? json_encode( $record['context'] ) : '',
'date' => $record['datetime']->format('Y-m-d H:i:s')
] );
}
}
\ No newline at end of file
......@@ -3,24 +3,26 @@
namespace Kudos\Service;
use DateTimeZone;
use Monolog\Handler\StreamHandler;
use Monolog\Logger as Monolog;
use Kudos\Service\LogHandlers\DatabaseHandler;
use Monolog\Logger;
use Kudos\Helpers\WpDb;
class LoggerService extends Monolog {
const LOG_DIR = KUDOS_STORAGE_DIR . 'logs/';
const LOG_FILENAME = 'kudos.log';
const LOG_SIZE = 2097152; // 2097152 = 2MB
const LOG_FILE = self::LOG_DIR . self::LOG_FILENAME;
class LoggerService extends Logger {
/**
* Kudos_Logger constructor.
* Table name without prefix
*
* @var string
*/
public function __construct() {
public const TABLE = 'kudos_log';
/**
* @param \Kudos\Helpers\WpDb $wpdb
*/
public function __construct( WpDb $wpdb ) {
parent::__construct(
'kudos',
[ new StreamHandler( self::LOG_FILE ) ],
[ new DatabaseHandler($wpdb) ],
[],
new DateTimeZone( wp_timezone_string() )
);
......@@ -28,68 +30,7 @@ class LoggerService extends Monolog {
}
/**
* Clears the log file
*
* @return bool|int
*/
public static function clear() {
if ( ! self::is_writeable() ) {
return false;
}
return file_put_contents( self::LOG_FILE, '' );
}
/**
* Checks if log file is writeable and returns true if it is
*
* @return bool
*/
private static function is_writeable(): bool {
if ( is_writable( self::LOG_DIR ) ) {
return true;
}
return false;
}
/**
* Downloads the log file
*/
public static function download() {
$file = self::LOG_FILE;
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: attachment; filename=kudos_' . sanitize_title( get_bloginfo( 'name' ) ) . '_' . gmdate( 'Y-m-d' ) . '.log' );
header( 'Content-Type: application/octet-stream' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate' );
header( 'Pragma: public' );
header( 'Content-Length: ' . filesize( $file ) );
readfile( $file );
exit;
}
/**
* Create the log directory
*/
public function init() {
if ( wp_mkdir_p( self::LOG_DIR ) ) {
$this->info( 'Log directory created successfully', [ 'location' => self::LOG_DIR ] );
}
}
/**
* Add checks to parent function
* Add checks to parent function.
*
* @param int $level Log level.
* @param string $message Message to record.
......@@ -104,63 +45,38 @@ class LoggerService extends Monolog {
return false;
}
// Check ig log is writeable before proceeding.
if ( ! $this->is_writeable() ) {
return false;
}
return parent::addRecord( $level, $message, $context );
}
/**
* Get the contents of the log file and return as array.
*
* @return array
*/
public static function get_as_array(): array {
if ( file_exists( self::LOG_FILE ) ) {
$limit = 26;
$reg = '/^\[(?<date>.*)\]\s(?<env>\w+)\.(?<type>\w+):(?<message>.*)/m';
$lines = [];
$fp = fopen( self::LOG_FILE, "r" );
while ( ! feof( $fp ) ) {
$line = fgets( $fp, 4096 );
preg_match( $reg, $line, $matches );
array_push( $lines, $matches );
if ( count( $lines ) > $limit ) {
array_shift( $lines );
}
}
fclose( $fp );
$lines = array_filter($lines);
usort( $lines, [ static::class, 'date_compare' ] );
return $lines;
}
return [];
public static function get_table_name(): string {
global $wpdb;
return $wpdb->prefix . self::TABLE;
}
/**
* Compares dates to sort log.
* Clears the log file.
*
* @param array $a First array.
* @param array $b Second array.
*
* @return false|int
* @return bool|int
*/
private static function date_compare( array $a, array $b ) {
public static function clear() {
$t1 = strtotime( $a['date'] );
$t2 = strtotime( $b['date'] );
global $wpdb;
$table = $wpdb->prefix . self::TABLE;
return $wpdb->query("TRUNCATE TABLE `{$table}`");
return $t2 - $t1;
}
/**
* Returns the log table contents as an array.
*
* @return array|object|null
*/
public static function get_as_array() {
global $wpdb;
$table = $wpdb->prefix . self::TABLE;
return $wpdb->get_results("SELECT * FROM {$table} ORDER BY `date` DESC LIMIT 100",ARRAY_A);
}
}
......@@ -34,19 +34,11 @@ $tab = $_GET['tab'] ?? $default_tab;
case 'log':
$url = add_query_arg( 'tab', 'log', $url );
$file = LoggerService::LOG_FILE;
// Quit if file does not exist.
if ( ! file_exists( $file ) ) {
return;
}
$log_array = LoggerService::get_as_array();
?>
<p>This logfile location: <?php echo esc_url( $file ); ?></p>
<p>Current filesize: <?php echo Utils::human_filesize( (int) filesize( $file ) ); ?></p>
<p><strong>Note: The log will be automatically cleared when it reaches 2MB.</strong></p>
<p>Kudos Donations logs to the "<?php echo LoggerService::get_table_name() ?>" table in the database.</p>
<form style="display:inline-block;" action="<?php echo esc_url( $url ); ?>"
method='post'>
......@@ -55,13 +47,6 @@ $tab = $_GET['tab'] ?? $default_tab;
Clear
</button>
</form>
<form style="display:inline-block;" action="<?php echo esc_url( $url ); ?>"
method='post'>
<?php wp_nonce_field( 'kudos_log_download' ); ?>
<button class="button-secondary" name='kudos_action' type='submit' value='kudos_log_download'>
Download
</button>
</form>
<table class='form-table'>
<tbody>
......@@ -69,12 +54,13 @@ $tab = $_GET['tab'] ?? $default_tab;
<th class='row-title'>Date</th>
<th>Level</th>
<th>Message</th>
<th>Context</th>
</tr>
<?php
foreach ( $log_array as $key => $log ) {
$level = $log['type'];
$level = LoggerService::getLevelName( $log['level'] );
$style = 'border-left-width: 4px; border-left-style: solid;';
switch ( $level ) {
......@@ -102,11 +88,14 @@ $tab = $_GET['tab'] ?? $default_tab;
?>
</td>
<td>
<?php echo esc_attr( $log['type'] ); ?>
<?php echo esc_attr( $level ); ?>
</td>
<td>
<?php echo( esc_textarea( $log['message'] ) ); ?>
</td>
<td>
<?php echo( esc_textarea( $log['context'] ) ); ?>
</td>
</tr>
......
......@@ -20,7 +20,7 @@ Add a donation button to any page on your website. Easy & fast setup. Works with
* Smart and modern design.
* One-off or recurring payments.
* Can add as many different buttons as you like.
* Can add as many buttons as you like.
* Connect with Mollie for secure payments by credit card, iDEAL and [many others](https://www.mollie.com/payments).
* Toggle Automated email receipts.
* Gutenberg block or shortcode to place your button virtually anywhere.
......@@ -123,6 +123,7 @@ This can occur as a result of a conflict with your theme or another plugin and t
* *NEW* Improved "Welcome Guide" making it easier to get started with Kudos Donations
* Upgrade to Block API version 2. This increases the min WordPress version to 5.6.
* Simplify completed payments settings (it is no longer possible to have a custom return url AND a pop-up message)
* Change logging to database storage
* Add "Clear object cache" to debug actions
* Add white background to form elements
* Fixed compatibility issues with JavaScript minifiers (e.g. "WP-Optimize", "Autoptimize")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment