Мониторинг PHP приложений с помощью Proto Observability
Установка PHP трейсера Proto Observability Platform
На этой странице:
- Установка PHP трейсера Proto Observability Platform
- Введение
- Если приложение работает в Kubernetes
- Поддерживаемые технологии
- Пользовательская (дополнительная) инструментация
Введение
Общий процесс подключения PHP приложения на мониторинг:
- Установка ProtoOBP Агента
- Установка трейсера
Если приложение запускается в Docker контейнере
-
Скачайте и разахивируйте архив с агентом:
curl --header "PRIVATE-TOKEN:<your_token>" "https://git.proto.group/api/v4/projects/125/packages/generic/pobptrace-php-agent/2.3.2/protoobp-php-agent-2.3.2.tar.gz" --output protoobp-php-agent-2.3.2.tar.gz tar -xzvf protoobp-php-agent-2.3.2.tar.gz
-
Добавьте соответствующий пакет с агентом в ваш контейнер:
Платформа Пакет Ubuntu, Debian protoobp-php-tracer_2.3.2_amd64.deb
Centos protoobp-php-tracer-2.3.2-1.x86_64.rpm
Alpine protoobp-php-tracer_2.3.2_x86_64.apk
-
Установите пакет:
Платформа Пакет Ubuntu, Debian RUN dpkg -i protoobp-php-tracer_2.3.2_amd64.deb
Centos RUN rpm -ivh protoobp-php-tracer-2.3.2-1.x86_64.rpm
Alpine RUN apk add --allow-untrusted protoobp-php-tracer_2.3.2_x86_64.apk
-
Добавьте следующие переменные окружения:
Переменная Значение Описание POBP_AGENT_HOST
<proto_backend_address>
IP адрес хоста, где запущен ProtoOBP агент, доступный из сети Docker контейнера. В случае если агент запускается в виде Docker контейнера, то достаточно указать имя контейнера (обычно это protoobp-agent
)POBP_SERVICE
<service_name>
имя сервиса, которое будет отображаеться в интерфейсе
Пример готового Dockerfile
FROM php:7.4-apache
RUN apt-get update && apt-get install -yqq unzip wget curl libzip-dev \
&& docker-php-ext-install pdo_mysql opcache zip
COPY status.conf /etc/apache2/mods-available/status.conf
RUN a2enmod rewrite && a2enmod status
WORKDIR /var/www/html
COPY html/ /var/www/html
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN composer install
RUN rm -Rf /var/www/var/*
RUN chown -R www-data /var/www
RUN chmod -R 777 /var/www
#Установка Proto Observability PHP Agent
ENV POBP_AGENT_HOST=protoobp-agent
ENV POBP_SERVICE=my_service
COPY ./protoobp-php-tracer_2.0.0_amd64.deb /opt
RUN dpkg -i /opt/protoobp-php-tracer_2.0.0_amd64.deb
Если приложение запускается в Linux среде
-
Скачайте и разахивируйте архив с PHP трейсером :
curl --header "PRIVATE-TOKEN:<your_token>" "https://git.proto.group/api/v4/projects/125/packages/generic/pobptrace-php-agent/2.3.2/protoobp-php-agent-2.3.2.tar.gz" --output protoobp-php-agent-2.3.2.tar.gz tar -xzvf protoobp-php-agent-2.3.2.tar.gz
-
Установите пакет PHP трейсера:
Платформа Пакет Ubuntu, Debian dpkg -i protoobp-php-tracer_2.3.2_amd64.deb
Centos rpm -ivh protoobp-php-tracer-2.3.2-1.x86_64.rpm
Alpine apk add --allow-untrusted protoobp-php-tracer_2.3.2_x86_64.apk
-
В файле 98-pobptrace.ini* укажите следующее:
protoobp.service = Hello_ProtoOBP ; название сервиса
*Расположение .ini файла вы можете узнать, выполнив
php --ini
-
Перезапустите PHP (например, Nginx, Apache )
Если приложение работает в Kubernetes
Убедитесь, что у вас успешно установлен и настроен ProtoOBP Агент для Kubernetes.
Дополнительно необходимо передать поду переменную окружения POBP_AGENT_HOST
со значением IP адреса воркер-ноды, а также переменные окружения для связи трейсов с инфраструктурой (имя k8s кластера нужно задать вручную).
apiVersion: apps/v1
kind: Deployment
#(...)
spec:
containers:
- name: "<CONTAINER_NAME>"
image: "<CONTAINER_IMAGE>/<TAG>"
env:
- name: POBP_SERVICE
value: dispatch
- name: POBP_AGENT_HOST
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POBP_TAGS
value: "pod_name:$(POD_NAME),node:$(NODE_NAME),kube_namespace:$(POD_NAMESPACE),kube_cluster_name:<my_cluster_name>"
Отключение PHP-трейсера
Для php-fpm
- остановите сервис php-fpm
, или остановите веб-сервер Apache.
Удалите файлы 98-pobptrace.ini
и 99-pobptrace-custom.ini
из папки конфигураций php.
Для php-fpm
- перезапустите сервис php-fpm
, или перезапустите веб-сервер Apache.
Если вы используете кэширование второго уровня в OPcache, задав параметр opcache.file_cache
- удалите папку с кэшем.
Также можно отключить работу трейсера (при этом PHP-модуль трейсера будет оставаться загруженным):
-
через файл конфигурации
pobptrace.trace.enabled=0
-
через переменную окружения
POBP_TRACE_ENABLED
Значение по умолчанию:
1
Комментарий: Включает трейсер глобально.
Поддерживаемые технологии
Версии PHP
Версия | Поддерживается |
---|---|
8.3.x | ✅ |
8.2.x | ✅ |
8.1.x | ✅ |
8.0.x | ✅ |
7.4.x | ✅ |
7.3.x | ✅ |
7.2.x | ✅ |
7.1.x | ✅ |
7.0.x | ✅ |
5.6.x | ✅ |
5.5.x | ✅ Поддерживается ProtoOBP трейсером версии 2.2.3 |
5.4.x | ✅ Поддерживается ProtoOBP трейсером версии 2.2.3 |
Режим работы PHP | Поддерживается |
---|---|
apache2handler | ✅ |
cli | ✅ |
fpm-fcgi | ✅ |
cgi-fcgi | ✅ |
Автоматическая инструментация библиотек и фреймворков
Трейсинг запросов включен по умолчанию после установки агента. Proto Observability Platform поддерживает все PHP фреймворки из коробки, с инструментацией на уровне фреймворка или стандартного трейсинга веб-приложения.
Автоматическая инструментация работает благодаря модификации PHP рантайма для оборачивания функций и методов для их трейсинга.
Благодаря автоматической инструментации вам доступна следующая информация:
- время исполнения метода;
- данные транзакции, такие как URL и код ответа для веб запросов, текст SQL запроса для запросов к базам данных;
- необработанные исключения, в том числе стэк трейс, если он доступен.
PHP фреймворки
По умолчанию Proto Observability Platform поддерживает все PHP фреймворки из коробки, с инструментацией на уровне фреймворка или стандартного трейсинга веб-приложения.
Инструментация на уровне фреймворка включает отслеживание внутренних методов и простановку тегов, специфичных для фреймворка.
Стандартный трейсинг веб-приложения включает спан web.request
для отслеживания задержки и ошибок, возникающих при вызове, в дополнение к спанам для вызовов поддерживаемых библиотек, например, при обращении к базам данных или HTTP-клиентам.
В следующей таблице перечислены некоторые из фреймворков и версий, для которых Proto Observability Platform успешно производит автоматический трейсинг.
Фреймворк | Версия | Версии PHP | Уровень инструментации |
---|---|---|---|
Битрикс | все | Все поддерживаемые версии PHP | Стандартный трейсинг веб-приложения |
CakePHP | 2.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
CodeIgniter | 2.x | PHP 7+ | Инструментация методов уровня фреймворка |
CodeIgniter | 3.x | PHP 7+ | Стандартный трейсинг веб-приложения |
Drupal | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка | |
FuelPHP | 1.1 | PHP 7+ | Стандартный трейсинг веб-приложения |
Laminas | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка | |
Laravel | 4.2, 5.x, 6.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Laravel 8+ | 8.x, 9.x, 10.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Lumen | 5.2+ | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Magento | 1 | Все поддерживаемые версии PHP | Стандартный трейсинг веб-приложения |
Magento | 2 | PHP 7+ | Инструментация методов уровня фреймворка |
Neos Flow | 1.1 | Все поддерживаемые версии PHP | Стандартный трейсинг веб-приложения |
Phalcon | 1.3, 3.4 | Все поддерживаемые версии PHP | Стандартный трейсинг веб-приложения |
RoadRunner | 2.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Slim | 2.x, 3.x, 4.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Symfony | 2.x, 3.3, 3.4, 4.x, 5.x, 6.x | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
WordPress | 4.x, 5.x, 6.x | PHP 7+ | Инструментация методов уровня фреймворка |
Yii | 1.1, 2.0 | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Zend Framework | 1.12, 1.21 | Все поддерживаемые версии PHP | Инструментация методов уровня фреймворка |
Zend Framework | 2.x | Все поддерживаемые версии PHP | Стандартный трейсинг веб-приложения |
CLI
Поддержка трейсинга PHP CLI отключена по умолчанию.
Для включения трейсинга PHP CLI скриптов, установите переменную окружения POBP_TRACE_CLI_ENABLED=true
.
Модуль | Версии | Поддерживается |
---|---|---|
CakePHP Console | 2.x | ✅ |
Laravel Artisan | 5.x, 8.x, 9.x, 10.x | ✅ |
Symfony CLI | 4.x, 5.x, 6.x | ✅ |
Базы данных и datastore
Модуль | Версии | Поддерживается |
---|---|---|
Amazon RDS (используя PDO или MySQLi) | Все | ✅ |
Elasticsearch | 1+ | ✅ |
Eloquent | Все поддерживаемые версии Laravel | ✅ |
Laravel Queues | Все поддерживаемые версии Laravel | ✅ |
Memcache | Все | ✅ |
Memcached | Все | ✅ |
MongoDB | 1.4.x | ✅ |
MySQLi | Все | ✅ |
PDO | Все | ✅ |
PhpRedis | 3, 4, 5 | ✅ PHP 7, 8 |
Predis | 1.1 | ✅ |
SQLSRV | Все | ✅ |
Прочие библиотеки и HTTP-клиенты
Модуль | Версии | Поддерживается |
---|---|---|
php-amqplib | 2.x, 3.x | ✅ PHP 7.1+ |
Curl | Все | ✅ |
Guzzle | 5.x, 6.x, 7.x | ✅ |
Пользовательская (дополнительная) инструментация
Инструментация через аннотации
Если вы используете PHP 8, то вы можете добавлять аннотации кода для его инструментации. Это более легкая альтернатива пользовательской инструментации, написанной в коде. Например, добавьте атрибут #[POBPTrace\Trace] к методам, чтобы Proto Observability Platform отслеживал их.
<?php
class Server {
#[POBPTrace\Trace(name: "spanName", resource: "resourceName", type: "Custom", service: "myService", tags: ["aTag" => "aValue"])]
static function process($arg) {}
#[POBPTrace\Trace]
function get() {
Foo::simple(1);
}
}
Вы можете указать следующие аргументы:
$name
: Имя операции, которое должно быть назначено спану. По умолчанию используется имя функции.$resource
: Ресурс, который будет присвоен спану.$type
: Тип, который будет присвоен спану.$service
: Имя сервиса, которое будет назначена спану. По умолчанию принимает наследуемое имя сервиса.$tags
: Теги, которые будут присвоены спану.$recurse
: Должны ли отслеживаться рекурсивные вызовы.$run_if_limited
: Должна ли функция трассироваться в ограниченном режиме. (Например, при превышении лимита спанов).
Добавление пользовательской инструментации в коде
Если вам необходимо добавить собственную инструментацию, рассмотрите следующий пример приложения и пройдитесь по примеру.
Пример приложения, которое необходимо инструментировать
Предположим, что структура каталогов следующая:
.
|-- composer.json
|-- docker-compose.yml
|-- index.php
`-- src
|-- Exceptions
| `-- NotFound.php
|-- Services
| `-- SampleRegistry.php
`-- utils
`-- functions.php
Внутри него в двух файлах содержатся функции и методы, которые интересны для инструментации. Наиболее значимыми файлами являются src/utils/functions.php
:
namespace App;
function some_utility_function($someArg)
{
return 'result';
}
И src/Services/SampleRegistry.php
:
namespace App\Services;
use App\Exceptions\NotFound;
use Exception;
class SampleRegistry
{
public function put($key, $value)
{
\App\some_utility_function('some argument');
// Возвращает идентификатор вставленного элемента
return 456;
}
public function faultyMethod()
{
throw new Exception('Генерируется во время выполнения');
}
public function get($key)
{
// Для сообщения о том, что ключ не найден, сервис использует исключение.
throw new NotFound('Ключ не был найден');
}
public function compact()
{
// Эта функция выполняет некоторые операции над реестром и
// ничего не возвращает. В середине функции имеется интересное значение,
// которое не возвращается, но может быть связано с замедлением функции
$numberOfItemsProcessed = 123;
// ...
}
}
Написание пользовательской инструментации
Чтобы не смешивать бизнес-логику приложения или сервиса с кодом инструментации, напишем необходимый код в отдельном файле.
-
Создадим файл
protoobp/instrumentation.php
и добавим его в автозагрузкуcomposer
.//composer.json { ... "autoload": { ... "files": [ ... "protoobp/instrumentation.php" ] }, ... }
-
Обновите
autoloader
, например, выполнивcomposer dump
.Файл, содержащий пользовательскую инструментацию, и реальные классы, которые подвергаются инструментации, не обязательно должны находиться в одной кодовой базе и пакете.
Регистрация входной точки инструментации в
composer.json
в секцииautoload.files
гарантирует, что файл всегда будет выполняться. -
В файле
protoobp/instrumentation.php
, проверьте, что расширение загружено. Если расширение не загружено, то все функции, используемые в этом файле, не существуют.#protoobp/instrumentation.php if (!extension_loaded('pobptrace')) { return; }
-
Инструментируем функцию
\App\some_utility_function
. Если вас не интересует какой-либо конкретный аспект функции, кроме времени выполнения, то это все, что требуется:#protoobp/instrumentation.php \POBPTrace\trace_function('App\some_utility_function', function (\POBPTrace\SpanData $span, $args, $ret, $exception) {});
-
Допустим, что для метода
SampleRegistry::put
, вы хотите не только сгенерировать спан, но и добавить тег со значением возвращаемого идентификатора элемента, а также тег для ключа. Посколькуput
- это метод, используйте\POBPTrace\trace_method
вместо\POBPTrace\trace_function
:#protoobp/instrumentation.php ... \POBPTrace\trace_method( 'App\Services\SampleRegistry', 'put', function (\POBPTrace\SpanData $span, $args, $ret, $exception) { $span->meta['app.cache.key'] = $args[0]; // Первый аргумент 'key' $span->meta['app.cache.item_id'] = $ret; // Возвращаемое значение } );
При задании дополнительнх тегов следует избегать перезаписи существующих тегов, автоматически добавляемых основной инструментацией.
Правильно:
$span->meta['mytag'] = 'value'
Неверно:
$span->meta = ['mytag' => 'value']
-
В коде примера
SampleRegistry::faultyMethod
генерирует исключение. При этом вам не требуется ничего дополнительно делать с точки зрения пользовательской инструментации. Если метод инструментирован, то стандартный механизм сообщения об исключениях позаботится о добавлении в спан сообщения об исключении и трассировки стека.#protoobp/instrumentation.php ... \POBPTrace\trace_method( 'App\Services\SampleRegistry', 'faultyMethod', function (\POBPTrace\SpanData $span, $args, $ret, $exception) { } );
-
Метод
SampleRegistry::get
использует исключениеNotFound
для уведомления о том, что элемент не найден. Допустим, это исключение является ожидаемой частью бизнес-логики приложения, и вы не хотите отмечать спан с этим исключением как ошибку. Тогда вы можете просто изменить имя ресурса, чтобы добавить его в пул операцийnot_found
. Для этого необходимо сделатьunset
исключению для спана:#protoobp/instrumentation.php ... \POBPTrace\trace_method( 'App\Services\SampleRegistry', 'get', function (\POBPTrace\SpanData $span, $args, $ret, $exception) { if ($exception instanceof \App\Exceptions\NotFound) { unset($span->exception); $span->resource = 'cache.get.not_found'; } } );
-
Метод
SampleRegistry::compact
демонстрирует интересный случай использования. Если вас интересует добавление тега со значением, которое не является ни аргументом, ни значением, возвращаемым функцией, то для этого отредактируйте файлprotoobp/instrumentation.php
и файл классаsrc/Services/SampleRegistry.php
:#protoobp/instrumentation.php ... \POBPTrace\trace_method( 'App\Services\SampleRegistry', 'compact', function (\POBPTrace\SpanData $span, $args, $ret, $exception) { } );
В файле
src/Services/SampleRegistry.php
отредактируйте тело метода:#src/Services/SampleRegistry.php ... public function compact() { // Эта функция выполняет некоторые операции над реестром и // ничего не возвращает. В середине функции имеется интересное значение, // которое не возвращается, но может быть связано с замедлением функции $numberOfItemsProcessed = 123; // Добавьте код инструментации в бизнес-логику. if (\function_exists('\POBPTrace\active_span') && $span = \POBPTrace\active_span()) { $span->meta['registry.compact.items_processed'] = $numberOfItemsProcessed; } // ... }
Подробнее о trace_function
и trace_method
Функции POBPTrace\trace_function
и POBPTrace\trace_method
инструментируют (трассируют) вызовы определенных функций и методов. Эти функции автоматически решают следующие задачи:
- Открытие спана перед выполнением кода.
- Добавление в спан всех ошибок, возникших при выполнении инструменированного вызова.
- Закрытие спана после завершения инструментированного вызова.
Дополнительные теги устанавливаются на спан из закрытия (называемого закрытием трассировки).
Например, в следующем фрагменте выполняется трассировка метода CustomDriver::doWork
и добавляются пользовательские теги. Исключения автоматически отслеживаются на спане.
<?php
\POBPTrace\trace_method(
'CustomDriver',
'doWork',
function (\POBPTrace\SpanData $span, array $args, $retval, $exception) {
// Это закрытие выполняется после инструментального вызова
// Спан был автоматически создан до вызова инструментированного вызова
// SpanData::$name по умолчанию устанавливается в 'ClassName.methodName' если не задано
$span->name = 'CustomDriver.doWork';
// SpanData::$resource по умолчанию устанавливается в SpanData::$name не задано
$span->resource = 'CustomDriver.doWork';
// Если исключение было выдано из неинструментированного вызова, возвращаемое значение является null
$span->meta['doWork.size'] = $exception ? 0 : count($retval),
// Доступ к членам объекта через $this
$span->meta['doWork.thing'] = $this->workToDo;
// Спан автоматически закроется
}
);
// Для функций
\POBPTrace\trace_function(
'doCustomDriverWork',
function (\POBPTrace\SpanData $span, array $args, $retval, $exception) {
// Закрытие такое же как для POBPTrace\trace_method
}
);
?>
Доступ к активным спанам
Встроенная и пользовательская инструментация создают спаны вокруг значимых операций. Вы можете получить доступ к активному спану, чтобы включить в него значимые данные.
Текущий спан
Следующий метод возвращает объект POBPTrace\SpanData
. Если трассировка отключена, возвращается null
.
<?php
$span = \POBPTrace\active_span();
if ($span) {
$span->meta['customer.id'] = get_customer_id();
}
?>
Корневой спан
Следующий метод возвращает объект POBPTrace\SpanData
. Если трассировка отключена, возвращается null
. Это полезно в тех случаях, когда метаданные, которые должны быть добавлены к корневому спану, не существуют на ранних этапах выполнения скрипта.
<?php
$span = \POBPTrace\root_span();
if ($span) {
$span->meta['customer.id'] = get_customer_id();
}
?>
Добавление тегов
При задании дополнительнх тегов следует избегать перезаписи существующих тегов, автоматически добавляемых основной инструментацией.
Правильно:
$span->meta['mytag'] = 'value'
Неверно:
$span->meta = ['mytag' => 'value']
Локально
Добавьте теги к спану с помощью массива POBPTrace\SpanData::$meta
.
<?php
\POBPTrace\trace_function(
'myRandFunc',
function(\POBPTrace\SpanData $span, array $args, $retval) {
// ...
$span->meta['rand.range'] = $args[0] . ' - ' . $args[1];
$span->meta['rand.value'] = $retval;
}
);
Глобально
Установите переменную окружения POBP_TAGS
для автоматического добавления тегов к каждому создаваемому спану.
POBP_TAGS=key1:value1,<TAG_KEY>:<TAG_VALUE>
Ошибки
Выброшенные исключения автоматически привязываются к активному спану, если только исключение не было выброшено на более глубоком уровне стека вызовов и не было поймано до того, как оно достигло какой-либо трассируемой функции.
<?php
function doRiskyThing() {
throw new Exception('Ой!');
}
\POBPTrace\trace_function(
'doRiskyThing',
function() {
// Спан будет помечен как ошибочный, и к нему будут добавлены в качестве тегов
// трассировка стека и сообщение исключения
}
);
Добавьте тег error.msg
, чтобы вручную отметить спан как ошибочный.
<?php
function doRiskyThing() {
return SOME_ERROR_CODE;
}
\POBPTrace\trace_function(
'doRiskyThing',
function(\POBPTrace\SpanData $span, $args, $retval) {
if ($retval === SOME_ERROR_CODE) {
$span->meta['error.msg'] = 'Ошибка Х';
// Опционально:
$span->meta['error.type'] = 'CustomError';
$span->meta['error.stack'] = (new \Exception)->getTraceAsString();
}
}
);