Szefo chce żeby można było wyciągnąć łatwo z bazy wszystkie logi należące do danej transakcji. Trzeba więc zapisać w logach numer transakcji. Logowanie odbywa się na zewnętrznych urządzeniach, które przesyłają logi do centralnej bazy poprzez webservie. Jak skojarzyć zdarzenia z numerami transakcji?
- Aktualne rozwiązanie, które nie podoba się szefowi:
- w kodzie używa się normalnej fasady SLF4J,
- zrobiłem odpowiedniego appendera, który sobie sam wyciąga "naokoło" numer transakcji i wrzuca parę (numer transakcji, ILoggingEvent) do kolejki,
- z kolejki asynchronicznie już lecą logi do bazy poprzez webservice (asynchroniczność jest właśnie dlatego, że to leci przez webservice),
- numer transakcji jest osobną kolumną w bazie/ polem w klasie opisującej logowane zdarzenie,
- Szefo proponuje:
- przepychanie numeru transakcji do każdej klasy w aplikacji, także niskopoziomowych warstwach, typu warstwy komunikacji z urządzeniami,
- opakowanie loggera we własne klasy; w zasadzie jest to napisanie w dużej mierze własnego loggera, bo standardowe appendery z logbacka czy log4ja nie obsługują dodatkowych pól w ILoggingEvent ZTCW,
- tak jak poprzednio byłaby kolejka do asynchronicznego wysyłania zdarzeń, a numer transakcji byłby osobnym polem/ kolumną,
- Mój nowy pomysł:
- zamiast kojarzyć każde zdarzenie z numerem transakcji logować osobno zdarzenie typu: rozpoczęcie transakcji, zakończenie transakcji, przerwanie transakcji, etc
- rozróżnienie pomiędzy normalnymi logami, a logami reprezentującymi zmianę stanu transakcji zrobić za pomocą markerów (to jeden z wbudowanych mechanizmów log4j/ logbacka do rozróżniania zdarzeń),
- nie trzeba opakowywać loggerów, nie trzeba wyciągać numeru transakcji "naokoło",
- zgodność ze wszystkimi appenderami wbudowanymi w logbacka,
- tak samo użyłbym kolejki do wypychania zdarzeń do zapisu w centralnej bazie,
- nie byłoby osobnego pola/ kolumny w bazie do numeru transakcji,
- przez co utrudnione byłoby wyszukiwanie logów należących do danej transakcji - załóżmy, że zdarzenie rozpoczęcia transakcji miałoby znacznik SessionBegin, znacznik zakończenia SessionEnd, a numer transakcji wepchnąłbym jako Stringa w pole message zdarzenia to, aby wyciągnąć zdarzenia z danej transakcji musiałbym:
-- wyciągnąć wszystkie zdarzenia z markerami SessionBegin lub SessionEnd,
-- z nich wybrać tylko te, które mają w message zapisany jako string numer transakcji, która mnie interesuje,
-- wyszukać te logi, które mają timestamp pomiędzy timestampem wyszukanego SessionBegin, a wyszukanego SessionEnd,
3a. Pomysł podobny do 3. z tym, że:
- timestampy rozpoczęcia, zakończenia, przerwania, itp znajdowałyby się w osobnej tabeli w bazie, dzięki czemu wyszukiwanie byłoby znacznie bardziej eleganckie i miało większą wydajność,
- w sumie dość rozsądne rozwiązanie, tyle że trzeba dwie tabele i tak samo jak w 3. nie widać od razu przy logu numeru transakcji, gdy przegląda się bazę bezpośrednio,
W rozwiązaniu 1. wadą którą mi szef wytyka jest to, że od momentu wywołania Logger.log do momentu odpalenia appendera, który obsługuje ten log może minąć dużo czasu i przez ten czas inny wątek zmieni numer transakcji. Nie zagłębiałem się jeszcze mocno w logbacka (to następca log4j więc powinien działać podobnie jak log4j), ale tam jest chyba tak, że metoda Logger.log czeka aż wszystkie appendery zakończą swoją działalność i wszystkie są odpalane po kolei w jednym wątku. W takim przypadku niewiele by to zmieniało, bo nawet jakbym miał numer sesji od razu podany, to mógłby nastąpić przypadek typu: wchodzimy do metody i na początku numer sesji to 1, metoda trwa długo i w międzyczasie inny wątek zmienia numer sesji na 2 albo null, a my potem w tej długiej metodzie chcemy coś zalogować. Zalogować ze starym numerem transakcji czy z nowym? Jak kojarzyć zdarzenia z transakcjami w aplikacjach wielowątkowych?
A czy jeśli mamy transakcję to nie powinien być jeden wątek, który nią zarządza? Załóżmy że jest główny wątek W0 i poboczne wątki W1..Wn stworzone przez W0. Najbezpieczniej byłoby wtedy, gdyby W0 zrobił join na wszystkich wątkach od W1 do Wn. Tzn dokładniej to w momencie zarówno rozpoczęcia jak i zakończenia transakcji byłby tylko jeden aktywny wątek - ten który zarządza transakcjami.
Dodam, że chodzi mi o programowanie automatu, który przyjmuje pieniądze, ale z funkcjonalnością logowania do serwisu przez internet i kupowania przez internet. W sumie w automatach tego typu (np banknomatach) transakcje są raczej do bólu liniowe, zdaje mi się, że nic nie jest robione w nich asynchronicznie. W takim przypadku nie ma problemu z dobieraniem się do numeru transakcji "naokoło" tzn nie podając go w Logger.log tylko zastępując to wyciąganiem numeru transakcji w appenderze - skoro wszystko dzieje się linowo, to i numer transakcji w appenderze będzie zawsze taki sam jak w momencie wywołania metody Logger.log