【问题标题】:Laravel - Log Guzzle requests to fileLaravel - 记录 Guzzle 请求文件
【发布时间】:2020-08-07 15:17:26
【问题描述】:

在处理一个项目时,我发现第三方 API 可以在 Postman 中使用,但不能在 Guzzle Client 中使用。

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

【问题讨论】:

    标签: laravel logging guzzle


    【解决方案1】:

    TLDR;

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

    通过 Laravel 的服务容器的漫长道路

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

    这就是我的做法。在您的AppServiceContainer.php 的引导方法中,我们将添加我们所有的代码。然后在 Controllers 中我们将使用我们的 Client 对象。

    在AppServiceContainer.php 文件的顶部添加此使用语句。

    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 语句中,我们返回一个函数,该函数将接受一个参数 $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

    【讨论】:

    【解决方案2】:

    使用Service Providers 可以很好地接受接受的答案。另一种选择是将GuzzleHttp\Middleware 的log 附加到您使用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,也就是"&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;\n{request}\n&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;\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 的任何位置。

    【讨论】:

    • 谢谢,这正是我想要的
    猜你喜欢
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2017-11-15
    • 2017-04-10
    • 2020-07-14
    • 2019-12-17
    • 2017-04-16
    相关资源
    最近更新 更多