Отладка запросов REST API

Query Monitor

Query Monitor включает некоторые функции для отладки и информации о производительности запросов REST API на сайте. Версия 3.7 представляет еще одну новую функцию, которая позволяет вам увидеть еще больше информации о производительности, которую вы ожидаете от Query Monitor.

Аутентификация

Подобно запросам к фронт-энду или админке вашего сайта, чтобы увидеть отладочную информацию для REST API, вам необходимо выполнить запрос, который аутентифицирован как пользователь, имеющий право просматривать результаты Query Monitor, например, администратор.

Ответ на такой аутентифицированный запрос будет включать дополнительные HTTP-заголовки, содержащие обзор времени генерации ответа, использования памяти и подробную информацию об ошибках PHP. Начиная с версии QM 3.7 ответ на запрос с конвертом также будет включать полную отладочную информацию о запросах, HTTP API запросах, объектном кэше и многом другом. Читайте дальше, чтобы узнать подробности!

Обзор и информация об ошибках PHP

В ответ будут включены следующие дополнительные HTTP-заголовки:

  • x-qm-overview-time_taken - Время генерации ответа в секундах

  • x-qm-overview-time_usage - Время генерации ответа в процентах от максимального лимита времени выполнения PHP

  • x-qm-overview-memory - Использование памяти в кБ

  • x-qm-overview-memory_usage - Использование памяти в процентах от лимита памяти PHP

  • x-qm-php_errors-error-count - Количество произошедших ошибок PHP (0 или более)

  • x-qm-php_errors-error-{n} - Подробности о каждой отдельной ошибке PHP

Полная информация о производительности и отладке

Когда выполняется запрос REST API, который запрашивает конвертированный ответ через параметр ?_envelope, в JSON-ответе будет присутствовать дополнительное свойство qm (начиная с QM 3.7) с информацией о:

  • qm.db_queries.dbs - Все запросы к базе данных.

  • qm.db_queries.dupes - Дублирующиеся запросы к базе данных

  • qm.db_queries.errors - Запросы к базе данных с ошибками

  • qm.cache - статистика кэша объектов для просмотров и промахов

  • qm.http - Детали HTTP API запросов и ответов

  • qm.logger - Зарегистрированные сообщения и переменные

  • qm.transients - Обновленные переходные процессы

Информация несколько урезана по сравнению с той, которую вы увидите на главной панели Query Monitor для обычного HTML-запроса, но она содержит ключевую информацию, необходимую для исследования проблем производительности.

Свойство qm.db_queries.dbs содержит обзорную информацию, а также полную информацию по каждому отдельному SQL-запросу, включая время, трассировку стека и возвращаемые строки, а свойство qm.http содержит подробную информацию о каждом запрошенном URL, код ответа, время и трассировку стека.

Пример данных

Учитывая GET запрос к конечной точке по умолчанию, такой как example.com/wp-json/wp/v2/posts/?_envelope, вы обычно не ожидаете увидеть серверные HTTP API запросы или переходные процессы, обновляемые при каждом запросе, но QM теперь будет показывать эту информацию для исследования проблем!

Вот пример свойства qm в ответе:

{
  "db_queries": {
	"dbs": {
	  "$wpdb": {
		"total": 15,
		"time": 0.0108,
		"queries": [
		  {
			"sql": "SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes'",
			"time": 0.0011,
			"stack": [
			  "wp_load_alloptions()",
			  "is_blog_installed()",
			  "wp_not_installed()"
			],
			"result": 317
		  },
		  {
			"sql": "SELECT * FROM wp_users WHERE ID = '1' LIMIT 1",
			"time": 0.0003,
			"stack": [
			  "WP_User::get_data_by()",
			  "WP_User->__construct()",
			  "wp_set_current_user()",
			  "_wp_get_current_user()",
			  "wp_get_current_user()",
			  "get_current_user_id()",
			  "get_user_option()",
			  "Classic_Editor::get_settings()",
			  "Classic_Editor::init_actions()",
			  "do_action('plugins_loaded')"
			],
			"result": 1
		  },
		  {
			"sql": "SELECT   wp_posts.ID FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'post' AND ((wp_posts.post_status = 'publish'))  ORDER BY wp_posts.post_date DESC LIMIT 0, 5",
			"time": 0.0003,
			"stack": [
			  "WP_Query->get_posts()",
			  "WP_Query->query()",
			  "get_posts()",
			  "DoubleUnderscore\\entrypoint()",
			  "do_action('init')"
			],
			"result": 5
		  }

		  /* snip */

		]
	  }
	},
	"errors": {
	  "total": 1,
	  "errors": [
		{
		  "caller": "do_action('init')",
		  "caller_name": "do_action('init')",
		  "sql": "SELECT *\n\t\tFROM table_that_does_not_exist",
		  "ltime": 0.00007200241088867188,
		  "result": {
			"errors": {
			  "1146": [
				"Table 'wp.table_that_does_not_exist' doesn't exist"
			  ]
			},
			"error_data": []
		  }
		}
	  ]
	},
	"dupes": {
	  "total": 1,
	  "queries": {
		"SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND ((wp_posts.post_status = 'publish')) ORDER BY wp_posts.post_date DESC LIMIT 0, 5": [
		  3,
		  14,
		  35
		]
	  }
	}
  },
  "cache": {
	"hit_percentage": 67.8,
	"hits": 931,
	"misses": 442
  },
  "http": {
	"total": 1,
	"time": 0.6586,
	"requests": [
	  {
		"url": "https://example.org",
		"method": "GET",
		"response": {
		  "code": 200,
		  "message": "OK"
		},
		"time": 0.6586,
		"stack": [
		  "WP_Http->request()",
		  "WP_Http->get()",
		  "wp_remote_get()",
		  "DoubleUnderscore\\entrypoint()",
		  "do_action('init')"
		]
	  }
	]
  },
  "logger": {
	"warning": [
	  {
		"message": "Preloading was not found, generating fresh",
		"stack": [
		  "DoubleUnderscore\\dispatcher()",
		  "DoubleUnderscore\\entrypoint()",
		  "do_action('init')"
		]
	  }
	],
	"debug": [
	  {
		"message": "Language: en_US",
		"stack": [
		  "DoubleUnderscore\\do_logs()",
		  "DoubleUnderscore\\entrypoint()",
		  "do_action('init')"
		]
	  }
	]
  }
}

--

Перевод