Przez kilka ostatnich tygodni pracowaliśmy na Supervisor w elixir. Pokazałem jak z tego możemy korzystać w różnych sytuacjach i jak nadzorcę możemy skonfigurować. Ostatnim krokiem było stworzenie projektu w oparciu o mix
który wykorzystywał wszystko to czego się nauczyliśmy. Dziś, na bazie tego co stworzyliśmy pobawimy się narzędziem które służy do analizy erlanga – Observer.
Narzędzie to, jest narzędziem erlanga, nie elixira. Dlatego też ciężko coś znaleźć na jego temat na blogach poświęconych elixirowi. Najlepszym miejscem do nauki Observer jest instrukcja obsługi dostępna na stronach erlang. My dziś tylko liźniemy to co to narzędzie umożliwia, więc wszystkich chętnych zapraszam do własnego eksplorowania.
Zanim zaczniemy
Przydałoby się byśmy mieli aplikację z zeszłego tygodnia. Może to być prosta aplikacja stworzona za pomocą mix
z Supervisor
i jednym GenServer
. Jeżeli jednak nie macie czasu i lub nie chcecie preparować przykładu to czysty iex
też powinien wystarczyć.
Co to jest Observer
Observer to narzędzie umożliwiające wgląd w aplikację elranga. Daje nam możliwość zorientowania się ile pamięci wszystko zajmuje, jakie jest obciążenie komputera. Ile procesów działa, jak wygląda drzewo nadzorców. Jest to narzędzie analityczno-debugerskie.
Narzędzie to można podzielić na kilka pomniejszych:
- Ogólny wgląd w system erlanga, aplikację itd.
- Narzędzie do analizy crash dumpów
- Narzędzie do pokazywania informacji na temat procesów erlanga w sposób podobny do komendy
top
w unix –etop
- Narzędzie do śledzenia (trace)
Z czego UI udostępnia wszystko. W tym artykule jednak kompletnie pominę trace i crash dumps.
Jak wystartować Observatora
Observatora możemy wystartować z iex, za pomocą komendy:
iex> :observer.start
W zależności od tego czy byliśmy w kontekście projektu (iex -S mix
) czy po prostu czystym iex
, możemy mieć różne informacje dostępne na zakładkach.
Okno główne
Okno główne podzielone jest na kilka zakładek, każdą z nich po krótce opiszę. Zaś dodatkowo istnieją okna pobocze – informujące o procesie czy też umożliwiające ustawienie trace. Część z nich omówię bardziej szczegółowo, a część pominę :)
To na co warto zwrócić uwagę, to to, że menu jest kontekstowe i uzależnione od zakładki którą mamy otwartą. Czyli na System mamy View | Refresh
i View | Refresh Intevral
, na Load Charts, menu View
daje nam już opcję Graph Settings
, zaś na Table Viwer możliwość wyboru jakie tabele będą wyświetlane.
Zakładka System
Ogólne informacje dotyczące całego systemu, wykorzystywanej pamięci i statystyki. Takie overview. Wiemy ile pamięci zajmują procesy, atomy, ETS czy też ile mamy logicznych procesorów (co przekłada się na Schedulery).
Tutaj więcej magii nie ma :)
Zakładka Load Charts
To samo co na system tylko graficznie i w perspektywie czasowej zamist sumarycznej. Na przykład utylizacja schedulerów, czy też wykorzystanie pamięci przez atomy, ETS, kod itp.
Zakładka Memory Allocators
Jest to informacja o alokowaniu wewnętrznym pamięci przez erlang. Dokładnie tabela pokazuje wszystkie allocators które są dostępne, a ich celem jest rozsądne zarządzanie pamięcią by osiągnąć niską fragmentację pamięci. Opis z dokumentacji erlanga:
The main idea with the erts_alloc library is to separate memory blocks that are used differently into different memory areas, to achieve less memory fragmentation. By putting less effort in finding a good fit for memory blocks that are frequently allocated than for those less frequently allocated, a performance gain can be achieved.
Zakładka Applications
Tutaj możecie przejrzeć wszystkie aplikacje i drzewka supervisor stworzone przez nas jak i przez system. Aplikacja tutaj jest rozumiana jako zbiór funkcjonalności zebrany w jeden unit który może być startowany, stopowany jak i re-użyty. Czyli taki exe
na windows.
Każda taka aplikacja (lewe menu), skłąda się z szeregu procesów. Jak dokładnie wygląda drzewo procesów, można zobaczyć to po prawej stronie ekranu. Dla każdej wystartowanej aplikacji będzie ono inne. Każdy taki node to proces. A proces może pełnić kila ról, w tym supervisor
jak i worker
. Każdy taki proces możemy przejrzeć (osobne okno, opisane na końcu), jak i na przykład ubić:
Jak widać, zadziałała tutaj strategia którą ustaliliśmy w zeszłym tygodniu – ponownego startowania procesu jak zostanie ubity. Fajne, w tym ekranie jest to, że to co robiliśmy z iex
, możemy zrobić z poziomy UI i zobaczyć na własne oczy jak się proces nagle tworzy.
Jednej rzczy której nie rozumiem i nie wiem dokładnie jak na tym ekranie działa (nie licząc trace), to opcja Send Msg
, która niezależnie jak próbowałem ją odpalić, nie dawała żadnych rezultatów. Tylko przy wysłaniu wiadomości do Supervisor
dostawałem:
17:00:44.127 [error] Supervisor received unexpected message: :fgh
Z drugiej strony, opcja ta nie jest opisana w dokumentacji erlanga, więc też ciężko się domyślić co dokładnie ona robi.
Zakładka Processes
Ekran ten pokazuje wszystkie procesy wystartowane we wszystkich aplikacjach. Jest to wizualny widok etop
erlanga. Oprócz ogólnego poglądu stanu procesów, umożliwia on podgląd informacji o procesie jak i jego ubicie.
Zakładka Ports
Listuje wszystkie porty (port
to prymitywny typ danych Erlanga, umożliwiający komunikację zewnętrzną za pomocą wiadomości binarnych). Ogólnie porty umożliwiają nam to by elixir/erlang komunikował się z inną aplikacją, która nie koniecznie jest napisana w elixir/erlang.
Jak chcecie więcej dowiedzieć się o portach to zachęcam do przeczytania artykułu Outside elixir.
Polecam także pobawić się prawym przyciskiem myszy.
Zakładka Teble Viewer
Table viewer odpowiada za wyświetlenie Erlang Term Storage (ETS, dokumentacja, więcej info). W skrócie, ETS to sposób przechowywania danych które są tak długo dostępne jak długo działa proces – tak zwana tabela in-memory. Możemy z niej sami skorzystać jak i nasze procesy mogą mają prawo też tam coś zapisywać.
Każdą taką tabelę, możemy otworzyć i obejrzeć dane w niej przetrzymywane. Dodatkowo, możemy te dane modyfikować.
Zaś prawym przyciskiem myszy na elemencie wyciągnąć informację na temat danej tabeli (sumaryczną):
Warto zwrócić jeszcze uwagę na menu View, które tutaj udostępnia dużo więcej opcji, w tym wyświetlanie różnych zbiorów tabel.
Jednak kwestię ETS na razie pominę. Pewnie do niej wrócę w kolejnych postach.
Zakładka Trace Overview
To tutaj możemy wizualnie budować trace dla naszego systemu – jest to nawet ładne wizualne narzędzie ale ma ono wiele opcji których sam jeszcze nie rozgryzłem i pewnie w najbliższym czasie tego nie będę robił. Warto jednak wiedzieć, że jest opcja robienia tego wizualnie a nie tylko z poziomu iex. Screen zaś za dużo nie mówi :) jednak jak już wszystkie dawałem to i dałem ten.
Zobaczcie sobie zaś jak to wszystko jest powiązane. To znaczy, poklikajcie prawym przyciskiem myszy w różnych miejscach i zobaczcie, że część opcji oferuje dodanie dla konfiguracji do trace. Fajne i bardzo przydatne! Jednak jeszcze nie wiem gdzie dokładnie ;)
Okno informacji o procesie
Okno to umożliwia podglądanie informacji dotyczącej danego procesu. Ma ono kilka fajnych opcji o których warto wiedzieć.
Zakłada Process Information
Zakładka Process Information zawiera ogólne informacje na temat procesu, w tym z jakimi innymi procesami dany proces jest połączony, jakie procesy monitoruje i przez jakie jest monitorowany. Do tego ile pamięci zajmuje, jaką funkcje wykonuje itp.
Zakłada Messages
Tutaj znajdzie listę wszystkich wiadomości wysłanych do procesu ale jeszcze przez proces nie przetworzonych. Najlepiej to widać jak zrobi się własny przykład z kodem, który nie odbiera wiadomości:
defmodule OneWay do def start, do: spawn(fn -> loop end) def loop, do: loop end
I potem:
iex> s = OneWay.start iex> send(s, "test") iex> send(s, "test2")
Następnie trzeba odnaleźć nasz proces w zakładce Processes, najlepiej po kolumnie Current Function
lub poprzez PID
(w iex
wpiszcie s
). Teraz też można się fajnie pobawić w wysłanie różnych danych i zobaczyć jak to będzie wyświetlone.
Zakłada Dictionary
Jest to Dictionary danego procesu – jest to lokalny storage dla procesu. Przyjmuje on wartośći key-value jak normalnie słownik. Dokładnie mówiąc do każdego procesu możemy dodać key-value . Jednak nie zaleca się tego robić. Tak czy siak, dla przykładu dodałem :) jakbyście chcieli też to zrobić to możecie:
iex> Process.put(:tt, :aa)
Zakładka StackTrace
Czyli informacja w którym miejscu aktualnie proces działa lub się zatrzymał. Typowy stack trace.
Zakłada State
Stan aktualnego procesu. Na przykład GenServer
przechowuje stan, a w tym konkretnym przypadku to jest to nasz PingPong.Server
:fromSupApp
który został odpalony już 4 razy.
Podsumowanie
Jak widać, możemy zrobić WIELE i wiele się dowiedzieć na temat procesów. Nawet jesteśmy wstanie podejrzeć takie informacje jak statcktrace danego procesu, ich stan, i informacje ogólne. Nie jest to narzędzie do wykorzystywania na co dzień. Jednak jeżeli chcemy dostać informację na temat czegoś konkretnego, lub dowiedzieć się czy coś działa czy też nie, to jest to jedno z miejsc do sprawdzenia.
Jedyne co musimy wiedzieć, to, to co nas interesuje :)
Zachęcam do eksplorowania samemu.
PS.: Screeny pochodzą z Windows i Mac. musiałem kilka rzeczy lepiej zademonstrować a to wymagało aktualizacji gotowych screenshotów. A, że w domu mac a w biurze win, stąd różnica :)
[…] – wszystko ze względu na dynamiczną naturę tych języków. Poprzednie opcje debugowania to observer, debugger w VS Code i debugger Erlanga, IEx.pry/0 oraz break! – trochę tego jest! […]
Comments are closed.