#Logging #Observability #OpenTelemetry #Monitoring
 
“Moim faworytem była firma z 15 poziomami logów. Piętnaście.” Szymon opisuje chaos w organizacjach: zespoły szukają logów w czterech różnych miejscach, Elastic pożera budżety, a deweloperzy dodają logi “na czuja” bez strategii. A Łukasz doprecyzowuje problem: “Logi mają wredną tendencję - tylko je dodajemy, nigdy nie usuwamy.”
Popularne “rozwiązania”? Sampling? “Zawsze będzie złem, bo odsampluje to, czego właśnie potrzebujecie.” Stdout jako standard? “Absolutne zło i ostateczność.” A wewnętrzne dyskusje o nazewnictwie? “Jeżeli macie dyskusję w firmie jak coś nazwać, oznacza to, że pierdolnik będzie kontynuowany.”
Jak z tego wyjść? Rozwiązanie zaczyna się od fundamentów: structured logging w JSON, Open Telemetry jako standard (koniec kłótni o “fatal” vs “critical”), Open Telemetry Collector do wzbogacania i filtrowania. Plus dokument definiujący pola, retencja zamiast samplingu, tenanty zamiast jednego indeksu, budżety zamiast bezładnego logowania wszystkiego.
Czy twoja organizacja tonie w logach, których nikt nie umie czytać? Sprawdź, zanim ktoś doda szesnasty poziom logowania. ⚠️
Linki i ciekawe znaleziska
Transkrypcja
Szymon Warda: Sampling zawsze będzie złem, bo wam odsampluje to, co właśnie potrzebujecie. I sampling jest trudny i realnie jest praktycznie nie do wykonania, żeby to miało ręce i nogi.
Łukasz Kałużny: Jeżeli macie dyskusję w firmie jak coś nazwać, zrobić, oznacza to, że pierdolnik będzie kontynuowany.
Szymon Warda: Jeżeli możemy, zamieniamy new line’y, żeby one jednak były w jednej linii. Ilość nie idzie w parze z jakością. My potrzebujemy logów dobrej jakości, a nie po prostu wszystkiego. Cześć, słuchacie Patoarchitektów. Prowadzą Szymon Warda…
Łukasz Kałużny: I Łukasz Kałużny. Wszystkie linki do tego odcinka znajdziecie na Patoarchitekci.io i prawdopodobnie tu na dole, gdzieś tu pod spodem w opisie, dacie radę.
Szymon Warda: Tak, wierzymy w Was. Dobrze Łukaszu, to informacyjnie, co tam się będzie u nas działo teraz?
Łukasz Kałużny: Tak, zaczynamy z jesiennymi szkoleniami. Na start moja Architektura 101 - 25 listopada, 26, 2 grudnia, 3 grudnia, spotkania poranne po 4 godziny. I to szkolenie będzie przechodziło, porządkowało wiedzę, czym jest architektura. Dlatego Architektura 101, bo dużo osób ma styczność z architekturą, z jej projektowaniem albo aspiruje bardziej do roli architekta. I jest to pokazanie w jaki sposób tą wiedzę ustrukturyzować. Będziemy przechodzić przez fundamenty architektury właśnie czym jest architektura, przez te wszystkie pojęcia, które się pojawiają, jak style architektury, potem przez wzorce budowy systemów. Trochę będzie też o charakterystykach architektury, które są problematyczne, bo z jednej strony bardzo ułatwiają, a z drugiej chcielibyśmy spełnić wszystko. Innym elementem, który cieszy się popularnością w trakcie szkoleń, to jest architektura versus bezpieczeństwo, czyli w jaki sposób rozmawiać z ludźmi od bezpieczeństwa, co mieć na uwadze. Potem też część, która jest, jeżeli ktoś z Was wywodzi się ze świata developerskiego, jest pain in the ass, czyli podstawy architektury sieciowej, jak to rozumieć. Potem takie podejście do build versus buy, czyli kiedy kupować gotowe, jak rozumieć, dlaczego niektórzy wybierają gotowe rozwiązania, a dlaczego niektórzy kalkulują, że skorzystajmy z open source albo zbudujmy własne? Więc podejście do tego, w jaki sposób do tego podchodzić. I do tego wszystkiego na koniec część na temat wybierania stosu aplikacyjnego, technologicznego i odpowiedzenie sobie na pytanie, czy Kubernetes i ekosystem CNCF-u to lekarstwo na wszystkie nasze potrzeby, jeżeli będziemy budować aplikację? I warto też dorzucić, że w całości jest sporo takich ćwiczeń grupowych, żeby pokazać, bo w pracy architekta istotne jest to, że jednak postępuje ta wymiana wiedzy i interakcji, więc mamy dużo ćwiczeń w postaci tak zwanych Architectural Kata, gdzie dostajemy małe zagadnienie, 40 minut i grupowo je projektujemy, a potem wspólnie te wszystkie elementy omawiamy. Więc jest parę takich ćwiczeń w trakcie tych spotkań, na których właśnie będzie okazja od razu do sprawdzania tej wiedzy i testowania tego i dostania od razu feedbacku.
Szymon Warda: Myślę sobie to jest szkolenie, które trochę porządkuje temat, który ja często widzę z ludźmi rozmawiając właśnie, którzy awansowali do roli architekta, mianowicie uporządkowania, co ja właściwie w organizacji powinienem robić? Jaka jest moja rola? Jakich narzędzi w ogóle, co, czym się posługiwać i jakie cele mam sobie wyznaczać? Tak trochę mentalnie porządkuje co i jak.
Łukasz Kałużny: Dobra Szymonie, Twoje jest kolejne.
Szymon Warda: Moje jest kolejne, tak. Jest to Observability ze stosem Grafana i to jest z taką gwiazdką, bo ten stos Grafana sobie wliczamy w Prometheus’za. I o czym to jest szkolenie? To jest takie trochę szkolenie, które zostało skrócone, bo wcześniej mieliśmy to dwudniowe i tym razem… Czego tam nie będzie? Może tego zacznijmy. Zakładamy, że już mniej więcej jakąś tam wiedzę macie o tym, po co w ogóle monitorować, czym jest observabili i tak dalej. I to jest takie czysto techniczne szkolenie, które skupia się na tym, jak używać narzędzi grafanowych, plus Prometheus’z oczywiście. Skupia się na kilku rzeczach. Po pierwsze, omawiamy sobie architekturę, ona jest bardzo ważna, jeżeli chodzi o nawet składnie, jak ona potem działa, jak się zachowuje i tak dalej. I zrozumienie tego jest bardzo, bardzo ważne. To nie są narzędzia typu Elastic, że sobie wpisujemy, error i działa, działa póki działa w sumie. Pierwsza rzecz, do której przychodzimy to jest Loki, czyli mianowicie system do agregacji logów i dużej agregacji logów, który skaluje się fenomenalnie i jest tani w utrzymaniu. Jednak UI i język kwerend nie jest taki intuicyjny jakby to mogło być. Ale po przejściu przez ten próg bólu i zrozumienia z czego to wynika, to już zaczyna być dość intuicyjne i można się tym ładnie posługiwać. Tam przede wszystkim duży, bardzo duży nacisk właśnie na składnię, ponieważ ona bardzo mocno wpływa właśnie na wydajność, a potem finalnie na nasze zadowolenie w ogóle z Loki. Sposoby zbierania i warsztaty (…) cały dzień, tam jest dość niewiele mojego mówienia. Dobrze, dalej przechodzimy przez kolejną bajkę, czyli Prometheus’z. Prometheus’z podobnie, jeżeli chodzi, mówimy o (…), które omawiamy sobie, jak to w ogóle działa? Ten sam problem, który występuje też w Loki, czyli mianowicie czym jest w ogóle kardynalność i jak się wiąże labelowanie, jak dobrze labelować, jakie są ryzyka złego labelowania, czyli właśnie eksplozja kardynalności. Przechodzimy przez całego prompt wella, czyli język zapytań od dość prostych, zrozumienie, czym są wektory czasowe, bo one są dość kluczowe i zrozumienie właśnie, omówienie jakie są metryki i zrozumienie, czemu właśnie w większości kwerend widzimy, będziemy mieli sumę od rate’a albo sumę od inkrementa i tego typu operacje i jak Prometheus’z ogarnia przerwy w zestawie. Jakie są konsekwencje wykorzystywania w ogóle push pull, zbierania metryk? A na końcu rzecz, którą ja osobiście bardzo lubię, ale która z reguły jest takim trochę rozczarowaniem, z mojej strony w sumie też trochę, w takim prostym wykorzystaniu, czyli mianowicie Tempo, czyli zbieranie trace’ów. I czemu z rozczarowaniem? Bo Tempo jest (…) system, bardzo fajnie działa. Jest to system z reguły zbudowany dla developerów w obecnej wersji, a cała agregacja tak naprawdę, to już musimy sobie z reguły napisać na boku. Oczywiście mówimy jak zrobić, żeby mieć dane zagregowane, mieć dane raportowe z tego, jak wykorzystać, jak zrobić dobrze trace’y. I przechodzimy sobie też dość mimo wszystko dość prosty, ale całkiem, całkiem przyjemny język zapytań właśnie dla trace’ów, czyli dla Tempo. I tak to się zamyka. Bardzo, bardzo mocny nacisk właśnie na część techniczną. I to jest szkolenie, po którym wychodzicie i znacie składnię w pełni praktycznie. No więc tyle, zapraszam. Łukasz, Ty masz jeszcze jedno.
Łukasz Kałużny: Tak, 16 grudnia i będzie to Kubernetes The Hard Way. Czyli sposób, żeby zobaczyć jak Kubernetes działa pod spodem, jeżeli chodzi o infrastrukturę, logikę komponentów, ich komunikację. I tutaj założenie jest takie, że omawiamy już bardziej w detalach architekturę klastra, Kubernetes jest pod spodem, co się dzieje i potem każdy z uczestników na przygotowanym labie dostaje gołe wirtualki i będziemy wspólnie stawiać Kubernetesa z binarek od podszewki, zaczynając od przygotowania wszystkich configów, certyfikatów. Więc zaczynamy od przygotowania sobie narzędzi, budowy własnego load balancer’a, następnie postawienie całego CA i wygenerowanie wszystkich certyfikatów do mTLS-a. Przechodzimy potem pod przygotowanie sobie szyfrowania etcd. Przechodzimy potem do robienia, stawiania ręcznie control plane’ów z binarek, potem odpalenie całych węzłów Kubernetes’owych, przygotowanie sobie configów pod kubectl’a, gdzie potem pójdziemy pod budowę tutaj całego stosu sieciowego, czyli kawałek własnego prostego CNI-a, w jaki sposób z tych gotowych komponentów poskładać. Co tam jeszcze jest? A, odpalimy DNS-a, potem testy wysokiej dostępności, trochę troubleshootingu, symulacji awarii i na koniec do tego wszystkiego jeszcze rozbudowujemy nasz load balancer o to, żeby on też był wysoko dostępny. I na koniec jeszcze dorzucamy On Top of Ingress Controller. I po całym dniu wiecie gdzie te elementy w Kubernetes’ie są, co za co odpowiada tak naprawdę i dziękujcie w większości przypadków, tak jak jest jeden z tych komentarzy, że docenia już teraz Azure AKS-a, że nie musi się z tym męczyć i utrzymywać tego. Więc można zobaczyć cały flow, jak wygląda pod spodem Kubernetes, ile jest tam decyzji. I z drugiej strony, jeżeli uważamy, że coś jest nielogiczne w Kubernetes’ie albo głupie, można też zrozumieć, z czego to dokładnie się wywodzi. Tutaj od razu taka podpowiedź, trzeba patrzeć na Kubernetes’a jak na cepa i wtedy od razu wiemy dlaczego coś nielogicznego jest bardzo logiczne.
Szymon Warda: Tak, dokładnie, poznać z czego wynikała decyzja, żeby zrozumieć dlaczego właśnie została taka podjęta. Dobrze, to tyle z parafialek tak naprawdę. To lecimy. O czym dzisiaj?
Łukasz Kałużny: Dzisiaj, Szymonie, chcę Cię przepytać z logów, bo pojawiło się gdzieś tam na zaprzyjaźnionym Discordzie pytanie też tam i dyskusję o logi. Nie oszukujmy się, to co widzimy, to Twoja działka najczęściej, to widzisz bałagan z nimi. Jaki jest główny problem z logami?
Szymon Warda: Główny problem z logami, są właściwie dwa problemy. Pierwsze to jest to, że jest ich za dużo i po prostu organizacja zaczyna tonąć od ilości, od kosztów ich utrzymania. Elastic szczególnie z tym, nie oszukujmy się, bo to jest ten główny element. Drugi element to jest to, że okej, mamy logi i właściwie nie umiemy z nich korzystać tak naprawdę. To jest szukanie zagrożenia, ale dosłownie na pałę, byle coś znaleźć i jest to taka próba łowienia. I jeżeli jest potrzeba, to właściwie z logów ciężko nam jest wywnioskować, co się właściwie stało i jak się stało i co było powodem. A finalnie tak naprawdę to trzeba znaleźć z reguły developera od konkretnego systemu, żeby on przypomniał, zrozumiał i wyszukał logi, które mogą pomóc w debugowaniu odpowiedniej sekcji.
Łukasz Kałużny: Tak, u naszego jednego klienta ogarnęło mnie trochę przerażenie, że w trakcie, mieliśmy jakieś tam prace serwisowe grubszej zmiany w infrze i kiedy ludzie z zespołów aplikacyjnych szukali w czterech różnych miejscach logów, czy we wszystkich komponent działa. I to jest przerażające.
Szymon Warda: Albo na przykład stwierdzają, że: nie, to trzeba zmienić poziom logowania, bo ta wiadomość pewnie jest na innym poziomie.
Łukasz Kałużny: Dobra, słuchaj, to teraz tak, to jest rzecz, o którą się trochę kłócimy, trochę zgadzamy, ale słuchaj, jakie mamy rodzaje logów, jeżeli teraz popatrzysz?
Szymon Warda: Dobrze, to pójdźmy o tych, gdzie się zgadzamy. Mamy tak, aplikacyjne, czyli te rzeczy, które wysyłają nasze aplikacje. Zgadzamy się? Tak, zgadzamy się, dobrze bardzo mocno. Systemowe, czyli mamy takie typowe infrastrukturalne, czyli co tam się wydarzyło, nasz klaster Kubernetesowy co loguje na przykład.
Łukasz Kałużny: Tak. Co leci na stdout’a, bo to są logi, które powinny trafiać na stdout’a i co powiedzieć szybko: aplikacja żyje, nie żyje, nie było stack trace’ów.
Szymon Warda: Dobrze, to teraz zasieję takie ziarenko zapytania, logi na przykład z naszego Ingressa, albo z naszego Mongo, albo z takich typowo aplikacyjnych komponentów z naszej infrastruktury. Gdzie je zaliczysz?
Łukasz Kałużny: Wiesz co, one pójdą sobie do… Właśnie i widzisz i teraz jest problem, bo Ingress to są logi dostępowe zazwyczaj, bo to jest access, to jest access control zazwyczaj, to są rzeczy, które są albo dostępowe, albo bezpieczeństwa. A tak jak powiedziałeś, rzuciłeś Mongo, to raczej jest to, co wypluwa Mongo, to jest systemówka.
Szymon Warda: Tak, to by znowu implikowało, że w tym momencie potencjalnie na przykład patrzy na to już nie developerzy, tylko patrzy na to bardziej OPS-i, admini i tak dalej.
Łukasz Kałużny: Raczej każdy z nich może to oglądać. To jest problem.
Szymon Warda: Ja bym to powiedział tak, ci, którzy chcieli wdrożyć i jeszcze nie przekazali do platformy, ci na te logi patrzą. Poważnie, bo tak to powinno działać, każdy może sobie… Okej, chcesz mieć jakiś system inny, to teraz go utrzymuj. Dobrze, idziemy kawałek dalej. Ruszyłeś dostępowe, więc faktycznie mamy. Mamy cały element Ingressa, który nam wchodzi, jak najbardziej. Wiemy co weszło, jak weszło, to jest kluczowe, przede wszystkim to potem będzie przy liczeniu jakiegoś tam SLA, jeżeli nie mamy metryk. Może tak się zdarzyć. Idziemy dalej. Bezpieczeństwo. Kto się zalogował, kiedy się zalogował, w jakiej roli i co zrobił. Mnie to…
Łukasz Kałużny: Typowa audytówka.
Szymon Warda: Tak. Teraz mamy taki element, który już jest trochę rozmyty, bo to nazwałem przez takie logi biznesowe, czyli żeby śledzić zdarzenia biznesowe. Ja bym tu już wchodził: a weź sobie użyj metryk.
Łukasz Kałużny: Właśnie, bo zobacz, jest teraz tak, to jest ten problem, który jak sobie popatrzymy, aplikacyjne versus biznesowe. I to jest bardzo duży problem, bo zwykle potem to, co powiedziałeś o tym pierdolniku, ja zawsze oglądam, że logi techniczne są wymieszane z logami biznesowymi i to jest jeden wielki pierdolnik.
Szymon Warda: Nie jest wymieszane. My próbujemy wywnioskować zdarzenia biznesowe z logów technicznych.
Łukasz Kałużny: Właśnie, wiesz i teraz jest pytanie czy to są statusy, które są jednak rzeczą, które są w produkcie, w naszych, czy to powinny być logi tak naprawdę, czy to są jednak eventy, które są w naszym stanie aplikacji?
Szymon Warda: Dla mnie to jest taka opcja. Jeżeli to jest tylko takie, żeby zorientować się, jak to wygląda, okej, używamy metryk. Jeżeli to ma być coś, z czego rozliczamy, z całym szacunkiem, zapisujemy to do jakiejś bazy i mamy jakieś kwerendy, które nam to wyliczają, jeżeli chcę mieć absolutne źródło prawdy. To zarówno logi, może zdarzyć się, że coś się zgubi, tak samo i metryki, może zdarzyć się, że gdzieś się machniemy, coś się wydarzy. Więc dla mnie tak zwane logi biznesowe nie mają obecnie za bardzo zastosowania w systemach. To powinno, wylatuje do metryk.
Łukasz Kałużny: I wylatuje do bazy danych, tam gdzie to się dzieje, ten proces.
Szymon Warda: Tak, gdzie mamy jakieś, właśnie jakieś zapytania, jakąś raportówkę, jeżeli tego potrzebujemy. Dobra. I na końcu diagnostyka, która znowu, kolejny element dla mnie do ubicia, to powinny być trace’y, koniec, kropka.
Łukasz Kałużny: Tak, czyli jakieś szczegółowe i włączane on demand raczej niż… Dla mnie to jest problem, że dla mnie to jest stara szkoła, że domyślnie trace debug jest włączany kiedy jest potrzebny albo jest składowany króciutko.
Szymon Warda: O właśnie i do tego dojdziemy, bo na naszym Discordzie była uwaga odnośnie, że nie poruszyliśmy tematu samplingu. Nie róbcie samplingu, logujcie, tylko miejcie krótszą retencję. Sampling zawsze będzie złem, bo Wam odsampluje to, co potrzebujecie. I sampling jest trudny i realnie jest praktycznie nie do wykonania, żeby to miało ręce i nogi. A jak macie awarię to potrzebujecie mieć wszystkiego praktycznie, więc dawajcie bardzo krótką retencję. I teraz to jest moment, kiedy powiedziałeś o tym, że aplikacje, kiedy logują. Tak i to właśnie jest bardzo ważne do powiedzenia, z któregomy kontekstu patrzymy. Bo teraz patrzymy z kontekstu tego, jak oglądamy te logi, a nie jak te logi wysyłamy. Bo dochodzimy teraz do tego, że mamy takie zabawki, jak na przykład Open Telemetry Collector, który może filtrować logi, więc aplikacja może logować więcej niż potrzebuje, a my potem pewne rzeczy ucinamy. Więc możesz taki Open Telemetry Collector zrobić, albo Grafanę Alloy. Możemy dynamicznie, bez restartu ich zmienić konfigurację i nagle zacząć wysyłać wszystkie logi i je zbierać. To jest dopiero fajna zabawka. Więc aplikacja będzie wymagała restartu, nie oszukujmy się, z reguły, albo będziemy jakieś mieli feature flagi na logowania, a to nie ma żadnego sensu powiedzmy sobie, to jest dużo roboty za mały zysk.
Łukasz Kałużny: Dobra Szymon, i teraz tak, jeżeli mówimy o sprzątaniu. Czyli zastajemy pierdolnik w organizacji, jeżeli na to popatrzymy, to jak wygląda sprzątanie tego?
Szymon Warda: Dobra, sprzątanie rozkładamy na kilka poziomów. Najważniejsze to powiedzieć sobie, co w ogóle możemy posprzątać. Mianowicie pogodzenie się z tym, że pewne logi będą bałaganem po prostu. Ale możemy ograniczyć ilość logów, które są bałaganem i to jest ważne tak naprawdę. Zaczynamy przede wszystkim od tego, żeby ustalić, jaki mamy format logów. I teraz co jest ważne? Bo i też jak te aplikacje mogą wysyłać. I tu idziemy dwojako, bo pierwszy element, gdzie ja polecam, to jest przejście na to, żeby aplikacje zaczęły wysyłać do naszego systemu logowania pośrednio czy bezpośrednio nasze logi. Czemu? Bo daje nam to możliwość używania logów ustrukturyzowanych. Jak mamy logi strukturyzowane, najlepiej JSON, nie oszukujmy się, to się sprawdzi najlepiej, to możemy jawnie określić, które pola są i które pola jak będą nazywane i jak się znajdą w naszym systemie do zbierania logów. To jest bardzo ważne. To jest też bardzo ważna rzecz, nie zawsze jest to, że aplikacja wszystko wie. Niektóre logi będziemy wzbogacali o pewne labele, więc też musimy określić na przykład co my chcemy mieć w naszym systemie do zbierania logów i co aplikacja nam może wysłać. I potem dalej tą dziurę, gdzie nam czegoś brakuje, określamy gdzie to możemy wzbogacić. To jest super ważne. Więc określamy tak naprawdę gdzie logujemy i godzimy się z drugim faktem, że pewne logi, jeżeli mówimy, że aplikacja będzie wysyłała, pewne logi będziemy musieli scrape’ować z stdouta i określamy dokładnie w jakiej sytuacji te logi, które będą dużo gorszej jakości, mają być wysyłane. Czyli mówimy prosto: tylko w sytuacjach krytycznych jak nie możemy wysłać, w sytuacjach jak nie mamy połączenia z systemem centralnym, jak nam się komponenty zewnętrzne wywaliły, to jest ostateczność. Więc wprowadzamy pewną formę (…) zamordyzmu, no sorry, tak po prostu musi być.
Łukasz Kałużny: Jak popatrzymy to to, co mówisz, to stdout to jest miejsce na logi systemowe, żeby szybko podejrzeć co się dzieje, co jest nie tak, a nie na tą część aplikacyjną.
Szymon Warda: Bardziej dla mnie to jest taka ostateczność, że jeżeli coś się pojawiło na stdout’cie to znaczy, że mamy już problem.
Łukasz Kałużny: Więc wiesz, ja trochę też patrzę z perspektywy OPS-owej, że coś mi się konkretnie gdzieś grzeje, to pójdę, zobaczę logi na podzie od instancji na przykład w tym, że to jest takie miejsce, z perspektywy osoby utrzymującej, do szybkiego również sprawdzenia tego, co się dzieje w niektórych miejscach.
Szymon Warda: To pójdziemy teraz całą długą dyskusję odnośnie wejścia na pod’a generalnie i kto tam może wejść. Z perspektywy OPS-owej, tak, częściowo, bo w tym momencie OPS nie zna kodu aplikacji, nie zna samych logów aplikacji, więc generalnie jeżeli coś będzie widział w logach aplikacji, to już tam generalnie znaczy, że jest niewesoło, powiedzmy sobie szczerze. Developer nie powinien wchodzić na stdout’a.
Łukasz Kałużny: Tak.
Szymon Warda: Tak, to już jest (…). Dobra, wspomnieliśmy odnośnie samego wysyłania i dla mnie to jest określenie elementu, który będzie ważny. Bo jeżeli mówimy, że aplikacja musi, znaczy powinna wysyłać logi do systemu, to w tym momencie poruszamy temat: to do czego ona wysyła? Bo możemy ustalić tak, jeżeli mamy mały system, mały wolumen, to wysyłajmy do tego naszego systemu docelowego. Jeżeli to jest jakaś, załóżmy, nie wiem, nawet jakaś usługa, nie wiem, niech to będzie jakiś Elastic, Loki i tak dalej, nie bawmy się. Bierzemy Sync’a czy jakiegoś writera, który umie komunikować się po naszym protokole, pewnie będzie to Open Telemetry, będzie jakiś tam właściwy protokół do komunikacji z naszym systemem do zbierania logów i tam wysyłamy bezpośrednio, nie bawimy się z tym. Zabawa zaczyna się właśnie w sytuacji, jak mamy średni wolumen i duży wolumen, bo w tym momencie wchodzi nam buforowanie, kilka (…), buforowanie i batchowanie. O co chodzi? Czym się one od siebie różnią? Buforowanie, to znaczy, że nasz system do zbierania logów może mieć czkawkę, może być niedostępny, więc musimy gdzieś ten bufor mieć. To właśnie pełni. Tu rolę mamy dwojaką, my widujemy często właściwie Kafkę, bo jak nie wiadomo co zrobić, to trzeba użyć Kafki. Ja bym polecał może jednak nie do końca z prostego powodu, mamy właśnie Open Telemetry Collector, mamy Grafanę Alloy, które umieją buforować, umieją tą rolę spełniać. (…) to jest to, że też mogą batchować. Czyli nie wysyłać logów per linie, tylko wysyłamy w tym momencie logi w samych batchach. Zyskujemy oczywiście dużą wydajność i zyskujemy lepsze utrzymanie, lepszą jakość i tak dalej. A teraz jeszcze czemu mamy tylko tego Alloya albo Open Telemetry Collectora? Bo możemy w tym momencie wzbogacać te nasze logi, możemy dodawać labele, pola które nas interesują i tak dalej, o których często nawet aplikacja może nie wiedzieć. Możemy filtrować i też możemy pilnować. To jest nasze narzędzie z poziomu na przykład OPS-ów i naszej platformy, gdzie pilnujemy, czy te logi są dobre i nie dopuszczamy na przykład tego całego bałaganu, który nam się nagle pojawi w naszym systemie do logowania i możemy robić dużo, dużo wcześniej tak naprawdę. Mamy polityki na przykład na Collectorze, one się nazywają dev test i (…) czy po prostu nie przypuszczamy. Załóżmy że ktoś użył fatal, a my ustaliliśmy, że pole nazywa się critical, poziom logów. Śmiejesz się Łukasz. Ile razy widziałeś ora gdzie ktoś szukał fatal albo critical?
Łukasz Kałużny: No jest takie coś. Ja wiem, bo to są… Tak to jest problem.
Szymon Warda: (…) że jak się pali to ktoś tego ora zapomni dać i nagle części logów nie widać.
Łukasz Kałużny: Wiem, nie, wiem, inaczej, to jest, ja się z tego śmieję, ale jest to prawda Szymon. To jest prawdziwy, napisane krwią i dupogodzinami oglądania takich przypadków. Albo troubleshooting tego… Inaczej, dla mnie z tym poziomem, albo jeszcze nadawanie jakichś własnych custom poziomów. Wiesz, że takie, widziałeś takie rzeczy, że ktoś uważał, że musi mieć swojego płatka śniegu dedykowanego.
Szymon Warda: Moim faworytem było, jak firma ma 15 poziomów logów. 15. Piękna sprawa po prostu bym powiedział. Dobra, ustaliliśmy kilka rzeczy. Dalej, jak już zaczęliśmy takie typowe podstawy podstaw, kolejna rzecz, ustalenie w jakim formacie jest ta data i w jakim czasie jest ta data. Doskonale wiesz, że ile razy jest sytuacji, gdzie odpytujesz się o logi, jest pytanie: ej, ale logujemy tu w UTC czy w czasie lokalnym? Przecież to jest… A najlepiej jest to, jak mamy jeden system loguje w UTC, a inny w czasie lokalnym.
Łukasz Kałużny: Tak.
Szymon Warda: To są rzeczy drobne. Tu nie będziemy mówić o żadnych rewolucjach, ale to są rzeczy, które jak macie awarie i jest to ułożone, to oszczędzacie naprawdę godziny czasami. Dobra, więc przeszliśmy dość płynnie do tego. Musimy ustalić, jakie pola mają znajdować się w systemie do zbierania logów. Niekoniecznie to są pola, które aplikacja loguje. Fajnie, gdyby aplikacja logowała jak najwięcej z nich, ale nie muszą. Idziemy po kolei. Data, oczywiście jest pierwszy. Kolejny, poziom, ustalenie nazw tych poziomów. To jest naprawdę ważne.
Łukasz Kałużny: Jeżeli masz dyskusję, oznacza to, że należy wrócić do standardu na przykład z Open Telemetry i nie dyskutować. I to jest nasza polecajka. Jeżeli macie dyskusję w firmie, jak coś nazwać, zrobić, oznacza to, że pierdolnik będzie kontynuowany i bierzemy na przykład właśnie standard z Open Telemetry.
Szymon Warda: Tak, bo to zamyka w ogóle tą dyskusję o tym, kto jest mądrzejszy, kto co wymyślił i odcięcie się od: to jest…
Łukasz Kałużny: Nasze.
Szymon Warda: Moja prawda jest mojsza, Twoja jest twojsza generalnie tak naprawdę i używamy czegoś zewnętrznego. W każdej opcji ustalenia standardów wspieranie się czymś zewnętrznym jest super pomysłem, rozwiązuje większość konfliktów. Dobra, dalsza opcja, określamy typ. Jak już aplikacja loguje, to określamy czy to mamy jakieś, powiedzmy, czy to są audytowe? Z tym jest pewien problem, bo najlepiej w ogóle gdyby audytowe były w innym strumieniu w ogóle wysyłane, inaczej filtrowane.
Łukasz Kałużny: Tak, to jest w ogóle rzecz, o którą się tam można pokłócić. Jeżeli zrobimy prawidłowo event sourcing, to logi…
Szymon Warda: Łukasz, wszędzie był outsourcing.
Łukasz Kałużny: Tak, ale to wiesz, to jest też, wychodzi na to, że ten log audytowy z tego, co się działo w systemie, też w niektórych miejscach zmian na obiektach mógłby być spokojnie w bazie danych, a nie aplikacji.
Szymon Warda: Ale nie zawsze jest, tak to bywa. Czy to jest (…) aplikacyjne? Nie, więc bywa. Dalej, kolejne w sumie staje się opcjonalne, bo ono jest zależne od tego, jak mamy ułożone środowisko. Jeżeli mamy system do zbierania logów per środowisko, to to pole po prostu omijamy. Nie ma sensu, żeby to pole było wszędzie takie samo.
Łukasz Kałużny: Tak, ewentualnie Szymon bym dorzucił, jeżeli tak jak w Lokim mamy tenanty.
Szymon Warda: O, i tak za chwilę powiemy, jak to w ogóle podzielić, bo to jest też bardzo, bardzo ważna rzecz.
Łukasz Kałużny: Tak, jeżeli nasz system do logowania używa tenantów, to też wtedy te pole staje się opcjonalne.
Szymon Warda: Tak. Kolejne pole to jest service name. I kolejna dyskusja, żeby była i… Co się śmiejesz? Ile razy widziałeś sytuację, gdzie część zespołów, gdzie serwis nazywa się czasami tak, czasami tak?
Łukasz Kałużny: Słuchaj, takich problemów z nazwami i nieposiadaniem wspólnego nazewnictwa to widziałem o wiele gorszych. Jest on standardowy, że ludzie mylą. My używamy tego serwisu i nazywamy go tak, a zespół, który dostarcza ten serwis nazywa go zupełnie inaczej.
Szymon Warda: Tak, tak, dokładnie. Więc moja propozycja to jest taka mała, drobna rzecz. Pamiętajcie, że label, że możecie część metadanych z Kubernetesa przekazywać i wstrzykiwać jako environment variable do pod’ów, żeby też aplikacja wiedziała, jak się nazywa. I to się przydaje, żeby aplikacja generalnie logując logowała pod nazwą, która jest. Pierdoła, cieszy i to też pokazuje widoczność, co jest źródłem prawdy. Dobra, idziemy dalej. Trace ID, Span ID, te dwie rzeczy nie trzeba tłumaczyć, bo chcemy czasami znaleźć wszystkie logi odnośnie trace’a, czyli całego procesu i logi odnośnie spana, czyli czynności.
Łukasz Kałużny: Czyli jak popatrzymy sobie, tak, trace właśnie i teraz, bo wrzuciłeś jeszcze Parent Trace ID. I to jest taki problem, który jest, czy my powinniśmy mieć 1 kontekst ID zrobione na cały taki właśnie, request ID, żeby prześledzić cały, czy jak to się powinno ułożyć?
Łukasz Kałużny: Właśnie i teraz dobrze, że powiedziałeś, że to… Nie powiedziałem o tym na starcie z prostego bardzo powodu, to jest trochę opcjonalne, zależy jaką mamy granularność tych trace’ów. Fajnie byłoby widzieć załóżmy Parent Trace… Czemu? Czemu to tu jest dodane? Bo nie mamy w logach wyszukania tej hierarchii tak naprawdę. A na przykład chcemy wiedzieć jak wygląda trace powiedzmy z całego procesowania naszego requestu. No i teraz to nie jest Trace ID, bo ten Trace ID można zrobić przez połączenie service i trace, ale czasami potrzebujemy większej agregacji. Więc jeżeli macie dość drobno rozbite trace’y, ponad ten poziom, który jest domyślny, to rozważenie Parent Trace ID pod dyskusję.
Łukasz Kałużny: I propagacji.
Szymon Warda: I propagacji, dokładnie. Idziemy dalej. Wiadomość, czyli co się w ogóle wydarzyło? Taki, żeby dało się odczytać. Albo to też może być ten message z errora. I na końcu lecimy właśnie taki error, który też jest stackiem tak naprawdę. Czmu jest na końcu? Bo on z reguły najczęściej się rozjeżdża. I tu super ważne. Jeżeli możemy zamieniamy new line’y, żeby one jednak były w jednej linii. Ktoś pomyśli: ale (…) czy coś? Tak, będziemy czytać. Ale w sytuacji jeżeli nie wiecie czy czego się udało zrobić i będziemy musieli wypisać ten error na stdout’, co nam się logi nie rozjeżdżą, bo stdout z reguły parsuje per nowa linia.
Łukasz Kałużny: Znaczy nie, standardowa klasyka: jak obsłużyć multiline’a, żeby nie został rozjechany?
Szymon Warda: Nie da się. To są godziny, naprawdę dziesiątki osobogodzin na pisanie jakichś regexów, które wałkują kolejny przykład kolejnego new line’a.
Łukasz Kałużny: Ja wiem, chciałem powiedzieć, że ludzie będą się kłócić w komentarzach pewnie, bo to jest znane, że w tym. Zawsze dla… Nie osiągniemy tego generycznie.
Szymon Warda: Więc jeżeli możemy, pozbądźmy się tego po prostu. To jest najlepszy scenariusz. A potem możemy to już w sytuacji, w której otrzymaliśmy logi, to możemy tam już sobie ładnie te new line’y porozbijać i to możemy spokojnie obsłużyć. Dobra, jak już mamy pola, to przekląłbym, ale nie będziemy tego robili, ustalamy sobie, zakladamy sobie repo, gdzie wpisujemy które pole co znaczy, żeby to nie było ustalone na mordę tu i teraz, że tak powiem. I tam ma być jasne, jak to się zmieni i tak dalej. To jest szczególnie o tyle ważne, że te pola będą się zmieniały, będą dochodziły nam pola konkretne, biznesowe. Niektóre zespoły będą miały konkretne swoje osobne pola. Czemu? To powiemy za chwilę. Więc to musi być udokumentowane, które pole co znaczy. Dobrze, idziemy dalej. To już taka trochę bajka, trochę moja, trochę Twoja, czyli ustalamy jawnie, bo (…) jest komunikacja, z czego zbieramy te logi.
Łukasz Kałużny: I teraz to jest kurde duży problem, jak sobie popatrzymy, bo wszyscy powiedzą, żeby zbierać ze wszystkiego.
Szymon Warda: Ta, jasne.
Łukasz Kałużny: Musimy mieć wszystko. Inaczej, po pierwszej awarii manager wygląda jak… Szymon, mam bardzo dobre porównanie, jest taka słynna scena w Hollywood “give me everyone” po kresce w łazience. I tak wygląda manager, który mówi, że chce mieć wszystkie logi, żeby potem troubleshootować.
Szymon Warda: A to jest to pytanie, ok. Czy chcesz mieć w takim razie logi systemowe z Windowsa? Jak załóżmy mamy Windowsa. Czy chcesz mieć event loga windowsowego? I nagle jest: o tym nie pomyślałem. Logi wszystkiego to naprawdę jest bardzo dużo logów, do których z reguły nie mamy żadnej potrzeby użycia. Więc musi być jasno określone co my właściwie zbieramy. I żeby potem nie było smutków i określenie też… Bo To jest kompromis kosztowy mimo wszystko i kompromis wydajnościowy, nie oszukujmy się, tak to wygląda. Architektura, to cały czas na Twoich szkoleniach, jest kompromisem.
Łukasz Kałużny: Dobra.
Szymon Warda: Dobra.
Łukasz Kałużny: Czyli mamy sobie co? Zbieramy, obowiązek to są logi z aplikacji, to jest pierwsza rzecz. Druga, to są części infrastruktury aplikacyjnej. I kurde, i to będzie już to tak, z mojej działki patrząc się na to, to też jest problem. Bo tak jak rzuciłeś (…) zapisałeś przykłady, dobra. Z Ingress kontrolerów jest to must have, żeby potem też tam dojść, coś troubleshotować. Z drugiej strony logi z bazy. No i tutaj będzie taka… W większości przypadków logi na przykład z dużej części infry, na przykład developerowi one nic nie powiedzą i w żaden sposób… Jedyna jaką korelację złapiesz, jakbyś chciał zrobić mega kwerendę, to zauważ, że Twoja piękna strukturyzacja się rozwali w pył.
Szymon Warda: Oczywiście, że tak.
Łukasz Kałużny: Tak. I jedyną rzeczą, którą zrobisz, to korelację linijek po czasie.
Szymon Warda: Wiesz co, mi bardziej chodzi o coś innego. Że na przykład dowiedziałem się na przykład po czasie, załóżmy (…) wpisu, że na przykład baza jest, baza na przykład ma, raportuje, że ma opóźnienia w zapisach. A widzieliśmy na przykład klientów, którym wyleciał cały klaster, bo mieli problemy z macierzami, o których nie wiedzieli.
Łukasz Kałużny: Tak.
Szymon Warda: I to jest takie wyłapanie, nie chodzi mi oczywiście o łapanie, że na poziomie bazy, że coś tam, ktoś się zalogował i tak dalej, tylko wyłapanie jakichś sytuacji, które jak zobaczymy, to nagle doskonale wiemy, co jest powodem. Zaóżmy że indeksy mu się rozjechały. Na przykład mimo że ma problemy z komunikacją, z replikami, też bardzo ważny błąd, ma problemy na przykład, że jest under memory pressure, że tak powiem, tak one są z reguły raportowane. Taki zestaw błędów tych właśnie infrastruktury aplikacyjnej, które nagle mówią dużo. Dobra. Potem dalej, jeżeli mówimy o Kubernetesie, to wiadomo, logi systemowe z node’ów, co tam się w ogóle dzieje i jak one się zachowują, też się przydaje, żeby też wiedzieć, czy nie są (…).
Łukasz Kałużny: Dobra, dojdziemy do tenantów i rozdzielania tego, bo to jest ciekawa sprawa w tym miejscu potem.
Szymon Warda: Tak. Dobra, mamy tyle znowu z rzeczy małych, drobnych, o których właściwie by się nie pomyślało. To jest formatowanie. Ustalamy. Jest to JSON, jest to UTF i jest to w jednej linii i koniec. Tak, tu nie ma co prowadzić większej dyskusji tak naprawdę. Szczególnie ta jedna linia. Naprawdę, jeżeli możemy to formatujemy to do jednej linii. To jest prosty replace na jakimś tekście, żeby to było w szczególności z trasy. I to naprawdę nieraz uratuje życie, jak głównie w sytuacji, jak się aplikacja wywali i będziemy po prostu obsrany mówiąc bardzo prosta, dobra, dobra rzecz do ustalenia też. I to jest bardziej taka praktyka dla developerów. Zapis jest asynchroniczny i dlatego się między innymi nie piszemy na terminal, bo terminal jest zapisem asynchronicznym i bardzo zwolnić, ale żeby ustalenie, żeby deweloperzy nie pada. Pomysł, że wysyła teologii powiedzmy po Open Letter Protocol czy czymkolwiek innym i czeka na ten zapis, tam wszędzie ma być asynchroni. Dobra, odnośnie samego wysyłania już mówiliśmy, to po prostu, że to jest bardzo, bardzo ważne. Mały wolumen, możemy całą architekturę ominąć, spoko, wysyłamy do jakiegoś tam systemu. Jeżeli mamy cokolwiek więcej niż aplikacja (…) przez kilka osób, nie jest to jakieś krytyczne, to właśnie dajemy tego Open Telemetry Collectora, Alloy’a, jak bardzo nie możemy, to najwyżej Kafkę dorzućmy, ale cokolwiek niech tam po drodze będzie. I teraz, żeby też było jasne, dorzuciliśmy, to już nie jest super szczęście, tylko wtedy pamiętajmy, że jeżeli aplikacja wysyła, to ma pewne obowiązki, jeżeli chodzi o wysyłanie. Ona też musi mieć retry, powtarzanie, też musi mieć jakieś buforowanie i raportowanie też, wypisywanie, że nie mogła się skomunikować i jak się nie mogła skomunikować, to te logi wypisuje na stdout’a w razie czego, żeby nie było tylko, że aplikacja zareaguje: nie mogę połączyć się z Open Telemetry Collectorem, ale to logi, to tam właściwie trudno się mówi i już ich nie zobaczysz. Super, fajnie, ale przydałoby się wiedzieć też, co się tam właściwie dzieje. Ponownie, stdout jest absolutnym złem i ostatecznością. Dobrze. Dochodzimy teraz do rzeczy dość krytycznej, czyli mianowicie używanie tenantów, bo sporo systemów do logowania to są systemy tenantowe. Jedna ważna rzecz, nie mamy jednego systemu z jednym tenantem dla całej organizacji. Widzieliśmy takie rzeczy. To nie jest nic dobrego i nagle każdy widzi wszystko i mamy totalny bałagan. Czemu tak jest?
Łukasz Kałużny: Jak to było? Próby jednego indeksu w Elasticu na wszystko, bo nie chcemy mieć ich za dużo.
Szymon Warda: Tak, żeby się wyszukiwało szybko. Z kilku powodów, po pierwsze, będziemy mieć sytuację, gdzie niektóre systemy będą miały własne pola. I jak ktoś ma na przykład pole customer, to customer będzie zupełnie inaczej rozumiany w innych systemach. I to rozdzielamy tenantami. To jest bardzo, bardzo potrzebne. Teraz jak rozdzielamy? Ja z reguły per system, nie serwis, tylko system. Czyli taki cały system, który się w miarę ze sobą komunikuje. To rozdzielamy i to z reguły jest jakoś tam tenantem, chyba że jakiś podzbiór naszej organizacji i tak dalej, dochodzą trochę polityka i jak ta organizacja jest zbudowana, to też jest bardzo ważne.
Łukasz Kałużny: To jest, Szymon, ja bym to podkreślił, że jest tutaj prawo Conwaya, które jest też dla Kubernetesa, że struktura namespace’ów i klastrów na Kubernetesie odzwierciedla strukturę komunikacyjną w firmie i struktura tenantów też to będzie odzwierciedlała.
Szymon Warda: Oczywiście, że tak. Powiem tak, zespoły mają dostęp do swojego tenanta, a OPS-i wiadomo, że będą mieli dostępy szersze. Dobra, kolejna rzecz do ustalenia, to żeby była zakomunikowana globalnie. I nie mówię globalnie teraz dla devów, tylko globalnie nawet dla biznesu. Retencja logów, jak długo je trzymamy? Czemu to jest ważne? Tak, mówiliśmy, jak mamy tę taką całą drobnicę logów i też trace’ów, bo to trochę bym w to wyliczył i różne strumienie różną mają retencję, żeby potem nie robić po prostu delete. Podzielmy to konkretnie co, gdzie, jak się dzieje i jasno zakomunikujmy. Moja propozycja jest taka, że lepiej jest zbierać w niektórych sytuacjach logów więcej, a krócej je trzymać. Ewentualnie potrzebujemy na przykład (…). Nie trzymajmy logów info na przykład w Archive, bo taki mamy pomysł, że o to będzie tańsze. Nie, odzyskanie tych logów i odzyskanie załóżmy paru terabajtów z Archive też będzie nas kosztowało i to dużo i będzie mało przyjemne. Więc też podzielmy, które logi trzymamy na dłuższy czas i trzymamy tam tylko te niezbędne, które musimy trzymać. Znowu, inne strumienie, ułatwi nam życie.
Szymon Warda: Jak już jesteśmy przy tym obszarze, to też ustalmy budżety kto może ile logować. I to może brzmieć śmiesznie, ale to jest ważne, bo doskonale wszyscy wiemy to, że trafi nam się jakiś zespół, który jest nadgorliwy i wypisuje, loguje wszystko na info, wypisuje wszystko i całą drobnicę i takie zespoły będą tym elementem, który nam trochę systemy wszystkie porozwalają. Więc określamy kto ma ile może logować w jakim czasie i to trzymamy na dev test. Wiadomo, na holdzie już bym tego nie trzymał.
Łukasz Kałużny: Właśnie chciałem powiedzieć, że z tym byłoby warto doprecyzować w którym miejscu.
Szymon Warda: Tak, produkcje już nie, bo nie chcielibyśmy logów gubić. Ale to ma być taki bicz na to, że chłopaki i dziewczyny ogarnijcie się. Może nie potrzebujecie wysyłać 50 megabajtów logów na sekundę, bo to trochę nie w tym kierunku. Zauważmy co tam się w ogóle dzieje. Dobra, idziemy teraz. I teraz właśnie jeszcze jedna uwaga, czemu ważne jest określenie ilości? Bo jak będziemy mieli tych logów za dużo, to ilość nie idzie w parze z jakością. A my potrzebujemy logów dobrej jakości, a nie po prostu wszystkiego co ktokolwiek wpadł na pomysł, żeby kiedykolwiek wysłać.
Łukasz Kałużny: Czasem mam wrażenie, że logi przypominają nasz troubleshooting dupą w niektórych momentach. Bo tak to trzeba określić, troubleshooting dupą. To co jest wysyłane czasem na prodzie też w ten sposób wygląda.
Szymon Warda: Oczywiście, że tak. Co więcej, logi mają taką wredną tendencję, że my je tylko dodajemy, nigdy ich nie usuwamy. Więc bez budżetów takich, które mówią co ile możemy wysyłać, to będzie to rosło, rosło, rosło, rosło o rzeczy totalnie bezużyteczne, bo ktoś kiedyś jakoś tu je dopisał. Więc to jest bardzo ważne. Dobra, takie (…) nazywamy quality of life, polepszenie jakości. Dobre logowanie zaczyna się też od pewnych standardów. Czyli prosta rzecz, ustalenie standardów labelowania w Kubenretesie, bo to nam da ładną politykę, jeżeli chodzi o źródło prawdy, co się jak nazywa. Linkowanie właśnie tych traceów, logów, czyli trace’ów z logami, czyli to, że ustalamy jak mamy trace’a, to wrzucamy na przykład w systemie, można na przykład to zrobić w Grafanie m.in., że w takim razie po jakim polu ma system szukać w logach dla konkretnych trace’ów. Bardzo wygodne, mała rzecz, ale bardzo cieszy. I nie bądźmy tutaj takim jednym panem z wąsem z Austrii, mianowicie pozwólmy developerom pisać lokalnie do stdouta, tylko na produkcji niech sobie piszą…
Łukasz Kałużny: Raczej odpowiednio nasza biblioteka do logowania powinna wspierać takie pierdoły jak różne configi. To jest chyba istotny element.
Szymon Warda: Produkcyjny czy… Tak, dokładnie tak. I rozumiem, lokalnie też będzie, też często logi są nieustrukturyzowane i tak dalej, bo nie ma co się porywać na to, że tak, będziemy w jednej linii wypisywali JSON. To nie zadziała. Za chwilę ten cały pomysł polegnie.
Łukasz Kałużny: Dobra, to Szymon, jakbyś miał powiedzieć trzy rzeczy, które trzeba zapamiętać z tego, co powiedziałeś wszystkiego dzisiaj?
Szymon Warda: Spisać dokument, jedna rzecz i ustalić.
Łukasz Kałużny: Co w nim ma być?
Szymon Warda: Pola z nazwami do czego służą. To jest w tym dokumencie. Druga rzecz, to jest ustalmy, gdzie te logi są wysyłane, czyli że pobierze to, wysyła aplikacja i czy wysyła do systemu logowania, czy wysyła do czegoś po drodze. Ja jestem za tym do czego po drodze. Jak już to zrobicie, to naprawdę będzie już całkiem nieźle. Dokument też jest standardem i to jest informacja dla całej organizacji co jak wygląda i potem ustalenie architektoniczne, jak właściwie wysyłamy. Zapamiętacie, będzie dobrze, a potem możemy dalej rozmawiać, że tak powiem.
Łukasz Kałużny: Dobra, następna rzecz, bo powiedzieliśmy o trzech.
Szymon Warda: Naprawdę będziesz tak te trzy wyciągał? Dobrze, to co jeszcze dorzucę? Wszystko w jednej linii. Spędziłem dużo czasu na pisanie tych regexów o tym, żeby wyłapywać multiline’y i nie zamierzam tego robić więcej.
Łukasz Kałużny: Dobra, dobra. To słuchajcie, tyle na dzisiaj. Trzymajcie się. Na razie.
Szymon Warda: Na razie. Hej.
Łukasz Kałużny: Hej.
 

Wypełnij poniższy formularz, aby być na bieżąco ze wszystkimi
odcinkami Patoarchitektów
i uzyskać dostęp do dodatkowych
materiałów.