Logowanie i transakcje

1

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?

  1. 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,
  1. 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ą,
  1. 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

0

(zaznaczam że nie znam Javy, ale log4j nie jest mi obce)
Appender w log4j akceptuje obiekty.
Logujesz obiekty (a) - ObjectRederer - czy sformatowane łańcuchy (b)?
Jeśli (a) to dodaj po prostu do obiektu pole nr transakcji i wypełniaj go jeśli masz taką możliwość.

Każde przełączanie kontekstu / rozpoczynanie transakcji / jej zamykanie to podawanie informacji nie-wprost i może prowadzić do jakichś dziwnych trudnych do znalezienia błędów (w tym wypadku błędów logowania).
Czy nie rozpoczynacie transakcji wewnątrz innej transakcji?
Co jeśli konteksty się przeplatają?

Edit: a co jest nie tak z MDC?
http://logback.qos.ch/manual/mdc.html

Gdzieś widziałem przykład że cały kontekst można było rozpoczynać i zwijać. To nie było w log4j?

0

Hmmm, z tego co widzę to w log4j można zalogować dowolny obiekt, a w logbacku można zalogować tylko i wyłącznie Stringa.

Mimo wszystko nie chciałbym przepychać obiektu z transakcją po całej aplikacji tzn po wszystkich modułach.

MDC w sumie byłoby OK z tym, że szef zakłada, że transakcje mogą być obsługiwane w wielu wątkach i to w taki sposób, że każdy może przeżyć dowolną ilość rozpoczęć i zakończeń transakcji. Wiem, że takie podejście to wielki młyn i ogólnie byłbym za tym, żeby np był wątek główny i przy rozpoczynaniu lub kończeniu transakcji jedynym działającym wątkiem był wątek główny, no ale szefowi nie przegadam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1