Search code examples
javaloggingjava-ee-6cdiinterceptor

Logging a user's Session ID via javax interceptor


I have created an Interceptor with a method annotated with @AroundInvoke to log method calls and associated timings. This is based on Richard Hightowers excellent blog posting on CDI AOP http://java.dzone.com/articles/cdi-aop):

@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
    Logger logger = Logger.getLogger(ctx.getTarget().getClass().getName());

    logger.trace("ENTERING : "+ctx.getMethod());

    long start = System.currentTimeMillis();

    Object returnMe = ctx.proceed();

    long executionTime = System.currentTimeMillis() - start;

    logger.trace("EXITING : "+ctx.getMethod()+":"+executionTime+"ms");

    return returnMe;
}

I would like to log the user's session id so I can readily analyse a users path through the application. How do I get hold of the user's session?

I looked at injecting the SessionContext but could not see how to use the API to extract this value.

I have looked at log4j MDC but I was hoping to avoid the need to add a servlet filter.


Solution

  • Really my question should have been "How do I log method invocations such that a given users path through the application can easily be parsed out of the log file?". The question as it stands assumes getting the session id is the answer which may well not be the case. With this better phrased question in mind I have now discovered that as long as all business logic of concern is accessed via EJBs you can indeed log a given users path as follows:

    Create an interceptor class that has an EJB SessionContext injected in to it:

    /**
    * SessionContext of this EJB; this will be injected by the EJB
    * Container because it's marked w/ @Resource
    */
    @Resource
    private SessionContext context;
    

    Add a method annotated with AroundInvoke that will intercept calls:

    @AroundInvoke
    public Object log(InvocationContext ctx) throws Exception {
        String originName = Thread.currentThread().getName();
        String currentUser = context.getCallerPrincipal().getName();
            try{
               String tracingName = currentUser + " " + originName;
               Thread.currentThread().setName(tracingName);
               return ctx.proceed();
            }finally{
                Thread.currentThread().setName(originName);
            }
        }
    

    Note we use the session context to get hold of the user who has caused this action. We then change the name of the thread to hold that users name. All subsequent logging in this call stack will output the users name assuming loggin is configured to also output the thread name regardless of if they are in an EJB or just some POJO class.

    This thread renaming was inspired by Adam Bien's server independent thread tracking utility:

    http://www.adam-bien.com/roller/abien/entry/server_independent_thread_tracking_utility

    Altering it to rename the thread to be the users name was a modification I made.