В mod_php вы можете использовать функцию apache_note ()
для регистрации переменных в Журнал доступа Apache:
<?php
apache_note('SCRIPT_TIME', '1234');
?>
С конфигурацией Apache:
LogFormat "%h %l %u %t [%D/%{SCRIPT_TIME}n] \"%r\" %>s %b" inc_info
...
CustomLog /path/to/access_log inc_info
Но функция apache_note ()
недоступна в PHP-FPM.
Точно так же вы не можете использовать apache_setenv ( )
или setenv ()
для установки переменных среды (для регистрации через % {SCRIPT_TIME} e
).
Одна из возможностей - установить заголовок, который Apache может регистрировать с "% {SCRIPT_TIME} i", но вы должны быть осторожны, чтобы не позволить конфиденциальной информации быть отправленной клиенту (например, знание точного времени обработки для сценария входа в систему может быть проблемой безопасности). Но, что более важно, это не работает если контент уже был отправлен клиенту, так как вы больше не можете отправлять заголовки (как показано в полном примере ниже).
Или PHP мог бы записать свой собственный файл журнала, но это будет дублировать многое из того, что Apache журнал уже есть, может пропустить l og записи (например, если в сценарии есть ошибка), и он будет создан с правами пользователя Apache (а не будет записан с правами root).
Для более подробной информации, это код, который я использую для регистрации времени обработки скрипта:
<?php
define('SCRIPT_START', microtime(true));
function log_shutdown() {
if (!defined('SCRIPT_END')) {
define('SCRIPT_END', number_format(round((microtime(true) - SCRIPT_START), 4), 4));
}
if (function_exists('apache_note')) {
apache_note('SCRIPT_TIME', SCRIPT_END);
}
}
register_shutdown_function('log_shutdown');
?>
И с точки зрения времени, в то время как Apache предоставляет "% D", чтобы регистрировать "время, затраченное на обслуживание запрос », это сильно зависит от подключения пользователя к Интернету.
Это относится к тому, что я пытался включить HTTP / 2 на моем сервере с конфигурацией:
Protocols h2 http/1.1
<FilesMatch \.php$>
CGIPassAuth on
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
SetHandler "proxy:fcgi://127.0.0.1:9001"
</FilesMatch>
Также связана версия Nginx
Если вы записываете только время обработки и используете nginx, предложение от @MichaelHampton может сработать, если записать переменную $ upstream_response_time
.
Но я хочу продолжать использовать Apache и хранить дополнительную информацию (идентификатор пользователя, время обработки определенных задач и т. Д.) ...
Мое решение - создать отдельный файл журнала, в который PHP может записывать в любое время time (даже после того, как заголовки были отправлены), где я создам уникальный (ish) ссылочный код для каждого запроса (чтобы два журнала можно было объединить).
Во-первых, получите свой PHP-скрипт для генерации ссылочного кода и отправьте его как заголовок:
<?php
// A more compact uniqid - which uses hex encoding, and a full UNIX timestamp
$start = microtime(true);
$sec = floor($start);
$usec = round(($start - $sec) * 1000000); // Only accurate to 6 decimal places.
$sec -= strtotime('-' . date('w', $sec) . ' days, 00:00:00', $sec); // Time since Sunday 00:00, max value = 604800 (60*60*24*7)
$code = '';
foreach([$sec, $usec, rand(100000, 999999)] as $code_part) {
$a = dechex($code_part); // decbin returns a string
$a = hex2bin(((strlen($a) % 2) == 0 ? '' : '0') . $a);
$a = base64_encode_rfc4648($a);
$code .= str_pad($a, 4, '.', STR_PAD_LEFT); // 4 characters max = 999999 -> "0f423f" (hex) -> "D0I/" (base64)
}
define('REQUEST_START', $start);
define('REQUEST_CODE', $code);
header('X-Request-Code: ' . $code); // For Apache
?>
Apache может зарегистрировать этот ссылочный код ( дополнительная информация ):
Header always note "X-Request-Code" "Request-Code"
Header always unset "X-Request-Code"
LogFormat "%h %l %u [%{%Y-%m-%d %H:%M:%S}t] [%{Request-Code}n] \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" inc_ref
CustomLog /path/to/access_log inc_ref
Затем вы можете добавить register_shutdown_function ()
, которая делает что-то вроде:
<?php
$log_values = [
date('Y-m-d H:i:s'),
REQUEST_CODE,
$user_id,
$_SERVER['REMOTE_ADDR'],
$_SERVER['REQUEST_METHOD'],
$_SERVER['REQUEST_URI'],
http_response_code(),
round((microtime(true) - REQUEST_START), 4),
];
if (($fp = fopen($log_file, 'a')) !== false) {
fputcsv($fp, $log_values);
fclose($fp);
}
?>
Я повторяю информацию, которая также находится в журнале доступа, из соображений лени (например, для поиска одного файла журнала с помощью grep).