使用 Laravel Telescope 记录外部 HTTP 请求
发布于 作者 史蒂夫·麦克杜格尔
与第三方 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. }}
这是一个大致轮廓。您可以根据需要添加尽可能多的方法来添加适合您的观察者。所以,事不宜迟,让我们创建一个新的观察者 app/Telescope/Watchers/GuzzleRequestWatcher.php
,我们将逐步了解它需要做什么。
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;}
首先,我们需要包含 trait 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; public function register($app) { $app->bind( abstract: Client::class, concrete: $this->buildClient( app: $app, ), ); }}
我们拦截 Guzzle 客户端并将其注册到容器中,但要做到这一点,我们需要指定如何构建客户端。让我们看一下 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, ); };}
我们返回一个静态函数,它在这里构建我们的 Guzzle 客户端。首先,我们获取任何 guzzle 配置——然后,如果 telescope 正在记录,我们添加一种记录查询的方法。最后,我们使用其配置返回客户端。那么,我们如何记录我们的 HTTP 查询呢?让我们看一下。
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()) ]), ); };}
因此,我们通过添加 on_stats
选项扩展了配置,它是一个回调。此回调将获取堆栈跟踪并记录一个新的查询。此新条目将包含所有与我们可以记录的查询相关的相关内容。所以,如果我们把它们放在一起。
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, ); }; }}
现在,我们只需要确保在 config/telescope.php
中注册这个新的观察者,我们应该开始看到我们的 Http 查询被记录下来。
'watchers' => [ // all other watchers App\\Telescope\\Watchers\\GuzzleRequestWatcher::class,]
为了测试这一点,创建一个测试路由。
Route::get('/guzzle-test', function () { Http::post('<https://jsonplaceholder.typicode.com/posts>', ['title' => 'test']);});
当您打开 Telescope 时,您现在应该在侧面看到一个名为 HTTP 客户端的导航项,如果您打开它,您将看到日志出现在这里——您可以检查标题、有效负载和请求的状态。因此,如果您开始看到来自 API 集成的故障,这将极大地帮助您进行调试。
您觉得这有用吗?您使用什么其他方法来监控和记录您的外部 API 请求?请在 Twitter 上告诉我们!