diff --git a/includes/class-tmdo-logger.php b/includes/class-tmdo-logger.php index 1ceff62..4d7785f 100644 --- a/includes/class-tmdo-logger.php +++ b/includes/class-tmdo-logger.php @@ -77,15 +77,16 @@ class TMDO_Logger { } /** - * Log a NOTICE-level event — alias of info() for callers that want a stronger - * level intent. Same routing (error_log only). + * Log a NOTICE-level event: always written to the PHP error log (unlike + * info()), for the audit trail of operator actions such as mode changes + * and snapshot deletions. * - * @param string $event Event name. - * @param array $context Structured context. + * @param string $event Event name. + * @param array $context Structured context. * @return void */ public static function notice( string $event, array $context = array() ): void { - self::info( $event, $context ); + error_log( sprintf( '[WPDO][NOTICE][%s] %s', $event, $context ? wp_json_encode( $context, JSON_UNESCAPED_UNICODE ) : '' ) ); } /** diff --git a/includes/engine/class-tmdo-mode-manager.php b/includes/engine/class-tmdo-mode-manager.php index fa79a90..78494fa 100644 --- a/includes/engine/class-tmdo-mode-manager.php +++ b/includes/engine/class-tmdo-mode-manager.php @@ -159,7 +159,7 @@ final class TMDO_Mode_Manager { $entered[ $entity_type ] = time(); update_option( self::OPT_ENTERED_AT, $entered, false ); - TMDO_Logger::info( + TMDO_Logger::notice( 'bridge_mode_changed', array( 'entity_type' => $entity_type, diff --git a/includes/snapshots/class-tmdo-snapshot-manager.php b/includes/snapshots/class-tmdo-snapshot-manager.php index a4ec226..b654de4 100644 --- a/includes/snapshots/class-tmdo-snapshot-manager.php +++ b/includes/snapshots/class-tmdo-snapshot-manager.php @@ -310,7 +310,7 @@ class TMDO_Snapshot_Manager { } $table = $wpdb->prefix . self::TABLE_SLUG; $deleted = $wpdb->delete( $table, array( 'snapshot_id' => $snapshot_id ), array( '%s' ) ); // phpcs:ignore WordPress.DB - TMDO_Logger::info( 'snapshot_deleted', array( 'snapshot_id' => $snapshot_id ) ); + TMDO_Logger::notice( 'snapshot_deleted', array( 'snapshot_id' => $snapshot_id ) ); return false !== $deleted; } diff --git a/tests/unit/LoggerTest.php b/tests/unit/LoggerTest.php index b4f9578..6b76817 100644 --- a/tests/unit/LoggerTest.php +++ b/tests/unit/LoggerTest.php @@ -145,13 +145,10 @@ class LoggerTest extends TestCase { return $out; } - public function test_info_and_notice_stay_out_of_the_log_unless_debug_logging_is_on(): void { + public function test_info_stays_out_of_the_log_unless_debug_logging_is_on(): void { $GLOBALS['_wp_filter_callbacks']['tmdo_log_info'] = array(); - $this->assertSame( '', $this->logged( static function () { - WPDO_Logger::info( 'cache_flushed' ); - WPDO_Logger::notice( 'mode_changed' ); - } ) ); + $this->assertSame( '', $this->logged( static fn() => WPDO_Logger::info( 'cache_flushed' ) ) ); add_filter( 'tmdo_log_info', static fn() => true ); try { @@ -161,6 +158,12 @@ class LoggerTest extends TestCase { } } + public function test_notices_are_always_logged_for_the_audit_trail(): void { + $GLOBALS['_wp_filter_callbacks']['tmdo_log_info'] = array(); + + $this->assertStringContainsString( '[WPDO][NOTICE][bridge_mode_changed]', $this->logged( static fn() => WPDO_Logger::notice( 'bridge_mode_changed', array( 'to' => 'dual_write' ) ) ) ); + } + public function test_warnings_are_always_logged(): void { $this->assertStringContainsString( '[WPDO][WARN][odd_return]', $this->logged( static fn() => WPDO_Logger::warning( 'odd_return' ) ) ); }