diff --git a/CHANGELOG.md b/CHANGELOG.md index 57a9c31..5dcc38d 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 v2] +## [2.2.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. + ## [2.2.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. @@ -73,7 +77,8 @@ V1 is continued to be updated for continued support for Monolog v1 and PHP versi No changelog had been maintained up to this point. Refer to the GIT commit history for more details. -[Unreleased v2]: https://github.com/bradmkjr/monolog-wordpress/compare/2.2.0...HEAD +[Unreleased v2]: https://github.com/bradmkjr/monolog-wordpress/compare/2.2.1...HEAD +[2.2.1]: https://github.com/bradmkjr/monolog-wordpress/tree/2.2.1 [2.2.0]: https://github.com/bradmkjr/monolog-wordpress/tree/2.2.0 [2.1.2]: https://github.com/bradmkjr/monolog-wordpress/tree/2.1.2 [2.1.1]: https://github.com/bradmkjr/monolog-wordpress/tree/2.1.1 diff --git a/composer.json b/composer.json index b03cbbe..01aa8e5 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": "2.2.0", + "version": "2.2.1", "authors": [ { "name": "Bradford Knowlton", diff --git a/src/WordPressHandler/WordPressHandler.php b/src/WordPressHandler/WordPressHandler.php index 65a9c02..9b97ead 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); } @@ -145,31 +151,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), @@ -178,11 +184,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; } /** @@ -192,7 +198,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); } @@ -224,11 +230,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): void { @@ -242,51 +254,50 @@ protected function write(array $record): void '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 {