Добавление пользовательских переменных в журнал доступа Apache из PHP-FPM

В 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

0
задан 8 April 2019 в 14:09
1 ответ

Если вы записываете только время обработки и используете 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).

0
ответ дан 24 December 2019 в 10:14

Теги

Похожие вопросы