Announcement Announcement Module
Collapse
No announcement yet.
best way for logging WHO did WHAT in spring web apps? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • best way for logging WHO did WHAT in spring web apps?

    i am doing a Spring web application and
    i have a design/implementation question. i have
    not figured out how to do it the best way.

    the requriement is to record WHO(which user)
    did WHAT (save, delete...) in the application.

    i have seen a few Spring web apps)
    but they only record WHAT.
    this can be accomplished in the service tier
    easily. specifically, when an operation is done,
    a service method simply writes a log entry.

    however, i have two issues with this
    approach. first, how can the service tier
    get User information (the WHO part)?
    i can make each method in a service manager
    take a parameter of user information, but
    this would service interface ugly. on the
    other hand, i think the logging/auditing is
    NOT a service manager's job.

    the other option for me is to write
    log entries (through an audit service manager)
    in web controllers. specifically,
    writing a log entry after a service method
    is called successfully. however, this approach
    is not ideal either, since the same method
    may be called in many places and i have
    to write logging statements the same way
    repeatedly. besides, i have to wire
    audit service manager with almost each
    web controller.

    then, the AOP approach? i dont know how
    Spring AOP can help me log WHO did WHAT.
    i have seen some examples, but they
    are really simplistic, most often missing
    both the WHO part and detailed information
    about WHAT.

    other approaches? somehow, i would like
    to do the logging in service managers.
    but i dont know how to make user information
    available to service managers in an
    elegant way.

    anybody has the same problem as i do?
    any advice? any solution?

    thanks!
    pete

  • #2
    the requriement is to record WHO(which user)
    did WHAT (save, delete...) in the application.
    Which part of the application is responsible for this requirement? Is it a key requirement or not? Which layer of the responsible sub-modules is affected? Is it affected within it's business or presentation layer?

    You might want to also take a look on the wikipedia code http://sourceforge.net/projects/wikipedia/. You may find valuable informations within the doc section of the current release, that keep you thinking. In the wikipedia world, knowing 'who did what' apears to be a key requirement.


    The other option for me is to write log entries (through an audit service manager) in web controllers. specifically, writing a log entry after a service method is called successfully. however, this approach is not ideal either, since the same method may be called in many places and i have to write logging statements the same way repeatedly. besides, i have to wire audit service manager with almost each web controller.
    The jMock people use an interface looking like this:

    Code:
    public interface SelfDescribing {
        StringBuffer describeTo( StringBuffer buffer );
    }
    In your case it might be preferable to use something similar. So seperate what is logged and if it is logged and how. You might already use the command/action pattern to implement the various parts of the chain of responsibility (decomposing processing of requests using highly focused sub-parts). So logging becomes like checking, if the current command is selfdescribing and log the description the command/action provides. And this checking and the actual logging can be done by using AOP for instance.


    [qote] other approaches? somehow, i would like to do the logging in service managers. but i dont know how to make user information available to service managers in an elegant way. [/quote]

    To log 'who is doing what', you surely need to identify the current user being logged into the system. This information is normaly part of the session (session datas). Optaining and tracking a session is a key issue of the J2EE domain. (very good introduction: http://java.sun.com/j2ee/1.4/docs/tu...1.html#wp64744)

    Also most web-tiers feature a single thread for a single request approach. In this case you might use a solution based on ThreadLocal to make the current implementation visible without the need of passing the sessionId or the HttpRequest along.


    Cheers,

    Martin (Kersten)

    Comment


    • #3
      You could bind the user information to a threadlocal and 'advice' your services with a logging aspect (that uses the userinformation from the threadlocal).

      Maybe you could have a look at:
      http://acegisecurity.sourceforge.net

      [edit]
      THe ThreadLocal solution was also mentioned by Martin (the reply above this one)

      Comment


      • #4
        Also most web-tiers feature a single thread for a single request approach. In this case you might use a solution based on ThreadLocal to make the current implementation visible without the need of passing the sessionId or the HttpRequest along.
        I don't mean the current implementation but the current session datas.

        Comment


        • #5
          There are already some good posts in here so I'm going to be short.
          The answer to the problem depends a lot of your requirements and frameworks that you use.
          From my experience, security is best implemented in the java world through some sort of AOP (be it filter, interceptor or smth else).
          +WHO+
          If you are using spring and don't have a complex framework in place then Acegi might be the thing for you.
          If you don't want to use it (thing well about this one) you can use the already mentioned functionality from the HttpRequest API.
          +WHAT+
          This depends a lot of what type of persistence do you use. In case of Hibernate at least there are interceptors which make saving changes a breeze - take a look at this example: http://www.hibernate.org/195.html

          Comment


          • #6
            The net.sf.acegisecurity.context package has been explicity designed to be usable by people who don't want to use the rest of Acegi Security at all. The package provides a comprehensive solution to ThreadLocal binding of context information and worries about cleanup etc after each request.

            ThreadLocal is a good solution, as many others pointed out. You can use the Acegi Security context package or write your own, but either approach is vastly superior to method arguments. On the Hibernate interceptor approach, that's more a case of which technology should be used to perform the advice. I'd personally use Hibernate extensively, but apply AOP using Spring. It's a more portable approach, and you have fewer Hibernate Session management complexities.

            Comment


            • #7
              hi, thanks so much to all of you for expert advice and thoughts.

              +WHAT+ This depends a lot of what type of persistence do you use. In case of Hibernate at least...
              i think where to log user activities depends on what you want to log
              and at what granularity. if log detailed database access, then log
              them at hibernate level. however, once caveat: on business method
              could invoke many database calls.

              i am going to use LocalThread to pass WHO information, and then use
              AOP approach to capture WHAT information at the business service tier
              (apply AOP to methods of service managers). There is issue i am still
              struggling with: generate meaningful WHAT information. Suppose, the
              activity format i want to capture is the following:

              John Smith (WHO) create user (WHAT-1), user ID is 100 (WHAT-2)

              Using AOP, I can at least get WHAT-1 information by getting the method
              name. But how can I generate MEANINFUL WHAT-2 information,
              considering there are many different methods which have different
              arguments? How do you address this need effectively?

              One solution in my mind is at the web tier, I also put WHAT-2 information
              in ThreadLocal and then AOP interceptor will not only get WHO but also
              get WHAT info. However, I donít like this approach very much. This
              means that in almost all web controllers I need to write a line of code to
              put in ThreadLocal WHAT-2 information before calls to methods of service
              managers (I can use AOP approach to put WHO info in ThreadLocal when
              controller methods are called and save one or two lines of code for each
              business method call).

              I think this issue also applies to the AOP approach at the Hibernate level if
              the logged info conforms to the above format.

              Please advise.

              Regards, Pete

              Comment


              • #8
                John Smith (WHO) create user (WHAT-1), user ID is 100 (WHAT-2)

                Using AOP, I can at least get WHAT-1 information by getting the method
                name.
                If you have control about the environment / requirements you might want to go for a true aspect oriented solution and try out AspectJ. Just advice the service interfaces forumlating advices on a single method base, so you can easily investigate the parameters and formulate usefull logging informations (also using AspectJ you can use polymorphism for the logging aspects).

                Another idea would be using the Command/Action pattern and let the command implement an interface making it possible for the command to describe itself. (see the second post in this thread).

                [edit]
                Please take a look at the BeforeMethodAdvice (or AfterMethodAdvice) within the AOP framework. It features the following abstract method:

                void before(Method method, Object[] args, Object target) throws Throwable;

                So you can catch the method being called, the WHO information and also the parameters. So you don't need to switch to AspectJ to just investigate the parameters also.

                So for your task it might look like:

                Code:
                void before(Method method, Object[] args, Object target) {
                   if(isAddUserMethod(method)) 
                       log("The user '"+getUser()+"' added a new user with the id "+args[0]+" and the name '"+args[1]+"'");
                }
                This looks ugly and can be improved for readabilty for sure but I think you get the meaning.

                [/edit]


                Cheers,

                Martin (Kersten)

                Comment


                • #9
                  Martin,

                  Thanks for your input. As mentioned in other posts, I dont
                  want to include WHO as a parameter in method signitures because
                  that gets interface ugly.
                  Futher, investigating parameter is difficult to create a meaningful
                  WHAT-2, because there are many methods with different
                  parameters in different modules of an application...

                  i am thinking about using:

                  Command/Action pattern and let the command implement an interface making it possible for the command to describe itself.
                  in a web controller which calls a business method, i create a
                  logging Command object and put it in ThreadLocal, then
                  apply an AOP interceptor to all business methods. This interceptor
                  grabs the Command object from ThreadLocal and write a log
                  entry after a method call.

                  Please take a look at the BeforeMethodAdvice (or AfterMethodAdvice) within the AOP framework
                  that is what i am going to do.

                  does it sound good to you?

                  regards, pete

                  Comment


                  • #10
                    Thanks for your input. As mentioned in other posts, I dont
                    want to include WHO as a parameter in method signitures because
                    that gets interface ugly.
                    You misunderstood me here, I guess. Please check out the method signature. I only referred to the user by using getUser(). It is up to you to decide how to implement this getUser method (ThreadLocal if you like, or anyother per session solution).


                    WHAT-2, because there are many methods with different
                    parameters in different modules of an application...
                    That's why I actually considered the above illustration as ugly. It was just to illustrate, that the use of AspectJ is preferred but not necessarily. Maybe using a plugable way, would solve you something.

                    I was thinking about the setup of the logging advice. Since logging is mostly referred as a default usecase, there should be something already out there.

                    But anyways, the best that I came up in a little break was:

                    1. Set up the advice by registering all methods that should be logged,

                    Code:
                    LoggingAspect {
                       void registerMethodToLog(String methodName, String loggingMessagePattern);
                    }
                    2. Using any logging message pattern format you might like (check out the internationalization support or the capabilites of Java 1.5), you may end up with something like this:

                    loggingAspect.registerMethodToLog("addUser", "The user '${user}' added a new user named '${param1}' with userId='${param0}'");

                    (for BusinessInterface.addUser(int userId, String userName))

                    Since now you can set up this advice dynamically, you may declare your logging messages using the usuall Spring way (using a xml declaration etc.) So you can easily edit your logging messages, if you need to.

                    So thinking about this, I guess I would go for the formatted messages instead of the command approach. For the pattern format you might want to use, it is up to you but I am very certain that there is a solution already out there.

                    [note]
                    By the way I didn't ment to push a Command about loggin in a ThreadLocal. I was referring to dispatch each web action into a command and pass this command into the business layer. (Command driven approach). (http://www.javaworld.com/javaworld/j...javatip68.html, http://www.leocrawford.org.uk/work/j...s.html#command)
                    [/note]


                    Cheers,

                    Martin (Kersten)

                    Comment


                    • #11
                      martin,

                      thanks very much for your info and thoughts. i will think about
                      it again and play with it and will come back to this thread
                      to report my experence.

                      thanks again!
                      pete

                      Comment


                      • #12
                        Here is what we did in our project.

                        1. Each method in business object, we have only one argument which is a container, let is call it BizRequest
                        2. In the BizRequest, we have a Identirybean defined which holds all the creditional info for the user, such as roles, userId, ...
                        3. We use AOP to intercept the bo method invocation, before the method, we capture the VO data ,action which couldbe methodName,userId, time, after the method invoication. if sucessful, capture the data returned, if there are exception, capture the exceptin info,
                        4. store the caputred data in to the database,

                        it works pretty well.

                        Comment


                        • #13
                          Vinson,

                          thanks for your input. glad to know it works for you.
                          however,

                          Each method in business object, we have only one argument which is a container, let is call it BizReq
                          what you did in your project contradicts what i know about "good" design:
                          interface for business objects which should, if possible,
                          be independent on specific technologies such as servlets.

                          your comment? maybe i have some misunderstanding about your approach.

                          thanks, pete

                          Comment


                          • #14
                            I don't know what do you mean 'good' design.

                            There are two approach to design the interface signature to the presention tier.

                            1. classic. something like
                            List getUserList(Integer userId, String firstName, String lastName)
                            the advantage is it is strongly type-safe, but it is not flexible.

                            2. another way is user an argument container.
                            BizResponse getUserList(BizRequest bizRequest)
                            it is something like command pattern. the disadvantage is it is not strong type safe,
                            but with JDK5 , it is not a problem.
                            <Response, Request> Response getUserList(Request bizRequest)

                            3. if we don't use JDK5. we have a trade-off solution.

                            List getUserList(IdentiryBean idBean,Integer userId, String firstName, String lastName)

                            IdentiryBean can hold all the creditional info.

                            we need to follow some code convention.
                            the first argument must be IdentiryBean for each biz method. may with the exception userLogon.

                            Hope it helps.

                            Comment


                            • #15
                              vinson,

                              thanks for your clarification and sorry my possible misunderstanding.
                              passing creditional info as argument (one or more) in business methods is
                              considered a bit "ugly" design and it is the theme of the messages in this thread.
                              i understand that this approach definitely works.
                              i like to hear your thoughts.

                              regards,
                              pete

                              Comment

                              Working...
                              X