javatomcatcross-cutting-concerns

Gather data across layers for writing audit logs


Background

The application in question is a Java web-app deployed in Tomcat and uses Apache CXF for exposing REST services. I found Spring configuration, but not sure how well it is wired up to the CXF infrastructure.

Every time something important happens, like an entity is updated or deleted, I'd like to log information including (but not limited to):

  1. What happened
  2. Who made the request
  3. What entity was changed
  4. New state of the entity if applicable
  5. Information about any notification emails sent
  6. etc...

Current Setup & challenge

We have several layers and the calls look like this: Controller > Service > Data Layer > Utils (Email, SMS sending etc...).

The problem is, the data I want to gather and log, begins to be available and is only available in separate layers. Some times the data is passed through arguments to the next layer, but other times they are not passed because the data isn't required in other layers. Here are some examples:

But I need to gather such information from across all layers and log them for audit purpose, as a single log line.

Constraints

My question is, how and where should I gather all this data and write them to the audit log? What is the best practice for doing the above, in a Java web application?


Solution

  • Sounds like your application is a mess.

    However it should still be possible to do this as long as everything is triggered based on a request.

    Here's two approaches:

    1) Use the MDC object from a logging framework like Logback. This object can be filled on a request basis with keys where you can attach arbitrary information that can be later extracted for logging (or it can be automatically attached as additional fields to your log message). Read up on it here: https://logback.qos.ch/manual/mdc.html

    It would be my recommended solution as it closely matches what you are trying to achieve. If that's not possible then:

    2) Create an object with static access to a ThreadLocal that you use for the purpose of keeping track of information accross various layers. Log it in a HTTP Filter when requests finish. And make sure to clear the information again so it is not mixed up with the next request that uses the same thread.

    If you don't want to pollute your code with audit logging, you may consider using Aspects (Aspect Orientated Programming) to add this functionality to your classes.