Laravel - 将 Guzzle 请求记录到文件

Laravel - Log Guzzle requests to file

在处理一个项目时,我发现第三方 API 正在使用 Postman,但不适用于 Guzzle Client。

调试 Guzzle 请求可能很困难,那么有没有什么方法可以记录 Guzzle 客户端发出的所有请求?

TLDR;

有一种简单的方法可以通过将第二个参数传递给客户端来记录所有 Guzzle 请求,然后它将记录所有请求。但如果你有很多方法使用 Guzzle 客户端向第三方服务器发送请求,那将是一种丑陋的方式。我已经使用 Laravel 的服务容器完成了它。

通过 Laravel 的服务容器

很长一段路要走

当我在我的项目中使用 Guzzle 客户端并使用处理程序记录所有请求时,它看起来不错。但后来在许多不同的 类 中有许多方法,所以我必须在每个地方编写记录器逻辑。然后我想为什么不利用 Laravel 的 Service Container 并绑定一个对象并在所有地方使用它。

我是这样做的。在您的 AppServiceContainer.php 的启动方法中,我们将添加所有代码。然后在控制器中我们将使用我们的客户端对象。

AppServiceContainer.php 文件顶部添加此 use 语句。

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Illuminate\Support\ServiceProvider;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;

将以下代码添加到您的 AppServiceContainer.php 的 boot 方法中

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
    {
        $this->app->bind('GuzzleClient', function () {

            $messageFormats = [
                'REQUEST: {method} - {uri} - HTTP/{version} - {req_headers} - {req_body}',
                'RESPONSE: {code} - {res_body}',
            ];

            $stack = HandlerStack::create();

            collect($messageFormats)->each(function ($messageFormat) use ($stack) {
                // We'll use unshift instead of push, to add the middleware to the bottom of the stack, not the top
                $stack->unshift(
                    Middleware::log(
                        with(new Logger('guzzle-log'))->pushHandler(
                            new RotatingFileHandler(storage_path('logs/guzzle-log.log'))
                        ),
                        new MessageFormatter($messageFormat)
                    )
                );
            });

            return function ($config) use ($stack){
                return new Client(array_merge($config, ['handler' => $stack]));
            };
        });
    }

说明

如果您注意到上面的代码,在启动方法的第一行我们告诉 Laravel 我们想在您的服务容器中将此代码注册为 GuzzleClient。

在最后一个 return 语句中,我们 return 将接受一个参数 $config 的函数。我们将此函数用作代理,以便我们可以将参数传递给它并且可以在客户端对象中使用。

return function ($config) use ($stack){
      return new Client(array_merge($config, ['handler' => $stack]));
};

其余代码正在构建 Guzzle 的处理程序对象,以使用 Monolog 库的 Logger 对象将所有请求记录到名为 guzzle-log.log 的文件中。如果启用每日日志,日期将附加到文件名,如 guzzle-log-2019-08-11.log。 用法

我们已经将我们的对象绑定到服务容器,现在是时候在我们的代码中的任何地方使用这个容器,并让它看起来干净。

出于演示目的,我直接在 routes/web.php 文件中使用了它。你可以在任何地方使用。

 Route::get('/', function () {

    $client = app('GuzzleClient')(['base_uri' => 'http://httpbin.org/']);

    $request = $client->get('get',[
        'query' => ['foo'=>'bar', 'baz' => 'baz2'] ,
        'headers' => [ 'accept' =>  'application/json']
    ]);
    $response = json_decode((string) $request->getBody());
    return response()->json($response);
});

如您所见,我正在使用 app() 助手创建一个对象 $client。您还可以将 Guzzle 客户端支持的任何有效参数数组作为第二个参数传递。这里我已经过了base_uri

来源:http://shyammakwana.me/laravel/laravel-log-guzzle-requests-to-file-using-service-container.html

接受的答案通过使用 Service Providers. Another option would be to attach GuzzleHttp\Middleware's log to wherever you use Illuminate\Support\Facades\Http 效果很好。记录请求、响应和发现的任何错误的示例是使用 Middleware::log:

<?php

namespace App\Services;


use Illuminate\Support\Facades\Http;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;

/**
 * Class TestService
 * @package App
 */
class TestService
{
    private function getAccessToken()
    {
        try {
            $response = Http::asForm()->withMiddleware(Middleware::log(with(new Logger('guzzle-log'))->pushHandler(
                new RotatingFileHandler(storage_path('logs/guzzle-log.log'))
            ), new MessageFormatter(MessageFormatter::DEBUG)))->post("https://test.com/oauth/v2/token", [
                'grant_type' => 'client_credentials',
            ]);
            $response->throw();
        } catch (\Throwable $th) {
            $accessToken = false;
        }
        return $accessToken;
    }
}

这会将日志记录写入 logs/guzzle-log-{currentDate}.log 文件。我在这个例子中使用的日志记录格式是 MessageFormatter::DEBUG">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}" 可以很好地输出请求、响应和任何错误。日志文件的示例是:

[2020-08-07T07:13:23.712124+00:00] guzzle-log.INFO: >>>>>>>> POST /oauth/v2/token HTTP/1.1 Content-Length: 29 User-Agent: GuzzleHttp/7 Host: xxxx:4000 Content-Type: application/x-www-form-urlencoded  grant_type=client_credentials <<<<<<<< HTTP/1.1 200 OK X-DNS-Prefetch-Control: off X-Frame-Options: SAMEORIGIN Strict-Transport-Security: max-age=15552000; includeSubDomains X-Download-Options: noopen X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Access-Control-Allow-Origin: * Content-Type: application/json; charset=utf-8 Content-Length: 113 ETag: W/"71-DyA+KEnetTKfUlb0lznokGTt0qk" Date: Fri, 07 Aug 2020 07:13:23 GMT Connection: keep-alive  {"data":{"token_type":"Bearer","access_token":"XYZ","expires_in":"7776000"}} -------- NULL [] []

注意:此选项的缺点是您必须将 withMiddleware(Middleware::log(...)) 附加到您使用 Illuminate\Support\Facades\Http 的任何地方。