Przejdź do treści
Architektura 8 min czytania

Observability sklepu B2B - logi, metryki, distributed tracing

Sklep B2B żyje na pograniczu sześciu warstw - serwer aplikacji, baza, kolejka, cache, ERP, OMS i kurier. Kiedy klient dzwoni z "cennik się długo otwiera", problem może siedzieć w którymkolwiek z nich i bez observability każda taka rozmowa to dwa dni zgadywanki na produkcji. Z dobrze poskładanym stosem - Grafana, Prometheus, Loki, Tempo i OpenTelemetry jako lepidło - lokalizujesz problem w kwadrans, a większą część incydentów łapiesz, zanim klient odbierze telefon. Nie chodzi tylko o spokój zespołu. Chodzi o to, że bez tego nie da się świadomie skalować sklepu powyżej pewnej skali.

Jakub Owsianka Autor
Zaktualizowano:
Okladka artykulu: Observability sklepu B2B - logi, metryki, distributed tracing
Okladka artykulu: Observability sklepu B2B - logi, metryki, distributed tracing
Spis treści (6)

Golden signals w sklepie B2B

Google SRE zdefiniował cztery sygnały, na których trzeba pilnować systemu: latency, traffic, errors, saturation. Dla sklepu B2B trzeba je doprecyzować, bo zbiorcze metryki "p95 całego sklepu" to za mało - PDP zwykłej maski oleju zachowuje się inaczej niż checkout z dziesięciopozycyjnym koszykiem i cennikiem kontraktowym.

