diff --git a/includes/classes/Stats.php b/includes/classes/Stats.php index a5dae9885e..1d3faf421f 100644 --- a/includes/classes/Stats.php +++ b/includes/classes/Stats.php @@ -73,6 +73,14 @@ class Stats { */ protected $nodes = 0; + /** + * Failed queries and their errors. + * + * @since 5.0.1 + * @var string + */ + protected $failed_queries = []; + /** * Makes an api call to elasticsearch endpoint * @@ -83,13 +91,29 @@ class Stats { protected function remote_request_helper( $path ) { $request = Elasticsearch::factory()->remote_request( $path ); - if ( is_wp_error( $request ) || empty( $request ) ) { + if ( empty( $request ) ) { + return false; + } + + if ( is_wp_error( $request ) ) { + $this->failed_queries[] = [ + 'path' => $path, + 'error' => $request->get_error_message(), + ]; return false; } - $body = wp_remote_retrieve_body( $request ); + $body = wp_remote_retrieve_body( $request ); + $return = json_decode( $body, true ); - return json_decode( $body, true ); + if ( ! empty( $return['errors'] ) ) { + $this->failed_queries[] = [ + 'path' => $path, + 'error' => wp_json_encode( $return['errors'] ), + ]; + } + + return $return; } /** @@ -292,6 +316,25 @@ public function convert_to_readable_size( $size ) { return round( pow( 1024, $base - floor( $base ) ), 1 ) . $suffix[ $f_base ]; } + /** + * Return all failed queries. + * + * @return array + * @since 5.0.1 + */ + public function get_failed_queries() { + return $this->failed_queries; + } + + /** + * Clear all failed queries registered. + * + * @since 5.0.1 + */ + public function clear_failed_queries() { + $this->failed_queries = []; + } + /** * Return singleton instance of class * diff --git a/includes/partials/stats-page.php b/includes/partials/stats-page.php index 67cca3ca7c..6a63ca0ac8 100644 --- a/includes/partials/stats-page.php +++ b/includes/partials/stats-page.php @@ -25,15 +25,33 @@ Stats::factory()->build_stats(); -$index_health = Stats::factory()->get_health(); -$totals = Stats::factory()->get_totals(); +$index_health = Stats::factory()->get_health(); +$totals = Stats::factory()->get_totals(); +$failed_queries = Stats::factory()->get_failed_queries(); ?>

- + +

+ +

+ +

diff --git a/tests/php/TestStats.php b/tests/php/TestStats.php index 0c436a9826..553f084ddc 100644 --- a/tests/php/TestStats.php +++ b/tests/php/TestStats.php @@ -8,6 +8,9 @@ namespace ElasticPressTest; use ElasticPress; +use ElasticPress\Elasticsearch; +use ElasticPress\Indexables; +use ElasticPress\Stats; /** * Stats test class @@ -29,10 +32,10 @@ public function set_up() { wp_set_current_user( $admin_id ); - ElasticPress\Elasticsearch::factory()->delete_all_indices(); - ElasticPress\Indexables::factory()->get( 'post' )->put_mapping(); + Elasticsearch::factory()->delete_all_indices(); + Indexables::factory()->get( 'post' )->put_mapping(); - ElasticPress\Indexables::factory()->get( 'post' )->sync_manager->reset_sync_queue(); + Indexables::factory()->get( 'post' )->sync_manager->reset_sync_queue(); $this->setup_test_post_type(); @@ -41,6 +44,8 @@ public function set_up() { global $hook_suffix; $hook_suffix = 'sites.php'; set_current_screen(); + + Stats::factory()->clear_failed_queries(); } /** @@ -65,15 +70,17 @@ public function tear_down() { */ public function testTotals() { $this->ep_factory->post->create(); - ElasticPress\Elasticsearch::factory()->refresh_indices(); + Elasticsearch::factory()->refresh_indices(); - ElasticPress\Stats::factory()->build_stats(); + Stats::factory()->build_stats(); - $totals = ElasticPress\Stats::factory()->get_totals(); + $totals = Stats::factory()->get_totals(); $this->assertEquals( 1, $totals['docs'] ); $this->assertTrue( ! empty( $totals['size'] ) ); $this->assertTrue( ! empty( $totals['memory'] ) ); + + $this->assertEmpty( Stats::factory()->get_failed_queries() ); } /** @@ -84,13 +91,69 @@ public function testTotals() { */ public function testHealth() { $this->ep_factory->post->create(); - ElasticPress\Elasticsearch::factory()->refresh_indices(); + Elasticsearch::factory()->refresh_indices(); - ElasticPress\Stats::factory()->build_stats(); + Stats::factory()->build_stats(); - $health = ElasticPress\Stats::factory()->get_health(); + $health = Stats::factory()->get_health(); $this->assertEquals( 1, count( $health ) ); $this->assertEquals( 'exampleorg-post-1', array_keys( $health )[0] ); } + + /** + * Test if a failed query is registered if a request returns a WP_Error + * + * @since 5.0.1 + * @group stats + */ + public function test_failed_queries_wp_error() { + add_filter( 'ep_intercept_remote_request', '__return_true' ); + + $return_wp_error = function () { + return new \WP_Error( 'code', 'Message' ); + }; + add_filter( 'ep_do_intercept_request', $return_wp_error ); + + Stats::factory()->build_stats( true ); + $failed_queries = Stats::factory()->get_failed_queries(); + $this->assertSame( + [ + [ + 'path' => '_stats?format=json', + 'error' => 'Message', + ], + ], + $failed_queries + ); + } + + /** + * Test if a failed query is registered if a request returns an Elasticsearch error + * + * @since 5.0.1 + * @group stats + */ + public function test_failed_queries_es_error() { + add_filter( 'ep_intercept_remote_request', '__return_true' ); + + $return_es_error = function () { + return [ + 'body' => wp_json_encode( [ 'errors' => [ 'some error data' ] ] ), + ]; + }; + add_filter( 'ep_do_intercept_request', $return_es_error ); + + Stats::factory()->build_stats( true ); + $failed_queries = Stats::factory()->get_failed_queries(); + $this->assertSame( + [ + [ + 'path' => '_stats?format=json', + 'error' => '["some error data"]', + ], + ], + $failed_queries + ); + } }