Posts Tagged logowanie

Rozdzielenie logów z aplikacji do plików w serwerze JBoss 5

Standardowy sposób logowanie w ramach serwera JBoss 5 sprowadza się do zapisywania informacji o zdarzeniach do pliku server.log. Trafiają tam wszystkie zdarzenia, jakie mają zostać zalogowane.

Niekiedy jednak istnieje potrzeba separacji logowania danych z rożnych aplikacji do oddzielnych plików. W przypadku serwera JBoss do logowania używana jest biblioteka log4j a jej konfiguracja znajduje się w pliku jboss-log4j.xml. Bibliotekę tę można skonfigurować do logowania danych z danej aplikacji w jeden z dwóch sposobów:

  • logować informacje pochodzące z odpowiednich pakietów (rozwiązanie uniwersalne, wymaga tylko odpowiedniej konfiguracji biblioteki log4j)
  • logować informacje pochodzące z danej aplikacji – rozwiązanie korzystające z bibliotek JBossa, będzie działać tylko w ramach serwera aplikacji

Przedstawię obie metody na przykładzie logowania informacji pochodzących z aplikacji Admin Console.

Podział logowania ze względu na pakiety

Konfiguracja logowanie informacji o wybranych pakietach sprowadza się do kilku kroków:

  • konfiguracja pliku, do którego będą zapisywane logi oraz konfiguracja odpowiedniego formatu ich zapisu:
    361
    362
    363
    364
    365
    366
    <appender name="AdminConsoleLog" class="org.apache.log4j.FileAppender">
      <param name="File" value="${jboss.server.home.dir}/log/admin_console.log"/>
      <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
      </layout>
    </appender>
  • identyfikacja pakietów, z których informacje powinny być logowane – czyli najlepiej przejrzeć plik JAR z aplikacją i wypisać odpowiednie pakiety, w przypadku aplikacji Admin Console będzie to pakiet org.jboss.on.embedded
  • konfigurację logowania wybranych pakietów do odpowiednio wcześniej zdefiniowanego pliku:
    368
    369
    370
    371
    372
    373
    374
    375
    376
    <category name="org.jboss.on.embedded">
      <priority value="DEBUG" />
      <appender-ref ref="AdminConsoleLog">
    </category>

    <category name="org.rhq.core">
      <priority value="DEBUG" />
      <appender-ref ref="AdminConsoleLog">
    </category>

Co zrobić jednak z takimi sytuacjami:

  • aplikacja składa się z różnych bibliotek i chcemy także uzyskać z nich uzyskać logi – najprościej, dodać kolejny wpis w pliku jboss-log4j.xml z odpowiednią kategorią (w przykładzie powyżej logowanie z pakietu org.rhq.core)
  • ta sama biblioteka jest wykorzystywana w wielu aplikacjach, ale logować informacje chcemy tylko z jednej aplikacji – i tutaj jest kłopot, powyższy sposób spowoduje logowanie danych z każdej instancji biblioteki, nawet jeżeli nie jest ona związana z daną aplikacją. Być może dałoby się skonfigurować logowanie w ramach danej aplikacji, ale nie widzę możliwości konfiguracji tego na poziomie serwera JBoss (w ramach takiej konfiguracji logowania)

Podział logowania ze względu na aplikację

W ramach serwera JBoss istnieje jednak możliwość konfiguracji logowania na podstawie samej aplikacji, ale wymaga do kilku dodatkowych kroków:

  1. Aktualizacja bibliotek odpowiedzialnych w JBossie za logowanie to nowsze wersji.

    Do konfiguracji logowania na poziomie aplikacji w przypadku JBossa 5.1 będzie trzeba użyć klasy filtrującej logi o nazwie org.jboss.logging.filter.TCLMCFilter, która jest dostępna w wersji 2.2.1 biblioteki jboss-logging (w ramach serwera dostępna jest wersja 2.2.0). Aktualizacja sprowadza się do:

  2. Konfiguracja logowania na poziomie aplikacji.
    • Najpierw należy zdefiniować w pliku jboss-log4j.xml nową pozycję, w której podamy do z jakiej aplikacji logi nas interesują oraz gdzie mają zostać zapisane:
      378
      379
      380
      381
      382
      383
      384
      385
      386
      387
      388
      389
      390
      391
      <appender name="AdminConsole2Log" class="org.apache.log4j.FileAppender">
        <param name="File" value="${jboss.server.home.dir}/log/admin_console2.log"/>
        <param name="Threshold" value="DEBUG"/>
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
        </layout>
        <filter class="org.jboss.logging.filter.TCLMCFilter">
          <param name="AcceptOnMatch" value="true"/>
          <param name="DeployURL" value="admin-console.war"/>
        </filter>    

        <!-- end the filter chain here -->
        <filter class="org.apache.log4j.varia.DenyAllFilter"></filter>
      </appender>

      Definicja odpowiedniego filtru, który ma za zadanie wybranie tylko logów pochodzących z wybranej aplikacji znajduje się w linii 384, sama nazwa aplikacji znajduje się w linii 386.

    • Teraz należy dodać zdefiniowany obiekt appender do kategorii root:
      402
           <appender -ref ref="AdminConsole2Log"/>