Latency mierzę per typ strony osobno (PDP, PLP, checkout, quick order, API katalogu), w trzech kwantylach p50, p95, p99, z rozróżnieniem na zalogowanych B2B i gości (różne ścieżki kodu, różne cache'e), oraz oddzielnie dla hitów i missów cache. Bez tego rozróżnienia jeden numer ukrywa siedem różnych historii.

Traffic to ruch z biznesowymi wymiarami, nie tylko liczba requestów. Liczba zamówień na godzinę, podział zalogowani vs goście, mobile vs desktop, integracje (PunchOut, API katalogu) vs przeglądarki. Jeśli widzisz spadek requestów z mobile'a o 40%, ale na desktopie wszystko OK, to nie awaria backendu tylko coś popsuło się w CSS-ie ostatnim deployem.

Errors to nie tylko 5xx z PHP. Liczę osobno 4xx z rozróżnieniem na podtypy: 404 dla wyszukiwarki (klient szukał towaru, którego nie ma), 403 dla niezalogowanych (próby dostania się do zasobu wymagającego loginu), 422 dla walidacji (źle wypełniony formularz). Plus wyjątki z integracji - ERP timeout, PIM 503, kurier "API niedostępne" - i wyjątki w kolejkach (failed jobs, głębokość kolejki dead letter).

Saturation to wykorzystanie zasobów. CPU, RAM i dysk serwerów aplikacji - oczywiste. Mniej oczywiste: pool połączeń bazy (czy max_connections nie zaraz się skończy), zużycie pamięci Redisa wraz z eviction rate (jeśli rośnie, cache zaczyna wyrzucać ważne klucze), workery kolejek - czy nadążają z przetwarzaniem czy głębokość rośnie liniowo.

Piąty sygnał, który dodaję na każdym wdrożeniu i który nie pojawia się w klasycznym SRE: business signals. Liczba zamówień na godzinę porównana z tym samym dniem tygodnia z poprzednich czterech tygodni. Średnia wartość koszyka. Dropoff w checkoucie. Bez tych metryk monitoring jest technicznie zielony, a sprzedaż spada o 40% i nikt nie wie, że klient nie może dokończyć zamówienia, bo nowa walidacja blokuje przelew. Widziałem to dwa razy.

Stos observability

Standardowy stos open-source dla sklepu B2B, którego używam najczęściej, to czterech graczy plus jeden, który ich spina.

Metryki zbiera Prometheus. Pull-based, scrapuje endpointy co 15-30 sekund, trzyma 15-30 dni lokalnie. Eksportery są banalne: node_exporter na system, mysqld_exporter na bazę, redis_exporter, php-fpm_exporter na pulę PHP-a, plus własny eksporter dla metryk aplikacyjnych (zamówienia, koszyki porzucone, dropoff).

Logi idą do Loki. Push-based, agent Promtail albo Vector zbiera z plików aplikacji i wysyła do centralnego storage. Loki indeksuje tylko labels (level, service, env), a nie pełny tekst, dzięki czemu jest tanie w zasobach. Query language - LogQL - jest składniowo podobny do PromQL, więc zespół, który zna jedno, łapie drugie w godzinę.

Traces zbieram do Tempo (lub Jaegera, jeśli klient już go ma). Instrumentacja przez OpenTelemetry - więcej niżej. Tempo jest lżejsze niż Jaeger i ładnie integruje się z Grafaną. Sampling typowo 1-10% wszystkich requestów plus 100% błędów - sample tych, w których faktycznie wydarzyło się coś nietrywialnego.

Spina to wszystko Grafana. Wspólne dashboardy ciągnące z trzech źródeł, alerty z routingiem do Slacka, PagerDuty i mailem do biznesu, oraz annotacje deployów - widać dokładnie, w której godzinie zaczęła się regresja i z czyją zmianą się pokrywa.

Alternatywy komercyjne to Datadog, New Relic, Dynatrace. Dla typowego sklepu B2B koszt wynosi 500-3000 USD miesięcznie, w zależności od wolumenu logów i liczby hostów. Czasem się opłaca - jeśli zespół DevOps nie ma kompetencji do utrzymania open-source albo jeśli czas onboardingu nowych ludzi jest cenniejszy niż licencja. Niżej rozliczam to dokładniej.

Kolejki w e-commerce - monitoring kolejek to osobny rozdział, bo wymaga specyficznych metryk.

OpenTelemetry w PHP

OpenTelemetry to standard CNCF dla instrumentacji aplikacji. Jeden SDK, wiele backendów - dzięki czemu jeśli za rok przeniesiesz się z Tempo na Datadog, kod aplikacji nie ulega zmianie, podmieniasz tylko endpoint eksportera. To jedyna sensowna ścieżka w 2026 roku.

Instalacja w Magento, Symfony, Laravel idzie przez composera:

composer require open-telemetry/opentelemetry
composer require open-telemetry/exporter-otlp

Auto-instrumentacja działa, jeśli zainstalujesz rozszerzenie PHP przez PECL i ustawisz kilka zmiennych środowiskowych:

pecl install opentelemetry
extension=opentelemetry.so

OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=sklep-b2b
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

Od momentu tego włączenia OpenTelemetry automatycznie obejmuje HTTP requests (Guzzle, Symfony HTTP Client), bazę danych (PDO, MySQLi), Redis przez Predis i sam framework. Dostajesz "darmowe" spans dla większości operacji w aplikacji bez modyfikacji kodu.

Tam, gdzie auto-instrumentacja nie dociera, dodaję custom spans dla logiki biznesowej. Klasyczny przykład - kalkulacja ceny kontraktowej, która potrafi schodzić do trzech sekund:

use OpenTelemetry\API\Trace\TracerInterface;

class PricingService
{
    public function __construct(private TracerInterface $tracer) {}

    public function calculateContractPrice(int $customerId, string $sku, int $qty): float
    {
        $span = $this->tracer->spanBuilder('pricing.contract')
            ->setAttribute('customer.id', $customerId)
            ->setAttribute('product.sku', $sku)
            ->setAttribute('product.qty', $qty)
            ->startSpan();

        try {
            return $this->compute($customerId, $sku, $qty);
        } finally {
            $span->end();
        }
    }
}

Korzyść jest namacalna. Zamiast "kalkulacja ceny zajęła 3.2s" widzisz w Tempo, że w środku był jeden span "cache.miss" (200 ms), drugi "erp.fetch_discount_tiers" (2.5 s), trzeci "compute.apply_rules" (500 ms). Wiesz dokładnie, że ERP odpowiada wolno - i to ERP optymalizujesz, a nie cache.

Distributed tracing przez integracje

Najmocniejsza wartość tracingu w sklepie B2B to nie diagnostyka pojedynczego requestu, tylko widzenie przepływu przez wszystkie systemy biorące udział w obsłudze zamówienia. Sklep, integracja katalogu, brama płatności, ERP, kolejka, worker, API kuriera - siedem warstw, w których coś może się zaciąć.

Typowy flow wygląda mniej więcej tak:

Browser → Sklep → API katalogu (sprawdzenie ceny)
                → Brama płatności (autoryzacja)
                → API ERP (zapis zamówienia)
                → Queue → Worker → API kuriera (etykieta)

Bez tracingu klient mówi "moje zamówienie składało się 30 sekund", a ty nie wiesz, czy stało dwa razy po 5 sekund na płatności, czy 22 sekundy w ERP, czy 8 sekund w kolejce. Z tracingiem otwierasz konkretne trace_id, widzisz 22 sekundy w spanie erp.create_order z dwoma retry'ami i wiesz, gdzie iść z miotłą.

Propagację trace_id między systemami załatwia W3C Trace Context. W HTTP to nagłówek traceparent - OpenTelemetry doda go automatycznie do wychodzących requestów. W kolejkach (Rabbit, Redis, SQS) dorzucasz traceparent do metadanych wiadomości i worker po drugiej stronie odczytuje go przy starcie spana. Jeśli ERP albo OMS klienta mają OpenTelemetry - dostajesz pełen obraz aż do ich wnętrza. Jeśli nie - widzisz przynajmniej moment wejścia i wyjścia z ich systemu, co już wystarczy do lokalizacji winnego.

Sampling jest decyzją, którą warto przemyśleć. Head-based decyduje na początku requestu, czy go w ogóle śledzić - typowo 5-10% requestów. Tail-based decyduje po zakończeniu - logujesz wszystkie błędy plus 1% sukcesów. Tail jest dużo cenniejszy dla diagnostyki ("pokaż mi wszystkie zamówienia, które trwały dłużej niż 10 sekund"), ale wymaga collectora z większym buforem pamięci. Dla sklepu B2B z umiarkowanym ruchem - polecam tail.

Alerting bez fałszywych alarmów

Najgorszy stan, w którym widziałem zespoły DevOps, to alert fatigue - 80% alertów to false positive, więc nikt już ich nie czyta, a kiedy przyjdzie prawdziwy, też go pominie. Lepiej mieć trzy alerty miesięcznie i każdy znaczący, niż 50 dziennie, z których nikt nie korzysta.

Pięć zasad, które stosuję przy konfigurowaniu alertów. Alert musi mieć przypisaną akcję - jeśli nikt nic nie robi po jego otrzymaniu, to nie alert, tylko dashboard, i miejsce takiego sygnału jest w Grafanie, nie w PagerDuty. Próg liczę z marginesem nad normą - nie "p95 > 500 ms", tylko "p95 > 1.5 razy średnia krocząca z 7 dni", bo bezwzględne progi nie nadążają za sezonowością ruchu. Dla SLO używam burn rate zamiast sztywnych progów: SLO 99.5% dostępności daje budżet błędu 0.5% miesięcznie, alert wystrzeliwa, gdy budżet zjadasz szybciej niż 1% miesięcznie - wcześnie, ale nie histerycznie.

Multi-window detection eliminuje false positive z chwilowych skoków. Nie "p95 przekroczył próg w ostatnich 5 minutach" tylko "p95 przekroczony przez 15 minut" - jeden 30-sekundowy peak nie wystawia alarmu. Grouping i deduplikacja po stronie Alertmanagera robi resztę roboty. Awaria bazy generuje teoretycznie 50 alertów (jeden per endpoint, który nagle ma 5xx) - z groupingem dostajesz jeden zbiorczy.

Zestaw alertów, który u mnie się sprawdza dla sklepu B2B średniej wielkości:

Alert Próg Routing
Error rate spike powyżej 1% przez 10 min Slack #incidents
Queue depth growing lag joba >5 min przez 15 min Slack + PagerDuty
Database connections powyżej 85% maks. przez 5 min Slack
Cache hit rate dropped poniżej 70% przez 30 min Slack
Order rate dropped poniżej 0.5x normy o tej porze przez 15 min Slack + email do biznesu
ERP integration down health check fail przez 5 min PagerDuty
Payment gateway 5xx powyżej 5 błędów w 5 min PagerDuty + email do biznesu

Order rate dropped wydaje się "miękki" - bo to metryka biznesowa, nie techniczna - ale w praktyce uratował mi tyłek dwa razy. Raz, gdy walidacja NIP przestała działać po deployu o 8:30 i klienci nie mogli złożyć zamówienia. Raz, gdy brama płatności wisiała, ale zwracała 200 OK na health check - tylko realne zamówienia nie szły dalej.

Koszt observability

Stos open-source dla typowego sklepu B2B z 30 tys. SKU wygląda budżetowo tak. Dwa serwery na obserwowalność (Grafana, Prometheus, Loki, Tempo na jednym, OpenTelemetry Collector i Alertmanager na drugim) o łącznej specyfikacji 8 vCPU i 16 GB RAM - około 80 EUR miesięcznie razem. Storage logów i metryk - 200 GB - kolejne 30 EUR. Instrumentacja samego sklepu to jednorazowo 3-5 dni pracy seniora. Utrzymanie - około 0.5 etatu DevOps, ale ten DevOps i tak zajmuje się sklepem.

Łącznie około 150 EUR miesięcznie plus koszt jednorazowego wdrożenia.

Stos komercyjny w Datadog dla tego samego sklepu wychodzi inaczej. APM kosztuje około 30 USD za hosta miesięcznie, dla typowego sklepu z 6 hostami to 180 USD. Logs liczone po wolumenie, około 1.50 USD za GB ingested - dla średniego ruchu sklepu B2B to 150-300 USD miesięcznie. Synthetics i RUM dorzucają kolejne 100 USD. Razem 500-700 USD miesięcznie.

Decyzja brzmi prościej, niż się wydaje. Dla zespołu pięciu i więcej inżynierów, którzy realnie korzystają z dashboardów codziennie, Datadog jest wart pieniędzy - znacznie szybszy onboarding, lepsza UI, mniej kodu do utrzymania. Dla zespołu dwóch-trzech osób przy stałym koszcie open-source wygrywa, bo różnica 500 USD miesięcznie to pół etatu juniora rocznie. W praktyce większość polskich sklepów B2B średniego rozmiaru leży w drugim przypadku.

Audyt wydajności sklepu - dane z observability są fundamentem każdego audytu, więc bez nich audyt zaczyna się od dwóch tygodni zbierania danych.

FAQ

Czym observability różni się od monitoringu? Monitoring odpowiada na pytanie "czy działa". Observability odpowiada na "dlaczego nie działa". Monitoring to znane pytania zadane z góry (czy CPU powyżej 80%, czy strona odpowiada). Observability to zdolność zadawania nowych pytań do zebranych danych po fakcie - kiedy klient zgłasza coś, czego nikt nie przewidział, że trzeba mierzyć.

Czy potrzebuję full-stack Datadog czy wystarczy darmowy Grafana? To pytanie o TCO, nie o cenę licencji. Dla zespołu 1-3 osób open-source wymaga pół etatu na utrzymanie, a UI Datadog jest bardziej "wchodzi i widzisz". Dla zespołu 5+ inżynierów Datadog często się opłaca przez szybszą diagnostykę i krótszy onboarding. Wybierałbym ten, który zespół zechce realnie używać, bo najlepszy stos to ten, do którego zaglądasz codziennie.

Jak instrumentować custom integracje z ERP? Wrap calls do ERP w spany OpenTelemetry z atrybutami: endpoint, metoda HTTP, status code, czas odpowiedzi, liczba retry'ów. Jeśli ERP ma propagację trace, łączysz konteksty i widzisz, co dzieje się w środku. Jeśli nie - co najmniej widzisz request i response z twojej strony, co już rozwiązuje 80% incydentów.

Czy logi można zastąpić tracingiem? Częściowo. Trace daje strukturę i kontekst, log daje swobodę "wrzuć tu cokolwiek". Praktyka, którą polecam: dla kluczowych ścieżek (zamówienie, płatność, integracja) używaj tracingu jako głównego źródła. Dla wszystkiego innego (debug, audit, akcje admina) - logi strukturalne, ale z trace_id w każdej linii, żeby móc je powiązać z tracem.

Jak długo trzymać dane observability? Metryki - 30 dni w wysokiej rozdzielczości, 1 rok zagregowane do dziennej. Logi - 30 dni dla aplikacji, 90 dni dla audytu, 1 rok dla wymagań prawnych (płatności, incydenty RODO). Traces - 7-30 dni dla typowego ruchu, dłużej dla błędów. Ważne, żeby ustalić politykę retencji przed wdrożeniem, bo doszacowanie storage'u przy 100 GB logów dziennie potrafi zaboleć.

Co dalej

O autorze

Jakub Owsianka

Architekt rozwiązania w WiseB2B - silniku platform B2B. Zaczynał po stronie biznesu (własne sklepy), potem deweloper, dziś projektuje wdrożenia dla sklepów z katalogami w dziesiątkach tysięcy SKU. W ostatnich latach wdrożył AI-development w zespole i funkcjonalności oparte o AI bezpośrednio w silniku sklepu.

Masz pytanie do tego artykułu?

Dodatkowy kontekst, problem z własnym wdrożeniem, druga opinia - napisz wprost. Odpowiadam osobiście w 1-2 dni robocze.