Największym problemem związanym z pracą z zewnętrznymi interfejsami API jest to, że mamy bardzo małą widoczność. Integrujemy je z naszą bazą kodu i testujemy - ale nie mamy pojęcia, jak często ich używamy, chyba że API, z którym integrujemy, ma metryki, z których możemy korzystać. Od dłuższego czasu jestem tym sfrustrowany – ale jest coś, co możemy zrobić.
Teleskop Laravel jest asystentem debugowania dla Twojej aplikacji, co oznacza, że będzie rejestrował i dawał Ci wgląd w to, co się dzieje z wysokiego poziomu. Możemy to wykorzystać i dodać niestandardowe obserwatory, aby umożliwić więcej debugowania i rejestrowania, i właśnie to zrobimy w tym krótkim samouczku.
Po zainstalowaniu Laravel Telescope, upewnij się, że opublikujesz konfigurację i zmigrujesz bazę danych, możemy zacząć tworzyć naszego obserwatora dla Guzzle - klienta pod fasadą HTTP. Najbardziej logicznym miejscem przechowywania tych klas, przynajmniej dla mnie, jest wnętrze app/Telescope/Watchers
, ponieważ kod należy do naszej aplikacji - ale rozszerzamy sam Telescope.Ale jak wygląda standardowy obserwator? Poniżej przedstawię przybliżony zarys podstawowych wymagań:
class YourWatcher extends Watcher
{
public function register($app): void
{
// handle code for watcher here.
}
}
To jest przybliżony zarys. Możesz dodać tyle metod, ile potrzebujesz, aby dodać obserwatora, który działa dla Ciebie. Więc bez zbędnych ceregieli, stwórzmy nową app/Telescope/Watchers/GuzzleRequestWatcher.php
obserwatora, a my przejdziemy przez to, co musi zrobić.
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;
}
br>Najpierw musimy uwzględnić cechę FetchesStackTrace, ponieważ pozwala nam to rejestrować, skąd i skąd pochodzą te żądania. Jeśli dokonamy refaktoryzacji tych wywołań HTTP do innych lokalizacji, możemy się upewnić, że wywołamy je tak, jak zamierzamy. Następnie musimy dodać metodę rejestracji naszego obserwatora:
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,
),
);
}
}
Przechwytujemy klienta Guzzle i rejestrujemy go w kontenerze, ale aby to zrobić, chcemy określić, w jaki sposób chcemy zbudować klienta. Spójrzmy na metodę buildClient:
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,
);
};
}
Zwracamy tutaj funkcję statyczną, która buduje naszego klienta Guzzle. Najpierw otrzymujemy dowolną konfigurację guzzle - a następnie, jeśli teleskop nagrywa, dodajemy sposób na zarejestrowanie zapytania.Na koniec zwracamy klientowi jego konfigurację. Jak więc rejestrujemy nasze zapytanie HTTP? Spójrzmy:
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())
]),
);
};
}
Więc rozszerzamy konfigurację dodając opcję on_stats
, która jest wywołaniem zwrotnym. To wywołanie zwrotne uzyska ślad stosu i zarejestruje nowe zapytanie. Ten nowy wpis będzie zawierał wszystkie istotne rzeczy związane z zapytaniem, które możemy zarejestrować. Więc jeśli zbierzemy to wszystko razem:
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,
);
};
}
}
Teraz wszystko, co musimy zrobić, to upewnić się, że zarejestrowaliśmy ten nowy obserwator w config/telescope.php
i powinniśmy zacząć widzieć, jak nasze zapytania HTTP są rejestrowane.
'watchers' => [
// all other watchers
App\\Telescope\\Watchers\\GuzzleRequestWatcher::class,
]
Aby to przetestować, utwórz trasę testową:
Route::get('/guzzle-test', function () {
Http::post('<https://jsonplaceholder.typicode.com/posts>', ['title' => 'test']);
});
Kiedy otworzysz Telescope, powinieneś teraz zobaczyć element nawigacji po stronie o nazwie Klient HTTP, a jeśli go otworzysz, zobaczysz tutaj logi - możesz sprawdzić nagłówki, ładunek i status żądania. Jeśli więc zaczniesz dostrzegać awarie integracji z interfejsem API, pomoże ci to znacznie w debugowaniu.
Czy uważasz to za pomocne?Jakich innych sposobów używasz do monitorowania i rejestrowania zewnętrznych żądań API? Daj nam znać na Twitterze!