Laravel - Запросы журнала Guzzle в файл

Во время работы над проектом я обнаружил, что сторонние API работают с Postman, но не работают с Guzzle Client.

Отладка запроса Guzzle может быть затруднена, поэтому есть ли способ, с помощью которого можно просмотреть все запросы, сделанные клиентом Guzzle?


person shyammakwana.me    schedule 17.08.2019    source источник


Ответы (2)


TLDR;

Есть простой способ зарегистрировать все запросы Guzzle, передав второй параметр Client, после чего он будет регистрировать все запросы. Но это некрасиво, если у вас есть много методов, использующих Guzzle Client для отправки запроса на сторонний сервер. Я сделал это с помощью сервисного контейнера Laravel.

Долгий путь через сервисный контейнер Laravel

Когда я использовал клиент Guzzle в своем проекте и использовал обработчик для регистрации всех запросов, он выглядел хорошо. Но позже было много методов во многих разных классах, поэтому мне приходилось везде писать логику логгера. Затем я подумал, почему бы не использовать Laravel Service Container, привязать объект один раз и использовать его везде.

Вот как я это сделал. В вашем методе загрузки AppServiceContainer.php мы добавим весь наш код. А затем в контроллерах мы будем использовать наш объект 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;

Добавьте приведенный ниже код в метод boot вашего AppServiceContainer.php.

/**
 * 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 для записи всех запросов в файл с именем guzzle-log.log с использованием объекта Logger библиотеки Monolog. Если у вас включены ежедневные журналы, к имени файла будет добавлена ​​дата, например 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);
});

Как видите, я создаю объект $client с помощью помощника app(). Также вы можете передать любой допустимый массив аргументов, который поддерживает клиент Guzzle, в качестве второго параметра. Здесь я прошел base_uri.

Запись в файле журнала

Источник: http://shyammakwana.me/laravel/laravel-log-guzzle-requests-to-file-using-service-container.html

person shyammakwana.me    schedule 17.08.2019
comment
Я использую Guzzle Http в laravel 7, не могли бы вы помочь мне, как мне добиться того же? Это мой опубликованный вопрос stackoverflow.com/questions/67920040/ - person Vinay Kaithwas; 10.06.2021

Принятый ответ хорошо работает при использовании поставщиков услуг. Другой вариант — прикрепить log GuzzleHttp\Middleware к тому месту, где вы используете 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.

person Osama Sayed    schedule 07.08.2020