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.


Nie ma jeszcze komentarzy.