Śledzenie rozproszone i APM
OxPHP obsługuje propagację W3C Trace Context, eksport OpenTelemetry (OTel) oraz wbudowany Application Performance Monitoring (APM). Przychodzące nagłówki traceparent są parsowane i kontynuowane, identyfikatory śledzenia są dostępne w PHP przez $_SERVER, logi dostępu zawierają pola śledzenia, a spany można eksportować do Jaegera, Grafany Tempo, Zipkina lub dowolnego zaplecza zgodnego z OTLP.
Wtyczka APM dodaje trzy warstwy śledzenia na fundamencie OTel:
- Automatyczna instrumentacja — wewnętrzne funkcje PHP (PDO, mysqli, cURL, Redis, Memcached, operacje we/wy na plikach) są podpinane na poziomie silnika; każde wywołanie staje się spanem bez żadnych zmian w kodzie
- Śledzenie oparte na atrybutach — oznacz dowolną funkcję lub metodę PHP atrybutem
#[OxPHP\Apm\Trace], aby automatycznie tworzyć spany - PHP SDK — 10 funkcji
oxphp_apm_*()do ręcznego tworzenia spanów, ustawiania atrybutów, zdarzeń i rejestrowania błędów
Jak to działa
- Przychodzące żądanie — OxPHP odczytuje nagłówki
traceparentitracestatezgodnie ze specyfikacją W3C Trace Context - Nowy span — dla tego skoku generowany jest nowy identyfikator spana. Przychodzący identyfikator spana staje się rodzicem
- Propagacja do PHP — identyfikatory śledzenia są wstrzykiwane do
$_SERVER['OXPHP_TRACE_ID'],$_SERVER['OXPHP_SPAN_ID']oraz$_SERVER['OXPHP_PARENT_SPAN_ID'] - Log dostępu — ustrukturyzowane logi JSON zawierają pola
trace_idispan_idna potrzeby korelacji logów - Nagłówki odpowiedzi — zaktualizowany nagłówek
traceparent(z identyfikatorem spana OxPHP) jest dodawany do odpowiedzi, dzięki czemu usługi w dalszej części łańcucha mogą kontynuować śledzenie - Eksport OTel (opcjonalnie) — gdy wtyczka OTel jest włączona, każde żądanie staje się spanem eksportowanym przez OTLP z atrybutami konwencji semantycznej HTTP
Jeśli nagłówek traceparent nie jest obecny, OxPHP generuje nowy identyfikator śledzenia i identyfikator spana oraz rozpoczyna nowe śledzenie.
Konfiguracja
W3C Trace Context (wbudowany)
| Zmienna | Wartość domyślna | Opis |
|---|---|---|
TRACE_CONTEXT |
false |
Włącza propagację W3C Trace Context. Ustaw na true lub 1 |
Wtyczka OpenTelemetry
Wtyczka OTel to funkcja włączana podczas kompilacji (plugin-otel). Po włączeniu automatycznie aktywuje propagację trace-context (ten sam efekt co ustawienie TRACE_CONTEXT=true).
| Zmienna | Wartość domyślna | Opis |
|---|---|---|
OTEL_ENABLED |
false |
Włącza wtyczkę OpenTelemetry. Wartość logiczna — zobacz Wartości logiczne |
OTEL_EXPORTER_OTLP_PROTOCOL |
grpc |
Protokół eksportu: grpc lub http/protobuf |
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4317 (gRPC) lub http://localhost:4318 (HTTP) |
Endpoint kolektora OTLP. Adres URL https:// jest eksportowany przez TLS na obu transportach, weryfikowany względem systemowego magazynu zaufania (obraz uruchomieniowy musi dostarczać pakiet CA, taki jak ca-certificates — oficjalny obraz go instaluje); niestandardowe pakiety CA oraz mTLS nie są jeszcze obsługiwane |
OTEL_EXPORTER_OTLP_TIMEOUT |
10000 |
Limit czasu eksportu w milisekundach |
OTEL_EXPORTER_OTLP_HEADERS |
(nieustawione) | Nagłówki uwierzytelniania: key=value,key2=value2 |
OTEL_SERVICE_NAME |
oxphp |
Nazwa usługi w eksportowanych spanach |
OTEL_SERVICE_VERSION |
(nieustawione) | Atrybut wersji usługi |
OTEL_RESOURCE_ATTRIBUTES |
(nieustawione) | Dodatkowe atrybuty zasobu: env=prod,region=us-east-1 |
OTEL_TRACES_SAMPLER |
parentbased_traceidratio |
Strategia próbkowania: always_on, always_off, traceidratio, parentbased_always_on, parentbased_always_off, parentbased_traceidratio |
OTEL_TRACES_SAMPLER_ARG |
1.0 |
Współczynnik próbkowania (0.0–1.0) dla samplerów opartych na współczynniku |
Nieprawidłowe lub wykraczające poza zakres wartości OTEL_TRACES_SAMPLER_ARG są przycinane do [0.0, 1.0] i logowane na poziomie warn. Nieznane wartości OTEL_TRACES_SAMPLER są zastępowane wartością parentbased_traceidratio i logowane.
Wtyczka APM
Wtyczka APM to funkcja włączana podczas kompilacji (plugin-apm), która zależy od wtyczki OTel. Dodaje automatyczną instrumentację, dekorator #[OxPHP\Apm\Trace] oraz PHP-owy SDK do śledzenia.
| Zmienna | Wartość domyślna | Opis |
|---|---|---|
OTEL_APM_ENABLED |
false |
Włącza APM: automatyczną instrumentację, przechwytywanie błędów, PHP SDK. Wymaga OTEL_ENABLED=true. Wartość logiczna — zobacz Wartości logiczne |
OTEL_APM_SLOW_QUERY_MS |
100 |
Próg wolnego zapytania w milisekundach. Zapytania powyżej tego progu otrzymują oxphp.db.slow=true na swoich spanach |
OTEL_APM_DB_CAPTURE_PARAMS_ENABLED |
false |
Rejestruje parametry powiązania w atrybucie spana db.params. Wartości są zapisywane w postaci surowej — w odróżnieniu od db.statement nie są maskowane, więc mogą umieścić w śladach dane osobowe (adresy e-mail, tokeny itp.). Włączaj tylko tam, gdzie jest to akceptowalne. Wartość logiczna — zobacz Wartości logiczne |
OTEL_APM_STACKTRACE_MAX_BYTES |
8192 |
Maksymalny rozmiar w bajtach atrybutu exception.stacktrace. Po przekroczeniu limitu ślad stosu jest przycinany od końca (ramka główna jest zachowywana) ze znacznikiem …(truncated). 0 wyłącza przycinanie |
OTEL_APM_MESSAGE_MAX_BYTES |
4096 |
Maksymalny rozmiar w bajtach atrybutu exception.message (wartość domyślna odpowiada limitowi wartości na atrybut w New Relic). Po przekroczeniu limitu komunikat jest przycinany od końca ze znacznikiem …(truncated). 0 wyłącza przycinanie |
Kontekst śledzenia w PHP
Gdy TRACE_CONTEXT=true, w skryptach PHP dostępne są trzy zmienne $_SERVER:
| Zmienna | Opis | Przykład |
|---|---|---|
OXPHP_TRACE_ID |
Identyfikator śledzenia W3C (32 znaki hex) | 4bf92f3577b34da6a3ce929d0e0e4736 |
OXPHP_SPAN_ID |
Identyfikator spana OxPHP dla tego żądania (16 znaków hex) | 00f067aa0ba902b7 |
OXPHP_PARENT_SPAN_ID |
Przychodzący identyfikator spana nadrzędnego (16 znaków hex, pusty przy nowym śledzeniu) | a3ce929d0e0e4736 |
Użyj ich, aby propagować kontekst śledzenia do usług w dalszej części łańcucha:
<?php
$traceId = $_SERVER['OXPHP_TRACE_ID'] ?? '';
$spanId = $_SERVER['OXPHP_SPAN_ID'] ?? '';
if ($traceId) {
// Build a traceparent header for downstream calls
$traceparent = "00-{$traceId}-{$spanId}-01";
$response = file_get_contents('https://api.example.com/data', false,
stream_context_create([
'http' => [
'header' => "traceparent: {$traceparent}\r\n",
],
])
);
}Z Guzzle
<?php
$traceId = $_SERVER['OXPHP_TRACE_ID'] ?? '';
$spanId = $_SERVER['OXPHP_SPAN_ID'] ?? '';
$client = new \GuzzleHttp\Client();
$response = $client->get('https://api.example.com/users', [
'headers' => [
'traceparent' => "00-{$traceId}-{$spanId}-01",
],
]);Korelacja logów dostępu
Gdy kontekst śledzenia jest włączony, ustrukturyzowane logi dostępu w formacie JSON zawierają pola trace_id i span_id:
{
"timestamp": "2026-03-23T10:15:30.123Z",
"level": "INFO",
"fields": {
"request_id": "4bf92f3577b34da6-00f067aa",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"method": "GET",
"path": "/api/users",
"status": 200,
"duration_us": 1523,
"remote_ip": "10.0.0.1",
"message": "request completed"
}
}Możesz następnie wyszukiwać logi według identyfikatora śledzenia w systemach agregacji logów (Loki, Elasticsearch, Splunk, CloudWatch), aby znaleźć każdy wpis logu dla śledzenia rozproszonego.
Nagłówki odpowiedzi
OxPHP dodaje nagłówek traceparent do każdej odpowiedzi, z własnym identyfikatorem spana OxPHP:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01Jeśli przychodzące żądanie zawierało nagłówek tracestate, jest on również przekazywany w odpowiedzi.
Integracja z OpenTelemetry
Gdy wtyczka OTel jest włączona, każde żądanie HTTP staje się spanem eksportowanym do Twojego zaplecza śledzenia przez OTLP.
Atrybuty spana
Eksportowane spany zawierają standardowe atrybuty konwencji semantycznej HTTP:
| Atrybut | Opis |
|---|---|
http.request.method |
Metoda HTTP (GET, POST itd.) |
url.path |
Ścieżka żądania |
http.response.status_code |
Kod statusu odpowiedzi |
client.address |
Adres IP klienta |
server.address |
Adres nasłuchiwania serwera |
oxphp.request_id |
ID żądania OxPHP |
http.request.body.size |
Rozmiar ciała żądania w bajtach (jeśli różny od zera) |
http.response.body.size |
Rozmiar ciała odpowiedzi w bajtach (jeśli różny od zera) |
Odpowiedzi 5xx są oznaczane jako spany błędów.
Zdarzenia spana
Spany potomne przenoszą również zdarzenia spana — opatrzone znacznikiem czasu
adnotacje eksportowane jako zdarzenia OpenTelemetry i renderowane natywnie przez
Jaegera, Grafanę Tempo oraz inne zaplecza OTLP. Atrybut oxphp.event.kind w każdym
zdarzeniu identyfikuje jego typ:
oxphp.event.kind |
Źródło | Atrybuty zdarzenia |
|---|---|---|
exception |
Funkcja #[OxPHP\Apm\Trace], która rzuciła wyjątek, oxphp_apm_error() lub nieobsłużony wyjątek / błąd krytyczny na spanie głównym żądania (zobacz Automatyczne przechwytywanie wyjątków na spanie głównym) |
exception.type, exception.message, exception.stacktrace |
custom |
oxphp_apm_event() |
dostarczone przez użytkownika |
mark |
adnotacja profilera #[Mark] |
dostarczone przez użytkownika |
slow |
przekroczenie profilera #[SlowThreshold] |
threshold_ms, elapsed_ms |
memory_spike |
przekroczenie profilera #[MemoryThreshold] |
threshold_kb, delta_bytes |
Atrybut oxphp.event.kind może dodatkowo przyjmować wartości sql, http lub alloc w zdarzeniach generowanych przez instrumentację APM.
Automatyczne przechwytywanie wyjątków na spanie głównym
Gdy żądanie kończy się nieobsłużonym wyjątkiem lub błędem krytycznym i zwraca 5xx, OxPHP automatycznie dołącza zdarzenie exception do spana głównego żądania — bez atrybutu #[OxPHP\Apm\Trace] i bez wywołania oxphp_apm_error(). Błąd 500 staje się w śladzie samoopisujący, a backendy grupujące błędy po zdarzeniu wyjątku (na przykład New Relic Errors Inbox) zapalają się bez żadnego kodu aplikacji.
Zdarzenie niesie standardowe exception.type, exception.message i exception.stacktrace oraz dwa rozszerzenia OxPHP, exception.file i exception.line, wskazujące miejsce rzucenia (lub lokalizację błędu krytycznego). Dla błędu krytycznego bez klasy — trigger_error(…, E_USER_ERROR), przerwania z powodu braku pamięci albo przekroczenia limitu czasu wykonania — exception.type jest nazwą syntetyczną (stałą błędu PHP, np. E_USER_ERROR) i stacktrace nie występuje. Wywołanie niezdefiniowanej funkcji nie jest w PHP 8 błędem krytycznym bez klasy: rzuca zwykły Error, który niesie pełny stacktrace jak każdy inny wyjątek. Komunikat i stacktrace podlegają tym samym limitom OTEL_APM_MESSAGE_MAX_BYTES / OTEL_APM_STACKTRACE_MAX_BYTES, co pozostałe zdarzenia wyjątków.
Działa to dla surowego PHP, aplikacji bez własnego handlera wyjątków oraz handlerów trybu worker.
Granica: frameworki, które połykają wyjątki (tradycyjna ścieżka żądania). W trybach Traditional / Framework / SPA aplikacja, która instaluje set_exception_handler() i renderuje własną stronę błędu (Laravel, Symfony, WordPress, …), z punktu widzenia silnika obsłużyła wyjątek. Nigdy nie propaguje się on jako nieprzechwycony, więc OxPHP widzi tylko status 500 i nie może odzyskać obiektu Throwable. Dla takich żądań automatyczne przechwytywanie nie zadziała; zamiast tego zarejestruj wyjątek jawnie z modułu raportowania błędów swojego frameworka, wywołując oxphp_apm_error($e).
Tryb worker nie przechodzi przez set_exception_handler(). Środowisko uruchomieniowe workera przechwytuje wyjątek, który wymknie się z Twojego domknięcia oxphp_worker(), bezpośrednio — bez wywoływania handlera wyjątków użytkownika w silniku. Dla handlerów workera automatyczne przechwytywanie zadziała więc zawsze, gdy wyjątek opuści domknięcie, nawet jeśli kod zarejestrował własny set_exception_handler() — ten handler dotyczy wtedy tylko wyjątków, które domknięcie samo przechwytuje, a nie tych, które z niego uciekają.
Odpowiedzi strumieniowe. Dla odpowiedzi strumieniowej (SSE lub dowolnej pętli oxphp_stream_flush()) status HTTP jest ustalony w chwili, gdy nagłówki trafiają na łącze, i od tego momentu żądanie jest traktowane jako zakończone. Błąd krytyczny rzucony po zatwierdzeniu statusu — w odpowiedzi strumieniowej albo takiej, która wywołała finish_request() — jest wyłącznie logowany; nie jest dodawany do spana głównego (ślad nadal pokazuje span, ale bez zdarzenia exception). To udokumentowana granica i obowiązuje tak samo dla zatwierdzonego 5xx, jak i zatwierdzonego 2xx.
ID żądania w połączeniu z OTel
Gdy wtyczka OTel jest aktywna, identyfikatory żądań są wyprowadzane z kontekstu śledzenia: pierwsze 16 znaków identyfikatora śledzenia oraz pierwsze 8 znaków identyfikatora spana, oddzielone myślnikiem. Pojawia się to w logach, nagłówku odpowiedzi X-Request-ID oraz w oxphp_request_id() w PHP.
APM: automatyczna instrumentacja
Gdy wtyczka APM jest włączona, OxPHP automatycznie podpina 34 wewnętrzne funkcje PHP na poziomie silnika. Każde wywołanie podpiętej funkcji tworzy span potomny pod spanem głównym bieżącego żądania — bez konieczności wprowadzania jakichkolwiek zmian w kodzie.
Podpięte funkcje
| Kategoria | Funkcje |
|---|---|
| PDO | PDO::__construct, PDO::query, PDO::exec, PDO::prepare, PDOStatement::execute |
| mysqli | mysqli::__construct, mysqli::query, mysqli::prepare, mysqli_stmt::prepare, mysqli_stmt::execute |
| cURL | curl_init, curl_setopt, curl_exec, curl_multi_exec |
| Redis | Redis::connect, Redis::get, Redis::set, Redis::del, Redis::mget, Redis::mset, Redis::hget, Redis::hset, Redis::lpush, Redis::rpush |
| Memcached | Memcached::get, Memcached::set, Memcached::delete, Memcached::getMulti, Memcached::setMulti |
| We/wy plików | fopen, fread, fwrite, file_get_contents, file_put_contents |
Podpięcia (hooks) są instalowane tylko dla rozszerzeń, które są faktycznie załadowane. Jeśli Twoja kompilacja nie zawiera rozszerzenia Redis, podpięcia Redis są po cichu pomijane.
Atrybuty spanów bazodanowych
Podpięcia bazodanowe (PDO, mysqli) dekorują swoje spany atrybutami zgodnymi z konwencjami semantycznymi OpenTelemetry:
| Atrybut | Źródło | Przykład |
|---|---|---|
db.statement |
Tekst zapytania z wartościami literalnymi zastąpionymi przez ?, dzięki czemu dane osobowe (adresy e-mail, tokeny) nigdy nie docierają do backendu śledzenia |
SELECT * FROM users WHERE email = ? |
db.operation |
Wiodące słowo kluczowe SQL | SELECT |
db.system |
Wyparsowane z DSN PDO / konstruktora mysqli | mysql, postgresql, sqlite |
server.address, server.port |
Host/port połączenia (pomijane dla gniazda uniksowego lub pliku SQLite) | db.internal, 5432 |
db.name |
Nazwa bazy danych lub ścieżka pliku dla SQLite | shop |
oxphp.db.slow |
true, gdy czas ścienny wywołania osiąga lub przekracza OTEL_APM_SLOW_QUERY_MS |
true |
db.params |
Parametry powiązania, zapisywane w postaci surowej (bez maskowania) — mogą więc zawierać dane osobowe; tylko gdy OTEL_APM_DB_CAPTURE_PARAMS_ENABLED=true |
[1, active] |
db.statement jest odczytywany z argumentów samego wywołania query / exec / prepare, więc pojawia się na tym spanie. Na spanie PDOStatement::execute jest również obecny — odczytany z właściwości queryString samego obiektu zapytania, więc nigdy nie może być SQL-em innego zapytania. Span mysqli_stmt::execute nie ma db.statement (mysqli nie udostępnia takiej właściwości), ale SQL znajduje się na poprzedzającym spanie mysqli::prepare. Każdy span execute niesie pomiar czasu, a wraz z nim flagę wolnego zapytania, a dla PDO także db.params. Podpięcia cache (Redis, Memcached), klienta HTTP (cURL) i we/wy plików emitują goły span z samym pomiarem czasu.
Instalacja podpięć
Instalacja podpięć wykorzystuje dwufazowy projekt zapewniający bezpieczeństwo wątkowe w PHP ZTS:
- Faza 1 (MINIT) — podczas inicjalizacji modułu OxPHP weryfikuje każdą docelową funkcję względem załadowanych rozszerzeń i przechwytuje oryginalne wskaźniki do handlerów na tylko-do-odczytu listę zatwierdzonych
- Faza 2 (RINIT) — przy pierwszym żądaniu na każdym wątku worker zatwierdzone podpięcia są instalowane w tablicach funkcji tego wątku
Zapewnia to, że każdy wątek worker ZTS ma spójne modyfikacje tablicy funkcji oraz stan lokalny wątku.
APM: śledzenie oparte na atrybutach
Atrybut #[OxPHP\Apm\Trace] automatycznie tworzy spany wokół udekorowanych funkcji i metod. W przeciwieństwie do podpięć automatycznej instrumentacji (które celują w wewnętrzne funkcje C), działa on na kodzie PHP zdefiniowanym przez użytkownika.
<?php
use OxPHP\Apm\Trace;
#[Trace]
function processOrder(int $orderId): void
{
// A span named "processOrder" is created on entry and closed on exit.
// If an exception is thrown, the span is marked as error and an
// "exception" span event records exception.type, exception.message
// and exception.stacktrace.
}
class PaymentService
{
#[Trace]
public function charge(float $amount): bool
{
// Span named "PaymentService::charge"
return true;
}
}Atrybut #[Trace] obejmuje zarówno funkcje, jak i metody. Nie jest potrzebne żadne wywołanie rejestrujące — wtyczka APM rejestruje dekorator automatycznie podczas inicjalizacji.
Jeśli udekorowana funkcja rzuci wyjątek, status spana jest ustawiany na error, a zdarzenie exception jest rejestrowane z pełnymi danymi konwencji semantycznej OpenTelemetry: exception.type (klasa), exception.message (komunikat) oraz exception.stacktrace (stos wywołań z getTraceAsString()). Komunikat jest przycinany do OTEL_APM_MESSAGE_MAX_BYTES bajtów (domyślnie 4096), a ślad stosu do OTEL_APM_STACKTRACE_MAX_BYTES bajtów (domyślnie 8192); 0 wyłącza dowolny z tych limitów. Przechwytywanie argumentów wewnątrz ramek jest zgodne z ustawieniem zend.exception_ignore_args w samym PHP.
APM: PHP-owy SDK do śledzenia
Wtyczka APM rejestruje 10 funkcji oxphp_apm_*() do ręcznego zarządzania spanami. Wszystkie funkcje są bezpiecznymi no-op, gdy APM jest wyłączony, więc Twój kod działa bez modyfikacji w dowolnym środowisku.
Tworzenie spanów
<?php
// Start a span and get its local ID
$spanId = oxphp_apm_start('cache.warm', ['cache.size' => '1024']);
// ... do work ...
// Close the span
oxphp_apm_end($spanId);Dodawanie atrybutów i zdarzeń
<?php
$spanId = oxphp_apm_start('order.process');
// Add attributes to the current span (or a specific one)
oxphp_apm_attribute('order.id', $orderId);
oxphp_apm_attribute('order.total', $total, $spanId);
// Record an event on the span
oxphp_apm_event('payment.authorized', [
'provider' => 'stripe',
'amount' => (string) $amount,
]);
oxphp_apm_end($spanId);Rejestrowanie błędów
<?php
$spanId = oxphp_apm_start('external.api');
try {
$result = callExternalApi();
} catch (\Throwable $e) {
// Mark the span as error
oxphp_apm_error($e, $spanId);
throw $e;
} finally {
oxphp_apm_end($spanId);
}Propagowanie kontekstu śledzenia
<?php
// Get the current trace ID and span ID
$traceId = oxphp_apm_trace_id();
$currentSpanId = oxphp_apm_span_id();
// Or get a ready-to-use traceparent header value
$traceparent = oxphp_apm_header();
// "00-{trace_id}-{span_id}-01"
// Propagate to downstream services
$response = file_get_contents('https://api.example.com/data', false,
stream_context_create([
'http' => [
'header' => "traceparent: {$traceparent}\r\n",
],
])
);Referencja funkcji
| Funkcja | Zwraca | Opis |
|---|---|---|
oxphp_apm_trace(name, callback, ?attributes) |
void |
Wykonuje callback wewnątrz spana (zarezerwowane do przyszłego użytku) |
oxphp_apm_start(name, ?attributes) |
int |
Otwiera span i zwraca jego lokalny ID. 0, gdy APM jest wyłączony |
oxphp_apm_end(span_id) |
void |
Zamyka span o podanym lokalnym ID |
oxphp_apm_attribute(key, value, ?span_id) |
void |
Ustawia atrybut na bieżącym lub wskazanym spanie |
oxphp_apm_event(name, ?attributes, ?span_id) |
void |
Rejestruje zdarzenie ze znacznikiem czasu na bieżącym lub wskazanym spanie |
oxphp_apm_error(exception, ?span_id) |
void |
Oznacza bieżący lub wskazany span jako error i rejestruje zdarzenie exception. Obiekt Throwable dostarcza exception.type, exception.message oraz exception.stacktrace; sam argument tekstowy jest rejestrowany jako exception.message z ogólnym exception.type równym Error (dzięki czemu zdarzenie pozostaje widoczne w zapleczach grupujących według typu) |
oxphp_apm_status(code, ?description, ?span_id) |
void |
Ustawia status spana: 0 = Unset, 1 = Ok, 2 = Error |
oxphp_apm_trace_id() |
string |
Bieżący identyfikator śledzenia (32 znaki hex). Pusty, gdy APM jest wyłączony |
oxphp_apm_span_id() |
string |
Bieżący identyfikator spana (16 znaków hex). Pusty, gdy brak aktywnego spana |
oxphp_apm_header() |
string |
Wartość nagłówka W3C traceparent dla bieżącego kontekstu spana |
Pełną referencję sygnatur funkcji znajdziesz w Funkcje PHP.
Przykład Docker
Gotowe do uruchomienia warianty compose.yaml:
Włącz propagację śledzenia W3C bez zewnętrznego zaplecza:
services:
app:
image: ghcr.io/oxphp/oxphp:0.11.0
ports:
- "80:80"
environment:
- TRACE_CONTEXT=true
- INTERNAL_ADDR=0.0.0.0:9090Pełny stos obserwowalności z Jaegerem jako zapleczem śledzenia:
services:
app:
image: ghcr.io/oxphp/oxphp:0.11.0
ports:
- "80:80"
environment:
- OTEL_ENABLED=true
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
- OTEL_SERVICE_NAME=my-app
- OTEL_SERVICE_VERSION=1.0.0
- OTEL_RESOURCE_ATTRIBUTES=env=production
- INTERNAL_ADDR=0.0.0.0:9090
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # Jaeger UI
- "4317:4317" # OTLP gRPCservices:
app:
image: ghcr.io/oxphp/oxphp:0.11.0
ports:
- "80:80"
environment:
- OTEL_ENABLED=true
- OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4317
- OTEL_SERVICE_NAME=my-app
tempo:
image: grafana/tempo:latest
ports:
- "4317:4317"
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"Pełna obserwowalność z automatyczną instrumentacją zapytań do bazy danych, wywołań HTTP, operacji na pamięci podręcznej oraz operacji we/wy na plikach:
services:
app:
image: ghcr.io/oxphp/oxphp:0.11.0
ports:
- "80:80"
environment:
- OTEL_ENABLED=true
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
- OTEL_SERVICE_NAME=my-app
- OTEL_APM_ENABLED=true
- OTEL_APM_SLOW_QUERY_MS=50
- INTERNAL_ADDR=0.0.0.0:9090
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # Jaeger UI
- "4317:4317" # OTLP gRPC
environment:
- COLLECTOR_OTLP_ENABLED=trueFunkcja Cargo plugin-apm musi być włączona podczas budowania. Oficjalny obraz OxPHP zawiera ją domyślnie.
Stos obserwowalności
OxPHP zapewnia trzy filary obserwowalności, które współpracują ze sobą:
| Filar | Funkcja | Korelacja |
|---|---|---|
| Metryki | Liczniki i histogramy Prometheusa na /metrics |
Zagregowane dane o wydajności |
| Logowanie | Ustrukturyzowane logi dostępu JSON z ACCESS_LOG |
Szczegóły dla każdego żądania, przeszukiwalne po trace_id |
| Śledzenie | W3C Trace Context + eksport OTLP | Kompleksowy (end-to-end) rozproszony przepływ żądań |
Wszystkie trzy współdzielą ten sam trace_id i request_id, dzięki czemu możesz przejść od alertu na pulpicie Grafany do śledzenia w Tempo, a następnie do linii logów w Loki dla pojedynczego żądania.
Rozwiązywanie problemów
Nagłówki śledzenia nie pojawiają się w odpowiedziach
TRACE_CONTEXT nie jest włączony.
Rozwiązanie: Ustaw TRACE_CONTEXT=true lub włącz wtyczkę OTel przez OTEL_ENABLED=true (co automatycznie włącza kontekst śledzenia).
Zmienne śledzenia w $_SERVER są puste
Kontekst śledzenia jest wyłączony lub zmienne są sprawdzane poza OxPHP.
Sprawdź: Zmienne OXPHP_TRACE_ID, OXPHP_SPAN_ID oraz OXPHP_PARENT_SPAN_ID istnieją tylko wtedy, gdy TRACE_CONTEXT=true i żądanie jest obsługiwane przez OxPHP. Przetestuj za pomocą:
<?php
echo $_SERVER['OXPHP_TRACE_ID'] ?? 'trace context not enabled';Spany nie pojawiają się w Jaegerze/Tempo
Sprawdź: Zweryfikuj, czy endpoint OTLP jest osiągalny z kontenera OxPHP:
docker compose exec app curl -v http://jaeger:4317Sprawdź: Zweryfikuj, czy wtyczka jest włączona:
curl -s http://localhost:9090/config | jq '.plugins'Rozwiązanie: Upewnij się, że OTEL_ENABLED=true, a OTEL_EXPORTER_OTLP_ENDPOINT wskazuje na poprawny adres kolektora.
Duża liczba próbkowanych spanów w produkcji
Eksportowanie każdego spana jest kosztowne przy dużym natężeniu ruchu.
Rozwiązanie: Zmniejsz współczynnik próbkowania:
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1 # Sample 10% of tracesPróbkowanie oparte na rodzicu (parent-based) oznacza, że jeśli przychodzące żądanie niesie próbkowane śledzenie, zostanie ono zawsze próbkowane niezależnie od współczynnika. Nowe śledzenia rozpoczynane w OxPHP są próbkowane ze skonfigurowaną częstotliwością. Jeśli OTEL_TRACES_SAMPLER jest ustawiony na nieznaną wartość, OxPHP loguje ostrzeżenie i wraca do parentbased_traceidratio.
Zobacz też
- Funkcje PHP — referencja funkcji
oxphp_apm_*() - Dekoratory — przechwytywanie funkcji oparte na atrybutach, w tym
#[Trace] - Rejestrowanie dostępu — ustrukturyzowane logi JSON z polami śledzenia
- ID żądań — jak identyfikatory żądań współdziałają z kontekstem śledzenia
- Metryki — referencja metryk Prometheusa
- Kontrole stanu — endpoint
/configpokazujący status kontekstu śledzenia - Referencja konfiguracji — wszystkie zmienne środowiskowe