Log4J a komunikatory internetowe
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:
private String receiver; public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; }
Następnie zdefiniujmy funkcję odpowiedzialną za wysyłanie wiadomości:
public void sendMessage(String content) { try { Skype.chat(receiver).send(content); } catch (SkypeException ex) { } }
oraz nadpiszmy metody dziedziczone z klasy AppenderSkeleton
:
@Override protected void append(LoggingEvent event) { sendMessage(getLayout().format(event)); } @Override public boolean requiresLayout() { return true; } @Override public void close() { }
Konfigurację możemy ustawić przykładowo w pliku właściwości:
log4j.appender.skype=log4jtests.SkypeAppender log4j.appender.skype.layout=org.apache.log4j.PatternLayout log4j.appender.skype.layout.ConversionPattern=[%p] %c - %m log4j.appender.skype.receiver= TU_PODAJESZ_NAZWE_ODBIORCY 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()
:
Logger logger = Logger.getRootLogger(); 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:
private int number; private String password; private int receiver; private boolean isReady; private boolean isFirst = true; private ISession session; 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:
public void connect() throws GGException { loginContext = new LoginContext(number, password); session = SessionFactory.createSession(); session.addSessionStateListener(new SessionStateListener() { public void sessionStateChanged(SessionState oldSessionState, SessionState newSessionState) { if (newSessionState.equals(SessionState.AUTHENTICATION_AWAITING)) { login(); } else if (newSessionState.equals(SessionState.LOGGED_IN)) { isReady = true; } else { isReady = false; } } }); IConnectionService connectionService = session.getConnectionService(); connectionService.addConnectionListener(new ConnectionListener.Stub() { @Override public void connectionEstablished() { System.out.println("Dokonano połączenia"); } @Override public void connectionError(Exception ex) { System.out.println("Błąd połączenia: " + ex.getMessage()); } @Override public void connectionClosed() { System.out.println("Połączenie zakończone"); } }); IServer server = session.getConnectionService().lookupServer( loginContext.getUin()); connectionService.connect(server); }
Teraz czas na funkcję login()
:
private void login() { ILoginService loginService = session.getLoginService(); loginService.addLoginListener(new LoginListener.Stub() { @Override public void loginOK() { System.out.println("Zalogowano"); } public void loginFailed() { System.out.println("Nieudane logowanie"); } }); try { loginService.login(loginContext); } catch (Exception e) { e.printStackTrace(); } }
oraz funkcję sendMessage
, która w argumencie przyjmuje treść wiadomości:
public void sendMessage(String content) { IMessageService messageService = session.getMessageService(); OutgoingMessage outMessage = OutgoingMessage.createNewMessage(receiver, content); try { messageService.sendMessage(outMessage); } catch (GGException e) { e.printStackTrace(); } }
Musimy także zaimplementować funkcję append
, w której definiujemy gdzie log jest zapisywany, funkcje close
oraz requiresLayout
:
@Override protected void append(LoggingEvent event) { if (isFirst) { try { connect(); } catch (GGException e) { e.printStackTrace(); } while (!isReady) { } isFirst = false; } sendMessage(getLayout().format(event)); } @Override public boolean requiresLayout() { return true; } @Override public void close() { }
Dzięki tej linii:
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:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender class="log4jtests.GGAppender" name="gg"> <param name="number" value="TU_PODAJESZ_SWÓJ_NUMER_GG" /> <param name="password" value="TU_PODAJESZ_SWOJE_HASŁO_GG" /> <param name="receiver" value="TU_PODAJESZ_NUMER_GG_ODBIORCY" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%p] %c - %m" /> </layout> </appender> <root> <priority value="debug"></priority> <appender-ref ref="gg" /> </root> </log4j:configuration>
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):
log4j.appender.gg=log4jtests.GGAppender log4j.appender.gg.layout=org.apache.log4j.PatternLayout log4j.appender.gg.layout.ConversionPattern=[%p] %c - %m log4j.appender.gg.number= TU_PODAJESZ_SWÓJ_NUMER_GG log4j.appender.gg.password=TU_PODAJESZ_SWOJE_HASŁO_GG log4j.appender.gg.receiver= TU_PODAJESZ_NUMER_GG_ODBIORCY log4j.rootLogger=DEBUG, gg
Przykładowy test, który możemy umieścić w statycznej funkcji main()
:
Logger logger = Logger.getRootLogger(); try { int i = 5 / 0; } catch (ArithmeticException ex) { 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:
public class GtalkAppender extends AppenderSkeleton { private String user; private String password; private String receiver; // tu umieść gettery i settery dla powyższych trzech zmiennych private boolean isFirst = true; XMPPConnection connection; ConnectionConfiguration connConfig; public void sendMessage(String content) { try { Skype.chat(receiver).send(content); } catch (SkypeException ex) { } } @Override protected void append(LoggingEvent event) { if (isFirst) { connConfig = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com"); connection = new XMPPConnection(connConfig); try { connection.connect(); connection.login(user, password); } catch (XMPPException ex) { } while (!connection.isConnected()) { } isFirst = !isFirst; } Message msg = new Message(receiver, Message.Type.chat); msg.setBody(getLayout().format(event)); connection.sendPacket(msg); } @Override public boolean requiresLayout() { return true; } @Override public void close() { } }
Przykładowa konfiguracja poprzez plik właściwości:
log4j.appender.gtalk=log4jtests.GtalkAppender log4j.appender.gtalk.layout=org.apache.log4j.PatternLayout log4j.appender.gtalk.layout.ConversionPattern=[%p] %c - %m log4j.appender.gtalk.user=TU_PODAJESZ_SWÓJ_ADRES_GMAIL log4j.appender.gtalk.password=TU_PODAJESZ_SWOJE_HASŁO log4j.appender.gtalk.receiver=TU_PODAJESZ_ADRES_GMAIL_ODBIORCY 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.