• Время чтения ~2 мин
  • 10.08.2022

Самая большая проблема при работе со сторонними API заключается в том, что у нас очень мало информации. Мы интегрируем их в нашу кодовую базу и тестируем, но понятия не имеем, как часто мы их используем, если только API, с которым мы интегрируемся, не имеет метрик, которые мы можем использовать. Меня это очень расстраивало в течение некоторого времени, но мы можем кое-что сделать.

Laravel Telescope — это помощник по отладке вашего приложения, что означает, что он будет регистрировать и давать вам представление о том, что происходит, с высокого уровня. Мы можем воспользоваться этим и добавить настраиваемых наблюдателей, чтобы включить больше отладки и ведения журнала, и это то, что мы сделаем в этом кратком руководстве.

После того, как вы установили Laravel Telescope, убедитесь, что вы опубликовали конфигурацию и перенесли базу данных, мы можем приступить к созданию нашего наблюдателя для Guzzle — клиента под Http-фасадом. Наиболее логичным местом для хранения этих классов, по крайней мере для меня, является app/Telescope/Watchers, поскольку код принадлежит нашему приложению, но мы расширяем сам Telescope.Но как выглядит стандартный наблюдатель? Ниже я покажу вам примерный план базовых требований:

class YourWatcher extends Watcher
{
  public function register($app): void
  {
    // handle code for watcher here.
  }
}

Это примерный план. Вы можете добавить столько методов, сколько вам нужно, чтобы добавить наблюдателя, который работает на вас. Итак, без лишних слов, давайте создадим новое приложение-наблюдатель /Telescope/Watchers/GuzzleRequestWatcher.php и рассмотрим, что ему нужно делать.

br>

Сначала нам нужно включить трейт FetchesStackTrace, поскольку это позволяет нам фиксировать, откуда и откуда поступают эти запросы. Если мы реорганизуем эти HTTP-вызовы в другие места, мы сможем убедиться, что вызываем их так, как собираемся. Далее нам нужно добавить метод для регистрации нашего наблюдателя:

declare(strict_types=1);
 
namespace App\\Telescope\\Watchers;
 
use GuzzleHttp\\Client;
use GuzzleHttp\\TransferStats;
use Laravel\\Telescope\\IncomingEntry;
use Laravel\\Telescope\\Telescope;
use Laravel\\Telescope\\Watchers\\FetchesStackTrace;
use Laravel\\Telescope\\Watchers\\Watcher;
 
final class GuzzleRequestWatcher extends Watcher
{
  use FetchesStackTrace;
}

Мы перехватываем клиент Guzzle и регистрируем его в контейнере, но для этого мы хотим указать, как мы хотим, чтобы клиент был построен. Давайте посмотрим на метод buildClient:

declare(strict_types=1);
 
namespace App\\Telescope\\Watchers;
 
use GuzzleHttp\\Client;
use GuzzleHttp\\TransferStats;
use Laravel\\Telescope\\IncomingEntry;
use Laravel\\Telescope\\Telescope;
use Laravel\\Telescope\\Watchers\\FetchesStackTrace;
use Laravel\\Telescope\\Watchers\\Watcher;
 
final class GuzzleRequestWatcher extends Watcher
{
  use FetchesStackTrace;
 
  public function register($app)
  {
    $app->bind(
      abstract: Client::class,
      concrete: $this->buildClient(
        app: $app,
      ),
    );
  }
}

Здесь мы возвращаем статическую функцию, которая создает наш клиент Guzzle. Сначала получаем любой конфиг жрать — а потом, если телескоп записывает, добавляем способ записи запроса.Наконец, мы возвращаем клиента с его конфигурацией. Так как же нам записать наш HTTP-запрос? Давайте посмотрим:

private function buildClient(Application $app): Closure
{
  return static function (Application $app): Client {
  	$config = $app['config']['guzzle'] ?? [];
 
    if (Telescope::isRecording()) {
      // Record our Http query.
    }
 
    return new Client(
      config: $config,
    );
  };
}

Итак, мы расширили конфигурацию, добавив параметр on_stats, который является обратным вызовом. Этот обратный вызов получит трассировку стека и запишет новый запрос. Эта новая запись будет содержать все важные вещи, связанные с запросом, который мы можем записать. Итак, если мы сложим все вместе:

if (Telescope::isRecording()) {
  $config['on_stats'] = static function (TransferStats $stats): void {
    $caller = $this->getCallerFromStackTrace(); // This comes from the trait we included.
 
    Telescope::recordQuery(
      entry: IncomingEntry::make([
        'connection' => 'guzzle',
        'bindings' => [],
        'sql' => (string) $stats->getEffectiveUri(),
        'time' => number_format(
          num: $stats->getTransferTime() * 1000,
          decimals: 2,
          thousand_separator: '',
        ),
        'slow' => $stats->getTransferTime() > 1,
        'file' => $caller['file'],
        'line' => $caller['line'],
        'hash' => md5((string) $stats->getEffectiveUri())
      ]),
    );
  };
}

Теперь все, что нам нужно сделать, это убедиться, что мы зарегистрировали этот новый наблюдатель внутри config/telescope.php, и мы должны начать видеть, что наши HTTP-запросы регистрируются.

declare(strict_types=1);
 
namespace App\Telescope\Watchers;
 
use Closure;
use GuzzleHttp\Client;
use GuzzleHttp\TransferStats;
use Illuminate\Foundation\Application;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\Watchers\FetchesStackTrace;
use Laravel\Telescope\Watchers\Watcher;
 
final class GuzzleRequestWatcher extends Watcher
{
    use FetchesStackTrace;
 
    public function register($app): void
    {
        $app->bind(
            abstract: Client::class,
            concrete: $this->buildClient(
                app: $app,
            ),
        );
    }
 
    private function buildClient(Application $app): Closure
    {
        return static function (Application $app): Client {
            $config = $app['config']['guzzle'] ?? [];
 
            if (Telescope::isRecording()) {
                $config['on_stats'] = function (TransferStats $stats) {
                    $caller = $this->getCallerFromStackTrace();
                    Telescope::recordQuery(
                        entry: IncomingEntry::make([
                            'connection' => 'guzzle',
                            'bindings' => [],
                            'sql' => (string) $stats->getEffectiveUri(),
                            'time' => number_format(
                                num: $stats->getTransferTime() * 1000,
                                decimals: 2,
                                thousands_separator: '',
                            ),
                            'slow' => $stats->getTransferTime() > 1,
                            'file' => $caller['file'],
                            'line' => $caller['line'],
                            'hash' => md5((string) $stats->getEffectiveUri()),
                        ]),
                    );
                };
            }
 
            return new Client(
                config: $config,
            );
        };
    }
}

Чтобы проверить это, создайте тестовый маршрут:

'watchers' => [
  // all other watchers
  App\\Telescope\\Watchers\\GuzzleRequestWatcher::class,
]

Когда вы открываете Telescope, вы должны увидеть элемент навигации на стороне под названием HTTP-клиент, и если вы откроете его, вы увидите, что здесь появляются журналы — вы можете проверить заголовки, полезную нагрузку и статус запроса. Поэтому, если вы начнете сталкиваться со сбоями из-за интеграции API, это очень поможет вам в отладке.

Route::get('/guzzle-test', function () {
    Http::post('<https://jsonplaceholder.typicode.com/posts>', ['title' => 'test']);
});

Вы нашли это полезным?Какие другие способы вы используете для мониторинга и регистрации ваших внешних запросов API? Дайте нам знать в Твиттере!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297