This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

best way for logging WHO did WHAT in spring web apps?Page Title Module

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.

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.

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.

Comment

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.

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

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

+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.

Comment

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:

Comment

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

Comment

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,

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.

Comment

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,

Comment

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)

Comment

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.