Published on

It describes how to build Instant Messenger logger using log4j with GTalk

Published in: Technology, Education
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


  1. 1. Instant Messenger logging: Rein- Rein-in the ability of log4j with abi Gtalk (PNotifyAppender) NotifyAppender) BY SAURAV PAUL1|Page
  2. 2. TABLE OF CONTENTS SL. NO TOPICS PAGE NO. 1. Introduction 3 2. Revisit-log4j framework in brief 3-7 3. Case study: real-world example appender 7-8 4. Overview of PNotifyAppender 9-11 5. Putting it all together 11-13 6. Conclusion 13 7. Resources 13Note:1. For Technical details – refer page no. 3-11.2. Guide to quick start – refer page no. 11-13.2|Page
  3. 3. 1. Introduction:No matter how many well-designed test cases you write, even the smallest application will hide one or more bugsonce it’s deployed in the production environment. While test-driven development and QA practices improvecode quality and provide confidence in the application, when a system fails, dev elopers and systemadministrators need contextual information about its execution. With the appropriate information, they canidentify the nature of the problem and fix it quickly, saving time and money.Logging application events is a central part of many applications. Most of our applications do some sort oflogging, using a variety of mechanisms. When things go wrong, the first course of action is usually to get hold ofthe application log file and go through its contents.Someone supporting live, deployed applications would probably appreciate the importance of getting notified ofapplication errors as early as possible. It is much better to be proactive dealing with errors, rather than waiting tohear from the customer that something seems to have gone wrong.So, how about getting notified immediately, by utilizing an instant messenger client like GtalkMessenger?2. Revisit-log4j framework in brief: Revisit it- brief:The log4j framework is the de facto logging framework written in the Java language. As part of the Jakartaproject, it is distributed under the Apache Software License, a popular open source license certified by theOpen Source Initiative (OSI). The log4j environment is fully configurable programmatically or throughconfiguration files, either in properties or XML format. In addition, it allows dev elopers to filter out loggingrequests selectively without modifying the source code.The log4j environment has three main components:Loggers: Control which logging statements are enabled or disabled. Loggers may be assigned the levels ALLDEBUG, INFO, WARN, ERROR, FATAL, or OFF. To make a logging request, you invoke one of the printingmethods of Logger instance.Layout: Format the logging request according to the users wishes.Appenders: Send formatted output to its destinations.2.1 Under the hood:All appenders must extend the org.apache.log4j.AppenderSkeleton class, an abstract class that implements theorg.apache.log4j.Appender and org.apache.log4j.spi.OptionHandler interfaces. The UML class diagram of theAppenderSkeleton:3|Page
  4. 4. Lets examine the methods of the Appender interface implemented by the AppenderSkeleton class. As Listingabove indicates, nearly all methods in the Appender interface are setter and getter methods:Appender Interface: package org.apache.log4j; public interface Appender{ void addFilter (Filter newFilter); public Filter getFilter (); public void close (); public void clearFilters (); public void close (); public String getName (); public void setErrorHandler (ErrorHandler errorHandler); public ErrorHandler setErrorHandler (); public void set Layout (Layout layout); public Layout getLayout (); public void setName (String name); public boolean requiresLayout () ;}These methods handle appender properties like the following:Name: Appenders are named entities so there is a setter/getter for its name.4|Page
  5. 5. Layout: Appenders may have a Layout associated with them, so there is another setter/getter method for the layout.Note as said it may but not must. The reason is that some appenders dont require a lay out. Layout managesformat output -- that is, it returns a String representation of the LoggingEvent. On the other hand, JMSAppendersends the event serialized, so youre not required to attach a layout with it. If your custom appender doesntrequire a layout, the requiresLayout () method must return false to prevent log4j from complaining aboutmissing layout information.ErrorHandler: Another setter/getter method exists for ErrorHandler. Appenders may delegate their errorhandling to an ErrorHandler object -- an interface in the org.apache.log4j.spi package. There are twoimplementing classes: OnlyOnceErrorHandler and FallbackErrorHandler. The OnlyOnceErrorHandlerimplements log4js default error handling policy, which consists of emitting a message for the first error in anappender and ignoring all following errors. The error message is printed on System.err. FallbackErrorHandlerimplements the ErrorHandler interface such that a secondary appender may be specified. This secondaryappender takes over if the primary appender fails. The error message is printed on System.err, then logged innew secondary appender.There are other methods to manage filters (such as the addFilter (), clearFilters (), and getFilter () methods).Even though log4j has several built-in ways to filter log requests (such as repository -wide level, logger level, andappender threshold), it is also very powerful in its approach to using custom filters.An appender can contain multiple filters. Custom filters must extend the org.apache.log4j.spi.Filter abstractclass. This abstract class requires filters to be organized in a linear chain. The decide (LoggingEvent) method,org.apache.log4j.spi.Filter, an abstract Class, of each filter is called sequentially, in the order it was added to thechain. Custom filters are based on ternary logic. The decide () method must return one of the DENY,NEUTRAL, or ACCEPT integer constants.Besides setter/getter methods and the ones related with filters, there are two other methods: close () anddoAppend (). The close () method releases any resources allocated within the appender, such as file handlers,network connections, and so on. When coding your custom appender, be sure you implement this method sothat when your appender is closed, its closed field is set to true.The doAppend () method, follows the Gang of Four (GOF) Template Method design patternThis method provides a skeleton of an algorithm, deferring some steps to subclasses:public synchronized void doAppend (LoggingEvent event) {if (closed) { // s t e p 1LogLog.error("Attempted to append to closed appender [" + name + "].");return;}if (! isAsSevereAsThreshold (event.level)) { // s t e p 2return;}Filter f = this.headFilter; // s t e p 3FILTER_LOOP:while (f! = null) {switch (f .decide (event)) {case Filter. DENY: return;case Filter.ACCEPT: break FILTER_LOOP;case Filter.NEUTRAL: f =;5|Page
  6. 6. }}this. append (e v e n t); // s t e p 4}2.1.1 The algorithm:1. Checks whether the appender is closed.2. Checks whether the logging event is below the threshold of the appender.3. Checks whether filters attached to the appender, if any, deny the request.4. Invokes append () method of the appender. This step is delegated to each subclass.The methods and properties that AppenderSkeleton inherits from Appender. Lets see why AppenderSkeletonimplements the OptionHandler interface. OptionHandler contains only one method: activateOptions (). Thismethod is invoked by a configurator class after calling setter methods for properties. Some properties depend oneach other so they cannot be activated until all of them have been loaded, such as in the activateOptions ()method. This method is a mechanism for developers to perform whatever tasks were necessary before theappender became activated and ready.In addition to all the methods mentioned, look again at Class diagram above. Notice that AppenderSkeletonprovides a new abstract method (append () method) and a new JavaBeans property (threshold). The thresholdproperty is used to filter logging requests by the appender, with only requests over the threshold handled. Wementioned append () method before when we talked about the doAppend () method. It is an abstract methodthat your custom appender must implement because the framework calls it within the doAppend () method. Theappend () method is one of the hooks of the framework.Now that we’ve seen all the methods available in the AppenderSkeleton class, lets see whats happening behindthe scenes. Below figure illustrates the life cycle of an appender object inside log4j:6|Page
  7. 7. 2.1.2 Let’s take a look in brief what is going on above diagram:The appender instance does not exist: Perhaps the framework has not been yet configured.The framework instantiates a new appender: This happens when the configurator classes parse an appenderdeclaration in configuration scripts. The configurator classes call Class.newInstanceYourCustomAppender.class), which is the dynamic equivalent of calling new YourCustomAppender (). Theframework does this so that the framework is not hard-coded to any specific appender name; the framework isgeneric and works with any appender.The framework determines whether the appender requires a layout: If the appender does not require a layout, then configurators dont try to load lay out information from configuration scripts.Log4j configurator calls setter methods: The framework transparently handles appenders propertiesfollowing JavaBeans naming conventions.Configurator invokes the activateOptions () method: After all the properties have been set, the frameworkinvokes this method. Programmers can activate properties here that have to be activated at the same time.Appender is ready: At this point, the framework can call append () method to handle a logging request. Thismethod is invoked by the AppenderSkeleton. doAppend () method.Finally, the appender is closed: When the framework is about to remove y our custom appender instance, itcalls y our appenders close () method. close () is a cleanup method, which means you need to free all theresources you have allocated. It is a required method, and it takes no parameters. It must set the closed fieldto true, alerting the framework when an attempt to use a closed appender occurs. Weve reviewed the conceptsrelated to building y our own appender. real eal-3. Case study: real-world example appender.3.1 Writing an Instant Messenger -based appender:The code presented in this document shows how you can extend the log4j framework to integrate IM features.Its designed to enable a log4j-compliant application to log its output onto Instant Messenger like GTalk. ThePNotifyAppender actually works as a customized IM client. However, instead of System.out, files, or TCP sockets,it takes Instant Messenger as the underlying output device.To provide IM support, we dont need to reinvent the wheel when developing ad-hoc solutions. Instead, weregoing to leverage a tool, here I considered the best of breed: GTalk, which internally uses XML based protocolfor instant messaging and presence i.e. XMPP (Extensible Messaging and Presence Protocol) which is anopen-standard communications protocol for message-oriented middleware based on XML, the protocoloriginally named as Jabber.We chose Jabber over other IM systems because it offers a wide variety of benefits, including its:1. Open source.2. Simplicity.3. Interoperability with other IM systems.4. Resource awareness.7|Page
  8. 8. 3.2 Usage Scenario of PNotifyAppender:Below diagram shows the PNotifyAppender usage scenario: Any application configured to usePNotifyAppender logs its debugging data wrapped as GTalk IM message. The instant message is routed overorganization network to the system administrator. Thus whenever system administrator needs to check on theapplication status, they simply log into their Gmail account using Gtalk IM using his desktop or laptops atwork, or when he is away from his desk, he may use Gtalk IM running on any handheld devices. As Gtalk IMhas the capability to notify us even when we are offline once we log in it will notify system administrator with thepending notifications or real time.But why do we need PNotifyAppender? The answer is that sending messages to IM (Gtalk) allows us tomonitor application behavior more easily with tools at our disposal.PNotifyAppender offers several advantages:1. You get real-time notification about the exception occurred at server, we can consider as “ImmediateLogging”2. GTalk IM isn’t just for desktop computers. It is also being developed for wireless devices such as PDA’s andmobile phones.3. No setup overhead.4. PNotifyAppender notifies the real time exception immediately with the exception details automatically to theInstant Messenger like GTalk and has the ability to keep track of the exception history into the GMail account.8|Page
  9. 9. 4. Overview of PNotifyAppender: Overview PNotifyAppender:PNotifyAppender is modeled based on SMTPAppender logging strategy. PNotifyAppender stores loggingevents in an internal cyclic buffer and send them as an instant message only when the logging request receivedtriggers a user-specified condition. Optionally, users may provide a triggering event evaluator class. However, bydefault, delivery is triggered on events assigned the level ERROR or higher.The number of logging events delivered in each message is limited by the buffer size. The cyclic buffer holds onlythe last buffer size logging events, overflowing when it becomes full and throwing away the older events.To connect to a GTalk, PNotifyAppender relies on Smack API. Smack is an open source, high-level library thathandles the protocol details for communicating with GTalk servers. As a result, you dont need any specialJabber or XML expertise to understand the code.The properties for PNotifyAppender are summarized in Table 1 Property Description Type Required username Gmail Account username e.g. anthing123 String Yes If SSL is true then e.g. password Gmail Account password. String Yes toNotify Recipients address. just as String Yes e-mail addresses do : SSL Used to secure connections. boolean No, defaults to false The maximum number of logging events that can be kept in buffersize the cyclic buffer. int defaults is 16 Takes as a value a string representing the fully qualified name of a class that implements the org.apache.log4j.spi. TriggeringEventEvaluator interface (in other words, a class that contains a custom triggering logic that overrides the No, defaults to evaluatorClass default one). If this option is not specified, String DefaultEvaluator PNotifyAppender uses an instance of the DefaultEvaluator class, which triggers a response to events assigned the level ERROR or higher. proxy It is used to identify whether log4j application behind any boolean No. Default is proxy. false. proxyHost If the proxy property is true, proxyHost takes the proxy String Yes, if proxy sets address. Example : 192.168.xx.xx to true else No. proxyPort Proxy Port. e.g. 3245 String Yes, if proxy sets to true else No. history This property is used, if we want to log the exception boolean No. Default is false history of the real time notification subject The subject option takes a string value which should be a String Yes if history sets the subject of the e-mail message to true else No. cc Set the cc recipient addresses. String No. bcc Set the bcc recipient addresses String No. SMTPHost The SMTPHost option takes a string value which should be String Yes if history sets a the host name of the SMTP server that will send the email to true else No. message9|Page
  10. 10. 4.1 Let’s take a closer look at below code:package com.pnotify.appender;import org.apache.log4j.AppenderSkeleton;import org.apache.log4j.Layout;import org.apache.log4j.helpers.CyclicBuffer;import org.apache.log4j.helpers.LogLog;import org.apache.log4j.helpers.OptionConverter;import org.apache.log4j.spi.LoggingEvent;import org.apache.log4j.spi.TriggeringEventEvaluator;public class PNotifyAppender extends AppenderSkeleton { protected CyclicBuffer cb; private int buffersize; private String username; private String password; private String toNotify; private boolean SSL; private String proxyHost; private String proxyPort; private boolean proxy; protected boolean checkEntryConditions () {} public boolean verifyRosterEntryJabberClient (XMPPConnection connection) {} // AppenderSkeleton callback method public void activateOptions () {} protected void sendBuffer () {} public synchronized void close () {} public boolean requiresLayout () { return true; } protected void append (LoggingEvent event) { } }Notice the following about the PNotifyAppender:a) The PNotifyAppender class extends org.apache.log4j.AppenderSkeleton, which all custom appendersmust do. PNotifyAppender inherits common functionalities from AppenderSkeleton such as appenderthreshold and custom filtering.b) The first part of our appender is straight-forward. We have the appenders fields and set/get methods f or eachof them. Properties and method signatures obey the JavaBeans naming convention. Thus, log4j can analyze theappender using ref lection, transparently handling the appender configuration.c) To complete our appender, we must implement the callback methods that the log4j framework calls tomanage our appender: requiresLayout (), activateOptions (), append (), and close ().The log4j frameworkcalls the requiresLayout () method to know whether the custom appender requires a lay out. Notice that someappenders use a built-in format or dont format the events at all, so they dont require a Layout object. ThePNotifyAppender requires a lay out, hence the method returns true.10 | P a g e
  11. 11. d) Notice that AppenderSkeleton implements the org.apache.log4j.spi.OptionHandler interface.AppenderSkeleton implements the single method of this interface, activateOptions (), as an empty method.PNotifyAppender needs this method because of the interdependence between its properties. For example, theconnection with a GTalk Server depends on the Host, Port, username, password and toNotify properties. soPNotifyAppender cannot establish a connection until these five properties have been initialized. The log4jframework calls the activateOptions () method to signal to the appenders that all the properties have been set.e) Once the activateOptions () method returns, the appender is ready to handle logging requests.AppenderSkeleton.doAppend () does most of the real appending work.f) The checkEntryConditions () method checks whether there is a Chat object available to append the outputand also whether there is a Layout object to format the incoming event object. If these preconditions are notsatisfied, then append () outputs a warning message and returns without proceeding.g) The sendBuffer () method sends the contents of the buffer as an IM message. The method loops through theevents kept in the buffer, formatting each one by invoking the format () method of the layout object. The stringrepresentation of the events is appended to a StringBuffer object. Finally, sendBuffer () calls the sendMessage() method of the chat object, sending the message.h) The AppenderSkeleton.doAppend () method, which invokes append (), is synchronized so sendBuffer ()already owns the monitor for the appender. This frees us from needing to synchronize the CyclicBuffer Object,cb.i) The verifyRosterEntryJabber () method subscribes to the given email Id provided to toNotify property ofthe PNotifyAppender, if it is not present into account.5. Putting it all togetherWell wrap up by showing you PNotifyAppender in action.STEP 1: Drop in the requisite Jars into application. a) commons-logging-1.1.1.jar b) log4j-1.2.16.jar c) mail.jar d) smack.jar (3.2.1) e) smackx.jar (3.2.1) f) pnotifyappender.jarSTEP 2: Configuring log4j.rootLogger=GTALK STEP 2.1: Minimum configuration required if we want real time notification of the exception in GTalk. log4j.appender.GTALK=com.pnotify.appender.PNotifyAppender log4j.appender.GTALK.Threshold=ERROR log4j.appender.GTALK.username=xxxxxxx or (if SSL/history property is set to true) log4j.appender.GTALK.password=xxxxxxx log4j.appender.GTALK.layout=org.apache.log4j.PatternLayout log4j.appender.GTALK.layout.ConversionPattern=%d{MM-dd@HH:mm:ss}[%-5p][%C.%M:%L]-(%F): %m%n11 | P a g e
  12. 12. log4j.additivity.GTALK=false // if behind a proxy log4j.appender.GTALK.proxy=true log4j.appender.GTALK.proxyHost=xxx.xx.xx.xx log4j.appender.GTALK.proxyPort=xxxx STEP 2.2: If we want to keep the history of notified exception into the respective GMail account. 2.2 log4j.appender.GTALK=com.pnotify.appender.PNotifyAppender log4j.appender.GTALK.Threshold=ERROR log4j.appender.GTALK.password=xxxxxxx log4j.appender.GTALK.layout=org.apache.log4j.PatternLayout log4j.appender.GTALK.layout.ConversionPattern=%d{MM-dd@HH:mm:ss}[%-5p][%C.%M:%L]-(%F): %m%n log4j.appender.GTALK.history=true log4j.appender.GTALK.subject=Email Notification from Application log4j.additivity.GTALK=falseThe above configuration script adds PNotifyAppender to the root logger, so each logging request received willbe dispatched to our appender.When we run our respective application, An IM message then pops up on the recipients screen and the belowscreenshots shows the resulting message received by GTalk and GMail.12 | P a g e
  13. 13. Notice that the above figure depicts the real time notification about the exception occurred in the application atGTalk in the mail Id mentioned in toNotify property of PNotifyAppenderThe above figure depicts the exception got recorded into the given GMail Account when history property inPNotifyAppender is set to true and setting the other dependent property.As we can see in the both cases the exception information contained in the last Logging events has been correctlytransmitted.This example application simply showcases use of the PNotifyAppender, so explore and have fun!6. ConclusionThe log4j network appenders, SocketAppender, JMSAppender, and SMTPAppender, already provide mechanismsto monitor Java-distributed applications. However, several factors make IM a suitable technology for remotelogging in real-time. In this article, weve covered the basics of extending log4j with y our custom appenders, andweve seen the implementation of a basic PNotifyAppender step by step. Many developers and systemadministrators can benefit from their use.7. Resources1. Book: Template Method - Design Patterns in Java by Steven John Metsker and William C.Wake4. Book: Instant Messaging in Java: the jabber Protocol by Ian Shigeoka6. MagicwithMerling: Exception and Logging | P a g e