Log4J a komunikatory internetowe
Michał Szynkaruk,
2010-03-30
Tags: [log4j, tools]
Logi informujące o błędach w trakcie działania aplikacji można zapisywać zarówno lokalnie (jako pliki tekstowe, krotki w bazie danych itd.) jak i wysyłać na inną maszynę, np. w postaci e-maila. Niewątpliwe wielu z nas ma na stałe uruchomiony jakiś komunikator internetowy niezależnie od tego czy jesteśmy w pracy, w domu czy w podróży. Skoro chcemy być w stałym kontakcie z naszymi znajomymi, to dlaczego nie możemy być z naszą aplikacją?
W tym artykule pokażę jak można wykorzystać bibliotekę Log4j i najpopularniejsze komunikatory w Polsce: Skype, Gadu-Gadu oraz Google Talk.
Skype i Log4j
Dzięki API o nazwie Skype4Java, które jest oficjalnie udostępnione poprzez stronę https://developer.skype.com/wiki/Java_API możemy w łatwy sposób wysyłać logi na podane konto. Aby to uczynić należy:
-
posiadać aktywne konto Skype
-
dołączyć bibliotekę skype_full.jar
-
dołączyć bibliotekę log4j
Na początku konstruujemy własny appender
w oparciu o abstrakcyjną klasę AppenderSkeleton
(jeśli nie masz podstawowej wiedzy dotyczącej biblioteki log4j, to polecam przeczytanie mojego artykułu, który znajduje się w poprzednim numerze Java Express oraz oficjalnej dokumentacji na stronie http://logging.apache.org/log4j/1.2/index.html). Nazwijmy naszą klasę SkypeAppender
i umieśćmy w niej tylko jedną zmienną wraz ze standardowym getterem i setterem:
1 | private String receiver; |
3 | public String getReceiver() { |
7 | public void setReceiver(String receiver) { |
8 | this .receiver = receiver; |
Następnie zdefiniujmy funkcję odpowiedzialną za wysyłanie wiadomości:
1 | public void sendMessage(String content) { |
3 | Skype.chat(receiver).send(content); |
4 | } catch (SkypeException ex) { |
oraz nadpiszmy metody dziedziczone z klasy AppenderSkeleton
:
02 | protected void append(LoggingEvent event) { |
03 | sendMessage(getLayout().format(event)); |
07 | public boolean requiresLayout() { |
Konfigurację możemy ustawić przykładowo w pliku właściwości:
1 | log4j.appender.skype=log4jtests.SkypeAppender |
2 | log4j.appender.skype.layout=org.apache.log4j.PatternLayout |
3 | log4j.appender.skype.layout.ConversionPattern=[%p] %c - %m |
4 | log4j.appender.skype.receiver= TU_PODAJESZ_NAZWE_ODBIORCY |
5 | log4j.rootLogger=DEBUG, skype |
Pozostało nam już tylko stworzyć obiekt typu Logger
i wysłać wpis.
Przykładowe wywołanie w statycznej funkcji main()
:
1 | Logger logger = Logger.getRootLogger(); |
2 | logger.info( "Czesc, tu aplikacja :)" ); |
Ważne jest by w trakcie działania aplikacji uruchomiony był Skype i umożliwiał on ingerencję naszej aplikacji w Javie.
Wysyłamy loGGi
Gadu-Gadu wykorzystuje własny protokół komunikacji, w którym m. in. każdy użytkownik jest jednoznacznie identyfikowany za pomocą unikalnego numeru. Aby móc wysyłać logi w postaci wiadomości musimy:
-
posiadać aktywne konto GG z którego dane logi wysyłamy,
-
dołączyć bibliotekę JGGApi która implementuje wymieniony protoków,
-
dołączyć bibliotekę Jakarta-Commons Logging, która jest wykorzystywana przez JGGApi,
-
dołączyć bibliotekę log4j.
W tym przykładzie skorzystałem z JGGApi w wersji 1.6, log4j w wersji 1.2.15, Commons Logging w wersji 1.1.1.
Gadu-Gadu wykorzystuje własny protokół komunikacji
Podobnie jak w poprzednim przykładzie konstruujemy własny appender
w oparciu o abstrakcyjną klasę AppenderSkeleton
. Niech nasza klasa przyjmie nazwę GGAppender
. Umieścimy w niej następujące zmienne:
2 | private String password; |
4 | private boolean isReady; |
5 | private boolean isFirst = true ; |
6 | private ISession session; |
7 | private LoginContext loginContext; |
Gdzie number
i password
odnoszą się do naszego konta gg, receiver
jest numerem GG, na który chcemy wysłać naszą wiadomość.
Zmienna isReady
mówi nam kiedy mamy połączenie z serwerem Gadu-Gadu, jesteśmy zalogowani i gotowi wysyłać wiadomości. Zmienna isFirst
określa czy potrzebujemy połączenia z serwerem Gadu-Gadu, session
jak sama nazwa wskazuje jest sesją, a loginContext
zawiera dane o naszym koncie GG. Dla wszystkich wyżej wymienionych zmiennych definiujemy standardowe gettery i settery (tak by móc przypisać im wartości określone w konfiguracji, o czym za chwile będzie mowa). Następnie definiujemy funkcję connect()
dzięki której połączymy się z serwerem Gadu-Gadu:
01 | public void connect() throws GGException { |
02 | loginContext = new LoginContext(number, password); |
03 | session = SessionFactory.createSession(); |
04 | session.addSessionStateListener( new SessionStateListener() { |
05 | public void sessionStateChanged(SessionState oldSessionState, |
06 | SessionState newSessionState) { |
07 | if (newSessionState.equals(SessionState.AUTHENTICATION_AWAITING)) { |
09 | } else if (newSessionState.equals(SessionState.LOGGED_IN)) { |
16 | IConnectionService connectionService = session.getConnectionService(); |
17 | connectionService.addConnectionListener( new ConnectionListener.Stub() { |
19 | public void connectionEstablished() { |
20 | System.out.println( "Dokonano połączenia" ); |
24 | public void connectionError(Exception ex) { |
25 | System.out.println( "Błąd połączenia: " + ex.getMessage()); |
29 | public void connectionClosed() { |
30 | System.out.println( "Połączenie zakończone" ); |
33 | IServer server = session.getConnectionService().lookupServer( |
34 | loginContext.getUin()); |
35 | connectionService.connect(server); |
Teraz czas na funkcję login()
:
02 | ILoginService loginService = session.getLoginService(); |
03 | loginService.addLoginListener( new LoginListener.Stub() { |
05 | public void loginOK() { |
06 | System.out.println( "Zalogowano" ); |
09 | public void loginFailed() { |
10 | System.out.println( "Nieudane logowanie" ); |
14 | loginService.login(loginContext); |
15 | } catch (Exception e) { |
oraz funkcję sendMessage
, która w argumencie przyjmuje treść wiadomości:
01 | public void sendMessage(String content) { |
02 | IMessageService messageService = session.getMessageService(); |
03 | OutgoingMessage outMessage = OutgoingMessage.createNewMessage(receiver, |
06 | messageService.sendMessage(outMessage); |
07 | } catch (GGException e) { |
Musimy także zaimplementować funkcję append
, w której definiujemy gdzie log jest zapisywany, funkcje close
oraz requiresLayout
:
02 | protected void append(LoggingEvent event) { |
06 | } catch (GGException e) { |
14 | sendMessage(getLayout().format(event)); |
18 | public boolean requiresLayout() { |
Dzięki tej linii:
1 | sendMessage(getLayout().format(event)); |
wysyłamy sformatowaną wiadomość według szablonu określonego w pliku konfiguracji.
Zdecydowałem się na konfigurację XML'ową w pliku log4j.xml:
01 | <? xml version = "1.0" encoding = "UTF-8" ?> |
02 | <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> |
04 | < appender class = "log4jtests.GGAppender" name = "gg" > |
05 | < param name = "number" value = "TU_PODAJESZ_SWÓJ_NUMER_GG" /> |
06 | < param name = "password" value = "TU_PODAJESZ_SWOJE_HASŁO_GG" /> |
07 | < param name = "receiver" value = "TU_PODAJESZ_NUMER_GG_ODBIORCY" /> |
08 | < layout class = "org.apache.log4j.PatternLayout" > |
09 | < param name = "ConversionPattern" value = "[%p] %c - %m" /> |
13 | < priority value = "debug" ></ priority > |
14 | < appender-ref ref = "gg" /> |
gdzie:
-
%p to priorytet zdarzenia,
-
%c to kategoria zdarzenia,
-
%m to treść komunikatu,
a poziom, od którego logi są wysyłane ustawiamy na debug.
Podobny efekt uzyskamy, jeśli stworzymy plik właściwości (log4j.properties):
1 | log4j.appender.gg=log4jtests.GGAppender |
2 | log4j.appender.gg.layout=org.apache.log4j.PatternLayout |
3 | log4j.appender.gg.layout.ConversionPattern=[%p] %c - %m |
4 | log4j.appender.gg.number= TU_PODAJESZ_SWÓJ_NUMER_GG |
5 | log4j.appender.gg.password=TU_PODAJESZ_SWOJE_HASŁO_GG |
6 | log4j.appender.gg.receiver= TU_PODAJESZ_NUMER_GG_ODBIORCY |
7 | log4j.rootLogger=DEBUG, gg |
Przykładowy test, który możemy umieścić w statycznej funkcji main()
:
1 | Logger logger = Logger.getRootLogger(); |
4 | } catch (ArithmeticException ex) { |
5 | logger.error( "Wystapil blad w programie" ); |
Google Talk
Wysyłanie wiadomości na konto Google Talk jest równie łatwe, gdyż dysponujemy darmowymi klientami protokołu xmpp, z którego korzysta ten komunikator. Osobiście skorzystałem z biblioteki Smack w wersji 3.1.0.
Sposób monitorowania działania naszej aplikacji
przy wykorzystaniu tych trzech komunikatorów
wydaje się być niezwykle ciekawy i skuteczny
Podobnie, jak w poprzednich dwóch przykładach, tworzymy własny appender, który u mnie prezentuje się następująco:
01 | public class GtalkAppender extends AppenderSkeleton { |
03 | private String password; |
04 | private String receiver; |
07 | private boolean isFirst = true ; |
08 | XMPPConnection connection; |
09 | ConnectionConfiguration connConfig; |
11 | public void sendMessage(String content) { |
13 | Skype.chat(receiver).send(content); |
14 | } catch (SkypeException ex) { |
20 | protected void append(LoggingEvent event) { |
22 | connConfig = new ConnectionConfiguration( "talk.google.com" , 5222 , |
24 | connection = new XMPPConnection(connConfig); |
27 | connection.login(user, password); |
28 | } catch (XMPPException ex) { |
31 | while (!connection.isConnected()) { |
35 | Message msg = new Message(receiver, Message.Type.chat); |
36 | msg.setBody(getLayout().format(event)); |
37 | connection.sendPacket(msg); |
41 | public boolean requiresLayout() { |
Przykładowa konfiguracja poprzez plik właściwości:
1 | log4j.appender.gtalk=log4jtests.GtalkAppender |
2 | log4j.appender.gtalk.layout=org.apache.log4j.PatternLayout |
3 | log4j.appender.gtalk.layout.ConversionPattern=[%p] %c - %m |
4 | log4j.appender.gtalk.user=TU_PODAJESZ_SWÓJ_ADRES_GMAIL |
5 | log4j.appender.gtalk.password=TU_PODAJESZ_SWOJE_HASŁO |
6 | log4j.appender.gtalk.receiver=TU_PODAJESZ_ADRES_GMAIL_ODBIORCY |
7 | log4j.rootLogger=DEBUG, gtalk |
Podsumowanie
Możliwości Log4j oraz istnienie javowych bibliotek dla Skype, Gadu-Gadu oraz Gtalk powodują, że każdy z nas ma możliwość szybkiego odbioru informacji o wystąpieniu ewentualnych błędów w trakcie działania naszej aplikacji. Dzięki temu szybko i skutecznie możemy rozpocząć akcje naprawcze. Sposób monitorowania działania naszej aplikacji przy wykorzystaniu tych trzech komunikatorów wydaje się być niezwykle ciekawy i skuteczny.
Nobody has commented it yet.