Teraz pozostaje jeszcze start (lub restart) serwera JBoss i w plikach powinny znaleźć się odpowiednie logi z poszczególnych aplikacji.

Źródła

Tags: , , ,

Logowanie zadawanych zapytań do bazy danych przy użyciu log4jdbc

Duża (jeżeli nie większość) część aplikacji korzysta z bazy danych. Zapisuje oraz pobiera z niej informacje praktycznie na okrągło i co ważniejsze, nie jest w stanie poprawnie funkcjonować bez niej. W przypadku Javy połączenia realizowane z bazą danych są opisane poprzez standard JDBC (Java DataBase Connectivity). Praktycznie wszystkie sterowniki do baz danych relacyjnych opierają się na tym standardzie i realizują opisane w nim funkcje. Ponieważ aplikacje tak silnie zależą od baz danych, często pojawiają się różne problemy związane z ich użyciem. W celu ich analizy przydatne może być możliwość sprawdzenia, jak wyglądają poszczególne zapytania do bazy danych wysłane przez aplikację, łącznie z informacje jakie dane są w nich przesyłane.

Jedną z możliwości sprawdzenia (dokładnego) jak wyglądają poszczególne zapytania do bazy danych, jest użycie specjalnego sterownika pośredniczącego pomiędzy naszą aplikacją a serownikiem bazodanowym. Pośrednik ten umożliwia zalogowanie odpowiedniego zapytania zanim zostanie ono przekazane do sterownika odpowiedzialnego za połączenie się z bazą danych i wykonywania na niej operacji. Takim sterownikiem pośredniczącym jest log4jdbc.

Instalacja biblioteki w aplikacji

Pierwszym krokiem powinno być pobranie odpowiedniej wersji biblioteki ze strony log4jdbc. Należy zwrócić uwagę, że inne wersje są zalecane w zależności od tego, jaka wersja Javy zostanie użyta do uruchomienia aplikacji. W moim przypadku najwłaściwszy był plik log4jdbc4-1.2beta1.jar.

Powyższy plik JAR należy dołączyć do ścieżki aplikacji. Ja w swoim przypadku korzystałem z aplikacji uruchomionej na serwerze aplikacyjnym JBoss, więc skopiowałem ten plik do katalogu [cc]common/lib[/cci]. Pozostał jeszcze tylko restart serwera i biblioteka jest gotowa do użycia.

Inicjalizacja połączenia

Istnieją dwa sposoby inicjalizacja biblioteki: w kodzie aplikacji poprzez wywołanie odpowiedniej klasy oraz poprzez odpowiednie utworzenie łańcucha połączenia z bazą danych w standardzie JDBC.

Inicjalizacja log4jdbc w kodzie aplikacji

Oto przykładowy kod źródłowy, jaki należy użyć w aplikacji :

1
2
3
4
5
6
7
// get connection from datasource
Connection conn = dataSource.getConnection();

// wrap the connection with log4jdbc
conn = new net.sf.log4jdbc.ConnectionSpy(conn);

// now use Connection as normal (but it will be audited by log4jdbc)

Czyli najpierw tworzymy lub pozyskujemy połączenie do bazy danych, a następnie przekazujemy je do instancji klasy ConnectionSpy, która od tej pory będzie pośredniczyć w wywoływaniu odpowiedniego kodu i logowaniu informacji przez bibliotekę log4jdbc.

Inicjalizacja połączenia przy użyciu JDBC

