Monthly Archives: February 2012

Parser logów w Groovy

Podczas debugowania wadliwego działania redeliveringu w ActiveMQ ostateczną metodą okazało się ‘echo dupa’ 😉 Jednakże przy próbie jednoczesnego obserwowania działania aplikacji przy 10 wiadomościach wpadających do kolejki okazało się, że metoda kartki i papieru zabiera trochę za dużo czasu. Zatem zaprzęgłem do pracy Grooviego i postanowiłem na szybko napisać mały parserek plików z logami.

Główne pomysły i kod podkradłem z tej strony. Jednakże ja do logów zapisywałem informację o tym, która to próba ponownego doręczenia się wykonuje, ilość łącznych, informację o wątku, który to wykonuje oraz informacji z samej wiadomości w kolejce JMS.  To oczywiście było dopisywane do wiersza ze wskazaniem informacji o wątku i daty. Całość wyglądała mniej więcej tak:

[#|2012-02-17T11:16:02.419+0100|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=80;_ThreadName=testowaKolejka-1;|CURRENT:4 MAX:4 id:identyfikator1-1-1-1|#]

I z tego narodził się poniższy kod. Być może komuś się przyda w przyszłości.

/* Mozna uzyc podejscia, ktore odczytuje plik linia po linii. Jednakze
 istnieje szansa, ze 1 wpis do loga zajmie wiecej niz domyslna 1 linie.
 Dlatego tez uzywamy podejscia, ktore wyciagnie plik do 1 lancucha tekstowego
 nastepnie zas kolejne przyporzadkowania do wzorca wyrazen regularnych.

 !!!UWAGA!!! - rozwiazanie moze byc malo wydajne przy duzych plikach

  */

def logLineStart = /^\[\#\|\d{4}-\d{2}-\d{2}/   // Wpis w logu o wyjatku
def log = new File('C:\\log.log').text
def informationEntries = []
def presentationData = [:]

def splitter = log =~ """(?xms)
    (    ${logLineStart}   .*?)
    (?=  ${logLineStart} | \\Z)
"""

splitter.each { matched, entry ->

    // Replace jest po to by otrzymac jeden lancuch tekstowy w przypadku dopasowan ze znakiem
    // nowej linii. Wowczas dane nie bylyby poprawne.
    if (entry =~ /CURRENT:/) {
         informationEntries.add( entry.replaceAll("[\r\n]","") )
    }

}

def redeliveryAttemptData = []

informationEntries.each {
    // Wpisy na liscie wygladaja mniej wiecej tak
    // [#|2012-02-17T15:49:50.525+0100|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=134;_ThreadName=testowaKolejka-1;|CURRENT:4 MAX:4 id:identyfikator1-1-1-1|#]

    // Zatem po prostu rozbijamy ten string i wyciagamy dane z listy
    redeliveryAttemptData = it.tokenize('|')

    String currentEntryData = redeliveryAttemptData.get(1)
    String currentEntryThread = redeliveryAttemptData.get(5)
    String currentEntryInfo = redeliveryAttemptData.get(6)

    // Wpierw potrzebna nam data i godzina z dokladnoscia do sekund
    def dataRegexp = /\d{2}:\d{2}:\d{2}\.\d{3}/
    def currentMinutesSec =  currentEntryData.find(dataRegexp)

    // Informacja o numerze watku, ktory procesowal wiadomosc
    def threadRegexp = /=jmsContainerEmailIn-\d{1,}/
    def currentThreadInfo =  currentEntryThread.find(threadRegexp).tokenize('-').get(1)

    // Logowane przeze mnie informacje o wiadomosci i metadane redeliveringu
    def listWithCurrentInfo = currentEntryInfo.tokenize(' ')
    def currentRound = listWithCurrentInfo.get(0).tokenize(':').get(1)
    def currentId = listWithCurrentInfo.get(2).tokenize(':').get(1)

    if( !presentationData[ currentId ] ) {
        presentationData[ currentId ] = [:]
    }

    presentationData[ currentId ][ 'id' ] = currentId
    presentationData[ currentId ][ currentRound ] = currentMinutesSec + '( ' + currentThreadInfo + ' )'

}

// Drukujemy na konsole w formie CSV. Mozna inaczej - stad
// zreszta zapisywanie danych do mapy
presentationData.each { key, value ->

    StringBuffer sb = new StringBuffer(64)

    sb.append( value.get('id')).append(',')

    for ( i in ['0','1','2','3','4'] ) {
        sb.append( value.get( i ) ).append(',')
    }

    println sb

}

Narzędzia JDK

W przypadku JDK najczęściej wiemy, że trzeba go zainstalować by móc coś zaprogramować. Często na samej instalacji nasza przygoda z JDK się kończy – resztę biorą na siebie IDE czy ścieżka systemowa do kompilatora i tyle. Tymczasem warto zapoznać się z JDK trochę bliżej – dostarcza on bowiem szeregu całkiem przyjemnych narzędzi. W swoim wywodzie pominę najbardziej oczywiste – java oraz javac. Chyba każdy wie, że używa kompilatora oraz uruchamia oddzielne instancje JVM 😉

Lista z całą pewnością nie jest kompletna, nie ma również służyć za tutorial dotyczący ich użycia. Ma tylko pokazać istnienie pewnych programików, które mogą nam się przydać. Wiekszość z niżej wymienionych posiada dodatkowe opcje i parametry, którymi możemy sterować uruchomienie oraz działanie programów. Całość testowałem na JDK od Sun/Oracle w wersjach 1.6 oraz 1.7

  • JPS  – jest to narzędzie pozwalające wylistować uruchomione (domyślnie) na lokalnym komputerze maszyny wirtualne. W charakterze parametru można podać dowolny adres komputera (zdalnego), oczywiście pod warunkiem, że mamy do niego dostęp. Również należy zwrócić uwagę na opis w dokumentacji:

    The jps command uses the java launcher to find the class name and arguments passed to the main method. If the target JVM is started with a custom launcher, the class name (or JAR file name) and the arguments to the main method will not be available. In this case, the jps command will output the string Unknown for the class name or JAR file name and for the arguments to the main method.

    The list of JVMs produced by the jps command may be limited by the permissions granted to the principal running the command. The command will only list the JVMs for which the principle has access rights as determined by operating system specific access control mechanisms.

    Dodatkowo dokumentacja mówi jasno, iż JPS nie jest już wspierane i może zniknąć w kolejnych wersjach Javy. U mnie w JDK 1.7.0 wciąż jest dostępne 😉

  • Appletviewer – zgodnie z nazwą służy do uruchamiania appletów bez konieczności osadzania ich na loklanej stronie WWW (czy też gdzieś indziej). Dla przykładu – mamy grę w Javie w formie apletu, ale nie chcemy uruchamiać całej otaczającej aplet strony (z masą reklam). Podajemy adres strony zawierającej element z apletem i do przodu. Niestety należy się również liczyć z tym, iż mogą wystąpić problemy z uruchomieniem – przekazywane parametry, sprawdzanie poprawności, cookie – ewentualnych przyczyn braku poprawnego uruchomienia jest wiele. Jednakże by zobaczyć choć w praktyce jak to wygląda wystarczy uruchomić z konsoli to narzędzie przekazując jako pierwszy argument adres: http://www.roseindia.net/tutorialfiles/java/applet-oline-example.html . Hello World!
  • JSTAT i JSTATD – to bardzo potężne narzędzia, które umożliwiają monitoring parametrów JVM. JStad uruchamia lokalny rejestr RMI, co umożliwia wystawienie informacji o JVM na zewnątrz (np. włączenie ładnego monitoringu w formie aplikacji webowej uruchomionej na innym serwerze). Na szybko zaś powiem więcej o Jstat, które to narzędzie pozwala na dość dokładne monitorowanie parametrów JVM. Głównie rzecz w zajętości pamięci oraz zdarzeniach Garbage Collectora. Jest to naprawdę bardzo istotne w przypadku wycieków pamięci, monitoringu zmian oraz badaniach efektywności. Zwracane wartości mogą być różnie formatowane i dobrze jest zapoznać się z nimi w dokumentacji .
  • Javap – narzędzie użyteczne dość w wąskim zakresie. Jego wywołanie z argumentem w formie klasy spowoduje zwrócenie danych o pakiecie oraz publicznych i chronionych polach/metodach. Oczywiście wynik programu możemy regulować za pomocą dużej ilości opcji. Przydatne kiedy debugujemy kod na zapomnianym serwerze z Javą 1.3 bez dostępu do API w innej postaci (man, internet, IDE) 😉
  • JDB – debugger dla Javy. Jeśli myśl o próbach zabawy z tym narzędziem bez IDE przyprawia Cię o drżenie rąk to wiedz, że nie jesteś jedynym.
  • JMap i JHat – narzędzia do tworzenia zrzutów sterty oraz do ich analizy. Parametrem do analizy przez program JHat może być efekt działania JMap. Program JHat po przeanalizowaniu pliku uruchamia serwer WWW i udostępnia dane na temat zrzutu.
  • JConsole i JVisualVM – ładne narzędzia graficzne do zarządzania i statystyki JVM (zarówno lokalnych jak i zdalnych). Są to nakładki wykorzystujace niektóre wspomniane powyżej narzędzia. Długo by pisać – zachęcam do zapoznania się z nimi.

Pozostałe narzędzia są w fazie eksperymentalnej (np. jrunscript) bądź też dość często używane, ale przez inne biblioteki i narzędzia (wsgen, javadoc, xjc, jar). Wielu z powyższych narzędzi możemy nigdy nie potrzebować. Warto jednak zajrzeć do folderu BIN, tak tylko z wrodzonej ciekawości 😉