Pierwsze info o awarii przyszło od klienta. Nie przez email, nie przez ticket – zadzwonił bezpośrednio. Produkcja nie działała od dwóch godzin. Nikt z zespołu nie wiedział. Aplikacja zwracała 500, logi rosły, baza zaczęła dławić się połączeniami. Klasyczny scenariusz: MVP na dedykowanym środowisku, zero monitoringu poza tym że „wczoraj działało”.
Problem z małymi projektami nie polega na tym że monitoring jest trudny do skonfigurowania. Problem polega na tym że zespół przekonuje sam siebie że „na początek nie jest potrzebny”. Przecież to tylko MVP. Przecież jak coś się zepsuje to będziemy wiedzieć. Przecież mamy tylko 100 użytkowników. A potem przychodzi sobotni wieczór, produkcja leży, a ty dowiadujesz się o tym 3 godziny po fakcie bo klient napisał na Slacku.
Nie chodzi o enterprise observability stack. Chodzi o prostą rzecz: wiedzieć że system padł zanim zadzwoni telefon.
Dlaczego "działa u mnie" to nie monitoring
Typowy setup MVP wygląda tak: deploy na VPS albo managed hosting, może Docker Compose, może Vercel. Developer sprawdza czy strona się ładuje, klika kilka buttonów, odpala „curl localhost:3000/health” na serwerze. Działa. Deploy zamknięty. Problem w tym że to sprawdzenie działa przez dokładnie 30 sekund po deploymencie. Potem zaczynają się rzeczywiste problemy.
Aplikacja może zwracać HTTP 200 i jednocześnie być kompletnie zepsuta. Health check endpoint odpowiada, ale worker queue stoi. Frontend się renderuje, ale API timeout”uje po 30 sekundach. Strona działa dla 90% użytkowników, ale ci z Polski widzą białą stronę bo CDN cache się zepsuł dla specific region. To wszystko są scenariusze które widziałem w produkcji przy projektach „za małych na monitoring”.
Kolejny klasyk: baza danych zaczyna się dławić bo przez tydzień rosły dane i nagle query które działało w 50ms teraz idzie 8 sekund. Strona technicznie działa, odpowiada HTTP 200, ale użytkownik czeka i czeka aż timeout go wyrzuci. Nikt nie wie że jest problem dopóki support nie zacznie dostawać maili.
Albo jeszcze lepiej: memory leak w Node.js. Proces żre coraz więcej RAM przez 3 dni, w końcu system zabija go OOM killerem, aplikacja restartuje się, przez godzinę działa ok, potem znowu to samo. Użytkownicy widzą losowe 502 co kilka godzin. Nikt nie wie dlaczego bo restart „naprawia” problem na tyle długo żeby zespół uznał że „само прошло”.
Podstawowy monitoring nie jest opcjonalny. To nie jest „nice to have na później”. To jest minimum żeby w ogóle móc nazwać środowisko produkcyjnym.
Three pillars za 2 godziny setupu
Sensowny monitoring dla małego projektu opiera się na trzech rzeczach: uptime, errors, performance. W tej kolejności. Można to wszystko skonfigurować w 2 godziny i będzie działać lepiej niż 80% MVP które widziałem.
Uptime monitoring to odpowiedź na pytanie: czy aplikacja w ogóle żyje. Czy odpowiada na requesty. Czy użytkownik widzi cokolwiek czy białą stronę. To nie wymaga żadnej integracji w kodzie. Zewnętrzny serwis pinguje twoją stronę co minutę i krzyczy jak przestaje odpowiadać.
Error tracking to odpowiedź na pytanie: co się psuje w środku. Jakie exceptiony lecą w backendzie. Jakie błędy JS widzą użytkownicy w przeglądarce. Które endpointy zwracają 500. To wymaga dodania jednej biblioteki do projektu i skonfigurowania kilku linijek.
Performance monitoring to odpowiedź na pytanie: czy aplikacja działa szybko czy ledwo zipie. To często jest opcjonalne dla MVP ale jak już to robić to z sensem. Response time, database query performance, memory usage. Nie averaged metrics tylko percentyle bo średnia nic nie mówi.
Jeśli masz te trzy rzeczy to masz wystarczająco dużo informacji żeby wiedzieć o problemie zanim klient zacznie dzwonić. Reszta tooptymalizacja.
Uptime monitoring: pierwszy alert w 15 minut
Najprostszy możliwy setup: UptimeRobot free tier. Dodajesz URL, ustawiasz interval na 5 minut, podajesz email albo webhook do Slacka. Gotowe. Jak strona przestanie odpowiadać HTTP 200, dostaniesz alert. To działa i jest darmowe do 50 monitorów.
Problem w tym że sprawdzanie samego HTTP 200 to za mało. Aplikacja może zwracać 200 i być zepsuta. Dlatego potrzebujesz health check endpointa który faktycznie sprawdza czy system działa.
// /health endpoint który coś faktycznie sprawdza
app.get("/health", async (req, res) => {
try {
// sprawdź połączenie z bazą
await db.query("SELECT 1");
// sprawdź czy Redis odpowiada
await redis.ping();
// sprawdź czy worker queue działa
const queueSize = await queue.size();
if (queueSize > 10000) {
throw new Error("Queue backlog too high");
}
res.status(200).json({ status: "ok" });
} catch (error) {
res.status(503).json({ status: "degraded", error: error.message });
}
});
Health check który sprawdza zależności łapie więcej problemów niż prosty ping głównej strony. Baza padła? Health zwraca 503. Redis nie odpowiada? 503. Queue się zapchał? 503. Uptime monitor widzi failure i triggeruje alert.
Ale jest haczyk: health check nie może być za ciężki. Widziałem endpoint który robił 5 database queries, walidował external API, sprawdzał filesystem.Timeout 30 sekund. Uptime monitor traktował to jako failure bo przekroczony limit czasu nawet jak aplikacja działała. False positive alerts co godzinę. Zespół zaczął ignorować alerty. Tydzień później prawdziwa awaria i nikt nie zareagował bo wszyscy myśleli że to kolejny false positive.
Health check powinien być szybki i sprawdzać tylko critical dependencies. Database ping, Redis ping, może sprawdzenie czy worker process żyje. Nic więcej. Cel to odpowiedź poniżej 1 sekundy.
Kolejna rzecz: monitoring powinien być zewnętrzny. Jeśli postawisz health check i będziesz go pingować z crona na tym samym serwerze co aplikacja, to jak serwer padnie to monitoring też padnie. Uptime monitor musi być zewnętrznym serwisem który pinguje z innej infrastruktury. UptimeRobot, BetterStack, Pingdom, StatusCake – dowolny, byle nie na tym samym serwerze.
Alert routing: email to minimum, ale email się gubi. Lepiej Slack webhook albo integracja z PagerDuty jeśli zespół ma on-call rotation. Dla małego projektu Slack wystarczy – channel dedykowany dla alertów, notyfikacje włączone, zespół widzi problem w czasie rzeczywistym.
"Produkcja ma ciekawą cechę: przez tygodnie cierpliwie toleruje złe decyzje, a potem przypomina o wszystkich naraz w sobotę o 21:37."
Error tracking: Sentry w 30 minut
Uptime monitoring mówi czy aplikacja żyje. Error tracking mówi co się psuje w środku. To nie jest optional. Bez error trackingu debugujesz w ciemno.
Sentry to standard dla większości stacków. Darmowy tier wystarczy dla małych projektów. Setup dla Node.js/Express:
const Sentry = require("@sentry/node");
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1, // 10% transakcji dla performance monitoring
});
// error handler middleware
app.use(Sentry.Handlers.errorHandler());
To wystarczy żeby łapać wszystkie unhandled exceptions w backendzie. Każdy błąd leci do Sentry z pełnym stacktrace, context, request details. Frontend podobnie – dodajesz SDK, konfigurujesz DSN, od teraz widzisz wszystkie JS errors z przeglądarek użytkowników.
Problem zaczyna się przy konfiguracji alertów. Default settings w Sentry triggerują alert przy każdym nowym errorze. Brzmi sensownie dopóki nie wejdziesz na produkcję i nie okaże się że dostajesz 50 alertów dziennie. Bot scraper trigger”uje błąd walidacji. Użytkownik z dziwną przeglądarką generuje JS error. External API timeout”uje raz na godzinę. Większość z tych errorów nie wymaga natychmiastowej reakcji ale Sentry i tak wyśle alert.
Alert fatigue to prawdziwy problem. Jak dostajesz 50 notyfikacji dziennie to przestajesz je czytać. Potem przychodzi prawdziwy critical error i giną w szumie. Dlatego alert rules muszą być skonfigurowane z sensem.
W Sentry można ustawić alerty based on frequency i severity. Przykład: alert tylko jeśli error wystąpił więcej niż 10 razy w ciągu godziny. Albo tylko dla specific tagów – production environment, critical endpoints. Albo tylko dla errorów które nie były widziane wcześniej. To filtruje 90% szumu.
Kolejna rzecz: grouping. Sentry grupuje errory po stacktrace ale czasem robi to źle. Ten sam błąd z różnymi parametrami może być traktowany jako osobne issues. Albo odwrotnie – różne błędy grupowane razem bo stacktrace wygląda podobnie. Trzeba to monitorować i czasem ręcznie mergować albo splitować issues.
Sourcemaps dla frontendowych bundli to must have. Bez sourcemaps stacktrace pokazuje zminifikowany kod: „t.n is not a function at bundle.js:1:4782”. Kompletnie bezużyteczne. Z sourcemaps widzisz oryginalny kod i dokładną linię. Setup zależy od bundlera ale w Webpack to plugin Sentry który uploaduje sourcemaps przy buildzie.
Performance monitoring: kiedy jest potrzebny
Dla większości MVP performance monitoring to overkill. Uptime i errors wystarczą żeby przeżyć pierwsze miesiące. Ale są sytuacje gdzie bez performance metrics debugujesz w ciemno.
Przykład: aplikacja zwraca HTTP 200, nie ma errorów w Sentry, uptime monitor happy. Ale użytkownicy skarżą się że jest wolna. Jak to zdebugować? Bez performance monitoringu możesz tylko zgadywać. Database queries? Network latency? Frontend rendering? Nie wiesz.
Response time monitoring mówi ile czasu zajmuje obsłużenie requestu. Ale średnia nic nie mówi. Average response time 200ms brzmi ok. Problem w tym że może to oznaczać że 95% requestów idzie w 50ms a 5% w 4 sekundy. Użytkownicy widzą te 4 sekundy i narzekają na wolność aplikacji.
Percentyle są jedynym sensownym sposobem mierzenia performance. P50 (median), P95, P99. Jeśli P95 to 300ms to znaczy że 95% użytkowników dostaje odpowiedź w 300ms lub szybciej. Jeśli P99 to 5 sekund to znaczy że 1% użytkowników ma kiepskie doświadczenie. To jest informacja która ma wartość.
Database query performance to kolejny częsty problem. Query które działało szybko przy 1000 rekordach zaczyna timeout”ować przy 100k. Bez query performance monitoring dowiesz się o tym dopiero jak użytkownicy zaczną się skarżyć. Postgres ma „pg_stat_statements”, MySQL ma slow query log. To wystarczy na początek.
APM tools typu New Relic albo Datadog są świetne ale kosztują. Dla małego projektu to za dużo. Można zacząć od prostszych rzeczy: logowanie slow queries, basic metrics w Sentry (traces sample rate 10%), response time tracking w middleware. To da wystarczająco dużo informacji żeby znaleźć bottlenecki.
Moment kiedy performance monitoring staje się konieczny to zwykle moment kiedy aplikacja zaczyna mieć traffic. Do 100 requestów na minutę można debugować ręcznie. Powyżej tego potrzebujesz metryk żeby w ogóle wiedzieć gdzie szukać problemów.
"Średni czas odpowiedzi wyglądał świetnie. Dopiero P99 przypomniało wszystkim, że statystyka potrafi być całkiem kreatywna."
Alert fatigue i jak nie zwariować
Najbardziej niebezpieczna rzecz w monitoringu to nie brak alertów. To za dużo alertów. Alert fatigue zabija czujność szybciej niż cokolwiek innego.
Widziałem zespół który miał skonfigurowane alerty dla wszystkiego. Uptime monitor co minutę. Sentry alert przy każdym errorze. CloudWatch alarm dla CPU > 70%. Disk space alert przy 80% usage. Memory alert przy 75%. Log error pattern matching. W sumie 30-40 alertów dziennie. Pierwszego tygodnia zespół reagował na wszystko. Drugiego zaczęli filtrować. Trzeciego przestali w ogóle patrzeć. Czwartego była prawdziwa awaria i nikt nie zareagował bo to był kolejny alert w morzu szumu.
Alert powinien oznaczać: coś się zepsuło, ktoś musi to naprawić teraz. Jeśli alert nie wymaga akcji to nie powinien być alertem. Może być metric, może być log, może być dashboard. Ale nie alert.
Przykład złego alertu: CPU usage > 70% przez 5 minut. Brzmi sensownie. Problem w tym że CPU spike może być normalny – scheduled job, backup, batch processing. Jeśli trigger”uje alert 3 razy dziennie i za każdym razem okazuje się że to false alarm to przestajesz zwracać uwagę.
Lepszy alert: CPU usage > 90% przez 15 minut. To już oznacza rzeczywisty problem. System nie radzi sobie z loadem. Trzeba sprawdzić co się dzieje. Alert ma sens.
Podobnie z error rate. Alert przy każdym errorze to za dużo. Alert przy error rate > 5% przez 10 minut to sensowna wartość. Pojedyncze errory się zdarzają. 5% error rate to już problem systemowy.
Escalation policy dla małego zespołu jest trudna bo często nie ma on-call rotation. Wszyscy dostają wszystkie alerty. To działa kiedy alertów jest mało. Przestaje działać jak zaczyna być ich więcej. Trzeba zdefiniować priority levels.
P0 (critical): aplikacja nie działa, wszyscy dostają alert natychmiast, SMS + phone call jeśli nie ma reakcji w 5 minut. P1 (high): degraded performance, alert na Slack, reakcja w godzinę. P2 (medium): błędy które nie blokują użytkowników, można czekać do rana. P3 (low): do sprawdzenia w ciągu dnia ale nie urgent.
Większość alertów powinna być P2 albo P3. P0 powinno być rzadkie. Jeśli masz P0 alert co drugi dzień to albo system jest faktycznie zepsuty albo progi są źle ustawione.
Zespół na początku projektu był przekonany że potrzebują real-time alertów na wszystko. Monitoring skonfigurowany agresywnie. Po tygodniu na produkcji wszyscy byli wykończeni. Alert o 3 w nocy że error rate wzrósł do 2% bo bot zaczął crawlować stronę. Alert o 6 rano że backup job zużył 80% CPU. Alert w południe że Redis memory usage przekroczył threshold. Żaden z tych alertów nie wymagał natychmiastowej akcji. Ale wymuszały reakcję bo były oznaczone jako critical. Po rozmowie z zespołem zmieniliśmy thresholdy i priority levels. P0 zostało tylko dla total outage. Reszta P1-P2. Ilość alertów spadła z 40 dziennie do 2-3. Zespół przestał być w permanentnym stresie i zaczął faktycznie reagować na prawdziwe problemy.
Logging dla post-mortem debugging
Monitoring mówi że coś się zepsuło. Logi mówią dlaczego się zepsuło. Bez sensownych logów debugowanie awarii to strzelanie w ciemno.
Podstawowa zasada: structured logging. Nie plain text, nie „console.log(„user logged in”)”, tylko JSON format z polami które można parsować i filtrować. W Node.js to Winston albo Pino. W Python to structlog. W Go to zap.
logger.info("User login attempt", {
userId: user.id,
email: user.email,
ipAddress: req.ip,
userAgent: req.headers["user-agent"],
timestamp: new Date().toISOString()
});
Structured logs można potem łatwo przeszukiwać: wszystkie loginy z specific IP, wszystkie błędy dla specific user, wszystkie requesty które zajęły > 5 sekund. Plain text logi to pain do parsowania.
Co logować: requesty (method, path, status, duration), errory (stacktrace, context), business events (user registered, payment processed), background jobs (started, completed, failed). Czego nie logować: hasła, tokeny, credit card numbers, personal data które nie są potrzebne do debugowania.
Widziałem setup gdzie każdy request logował pełny request body. Brzmi jak dobry pomysł dla debugowania. Problem: request body zawierało PII. Logi były zapisywane bez encryption. RODO violation. Plus log volume wzrósł tak bardzo że logowanie zaczęło spowalniać aplikację. Musieli wyczyścić 3 miesiące logów i zmienić retention policy.
Log aggregation dla multi-server setup to konieczność. Jeśli masz więcej niż jeden serwer to logi muszą być w jednym miejscu. Logtail, Papertrail, CloudWatch Logs, ELK stack. Bez tego jak jest awaria musisz SSH”ować się na każdy serwer i grepować logi ręcznie.
Retention policy zależy od legal requirements i storage costs. RODO mówi że personal data w logach podlega tym samym zasadom co w bazie. Jeśli logujesz email, IP address, user ID to muszą być odpowiednio chronione i usuwane po określonym czasie. Typowo 30-90 dni retention wystarczy dla debugowania. Starsze logi rzadko są potrzebne. Plus storage kosztuje – im dłużej trzymasz, tym więcej płacisz.
Monitoring dla serverless i managed services
Serverless zmienia co i jak trzeba monitorować. Nie masz dostępu do serwera, nie widzisz CPU ani memory na poziomie infrastruktury, nie możesz SSH”ować się i sprawdzać procesów. Monitoring musi działać inaczej.
Vercel ma built-in Analytics i Logs. Wystarczy dla większości Next.js projektów. Widzisz response time, error rate, geographic distribution. CloudWatch dla Lambda pokazuje invocations, duration, errors, throttles. To już jest wystarczające dla basic monitoring.
Problem z serverless to cold starts i distributed tracing. Function może działać szybko ale jak ma cold start to pierwsze wywołanie zajmuje 3 sekundy. Użytkownik widzi opóźnienie. Monitoring pokazuje średnio 200ms response time bo cold start to 1% przypadków ale te 1% generuje complaints. Trzeba śledzić cold start metrics osobno.
Distributed tracing dla serverless to kolejny poziom complexity. Request przechodzi przez API Gateway, Lambda, DynamoDB, SQS, kolejną Lambda. Jak coś jest wolne to trzeba wiedzieć gdzie. AWS X-Ray może to śledzić ale setup nie jest trivial. Dla małych projektów często wystarczy logowanie request ID i śledzenie flow przez logi.
Różnica między serverless a tradycyjnym hostingiem: w serverless nie monitorujesz infrastruktury, monitorujesz functions i services. Nie CPU usage tylko Lambda duration. Nie memory leaks tylko function timeouts. Nie disk space tylko storage limits.
Managed services typu RDS, ElastiCache, SQS mają własny monitoring w CloudWatch. Trzeba go skonfigurować ale metryk jest dużo – database connections, cache hit rate, queue depth. To wszystko może być źródłem problemów i trzeba to obserwować.
"Po kilku miesiącach większość alertów nie opisuje już problemów systemu. Opisuje problemy z konfiguracją alertów."
Incident response: pierwsze 15 minut
Alert przyszedł. Aplikacja nie działa. Co teraz?
Pierwsze 15 minut decyduje czy awaria potrwa godzinę czy 6 godzin. Większość zespołów nie ma zdefiniowanego incident response process. Zaczyna się chaos: jeden developer sprawdza logi, drugi restart”uje serwer, trzeci debuguje lokalnie. Nikt nie wie co inni robią. Nikt nie komunikuje się z klientem.
Prosty checklist dla małego zespołu:
- Jedna osoba bierze lead. Incident commander. Reszta raportuje do tej osoby. Bez tego wszyscy debugują jednocześnie i duplikują pracę.
- Sprawdź uptime monitor i error tracking. Co mówią alerty. Czy to total outage czy degraded performance. Czy problem dotyczy wszystkich użytkowników czy specific region/feature.
- Sprawdź status external services. AWS status page, database provider status, CDN status. Może problem nie jest po twojej stronie.
- Sprawdź recent deployments. Czy coś wdrożone w ostatnich godzinach. Rollback to często najszybsza opcja.
- Sprawdź logi z ostatnich 30 minut. Szukaj errorów, timeoutów, unusual patterns.
- Jak masz diagnozę: fix albo mitigate. Fix jeśli wiesz co jest nie tak i możesz naprawić szybko. Mitigate jeśli fix zajmie długo - rollback, wyłącz broken feature, przełącz na backup.
- Komunikacja z klientem. Jeśli awaria trwa > 15 minut, klient musi wiedzieć. Krótki update: wiemy o problemie, pracujemy nad tym, ETA. Nie obiecuj konkretnej godziny jeśli nie jesteś pewien.
- Post-mortem po awarii. Co się zepsuło, dlaczego, jak naprawiliśmy, jak zapobiec w przyszłości. Nie chodzi o szukanie winnych. Chodzi o uczenie się na błędach.
Podsumowanie
Monitoring dla małych projektów to nie rocket science. To kilka godzin setupu i świadomość że produkcja nie będzie się pilnować sama. Uptime monitoring wyłapuje outage. Error tracking mówi co się psuje w środku. Logi pozwalają zrozumieć dlaczego. Alert rules muszą być skonfigurowane tak żeby nie generować szumu.
Prawdziwy test monitoringu przychodzi w sobotni wieczór kiedy aplikacja padnie i nie będzie nikogo online. Jeśli dowiesz się o tym z alertu w 5 minut – masz sensowny monitoring. Jeśli dowiesz się rano z email od klienta – masz problem do naprawienia.
Zobacz powiązane case studies i analizy
Procesy, architektura i workflow powiązane z tematami poruszanymi w tym materiale – od integracji i realtime systems po automatyzacje operacyjne.