Guzzle TransferStats HandlerStats documentation/explanation?

Guzzle TransferStats HandlerStats documentation/explanation?

在 Guzzle 文档中,您可以找到名为 on_statsa request option 可调用函数,它允许您访问请求的传输统计信息并访问与您的客户端关联的处理程序的较低级别传输详细信息。

TransferStats object 为您提供了一些方法来检查您的请求,其中之一是 getHandlerStats()。根据文档块,此方法为您提供了所有处理程序特定传输数据的数组。

但是我找不到关于这个数组的特定键的任何文档。有些很简单,例如 primary_ipurl,但对于其他人,我有以下问题。

$handlerStats = [
    "url" => "https://example.com",
    "content_type" => "application/json; charset=utf-8",
    "http_code" => 200,
    "header_size" => 569,
    "request_size" => 731,  // is request size purely the body? and is this in bytes or kb or..?
    "filetime" => -1,
    "ssl_verify_result" => 0, // what are the options here?
    "redirect_count" => 0, 
    "total_time" => 0.33132, // is this in seconds, i guess so? this is supposed to be the same as the getTransferTime() method.
    "namelookup_time" => 0.067308, // i assume purely for the dns lookup?
    "connect_time" => 0.078286, // what is this?
    "pretransfer_time" => 0.111673, // what is this? and do some of these times overlap.
    "size_upload" => 0.0, // again are sizes in bytes?
    "size_download" => 7717.0,
    "speed_download" => 23314.0, // is this in bytes per second?
    "speed_upload" => 0.0,
    "download_content_length" => -1.0,
    "upload_content_length" => -1.0,
    "starttransfer_time" => 0.320876,
    "redirect_time" => 0.0,
    "redirect_url" => "",
    "primary_ip" => "1.1.1.1",
    "certinfo" => [],
    "primary_port" => 443,
    "local_ip" => "192.168.208.5",
    "local_port" => 39868,
    "http_version" => 2,
    "protocol" => 2,
    "ssl_verifyresult" => 0, // why is this duplicated, deprecated? 
    "scheme" => "HTTPS",
    "appconnect_time_us" => 111513,
    "connect_time_us" => 78286,
    "namelookup_time_us" => 67308,
    "pretransfer_time_us" => 111673,
    "redirect_time_us" => 0,
    "starttransfer_time_us" => 320876,
    "total_time_us" => 331320,
    "appconnect_time" => 0.111513, // what does the appconnectime do?
  ];

有没有人有文档 link 或者可以解释这些键?非常感谢。

appconnect: 从开始到 SSL/SSH/etc connect/handshake 到远程主机完成所花费的时间,以秒为单位

pretransfer:从开始到文件传输即将开始所花费的时间,以秒为单位。这包括特定于所涉及的特定协议的所有预传输命令和协商。

...好吧,我不确定其他人,你能分享你想要描述的键吗?

T运行sfer 统计数据由 T运行sferStats class 提供,但是 Guzzle documentation 没有描述 return 的键和值统计数据。 阅读 TransferStats 评论提供了一些线索。

T运行sferStats 在三个 classes:

中创建

CurlFactory

private static function invokeStats(EasyHandle $easy): void
{
    $curlStats = \curl_getinfo($easy->handle);
    $curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
    $stats = new TransferStats(
        $easy->request,
        $easy->response,
        $curlStats['total_time'],
        $easy->errno,
        $curlStats
    );
    ($easy->options['on_stats'])($stats);
}

MockHandler

private function invokeStats(
        RequestInterface $request,
        array $options,
        ResponseInterface $response = null,
        $reason = null
): void {
    if (isset($options['on_stats'])) {
        $transferTime = $options['transfer_time'] ?? 0;
        $stats = new TransferStats($request, $response, $transferTime, $reason);
        ($options['on_stats'])($stats);
    }
}

StreamHandler

