Strategies for centralized logging


In the previous section, we saw how to avoid duplicate logging. But when it comes to the entire application, you also learnt that logging should not only be done once but also centralized for disparate modules of the system if possible. There are various strategies to achieve centralized logging in the web tier . This section will cover those strategies.

Consider the web-tier for MyBank . After the Struts Forms are populated the RequestProcessor invokes the execute method on Action classes. Typically, in the execute method you access enterprise data and business logic in session ejbs and legacy systems. Since you want to decouple your web tier from the business logic implementation technology (EJB for example ‚ which forces you to catch RemoteException ) or the legacy systems, you are most likely to introduce Business Delegate s. (Business Delegate is a Core J2EE Pattern). The Business Delegates might throw a variety of exceptions, most of which you want to handle by using the Struts declarative exception handling. When using the declarative exception handling you are most likely to log the exceptions in the JSPs since the control passes out of your code at the end of the execute method. Instead of adding the exception logging code to every JSP declared in Struts Config file, you can create a parent of all the error JSPs and put the logging code in there. Listing 9.14 shows a sample base JSP class.

Listing 9.14: Base JSP class for error pages
 public abstract class MybankBaseErrorJsp implements HttpJspPage {   private ServletConfig servletConfig;   public ServletConfig getServletConfig() {     return servletConfig;   }   public String getServletInfo() {     return "Base JSP Class for My Bank Error Pages";   }   public void init(ServletConfig config)                                 throws ServletException {     this.servletConfig = config;     jspInit();   }   public void jspInit()    {}   public void jspDestroy() {}   public void service(ServletRequest req, ServletResponse res)                    throws ServletException, IOException  {      HttpServletRequest request = (HttpServletRequest)req;      HttpServletResponse response = (HttpServletResponse)res;              JspFactory  factory     = JspFactory.getDefaultFactory();      PageContext pageContext = factory.getPageContext(                              this, request, response,                              null,  // errorPageURL                              false, // needsSession                              JspWriter.DEFAULT_BUFFER,                              true   // autoFlush                              );          Exception exc = pageContext.getException();      String trace =StackTraceTool.getStackTraceAsString(exc);      Logger.getLogger(getClass().getName()).error(trace);      //proceed with container generated code from here      _jspService(request,response);   }   public abstract void _jspService(HttpServletRequest request,                                              HttpServletResponse response)                         throws ServletException, IOException; } 
 

There is quite a bit going on in Listing 9.14. First the class implements the javax.servlet.jsp.HttpJspPage interface. All the methods in this interface except the _jspService() have concrete implementations . These methods represent the various methods called during the JSP life cycle. In particular you will recognize the service method that is similar to the servlet ‚ s service method. In the course of this method execution, the _jspService() method is also executed. _jspService() method is not implemented by the page author or the developer. Instead it is auto generated by the servlet container during JSP pre-compilation or run time. All the markup, tags and scriptlets contained in the JSP get transformed into Java code and form the gist of the _jspService() method. The page author indicates that the jsp extends from this java class by adding the directive

 <%@ page extends="mybank.webtier.MybankBaseErrorJsp" %> 

If all of the Error-JSPs extend from this abstract JSP class, centralized logging is achieved. Before you celebrate for having nailed down the problem, shall we remind you that this solution may not work in all servlet containers. The reason for this is JspFactory and PageContext implementations are vendor dependent. Normally the calls for JspFactory.getDefaultFactory() and factory.getPageContext() occur in the auto generated _jspService() method. It is possible that some of the implementations may not initialize these objects we accessed in the service() method until they reach the _jspService() method !

Don ‚ t panic. We have an alternate solution, which is less elegant but is guaranteed to work across vendor implementations. Let us create a custom tag to be invoked from all of the Error-JSPs. Listing 9.15 shows the logic for doStartTag() method of this custom tag. You will notice that it is very much similar to the service() method in Listing 9.14. After obtaining the exception object, it is logged by obtaining the Logger from Log4J. Since this tag is invoked within the _jspService() method for the JSP, it is guaranteed to have access to all of the implicit objects including pagecontext and exception in every vendor implementation.

Listing 9.15: Custom Tag for exception logging
 public class ExceptionLoggingTag extends TagSupport {     public int doStartTag() throws ServletException, IOException      {        Exception exc = pageContext.getException();        String trace =StackTraceTool.getStackTraceAsString(exc);        LogFactory.getLog(getClass().getName()).error(trace);        return EVAL_BODY_INCLUDE;     } } 
 

For those of you who are visualizing the big picture, you will realize that logging from the JSP is not the right way. However there is no ideal way to achieve centralized logging without taking this approach. Each mechanism has its drawbacks and tradeoffs. This is something you will experience whenever design abstractions meet reality.

Until now you have seen a JSP based approach of exception handling and logging. What if you have a requirement to handle the exceptions originating from your application differently? Let us consider the application exceptions from our very own MyBank . The exceptions originating from the MyBank are subclasses of MybankException and MybankRuntimeException . When using Struts as the framework in your web applications, then you will most likely have a base Action class with trivial functionality common to all of the Actions factored out. The base Action class is the ideal location to centralize the special processing for the application exceptions. Listing 9.16 shows a sample base Action, MybankBaseAction for the special processing just mentioned.

Listing 9.16: Mybank Base Action
 public class MybankBaseAction extends Action {   public ActionForward execute(ActionMapping mapping,           ActionForm form, HttpServletRequest request,           HttpServletResponse response) throws Exception    {     ActionForward aForward = null;     MybankBaseForm aForm = (MybankBaseForm)form;     try  {       preprocess(mapping, aForm, request, response);       aForward = process(mapping, aForm, request, response);       postprocess(mapping, aForm, request, response);     }      catch(MybankException ae) {        //Any Special Processing for Mybank goes here       if (ae.isLogged()) {         String trace = StackTraceTool.getStackMessage(ae);         LogFactory.getLog(getClass().getName()).error(                  ae.getUniqueID() + ":" + trace);         ae.setLogged(true);       }       aForward = errorPage;     }     return aForward;   }   protected abstract void preprocess(ActionMapping mapping,           MybankBaseForm form, HttpServletRequest request,           HttpServletResponse response) throws Exception;   protected abstract void process(ActionMapping mapping,           MybankBaseForm form, HttpServletRequest request,           HttpServletResponse response) throws Exception;   protected abstract void postprocess(ActionMapping mapping,           MybankBaseForm form, HttpServletRequest request,           HttpServletResponse response) throws Exception; } 
 

This class implements the execute method, but defines three abstract methods preprocess() , process() and postprocess() which take the same arguments as the execute() method but are invoked before, during and after the actual processing of the request. In the execute method, the MybankException is caught and any special processing required is done and then re-throw the exception for the declarative exception handling to work or programmatically forward to the relevant error page.

Note that you can achieve the same result by creating a custom exception handler for the MybankException . The custom exception handler ‚ s execute() method will do exactly what the catch block in Listing 9.16 is doing.




Struts Survival Guide. Basics to Best Practices
Struts Survival Guide: Basics to Best Practices (J2ee Survival Series)
ISBN: 0974848808
EAN: 2147483647
Year: 2004
Pages: 96

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net