OpenTelemetry PHP 서비스 관측 가능성 모범 사례¶
서문¶
이 문서에서는 GuanceCloud/opentelemetry-php-instrumentation을 기반으로 PHP 서비스를 Guance에 연결하고, 로그, PHP-FPM 메트릭 및 프로파일링을 보완하여 즉시 적용 가능한 관측 가능성 솔루션을 구성하는 방법을 소개합니다.
이 솔루션은 PHP-FPM, CLI Worker, Supervisor, 컨테이너 내 PHP 프로세스 등 일반적인 배포 방식에 적합합니다. 트레이스 데이터는 기본적으로 DataKit 4317 포트를 통해 OTLP gRPC 방식으로 전송됩니다. 연동 및 문제 해결 단계에서는 임시로 9529/otel의 HTTP OTLP 방식으로 전환하여 트레이스 연결이 정상적인지 빠르게 확인할 수 있습니다.
환경 정보¶
- 시스템 환경: Linux
- 개발 언어: PHP 8.2
- 배포 방식: PHP-FPM / CLI
- APM 확장:
GuanceCloud/opentelemetry-php-instrumentation 1.3.1-gtrace - 수집기: DataKit
구현 목표¶
- 애플리케이션 트레이스 연결
- 애플리케이션 로그 연결
- PHP-FPM 메트릭 연결
- 프로파일링 연결 (선택 사항)
연결 솔루션¶
GuanceCloud Fork 기반 설명¶
이 문서의 연결 방식은 GuanceCloud/opentelemetry-php-instrumentation을 기반으로 하며, 이는 OpenTelemetry 공식 저장소에서 fork된 확장 저장소입니다.
명확히 구분해야 할 두 가지 경계가 있습니다.
- 확장의 출처는
GuanceCloudfork의 릴리스 에셋을 사용할 수 있습니다. composer require로 설치하는open-telemetry/sdk,open-telemetry/exporter-otlp,open-telemetry/opentelemetry-auto-*는 여전히 공식 PHP 패키지입니다.
즉, 현재 fork의 변경 사항은 주로 PHP 확장 레이어에 있으며, 전체 PHP SDK, exporter 및 auto instrumentation 에코시스템이 fork된 것은 아닙니다.
구성 요소 목록¶
OpenTelemetry PHP를 적용하려면 최소한 다음 구성 요소가 필요합니다.
- DataKit: 트레이스, 로그, 메트릭, 프로파일 데이터를 수신합니다.
- PHP
opentelemetry확장: 자동 계측 기능을 담당합니다. - OpenTelemetry PHP SDK: 데이터 구성 및 내보내기를 담당합니다.
- OTLP Exporter:
gRPC또는HTTP를 통해 DataKit에 데이터를 전송합니다. - 해당 프레임워크 또는 구성 요소의 계측 라이브러리: Laravel, Slim, Symfony, PDO, Guzzle 등의 자동 계측을 담당합니다.
opentelemetry 확장만 설치하는 것으로는 충분하지 않으며, 프로젝트 내에 SDK + exporter + 해당 자동 계측 패키지를 반드시 설치해야 합니다. 그렇지 않으면 확장이 로드되어도 완전한 트레이스 데이터를 생성할 수 없습니다.
사전 준비¶
DataKit 설치¶
호스트에 DataKit을 먼저 설치하고, 해당 호스트에서 127.0.0.1:4317 또는 127.0.0.1:9529에 접근 가능한지 확인하세요.
OpenTelemetry 수집기 활성화¶
DataKit 설치 디렉터리로 이동하여 sample 구성을 복사하고 DataKit을 재시작합니다.
mkdir -p /usr/local/datakit/conf.d/opentelemetry
cp /usr/local/datakit/conf.d/samples/opentelemetry.conf.sample \
/usr/local/datakit/conf.d/opentelemetry/opentelemetry.conf
systemctl restart datakit
DataKit이 정상적으로 작동하는지 확인합니다.
Warning
애플리케이션이 http://127.0.0.1:9529/otel/v1/traces로 전송했을 때 404가 반환되면, 일반적으로 PHP 측 문제가 아니라 DataKit의 opentelemetry 입력이 실제로 활성화되지 않은 것입니다. 먼저 opentelemetry.conf가 존재하고 DataKit 재시작과 함께 적용되었는지 확인하세요.
트레이스 연결¶
1. OTEL 확장 설치 및 활성화¶
OpenTelemetry 공식 zero-code 문서에 따르면, 가장 간단한 경로는 처음부터 컴파일하는 것이 아니라 "시스템 패키지" 또는 "이미지 설치"를 우선 선택하는 것입니다.
권장 순서는 다음과 같습니다.
- Linux 패키지 관리자 설치
- Docker 이미지 설치
- 호스트에
pecl이 있는 경우pecl사용 - 마지막으로 소스 컴파일 고려
Warning
Linux 호스트에 항상 pecl이 있다고 가정하지 마세요. 예를 들어, 이 문서에서 검증에 사용된 호스트의 2026-07-30 실제 상태는 "phpize는 있지만 pecl은 없음"이었습니다.
또한 yum install php-pecl-opentelemetry 또는 pecl install opentelemetry로 설치되는 것은 일반적으로 공식 upstream 확장이며, GuanceCloud fork의 gtrace 버전이 아닙니다. 1.3.1-gtrace를 검증하거나 제공하려는 경우 설치 출처를 GuanceCloud fork의 릴리스 에셋 또는 내부 빌드 산출물로 변경해야 합니다.
배포판에 기성 패키지가 있다면 우선 직접 설치하세요.
CentOS/RHEL 계열 시스템은 공식 권장 Remi 저장소 방식을 참고할 수 있습니다.
yum update -y
yum install -y epel-release yum-utils
yum install -y http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum-config-manager --enable remi-php81
yum install -y php php-pecl-opentelemetry
php --ri opentelemetry
Alpine은 APK 패키지를 직접 설치할 수 있습니다.
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
apk add php php81-pecl-opentelemetry@testing
php --ri opentelemetry
Docker 공식 PHP 이미지:
호스트에 이미 pecl이 있는 경우 다음을 직접 실행할 수 있습니다.
호스트에 pecl이 없는 경우 다음 중 하나를 우선 선택하세요.
- 플랫폼 측에서 PHP 버전과 일치하는
opentelemetry.so를 직접 제공 - 시스템 패키지 관리자를 사용하여 설치
- 컨테이너 이미지 내에서
install-php-extensions를 통해 설치
GuanceCloud fork의 경우 현재 엔터프라이즈 적용에 더 권장되는 방식은 다음과 같습니다.
- Windows: 릴리스에 이미 패키징된 zip 에셋을 직접 사용
- Linux: CI에서 해당 PHP 마이너 버전의
opentelemetry.so를 빌드한 후, 운영 또는 아티팩트 저장소를 통해 통합 배포
이렇게 해야 설치된 것이 실제로 gtrace 버전임을 보장할 수 있으며, 공식 upstream 확장이 아닙니다.
Windows:
GuanceCloud/opentelemetry-php-instrumentation릴리스 페이지에서 현재 PHP 마이너 버전,ts/nts, 컴파일러와 일치하는 zip 패키지를 다운로드합니다.php_opentelemetry.dll을 PHPext/디렉터리에 넣습니다.php.ini에서 확장을 활성화합니다.
어떤 방식을 사용하든 확장 패키지를 선택할 때는 다음 조건을 엄격히 일치시켜야 합니다.
- PHP 마이너 버전 (예:
8.1/8.2/8.3/8.4) ts/nts- 플랫폼 및 컴파일러
- 대상 실행 방식에 해당하는 PHP 바이너리
php.ini에서 확장을 활성화합니다.
확장이 로드되었는지 확인합니다.
2. SDK 및 자동 계측 의존성 설치¶
공식 문서의 핵심 사항은 확장만 설치한다고 해서 트레이스가 생성되지 않는다는 것입니다. 프로젝트 내에 SDK + exporter + 계측 라이브러리를 반드시 설치해야 합니다.
Slim + PSR-18을 예로 들면, 최소 의존성은 다음과 같습니다.
composer config allow-plugins.php-http/discovery false
composer require \
open-telemetry/sdk \
open-telemetry/exporter-otlp \
php-http/guzzle7-adapter \
nyholm/psr7
애플리케이션이 Slim이 아닌 다른 프레임워크나 구성 요소를 사용하는 경우, 실제 기술 스택에 맞는 자동 계측 패키지를 설치하세요. 일반적인 예시는 다음과 같습니다.
# PSR-18 HTTP Client
composer require open-telemetry/opentelemetry-auto-psr18
# Slim
composer require open-telemetry/opentelemetry-auto-slim
# Laravel
composer require open-telemetry/opentelemetry-auto-laravel
# Symfony
composer require open-telemetry/opentelemetry-auto-symfony
# PDO
composer require open-telemetry/opentelemetry-auto-pdo
# Guzzle
composer require open-telemetry/opentelemetry-auto-guzzle
최소 원칙은 다음과 같습니다.
- 확장 설치
sdk설치exporter-otlp설치- 현재 프레임워크 및 미들웨어와 일치하는
auto-*패키지 설치
그렇지 않으면 불완전하거나 빈 트레이스 데이터만 얻을 수 있습니다.
3. 트레이스 전송 파라미터 구성¶
로컬 DataKit 4317에 직접 연결하려면 OTLP gRPC를 사용하는 것이 좋습니다.
OTEL_PHP_AUTOLOAD_ENABLED=true \
OTEL_SERVICE_NAME=my-php-service \
OTEL_SERVICE_VERSION=1.3.1-gtrace \
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317 \
OTEL_PROPAGATORS=baggage,tracecontext
문제 해결 시 HTTP OTLP로 전환할 수 있습니다.
PHP-FPM, Apache, Supervisor, systemd 또는 컨테이너를 통해 PHP를 시작하는 경우, 위 환경 변수를 현재 셸 세션에만 설정하지 말고 프로세스 시작 환경에 구성하세요.
권장 최소 구성은 다음과 같습니다.
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-php-service
OTEL_SERVICE_VERSION=1.3.1-gtrace
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=none
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
환경을 구분해야 하는 경우 다음을 추가하세요.
4. 비즈니스 계측 추가¶
프레임워크 자동 계측은 일반적인 진입점만 다룰 수 있습니다. 주문, 결제, 외부 API 호출, 배치 처리 등 주요 비즈니스 노드에는 WithSpan을 사용하여 계측을 추가하는 것이 좋습니다.
<?php
declare(strict_types=1);
use OpenTelemetry\API\Instrumentation\SpanAttribute;
use OpenTelemetry\API\Instrumentation\WithSpan;
#[WithSpan('order.submit')]
function submitOrder(#[SpanAttribute] string $orderNo): void
{
// 비즈니스 로직
}
로그 연결¶
애플리케이션에서 JSON 형식으로 로그를 출력하고 service, env, version을 명시적으로 포함하는 것이 좋습니다. 로그와 트레이스를 연동해야 하는 경우 현재 trace_id와 span_id를 함께 출력할 수 있습니다.
use OpenTelemetry\API\Trace\Span;
$context = Span::getCurrent()->getContext();
$traceId = $context->isValid() ? $context->getTraceId() : '';
$spanId = $context->isValid() ? $context->getSpanId() : '';
DataKit 측에서 logging 수집기를 활성화합니다. 예시 구성은 다음과 같습니다.
[[inputs.logging]]
logfiles = ["/var/log/php-app/*.log"]
source = "php"
service = "my-php-service"
pipeline = "php-json.p"
로그 필드에는 최소한 다음이 포함되어야 합니다.
messagestatusserviceenvversiontrace_idspan_id
PHP-FPM 메트릭 연결¶
애플리케이션이 PHP-FPM을 통해 실행되는 경우 phpfpm 수집기도 함께 활성화하는 것이 좋습니다.
www.conf에서 상태 페이지를 활성화합니다.
-
Nginx 또는 Apache를 통해
/status를 노출합니다. -
DataKit에서
phpfpm수집기를 활성화합니다.
이렇게 하면 다음을 동시에 관찰할 수 있습니다.
- 활성 프로세스 수
- 유휴 프로세스 수
- 연결 큐 길이
- 느린 요청 수
- 단일 프로세스 요청 처리 시간 및 메모리 소비
프로파일링 연결 (선택 사항)¶
트레이스 외에도 CPU, 메모리 할당 및 핫 함수 문제를 파악해야 하는 경우 PHP 프로파일링을 별도로 활성화할 수 있습니다.
현재 더 안정적인 방법은 다음과 같습니다.
- DataKit에서
profile수집기를 활성화합니다. - PHP에
dd-trace-php를 설치하고 프로파일링을 활성화합니다. - PHP 프로세스에 다음과 같은 환경 변수를 구성합니다.
DD_PROFILING_ENABLED=true
DD_SERVICE=my-php-service
DD_ENV=prod
DD_VERSION=1.3.1-gtrace
DD_AGENT_HOST=127.0.0.1
DD_TRACE_AGENT_PORT=9529
프로파일링은 트레이스를 보완하는 기능이므로 필요에 따라 활성화하고, 모든 서비스에서 기본적으로 전부 켤 필요는 없습니다.
최소 연결 순서¶
트레이스를 먼저 연결하고 점차적으로 다른 관측 데이터를 보완하려는 경우 다음 순서로 연결하는 것이 좋습니다.
- DataKit
opentelemetry입력 활성화 - PHP
opentelemetry확장 설치 및 활성화 - 프로젝트 내
sdk + exporter-otlp + 해당 auto-*의존성 설치 OTEL_*프로세스 환경 변수 구성- 실제 요청을 한 번 보내 트레이스가 Guance에 들어왔는지 확인
- 그런 다음 로그 수집, PHP-FPM 메트릭 및 프로파일링 추가
이렇게 하면 트레이스 연동 단계를 최소한으로 줄이고 처음부터 너무 많은 구성 요소를 동시에 처리하는 것을 피할 수 있습니다.
현재 Fork의 한계¶
OpenTelemetry 공식 zero-code 경험과 완전히 동일하게 맞추려면 현재 GuanceCloud fork에는 몇 가지 명확한 격차가 있습니다.
- Linux용 사전 컴파일된 바이너리 에셋이 없어 Linux 측 설치 경로가 충분히 짧지 않습니다.
- 독립적으로 식별 가능한 패키지 배포 채널이 없어
pecl install opentelemetry가 upstream이 아닌gtrace로 연결되지 않습니다. - 릴리스 에셋과 공식 문서의 "시스템 패키지 설치" 경로가 완전히 연결되지 않아 문서에서 공식 설치 명령을 그대로 사용할 수 없습니다.
- "확장은 fork에서 제공되지만 SDK 및 auto instrumentation 의존성은 여전히 공식 Composer 패키지에서 제공된다"는 점을 별도로 설명해야 합니다.
향후 연결 경험을 계속 개선해야 한다면 우선 순위는 다음과 같습니다.
- Linux용 일반적인 PHP 마이너 버전의 사전 컴파일된 확장 에셋 추가
- PHP 버전,
ts/nts및 확장 디렉터리를 자동으로 감지하는 설치 스크립트 제공 - 릴리스 페이지에서 "어떤 PHP 버전/실행 모드에 적합한지"에 대한 에셋 설명을 고정적으로 제공
- fork README에서 "upstream 설치 경로"와 "GuanceCloud gtrace 설치 경로"를 명확히 구분
실습 효과¶
위 연결을 완료하면 일반적으로 다음과 같은 관측 기능을 얻을 수 있습니다.
- 애플리케이션 성능 모니터링(APM)에서 PHP 서비스 진입점 요청, 데이터베이스 호출, 다운스트림 HTTP 호출 등의 트레이스 정보 확인
- 로그에서
service/env/version기준으로 필터링하고trace_id를 기반으로 동일한 요청 추적 - 인프라스트럭처 또는 사용자 정의 보기에서 PHP-FPM의 활성 프로세스, 대기열, 느린 요청 등의 실행 상태 관찰
- 프로파일링 보기에서 CPU 핫스팟, 메모리 할당 핫스팟 및 느린 함수 파악
모범 사례 권장 사항¶
- 리소스 속성 통일: 최소한
service.name,service.version,deployment.environment를 고정합니다. - 릴리스 명명 통일: 확장 버전, 애플리케이션 버전, 릴리스 태그를 최대한 일관되게 유지하여 버전 추적을 용이하게 합니다.
4317/gRPC우선 사용: 프로덕션 환경에서는OTLP gRPC를 우선 사용하고,9529/otel은 연동 및 문제 해결에 더 적합합니다.- 기성 설치 방식 우선 사용: 이미지 사전 설치, 빌드된 아티팩트 배포 또는
pecl이 있는 환경에서의PECL설치를 우선하며, 소스 컴파일을 주 권장 경로로 사용하지 않습니다. - 프로세스 수준 환경 변수 사용: 로그인 셸에서만
OTEL_*을 설정하지 말고,php-fpm,systemd, 컨테이너 또는 시작 스크립트에 작성합니다. - 속성 카디널리티 제어: 전화번호, 전체 주문 번호, 원시 SQL, 초장기 URL 등을 span attribute에 전체를 기록하지 않습니다.
- 주요 비즈니스 수동 계측: 자동 계측이 다루지 못하는 비즈니스 노드는
WithSpan을 사용하여 정확하게 보완합니다. - 로그에 트레이스 필드 유지:
trace_id/span_id를 통일적으로 출력하지 않으면 로그와 트레이스가 안정적으로 연동되지 않습니다. - DataKit 입력 먼저 확인: 트레이스가 연결되지 않을 때는
opentelemetry,logging,phpfpm,profile수집기가 활성화되었는지 먼저 확인합니다.