private function invokeStats(
    array $options,
    RequestInterface $request,
    ?float $startTime,
    ResponseInterface $response = null,
    \Throwable $error = null
): void {
    if (isset($options['on_stats'])) {
        $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
        ($options['on_stats'])($stats);
    }
}
文档中的

Note

Guzzle no longer requires cURL in order to send HTTP requests. Guzzle will use the PHP stream wrapper to send HTTP requests if cURL is not installed. Alternatively, you can provide your own HTTP handler used to send requests. Keep in mind that cURL is still required for sending concurrent requests.

因此,您从统计信息中收到的键和值很可能取决于 Guzzle 是否使用 cURL。您还可以在创建 T运行sferStats 的示例中看到它因不同的 类 (CurlFactory/MockHandler/StramHandler) 而异。这可能就是统计文档丢失的原因。

请注意,您可能从统计信息中收到的键和值也将取决于您使用的 cURL 版本,甚至是您使用的 PHP 版本。 PHP 的 curl_getinfo 的更新日志指出:

Version     Description
7.3.0       Introduced CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, CURLINFO_CONTENT_LENGTH_UPLOAD_T (...)

所以低于 7.3.0 的 PHP 版本不应该有像 CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 和许多其他的任何统计数据。

谨慎对待您可能收到的任何特定密钥是个好主意,因此我始终建议将 array_key_exists 与传输的状态数组一起使用。

假设 Guzzle 对请求使用 cURL,那么统计数据由 PHP 的本机函数 curl_getinfo 获取,该函数描述了许多统计数据:

CURLINFO_EFFECTIVE_URL - Last effective URL
CURLINFO_HTTP_CODE - The last response code. As of PHP 5.5.0 and cURL 7.10.8, this is a legacy alias of CURLINFO_RESPONSE_CODE 
(...)

和可能的数组键:

"url"
"content_type"
"http_code" 
(...)

但是您可能会注意到 PHP 的预定义常量提供的排序描述不一致:

CURLINFO_HTTP_CODE - The last response code. As of PHP 5.5.0 and cURL 7.10.8, this is a legacy alias of CURLINFO_RESPONSE_CODE 

和键列表:

"content_type"

CURLINFO_HTTP_CODE 在常量列表中排在第二位,与 returned 键列表中的第二个键 content_type 不匹配。
此外,一些预定义常量如:APPCONNECT_TIME_T 在 returned 数组键列表中没有它们各自的名称。假设 APPCONNECT_TIME_T 有数组键 appconnect_time_t 是错误的,因为它实际上是 appconnect_time_us.


PHP 的 curl_getinfo 文档既不广泛也不一致。

要获取 PHP 的预定义常量和相应的数组键名,最好查看 PHP 7.4 source of ext/curl/interface.c 代码,您可能会在其中看到对本机 cURL 函数的调用:

if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
    CAAL("http_code", l_code);
}

并且您可以轻松地将 curl_easy_getinfo 的第二个参数 CURLINFO_HTTP_CODECAAL 的第一个参数 http_code 相匹配。
通过这种方式,您可以从最可靠的来源构建自己的匹配列表,例如
[CURLINFO_HTTP_CODE => 'http_code', <PHPConstant> => <array-key>]
,因为来自 PHP 本身的来源。

因为 PHP 使用 cURL 的 curl_easy_getinfo 然后查看文档:

curl_easy_getinfo - 从 curl

中提取信息

将为您带来更多细节,特别有趣的是关于TIMES的这些:

An overview of the six time values available from curl_easy_getinfo()

curl_easy_perform()
    |
    |--NAMELOOKUP
    |--|--CONNECT
    |--|--|--APPCONNECT
    |--|--|--|--PRETRANSFER
    |--|--|--|--|--STARTTRANSFER
    |--|--|--|--|--|--TOTAL
    |--|--|--|--|--|--REDIRECT

例如:

CURLINFO_APPCONNECT_TIME_T

