diff --git a/CHANGELOG.md b/CHANGELOG.md index b411a2b..a4b1ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.8.1] - 2022-02-10 +### Improved +- More concise fallback error logging when wpdb fails: The error message is only logged once per execution, it is adjusted based on the actual WordPress version and the format of the actual fallback logging is more compact as well. + ## [1.8.0] - 2022-02-09 ### Improved - The handler did not check if inserting the records into the db was successful or not. This could cause important log messages to be lost unnoticed. The handler now logs a warning into the default PHP error log and also logs the failed record there for reference. @@ -65,7 +69,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 No changelog had been maintained up to this point. Refer to the GIT commit history for more details. -[Unreleased]: https://github.com/bradmkjr/monolog-wordpress/compare/1.8.0...v1 +[Unreleased]: https://github.com/bradmkjr/monolog-wordpress/compare/1.8.1...v1 +[1.8.1]: https://github.com/bradmkjr/monolog-wordpress/tree/1.8.1 [1.8.0]: https://github.com/bradmkjr/monolog-wordpress/tree/1.8.0 [1.7.2]: https://github.com/bradmkjr/monolog-wordpress/tree/1.7.2 [1.7.1]: https://github.com/bradmkjr/monolog-wordpress/tree/1.7.1 diff --git a/composer.json b/composer.json index 36c9daf..2f316d9 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "keywords": ["wordpress", "log", "logging", "monolog", "mysql", "database"], "homepage": "https://github.com/bradmkjr/monolog-wordpress", "license": "MIT", - "version": "1.8.0", + "version": "1.8.1", "authors": [ { "name": "Bradford Knowlton", diff --git a/src/WordPressHandler/WordPressHandler.php b/src/WordPressHandler/WordPressHandler.php index f1edadc..6a027b4 100644 --- a/src/WordPressHandler/WordPressHandler.php +++ b/src/WordPressHandler/WordPressHandler.php @@ -46,6 +46,12 @@ class WordPressHandler extends AbstractProcessingHandler * Do not choose a value too low, because it may generate huge database overhead! */ protected $truncate_batch_size = 1; + /** + * @var bool Indicates, if {@see \wpdb} has failed to write a log records and the related message has been logged + * into the default system log already. This is used to only write such message to the log file once + * per execution. + */ + protected $wpdb_no_error_message_logged = false; /** * Constructor of this class, sets own fields and calls parent constructor * @@ -93,7 +99,7 @@ public function __construct( } $this->table = $table; $this->prefix = $this->wpdb->prefix; - + $this->additionalFields = $additionalFields; parent::__construct($level, $bubble); } @@ -151,31 +157,31 @@ public function get_table_name() */ public function initialize(array $record) { - + // referenced // https://codex.wordpress.org/Creating_Tables_with_Plugins - + // $this->wpdb->exec( // 'CREATE TABLE IF NOT EXISTS `'.$this->table.'` ' // .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)' // ); - + $charset_collate = $this->wpdb->get_charset_collate(); - + $table_name = $this->get_table_name(); - + // allow for Extra fields $extraFields = ''; foreach ($record['extra'] as $key => $val) { $extraFields.=",\n`$key` TEXT NULL DEFAULT NULL"; } - + // additional fields $additionalFields = ''; foreach ($this->additionalFields as $f) { $additionalFields.=",\n`$f` TEXT NULL DEFAULT NULL"; } - + $sql = "CREATE TABLE $table_name ( id INT(11) NOT NULL AUTO_INCREMENT, channel VARCHAR(255), @@ -184,11 +190,11 @@ public function initialize(array $record) time INTEGER UNSIGNED$extraFields$additionalFields, PRIMARY KEY (id) ) $charset_collate;"; - - + + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); - + $this->initialized = true; } /** @@ -198,7 +204,7 @@ public function uninitialize() { $table_name = $this->get_table_name(); $sql = "DROP TABLE IF EXISTS $table_name;"; - + if (!is_null($this->wpdb)) { $this->wpdb->query($sql); } @@ -230,11 +236,17 @@ protected function maybe_truncate() { } return false; } + /** * Writes the record down to the log of the implementing handler * - * @param $record[] + * @param $record [] + * * @return void + * + * @throws \Psr\Log\InvalidArgumentException + * + * @noinspection ForgottenDebugOutputInspection */ protected function write(array $record) { @@ -248,55 +260,54 @@ protected function write(array $record) 'message' => (isset($record['formatted']['message'])) ? $record['formatted']['message'] : $record['message'], 'time' => $record['datetime']->format('U') ); - + // Make sure to use the formatted values for context and extra, if available $recordExtra = (isset($record['formatted']['extra'])) ? $record['formatted']['extra'] : $record['extra']; $recordContext = (isset($record['formatted']['context'])) ? $record['formatted']['context'] : $record['context']; - + $recordContExtra = array_merge( $recordExtra, $recordContext ); - + // json encode values as needed array_walk($recordContExtra, function(&$value, $key) { if(is_array($value) || $value instanceof \Traversable) { $value = json_encode($value); } }); - + $contentArray = $contentArray + $recordContExtra; - + if(count($this->additionalFields) > 0) { //Fill content array with "null" values if not provided $contentArray = $contentArray + array_combine( - $this->additionalFields, - array_fill(0, count($this->additionalFields), null) - ); + $this->additionalFields, + array_fill(0, count($this->additionalFields), null) + ); } - + $table_name = $this->get_table_name(); - + if (!$this->wpdb->insert( $table_name, $contentArray )) { - - // E_USER_ERROR would terminate PHP so we must only use WARNING or NOTICE - $php_error_level = ($record['level'] <= Logger::NOTICE) ? E_USER_NOTICE : E_USER_WARNING; - if ( '' === $this->wpdb->last_error ) { - trigger_error('WordPressHandler failed to write a log record into the database and wpdb returned no error message. This typically happens in WordPress versions prior v5.9 when the message, or a context or an extra field is too long or contains invalid data. Since WordPress v5.9 too long or invalid data triggers a specific error message. If you are using WordPress v5.9 or later the root cause of the issue is unknown.', E_USER_WARNING); + // Since this error message does not include details it is enough to log it only once + if (!$this->wpdb_no_error_message_logged) { + if ( function_exists('is_wp_version_compatible') && is_wp_version_compatible('5.9') ) { + $this->wpdb_no_error_message_logged = error_log( 'Monolog Error: WordPressHandler failed to write a log record into the database and wpdb returned no error message. The root cause of the issue is unknown.' ); + } + else { + $this->wpdb_no_error_message_logged = error_log( 'Monolog Error: WordPressHandler failed to write a log record into the database and wpdb returned no error message. This typically happens when the message or a context or an extra field is too long or contains invalid data.' ); + } + } } else { - trigger_error('WordPressHandler failed to write a log record into the database. ' . $this->wpdb->last_error, E_USER_WARNING); + error_log('Monolog Error: WordPressHandler failed to write a log record into the database. ' . $this->wpdb->last_error); } - - trigger_error( - 'WordPressHandler failed to log the following record.'. - ' Time: '.$contentArray['time']. - ' Channel: '.$contentArray['channel']. - ' Level: '.$contentArray['level']. - ' Message: `'.$contentArray['message'].'`', - $php_error_level + + error_log( + 'Monolog fallback: '.$contentArray['channel'].' '.ucfirst(strtolower(Logger::getLevelName($contentArray['level']))).': '.$contentArray['message'] ); } - else { - $this->maybe_truncate(); - } + else { + $this->maybe_truncate(); + } } }