Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add StdOutLogger and LoggingTrait #578

Merged
merged 53 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5de2301
Add the StdOutLogger and Logging Trait
Hectorhammett Sep 4, 2024
f393157
Fix types and style
Hectorhammett Sep 4, 2024
e5540f6
fix typing for PSR-3 logger interface
Hectorhammett Sep 5, 2024
ff21a95
Add logging to the Guzzle6HttpHandler
Hectorhammett Sep 9, 2024
0c65a32
Change logic for getDefaultLogger
Hectorhammett Sep 9, 2024
8c7c101
Fix style issues
Hectorhammett Sep 9, 2024
301d28e
Fix phpstan typing for getJwtToken
Hectorhammett Sep 9, 2024
5ae7c1e
Add a flag for disabling logger
Hectorhammett Sep 13, 2024
7aa7ee2
Add logging to the invoke method for apiary support
Hectorhammett Sep 16, 2024
331e97c
Fix style issue on build method
Hectorhammett Sep 16, 2024
35f8dde
Change logic for disabling logging
Hectorhammett Sep 20, 2024
36fd1ac
Fix logic for disabling logging
Hectorhammett Sep 20, 2024
2ff7d1a
Add a function to log a gRPC status only
Hectorhammett Sep 25, 2024
dbfb61c
Removed unused method
Hectorhammett Sep 25, 2024
2f87636
Fix style for LoggingTrait
Hectorhammett Sep 25, 2024
0cb0c27
Fix typing
Hectorhammett Sep 25, 2024
8e4a7e5
Updated type annotations
Hectorhammett Sep 25, 2024
6ca6bc7
Change logic for logging responses to exclude the info log
Hectorhammett Sep 27, 2024
16d9372
Change logic for logResponse
Hectorhammett Sep 27, 2024
b1ff503
Handle false for the case when json_encode returns false
Hectorhammett Oct 8, 2024
b9fb817
Fix serialization bug
Hectorhammett Oct 16, 2024
33c156a
Add support for logger in
Hectorhammett Oct 18, 2024
2a8f880
Update the StdOutLogger to use Psr the LoggerTrait
Hectorhammett Nov 11, 2024
13c516e
Fix style and improved readability
Hectorhammett Nov 11, 2024
e5ff048
Fix style issues
Hectorhammett Nov 11, 2024
374c859
Add milliseconds via microtime to the LogEvent class for latency calc…
Hectorhammett Nov 18, 2024
6655bd6
Fix unit testing for latency
Hectorhammett Nov 18, 2024
5bdbc7d
Update LoggingTrait to check fo is_null instead of falsey
Hectorhammett Nov 19, 2024
7aea4e9
Use the passed requestId option inside the options array
Hectorhammett Nov 21, 2024
7e2df5c
Change LogEvent name to RpcLogEvent
Hectorhammett Nov 22, 2024
1591d59
Use the round method to store miliseconds on RPCLogEvent
Hectorhammett Nov 25, 2024
53ce7fa
Change the array type of payload to string
Hectorhammett Nov 25, 2024
b05fd63
Fix null payload bug on the truncatePayload method
Hectorhammett Nov 25, 2024
a897b0b
Change the debug flag to GOOGLE_SDK_PHP_LOGGING
Hectorhammett Nov 26, 2024
027096e
Cast a response url to String
Hectorhammett Nov 30, 2024
db765ec
Fix type notation on phpDoc
Hectorhammett Dec 2, 2024
f35e295
Add the internal tag to internal classes
Hectorhammett Dec 3, 2024
636f650
Swap logic to log the info level log
Hectorhammett Dec 4, 2024
3bbac24
Fix the LoggingTrait test
Hectorhammett Dec 5, 2024
1a7523b
Fix Style
Hectorhammett Dec 5, 2024
876f14a
Change the client ID field to represent a Gapic Client
Hectorhammett Dec 5, 2024
7869f8c
Change clientId for processId in rpcLogEvent
Hectorhammett Dec 9, 2024
7d3a494
Change the httpHandler requestId fallback to a hash
Hectorhammett Dec 10, 2024
8d9ade7
Handle the getmypid false case
Hectorhammett Dec 10, 2024
ffaff38
Remove the INFO level log
Hectorhammett Dec 10, 2024
6aaf4de
Move logging logic of guzzle logging to private methods
Hectorhammett Dec 11, 2024
d611f8e
Update max lenght to be in a variable
Hectorhammett Dec 11, 2024
1df9dec
Update type doc for requestLog
Hectorhammett Dec 11, 2024
561d198
Remove unused mock class
Hectorhammett Dec 11, 2024
dbca5c8
Merge branch 'main' into http-logging
bshaffer Dec 11, 2024
79fbf1b
Apply suggestions from code review
bshaffer Dec 11, 2024
679f1bd
Remove readonly properties
Hectorhammett Dec 11, 2024
82388a7
Merge branch 'http-logging' of https://github.com/googleapis/google-a…
Hectorhammett Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"guzzlehttp/guzzle": "^7.4.5",
"guzzlehttp/psr7": "^2.4.5",
"psr/http-message": "^1.1||^2.0",
"psr/cache": "^2.0||^3.0"
"psr/cache": "^2.0||^3.0",
"psr/log": "^3.0"
},
"require-dev": {
"guzzlehttp/promises": "^2.0",
Expand Down
42 changes: 39 additions & 3 deletions src/ApplicationDefaultCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
use Google\Auth\Credentials\UserRefreshCredentials;
use Google\Auth\HttpHandler\HttpClientCache;
use Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Auth\Logging\StdOutLogger;
use Google\Auth\Middleware\AuthTokenMiddleware;
use Google\Auth\Middleware\ProxyAuthTokenMiddleware;
use Google\Auth\Subscriber\AuthTokenSubscriber;
use GuzzleHttp\Client;
use InvalidArgumentException;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerInterface;

/**
* ApplicationDefaultCredentials obtains the default credentials for
Expand Down Expand Up @@ -70,6 +72,8 @@
*/
class ApplicationDefaultCredentials
{
private const SDK_DEBUG_ENV_VAR = 'GOOGLE_SDK_PHP_LOGGING';

/**
* @deprecated
*
Expand Down Expand Up @@ -146,7 +150,8 @@ public static function getMiddleware(
* user-defined scopes exist, expressed either as an Array or as a
* space-delimited string.
* @param string|null $universeDomain Specifies a universe domain to use for the
* calling client library
* calling client library.
* @param null|false|LoggerInterface $logger A PSR3 compliant LoggerInterface.
*
* @return FetchAuthTokenInterface
* @throws DomainException if no implementation can be obtained.
Expand All @@ -158,7 +163,8 @@ public static function getCredentials(
?CacheItemPoolInterface $cache = null,
$quotaProject = null,
$defaultScope = null,
?string $universeDomain = null
?string $universeDomain = null,
null|false|LoggerInterface $logger = null,
) {
$creds = null;
$jsonKey = CredentialsLoader::fromEnv()
Expand All @@ -171,7 +177,7 @@ public static function getCredentials(
HttpClientCache::setHttpClient($client);
}

$httpHandler = HttpHandlerFactory::build($client);
$httpHandler = HttpHandlerFactory::build($client, $logger);
}

if (is_null($quotaProject)) {
Expand Down Expand Up @@ -318,6 +324,36 @@ public static function getIdTokenCredentials(
return $creds;
}

/**
* Returns a StdOutLogger instance
*
* @internal
*
* @return null|LoggerInterface
*/
public static function getDefaultLogger(): null|LoggerInterface
Hectorhammett marked this conversation as resolved.
Show resolved Hide resolved
{
$loggingFlag = getenv(self::SDK_DEBUG_ENV_VAR);

// Env var is not set
if (empty($loggingFlag)) {
return null;
}

$loggingFlag = strtolower($loggingFlag);

// Env Var is not true
if ($loggingFlag !== 'true') {
if ($loggingFlag !== 'false') {
trigger_error('The ' . self::SDK_DEBUG_ENV_VAR . ' is set, but it is set to another value than false or true. Logging is disabled');
}

return null;
}

return new StdOutLogger();
}

/**
* @return string
*/
Expand Down
84 changes: 81 additions & 3 deletions src/HttpHandler/Guzzle6HttpHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,35 @@
*/
namespace Google\Auth\HttpHandler;

use Google\Auth\Logging\LoggingTrait;
use Google\Auth\Logging\RpcLogEvent;
use GuzzleHttp\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;

class Guzzle6HttpHandler
{
use LoggingTrait;

/**
* @var ClientInterface
*/
private $client;

/**
* @var null|LoggerInterface
*/
private $logger;

/**
* @param ClientInterface $client
* @param null|LoggerInterface $logger
*/
public function __construct(ClientInterface $client)
public function __construct(ClientInterface $client, ?LoggerInterface $logger = null)
{
$this->client = $client;
$this->logger = $logger;
}

/**
Expand All @@ -44,7 +56,19 @@ public function __construct(ClientInterface $client)
*/
public function __invoke(RequestInterface $request, array $options = [])
{
return $this->client->send($request, $options);
$requestEvent = null;

if ($this->logger) {
$requestEvent = $this->requestLog($request, $options);
}
Hectorhammett marked this conversation as resolved.
Show resolved Hide resolved

$response = $this->client->send($request, $options);

if ($this->logger) {
$this->responseLog($response, $requestEvent);
}

return $response;
}

/**
Expand All @@ -57,6 +81,60 @@ public function __invoke(RequestInterface $request, array $options = [])
*/
public function async(RequestInterface $request, array $options = [])
{
return $this->client->sendAsync($request, $options);
$requestEvent = null;

if ($this->logger) {
$requestEvent = $this->requestLog($request, $options);
}

$promise = $this->client->sendAsync($request, $options);

if ($this->logger) {
$promise->then(function (ResponseInterface $response) use ($requestEvent) {
$this->responseLog($response, $requestEvent);
return $response;
});
}

return $promise;
}

/**
* @internal
bshaffer marked this conversation as resolved.
Show resolved Hide resolved
* @param RequestInterface $request
* @param array<mixed> $options
*/
public function requestLog(RequestInterface $request, array $options): RpcLogEvent
{
$requestEvent = new RpcLogEvent();

$requestEvent->method = $request->getMethod();
$requestEvent->url = (string) $request->getUri();
$requestEvent->headers = $request->getHeaders();
$requestEvent->payload = $request->getBody()->getContents();
$requestEvent->retryAttempt = $options['retryAttempt'] ?? null;
$requestEvent->serviceName = $options['serviceName'] ?? null;
$requestEvent->processId = (int) getmypid();
$requestEvent->requestId = $options['requestId'] ?? crc32((string) spl_object_id($request) . getmypid());

$this->logRequest($requestEvent);

return $requestEvent;
}

/**
* @internal
*/
public function responseLog(ResponseInterface $response, RpcLogEvent $requestEvent): void
{
$responseEvent = new RpcLogEvent($requestEvent->milliseconds);

$responseEvent->headers = $response->getHeaders();
$responseEvent->payload = $response->getBody()->getContents();
$responseEvent->status = $response->getStatusCode();
$responseEvent->processId = $requestEvent->processId;
$responseEvent->requestId = $requestEvent->requestId;

$this->logResponse($responseEvent);
}
}
17 changes: 13 additions & 4 deletions src/HttpHandler/HttpHandlerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,28 @@
*/
namespace Google\Auth\HttpHandler;

use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\BodySummarizer;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Log\LoggerInterface;

class HttpHandlerFactory
{
/**
* Builds out a default http handler for the installed version of guzzle.
*
* @param ClientInterface|null $client
* @param null|false|LoggerInterface $logger
* @return Guzzle6HttpHandler|Guzzle7HttpHandler
* @throws \Exception
*/
public static function build(?ClientInterface $client = null)
{
public static function build(
?ClientInterface $client = null,
null|false|LoggerInterface $logger = null,
) {
if (is_null($client)) {
$stack = null;
if (class_exists(BodySummarizer::class)) {
Expand All @@ -45,6 +50,10 @@ public static function build(?ClientInterface $client = null)
$client = new Client(['handler' => $stack]);
}

$logger = ($logger === false)
? null
: $logger ?? ApplicationDefaultCredentials::getDefaultLogger();

$version = null;
if (defined('GuzzleHttp\ClientInterface::MAJOR_VERSION')) {
$version = ClientInterface::MAJOR_VERSION;
Expand All @@ -54,9 +63,9 @@ public static function build(?ClientInterface $client = null)

switch ($version) {
case 6:
return new Guzzle6HttpHandler($client);
return new Guzzle6HttpHandler($client, $logger);
case 7:
return new Guzzle7HttpHandler($client);
return new Guzzle7HttpHandler($client, $logger);
default:
throw new \Exception('Version not supported');
}
Expand Down
Loading
Loading