Time from start until SSL/SSH handshake completed. See CURLINFO_APPCONNECT_TIME_T

然后link你可以得到更详细的解释:

(...) This time is most often very near to the CURLINFO_PRETRANSFER_TIME_T time, except for cases such as HTTP pipelining where the pretransfer time can be delayed due to waits in line for the pipeline and more.

When a redirect is followed, the time from each request is added together. (...)

我希望全部知识结合起来能回答您的问题,并且您喜欢我揭示的整个挖掘过程,而不是在没有任何证据的情况下只是说 X 是 Y。

现在让我们玩得开心:)

运行 这段代码:

<?php

error_reporting(E_ALL);
header("Content-Type: text/plain");

$urlPhpSource = 'https://raw.githubusercontent.com/php/php-src/5caaf40b43303887a38d738a9c2a2f4cf6dc9b1a/ext/curl/interface.c';
$phpSourceArr = explode(\PHP_EOL, file_get_contents($urlPhpSource));

$option = '';
$optionNameArr = [];
foreach ($phpSourceArr as $line) {

    $line = trim($line);
    if (preg_match('/curl_easy_getinfo.+(CURLINFO_[A-Z_]+)/', $line, $matches)) {
        $option = $matches[1];
    }

    if (!empty($option) && preg_match('/^CAA.+\"(.+)\"/', $line, $matches)) {
        $optionNameArr[$option] = $matches[1];
        $option = '';
    }
}

$urlDescriptions = 'https://curl.se/libcurl/c/easy_getinfo_options.html';
$descriptionsArr = explode(\PHP_EOL, file_get_contents($urlDescriptions));

$descriptionResultArr = [];
foreach ($descriptionsArr as $line) {
    $pattern = '/(CURLINFO_[A-Z_]+).*';
    $pattern .= '<\/td><td>(.*)<\/td><\/tr>/';
    if (preg_match($pattern, $line, $matches)) {
        $descriptionResultArr[trim($matches[1])] = ucfirst(trim($matches[2]));
    }
}

