Мониторинг PHP-приложений с помощью OpenTelemetry и SigNoz
PHP является самым популярным языком для серверной разработки, по праву занимая первое место на рынке. Приложения многих всемирно известных организаций, таких как Facebook, написаны на PHP. WordPress, на котором работает 43% всех веб-сайтов, также создан на основе PHP. В этом туториале я научу вас инструментировать PHP-приложение при помощи OpenTelemetry для получения данных телеметрии.
Мониторинг PHP-приложения на предмет проблем с производительностью и ошибок очень важен. Чтобы эффективно мониторить приложение, вам нужны надежные данные телеметрии из него. И с этим нам может помочь OpenTelemetry. OpenTelmetry предоставляет клиентские библиотеки для множества языков программирования, включая PHP, которые можно использовать для инструментирования приложений.
Что такое инструментирование приложения?
Инструментирование — это внедрение в код приложения процессов генерации данных телеметрии (логов, метрик и трейсов). OpenTelemetry предоставляет как библиотеки автоматического инструментирования, так и API для ручного инструментирования приложения.
OpenTelemetry помогает генерировать и собирать данные телеметрии. Затем собранные данные необходимо отправить в инструмент анализа на бэкенде. OpenTelemetry предоставляет свободу выбора любого внутреннего инструмента, с помощью которого будет удобнее всего хранить и визуализировать данные телеметрии. А с этим нам может помочь SigNoz.
SigNoz и OpenTelemetry
SigNoz.io — это опенсорсная платформа для комплексного мониторинга и наблюдения за приложениями, которую можно развернуть в вашей инфраструктуре. SigNoz обеспечивает мониторинг метрик и исключений, распределенную трассировку и настраиваемые дашборды — все это в пределах одного окна. Вы также можете настроить оповещения с важными метриками, чтобы всегда быть в курсе.
SigNoz нативно поддерживает OpenTelemerty, что делает его отличным выбором для бэкенда OpenTelemetry.
Установка SigNoz
С помощью простого скрипта установки SigNoz можно установить на компьютеры с macOS или Linux всего за три шага.
В Linux скрипт установки автоматически устанавливает Docker Engine. Однако в macOS нужно вручную установить Docker Engine перед запуском скрипта установки.
git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy/
./install.sh
В нашей документации вы можете найти детальные инструкции по установке SigNoz с помощью Docker Swarm и Helm Charts.
Когда вы закончите с установкой SigNoz, доступ к пользовательскому интерфейсу можно будет получить по адресу http://localhost:3301
Инструментирование PHP-приложения при помощи OpenTelemetry:
Шаг 1: Установка необходимых зависимостей из PHP-библиотеки OpenTelemetry:
use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\API\Trace\SpanKind;
Шаг 2: Инициализация модуля трассировщика и создание самого трассировщика:
$tracerProvider = new TracerProvider(
new SimpleSpanProcessor(
new ConsoleSpanExporter()
)
);
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php',);
Шаг 3: Создание спанов (диапазонов)
Создайте корневой спан и активируйте его:
$rootSpan = $tracer->spanBuilder('root')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
$rootSpan->activate();
Создайте и инициируйте свой первый спан:
$span1 = $tracer->spanBuilder('foo')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
$span1->activate();
Создайте еще один спан:
$span2 = $tracer->spanBuilder('bar')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
Не забудьте закрыть их:
$span2->end();
$span1->end();
Теперь закройте корневой спан:
$rootSpan->end();
Вот как это все выглядит, когда собрано воедино + немного обработки ошибок:
<?php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\API\Trace\SpanKind;
echo 'Starting ConsoleSpanExporter' . PHP_EOL;
$tracerProvider = new TracerProvider(
new SimpleSpanProcessor(
new ConsoleSpanExporter()
)
);
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php',);
$rootSpan = $tracer->spanBuilder('root')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
$rootSpan->activate();
try {
$span1 = $tracer->spanBuilder('foo')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
$span1->activate();
try {
$span2 = $tracer->spanBuilder('bar')->setSpanKind(SpanKind::KIND_SERVER)->startSpan();
echo 'OpenTelemetry welcomes PHP' . PHP_EOL;
} finally {
$span2->end();
}
} finally {
$span1->end();
}
$rootSpan->end();
Шаг 4: Запуск PHP-приложения
Запустите PHP-приложение при помощи следующей команды:
php 1-getting-started-console-exporter.php
Вы должны увидеть подобный вывод:
// Вывод
Starting ConsoleSpanExporter
OpenTelemetry welcomes PHP
[
{
"name": "bar",
"context": {
"trace_id": "8e447a8a939de0a65c3d2c5255012398",
"span_id": "b829010efdadb302",
"trace_state": ""
},
"resource": {
"host.name": "Pranshus-MacBook-Pro.local",
"host.arch": "arm64",
"os.type": "darwin",
"os.description": "21.4.0",
"os.name": "Darwin",
"os.version": "Darwin Kernel Version 21.4.0: Fri Mar 18 00:47:26 PDT 2022; root:xnu-8020.101.4~15\/RELEASE_ARM64_T8101",
"process.pid": 42913,
"process.executable.path": "\/opt\/homebrew\/Cellar\/php\/8.1.5\/bin\/php",
"process.command": ".\/src\/1-getting-started-console-exporter.php",
"process.command_args": [
".\/src\/1-getting-started-console-exporter.php"
],
"process.owner": "pranshuchittora",
"process.runtime.name": "cli",
"process.runtime.version": "8.1.5",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.language": "php",
"telemetry.sdk.version": "dev-main",
"service.name": "unknown_service"
},
"parent_span_id": "c6b0f081c30f5519",
"kind": "KIND_SERVER",
"start": 1652959406327378349,
"end": 1652959406327383891,
"attributes": [],
"status": {
"code": "Unset",
"description": ""
},
"events": [],
"links": []
}
]
[
{
"name": "foo",
"context": {
"trace_id": "8e447a8a939de0a65c3d2c5255012398",
"span_id": "c6b0f081c30f5519",
"trace_state": ""
},
"resource": {
"host.name": "Pranshus-MacBook-Pro.local",
"host.arch": "arm64",
"os.type": "darwin",
"os.description": "21.4.0",
"os.name": "Darwin",
"os.version": "Darwin Kernel Version 21.4.0: Fri Mar 18 00:47:26 PDT 2022; root:xnu-8020.101.4~15\/RELEASE_ARM64_T8101",
"process.pid": 42913,
"process.executable.path": "\/opt\/homebrew\/Cellar\/php\/8.1.5\/bin\/php",
"process.command": ".\/src\/1-getting-started-console-exporter.php",
"process.command_args": [
".\/src\/1-getting-started-console-exporter.php"
],
"process.owner": "pranshuchittora",
"process.runtime.name": "cli",
"process.runtime.version": "8.1.5",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.language": "php",
"telemetry.sdk.version": "dev-main",
"service.name": "unknown_service"
},
"parent_span_id": "b641f1ef2683f70f",
"kind": "KIND_SERVER",
"start": 1652959406327364474,
"end": 1652959406327551099,
"attributes": [],
"status": {
"code": "Unset",
"description": ""
},
"events": [],
"links": []
}
]
[
{
"name": "root",
"context": {
"trace_id": "8e447a8a939de0a65c3d2c5255012398",
"span_id": "b641f1ef2683f70f",
"trace_state": ""
},
"resource": {
"host.name": "Pranshus-MacBook-Pro.local",
"host.arch": "arm64",
"os.type": "darwin",
"os.description": "21.4.0",
"os.name": "Darwin",
"os.version": "Darwin Kernel Version 21.4.0: Fri Mar 18 00:47:26 PDT 2022; root:xnu-8020.101.4~15\/RELEASE_ARM64_T8101",
"process.pid": 42913,
"process.executable.path": "\/opt\/homebrew\/Cellar\/php\/8.1.5\/bin\/php",
"process.command": ".\/src\/1-getting-started-console-exporter.php",
"process.command_args": [
".\/src\/1-getting-started-console-exporter.php"
],
"process.owner": "pranshuchittora",
"process.runtime.name": "cli",
"process.runtime.version": "8.1.5",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.language": "php",
"telemetry.sdk.version": "dev-main",
"service.name": "unknown_service"
},
"parent_span_id": "",
"kind": "KIND_SERVER",
"start": 1652959406327223724,
"end": 1652959406327563766,
"attributes": [],
"status": {
"code": "Unset",
"description": ""
},
"events": [],
"links": []
}
]
Мониторинг PHP-приложение с помощью SigNoz
Для этого мы будем генерировать спаны в цикле for. Кроме того, мы будем присоединять к каждому сапны атрибуты, которые могут помочь нам собрать важные метаданные, которые будут полезными для нас во время отладки.
Импортируйте зависимости OpenTelemetry и Guzzle (для HTTP):
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\Contrib\OtlpHttp\Exporter as OTLPExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
Нам нужно определить переменную среды для конечной точки OTLP. Для прослушивания данных, собранных OpenTelemetry из PHP-приложений, SigNoz использует порт 4318
. Поскольку мы установили SigNoz на локальном хосте, конечная точка OTLP будет:
OTEL_EXPORTER_OTLP_ENDPOINT — http://localhost:4318/v1/traces
Определите переменные среды:
putenv('OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces'); // SigNoz OTel collector's path
При желании вы можете передавать переменную env
во время работы приложения.
Инициализируйте экспортер:
$exporter = new OTLPExporter(
new Client(),
new HttpFactory(),
new HttpFactory()
);
Инициализируйте Tracer Provider с экспортером:
$tracerProvider = new TracerProvider(
new SimpleSpanProcessor(
$exporter
)
);
Создайте и активируйте корневой спан:
$root = $span = $tracer->spanBuilder('root')->startSpan();
$span->activate();
Создание, инициализация, установка данных и закрытие спанов внутри цикла for:
for ($i = 0; $i < 3; $i++) {
// открытие спана, регистрация некоторых событий
$span = $tracer->spanBuilder('loop-' . $i)->startSpan();
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
'id' => md5((string) microtime(true)),
]));
$span->end();
}
Не забудьте закрыть корневой спан:
$root->end();
Запустите ваше PHP-приложение:
> OTEL_SERVICE_NAME=signoz-php-app php ./src/2-send-trace-to-collector.php
После запуска приложения вы можете немного поработать с ним, чтобы сгенерировать фиктивные данные для мониторинга.
Теперь откройте пользовательский интерфейс SigNoz по адресу: http://localhost:3301, перейдите на вкладку Traces
и выберите спан из сервиса signoz-php-app
.
После выбора спана вы попадете на Trace Detail Page (страницу сведений о трейсе), где сможете визуализировать запрос с помощью Flamegraph’ов и диаграмм Ганта. OpenTelemetry фиксирует каждый компонент программной системы посредством атрибутов (пар ключ-значение). Вы также можете просмотреть все эти атрибуты для каждого спана, что поможет вам проще вникнуть в контекст.
Заключение
Используя библиотеки OpenTelemetry, вы можете значительно повысить наблюдаемость своего PHP-приложения. Затем вы можете использовать какой-нибудь опенсорсный APM-инструмент, такой как SigNoz, чтобы обеспечить бесперебойную работу ваших PHP-приложений.
OpenTelemetry — это будущее в мире наблюдаемости облачных приложений. Он поддерживается огромным сообществом и охватывает широкий спектр технологий и фреймворков. Используя OpenTelemetry, команды разработчиков могут спокойно управлять многоязычными и распределенными приложениями.
SigNoz — это опенсорсный инструмент для мониторинга приложений, который работает как SaaS. Вы можете попробовать SigNoz, посетив его GitHub-репозиторий
Если у вас есть какие-либо вопросы или вам нужна помощь в настройке, присоединяйтесь к нашему slack-сообществу и пишите в #support.
Дополнительная литература:
SigNoz — альтернатива DataDog с открытым исходным кодом.
Мониторинг вашего Spring Boot приложения с помощью OpenTelemetry
Приглашаем всех желающих на бесплатный мастер-класс по разработке одностраничного приложения на PHP с помощью Symfony и Vue.js, на котором мы:
- разработаем API на стороне back-end,
- создадим несложное приложение для работы с этим API на стороне front-end и
- настроим JWT-аутентификацию.
Регистрация по ссылке.