Drugim sposobem jest zdefiniowanie połączenia do bazy danych przy użyciu łańcucha JDBC. Robi się to dodając informację o użyciu biblioteki log4jdbc w łańcuchu definiującym połączenie. Jeżeli podstawowe połączenie z bazą danych wygląda następująco (połączenie z bazą danych MySQL):

jdbc:mysql://localhost:3306/baza_danych

To należy dodać do łańcucha ten ciąg znaków log4jdbc, tak aby wyglądał on następująco:

jdbc:log4jdbc:mysql://localhost:3306/baza_danych

Jako klasę sterownika należy użyć klasy: net.sf.log4jdbc.DriverSpy. Przykładowa konfiguracja źródła danych dla JBossa wygląda następująco:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
  <local-tx-datasource>
    <jndi-name>bazaDanychDS</jndi-name>
    <connection-url>jdbc:log4jdbc:mysql://localhost:3306/baza_danych</connection-url>
    <driver-class>net.sf.log4jdbc.DriverSpy</driver-class>
    <!-- definicja użytkownika, hasła, innych parametrów potrzebnych do połączenia z bazą danych -->
  </local-tx-datasource>
</datasources>

Biblioteka log4jdbc automatycznie postara się zaincjalizować odpowiednią klasę sterownika dla używanej bazy danych. Pełna list domyślnie używanych klas (w zależności od wybranej bazy danych) znajduje się na stronie domowej tego projektu, poniżej znajduje się wybór kilku najczęściej używanych:

Baza danych Klasa sterownika
Oracle oracle.jdbc.driver.OracleDriver
MySQL com.mysql.jdbc.Driver
PostgresSQL org.postgresql.Driver
HSQLDB org.hsqldb.jdbcDriver

Jeżeli istnieje potrzeba użycia innego sterownika do bazy danych, można te informacje przekazać do biblioteki konfigurując odpowiednią zmienną systemową log4jdbc.drivers:

-Dlog4jdbc.drivers=<driverclass>[,</driverclass><driverclass>...]

Teraz pozostaje uruchomić aplikację i w logach powinny znaleźć się informacje o zadawanych zapytaniach, o wartościach poszczególnych parametrów w zapytaniu (szczególnie pomocne w podczas używania klasy PreparedStatement).

Konfiguracja loggerów

Biblioteka log4jdbc definiuje pięć różnych loggerów odpowiedzialnych za zapisywanie różnych informacji dotyczących komunikacji z bazą danych. Każdy z nich może mieć ustawiony jeden z poziomów logowania: DEBUG, INFO, ERROR, FATAL.

Jeżeli wszystkie będą ustawione na poziom FATAL, to faktycznie log4jdbc zostanie wyłączony. Wtedy też nowo tworzone połączenie nie będą otaczane klasą ConnectionSpy tylko będzie to bezpośrednie połączenie z bazą danych. Taki sposób działania jest przydatny, ponieważ można nawet w środowisku produkcyjnym mieć zdefiniowane połączenie z bazą danych przy użyciu log4jdbc, ale włączać je za pomocą definicji odpowiednich zmiennych, bez potrzeby modyfikowania łańcucha definiującego połączenie.

Znaczenie pozostałych poziomów logowania:

  • ERROR – wypisanie stack trace w logu w przypadku wystąpienia wyjątku SQLException
  • INFO – dodanie wyświetlania poleceń SQL
  • DEBUG – dodanie nazwy klasy oraz numeru linii w której zostało wykonane dane polecenie SQL (powoduje także większy narzut czasowy na zapisanie takie informacji w logu)

Dostępne loggery:

Logger Opis
jdbc.sqlonly logowanie samych poleceń SQL, w przypadku korzystania z klasy PreparedStatement także zostaną podane wartości poszczególnych parametrów
jdbc.sqltiming informacje o czasie wykonywania poszczególnych zapytań SQL
jdbc.audit logowanie wszystkich wywołań JDBC poza wynikami (używane do wyszukiwania problemów z JDBC)
jdbc.resultset logowanie wszystkich wywołań do klasy ResultSet
jdbc.connection logowanie informacji o otwieraniu i zamykaniu połączeń, pomocne w przypadku wystąpienia problemów z wyciekami połączeń

Przykładowa fragment linii poleceń wywołującej JVM w którym są te loggery włączane:

-Djdbc.sqlonly=DEBUG -Djdbc.sqltiming=DEBUG -Djdbc.audit=INFO -Djdbc.connection=INFO

Źródła

Tags: , , , , , , , ,