$resultCombinedArr = [];
foreach($optionNameArr as $option => $name) {
    if (!key_exists($option, $descriptionResultArr)) {
        $desciption = '<not found>';
    } else {
        $desciption = $descriptionResultArr[$option];
    }

    $tmpArr = [];
    $tmpArr['name'] = $name;
    $tmpArr['option'] = $option;
    if (defined($option)) {
        $tmpArr['optionValue'] = constant('\' . $option);
    }
    $tmpArr['desciption'] = $desciption;
    $resultCombinedArr[$name] = $tmpArr;
}

echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;
echo "All Options:\n";
print_r($resultCombinedArr);
echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;

echo "Available Options:\n";
print_r(array_filter($resultCombinedArr, function($data) {
    return key_exists('optionValue', $data);
}));
echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;

echo "Not available Options:\n";
print_r(array_filter($resultCombinedArr, function($data) {
    return !key_exists('optionValue', $data);
}));

会给出全部可能的列表

  • 预定义常量(选项)
  • 选项的整数值 (optionValue)
  • 选项各自的数组键(名称)
  • 选项的描述(描述)

这样:

All Options:
Array
(
    [url] => Array
        (
            [name] => url
            [option] => CURLINFO_EFFECTIVE_URL
            [optionValue] => 1048577
            [desciption] => Get the last used URL
        )

    [content_type] => Array
        (
            [name] => content_type
            [option] => CURLINFO_CONTENT_TYPE
            [optionValue] => 1048594
            [desciption] => Get Content-Type
        )

    [http_code] => Array
        (
            [name] => http_code
            [option] => CURLINFO_HTTP_CODE
            [optionValue] => 2097154
            [desciption] => <not found>
        )

        (...)

您的 PHP 选项支持:

Available Options:
Array
(
    [url] => Array
        (
            [name] => url
            [option] => CURLINFO_EFFECTIVE_URL
            [optionValue] => 1048577
            [desciption] => Get the last used URL
        )

    [content_type] => Array
        (
            [name] => content_type
            [option] => CURLINFO_CONTENT_TYPE
            [optionValue] => 1048594
            [desciption] => Get Content-Type
        )

    [http_code] => Array
        (
            [name] => http_code
            [option] => CURLINFO_HTTP_CODE
            [optionValue] => 2097154
            [desciption] => <not found>
        )

     (...)

不支持:

Not available Options:
Array
(
    [appconnect_time_us] => Array
        (
            [name] => appconnect_time_us
            [option] => CURLINFO_APPCONNECT_TIME_T
            [desciption] => Get the time until the SSL/SSH handshake is completed
        )

    [connect_time_us] => Array
        (
            [name] => connect_time_us
            [option] => CURLINFO_CONNECT_TIME_T
            [desciption] => Get the time until connect
        )

    [namelookup_time_us] => Array
        (
            [name] => namelookup_time_us
            [option] => CURLINFO_NAMELOOKUP_TIME_T
            [desciption] => Get the name lookup time in microseconds
        )

    (...)

请注意,如果 CURLINFO_APPCONNECT_TIME_T 等预定义常量未在 PHP 中定义,则选项 CURLINFO_APPCONNECT_TIME_T 被视为不受支持,但这并不一定意味着您将获得 t运行没有相应键 appconnect_time_us 或键 appconnect_time_us 的 sfer stat 将有一些未定义的值。

另一件奇怪的事情是我 运行 这个 scipt 的 PHP 版本:

PHP 7.3.27-9+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Feb 23 2021 15:10:08) ( NTS )

我得到这些常量未定义:

Array
(
    [0] => CURLINFO_APPCONNECT_TIME_T
    [1] => CURLINFO_CONNECT_TIME_T
    [2] => CURLINFO_NAMELOOKUP_TIME_T
    [3] => CURLINFO_PRETRANSFER_TIME_T
    [4] => CURLINFO_REDIRECT_TIME_T
    [5] => CURLINFO_STARTTRANSFER_TIME_T
    [6] => CURLINFO_TOTAL_TIME_T
)

这与 curl_getinfo 文档中的声明相互排斥,在 Changelog 部分下声明所有这些都应该已经在 PHP 7.3.0 及更高版本中引入。要么我做错了什么,要么 curl_getinfo 的文档再次被证明是不准确的。

不过我自己的图片是基于官方的

PHP 7.3.8 (cli) (built: Aug 2 2019 05:16:32) ( NTS )

Docker 图片每个选项都可用。

这是为参数生成的非官方文档,您可以将其复制并粘贴到您的项目中:

<?php

array (
  'url' => 
  array (
    'name' => 'url',
    'option' => 'CURLINFO_EFFECTIVE_URL',
    'optionValue' => 1048577,
    'desciption' => 'Get the last used URL',
  ),
  'content_type' => 
  array (
    'name' => 'content_type',
    'option' => 'CURLINFO_CONTENT_TYPE',
    'optionValue' => 1048594,
    'desciption' => 'Get Content-Type',
  ),
  'http_code' => 
  array (
    'name' => 'http_code',
    'option' => 'CURLINFO_HTTP_CODE',
    'optionValue' => 2097154,
    'desciption' => '<not found>',
  ),
  'header_size' => 
  array (
    'name' => 'header_size',
    'option' => 'CURLINFO_HEADER_SIZE',
    'optionValue' => 2097163,
    'desciption' => 'Get size of retrieved headers',
  ),
  'request_size' => 
  array (
    'name' => 'request_size',
    'option' => 'CURLINFO_REQUEST_SIZE',
    'optionValue' => 2097164,
    'desciption' => 'Get size of sent request',
  ),
  'filetime' => 
  array (
    'name' => 'filetime',
    'option' => 'CURLINFO_FILETIME',
    'optionValue' => 2097166,
    'desciption' => 'Get the remote time of the retrieved document',
  ),
  'ssl_verify_result' => 
  array (
    'name' => 'ssl_verify_result',
    'option' => 'CURLINFO_SSL_VERIFYRESULT',
    'optionValue' => 2097165,
    'desciption' => 'Get the result of the certificate verification',
  ),
  'redirect_count' => 
  array (
    'name' => 'redirect_count',
    'option' => 'CURLINFO_REDIRECT_COUNT',
    'optionValue' => 2097172,
    'desciption' => 'Get the number of redirects',
  ),
  'total_time' => 
  array (
    'name' => 'total_time',
    'option' => 'CURLINFO_TOTAL_TIME',
    'optionValue' => 3145731,
    'desciption' => 'Get total time of previous transfer',
  ),
  'namelookup_time' => 
  array (
    'name' => 'namelookup_time',
    'option' => 'CURLINFO_NAMELOOKUP_TIME',
    'optionValue' => 3145732,
    'desciption' => 'Get the name lookup time',
  ),
  'connect_time' => 
  array (
    'name' => 'connect_time',
    'option' => 'CURLINFO_CONNECT_TIME',
    'optionValue' => 3145733,
    'desciption' => 'Get the time until connect',
  ),
  'pretransfer_time' => 
  array (
    'name' => 'pretransfer_time',
    'option' => 'CURLINFO_PRETRANSFER_TIME',
    'optionValue' => 3145734,
    'desciption' => 'Get the time until the file transfer start',
  ),
  'size_upload' => 
  array (
    'name' => 'size_upload',
    'option' => 'CURLINFO_SIZE_UPLOAD',
    'optionValue' => 3145735,
    'desciption' => 'Get the number of uploaded bytes',
  ),
  'size_download' => 
  array (
    'name' => 'size_download',
    'option' => 'CURLINFO_SIZE_DOWNLOAD',
    'optionValue' => 3145736,
    'desciption' => 'Get the number of downloaded bytes',
  ),
  'speed_download' => 
  array (
    'name' => 'speed_download',
    'option' => 'CURLINFO_SPEED_DOWNLOAD',
    'optionValue' => 3145737,
    'desciption' => 'Get download speed',
  ),
  'speed_upload' => 
  array (
    'name' => 'speed_upload',
    'option' => 'CURLINFO_SPEED_UPLOAD',
    'optionValue' => 3145738,
    'desciption' => 'Get upload speed',
  ),
  'download_content_length' => 
  array (
    'name' => 'download_content_length',
    'option' => 'CURLINFO_CONTENT_LENGTH_DOWNLOAD',
    'optionValue' => 3145743,
    'desciption' => 'Get content-length of download',
  ),
  'upload_content_length' => 
  array (
    'name' => 'upload_content_length',
    'option' => 'CURLINFO_CONTENT_LENGTH_UPLOAD',
    'optionValue' => 3145744,
    'desciption' => 'Get the specified size of the upload',
  ),
  'starttransfer_time' => 
  array (
    'name' => 'starttransfer_time',
    'option' => 'CURLINFO_STARTTRANSFER_TIME',
    'optionValue' => 3145745,
    'desciption' => 'Get the time until the first byte is received',
  ),
  'redirect_time' => 
  array (
    'name' => 'redirect_time',
    'option' => 'CURLINFO_REDIRECT_TIME',
    'optionValue' => 3145747,
    'desciption' => 'Get the time for all redirection steps',
  ),
  'redirect_url' => 
  array (
    'name' => 'redirect_url',
    'option' => 'CURLINFO_REDIRECT_URL',
    'optionValue' => 1048607,
    'desciption' => 'Get the URL a redirect would go to',
  ),
  'primary_ip' => 
  array (
    'name' => 'primary_ip',
    'option' => 'CURLINFO_PRIMARY_IP',
    'optionValue' => 1048608,
    'desciption' => 'Get IP address of last connection',
  ),
  'certinfo' => 
  array (
    'name' => 'certinfo',
    'option' => 'CURLINFO_CERTINFO',
    'optionValue' => 4194338,
    'desciption' => 'Get the TLS certificate chain',
  ),
  'primary_port' => 
  array (
    'name' => 'primary_port',
    'option' => 'CURLINFO_PRIMARY_PORT',
    'optionValue' => 2097192,
    'desciption' => 'Get the latest destination port number',
  ),
  'local_ip' => 
  array (
    'name' => 'local_ip',
    'option' => 'CURLINFO_LOCAL_IP',
    'optionValue' => 1048617,
    'desciption' => 'Get local IP address of last connection',
  ),
  'local_port' => 
  array (
    'name' => 'local_port',
    'option' => 'CURLINFO_LOCAL_PORT',
    'optionValue' => 2097194,
    'desciption' => 'Get the latest local port number',
  ),
  'http_version' => 
  array (
    'name' => 'http_version',
    'option' => 'CURLINFO_HTTP_VERSION',
    'optionValue' => 2097198,
    'desciption' => 'Get the http version used in the connection',
  ),
  'protocol' => 
  array (
    'name' => 'protocol',
    'option' => 'CURLINFO_PROTOCOL',
    'optionValue' => 2097200,
    'desciption' => 'Get the protocol used in the connection',
  ),
  'ssl_verifyresult' => 
  array (
    'name' => 'ssl_verifyresult',
    'option' => 'CURLINFO_PROXY_SSL_VERIFYRESULT',
    'optionValue' => 2097199,
    'desciption' => 'Get the result of the proxy certificate verification',
  ),
  'scheme' => 
  array (
    'name' => 'scheme',
    'option' => 'CURLINFO_SCHEME',
    'optionValue' => 1048625,
    'desciption' => 'Get the URL scheme (sometimes called protocol) used in the connection',
  ),
  'appconnect_time_us' => 
  array (
    'name' => 'appconnect_time_us',
    'option' => 'CURLINFO_APPCONNECT_TIME_T',
    'optionValue' => 6291512,
    'desciption' => 'Get the time until the SSL/SSH handshake is completed',
  ),
  'connect_time_us' => 
  array (
    'name' => 'connect_time_us',
    'option' => 'CURLINFO_CONNECT_TIME_T',
    'optionValue' => 6291508,
    'desciption' => 'Get the time until connect',
  ),
  'namelookup_time_us' => 
  array (
    'name' => 'namelookup_time_us',
    'option' => 'CURLINFO_NAMELOOKUP_TIME_T',
    'optionValue' => 6291507,
    'desciption' => 'Get the name lookup time in microseconds',
  ),
  'pretransfer_time_us' => 
  array (
    'name' => 'pretransfer_time_us',
    'option' => 'CURLINFO_PRETRANSFER_TIME_T',
    'optionValue' => 6291509,
    'desciption' => 'Get the time until the file transfer start',
  ),
  'redirect_time_us' => 
  array (
    'name' => 'redirect_time_us',
    'option' => 'CURLINFO_REDIRECT_TIME_T',
    'optionValue' => 6291511,
    'desciption' => 'Get the time for all redirection steps',
  ),
  'starttransfer_time_us' => 
  array (
    'name' => 'starttransfer_time_us',
    'option' => 'CURLINFO_STARTTRANSFER_TIME_T',
    'optionValue' => 6291510,
    'desciption' => 'Get the time until the first byte is received',
  ),
  'total_time_us' => 
  array (
    'name' => 'total_time_us',
    'option' => 'CURLINFO_TOTAL_TIME_T',
    'optionValue' => 6291506,
    'desciption' => 'Get total time of previous transfer in microseconds',
  ),
)