In our application we have several transactions, where each step is extensively logged.
Pseudocode:
@Component
public class OurServiceImpl implements OurService {
...
@Transactional
public void doComplexTransaction(...){
String transactionId = generateTransactionId(userid, date)
log.info("==========================Start Transaction" + transactionId);
log.info("Doing A");
doA(..., transcationId);
log.info("Doing B");
doB(..., transcationId);
log.info("Doing C");
doC(... transcationId);
log.info("==========================End Transaction" + transactionId);
}
...
public void doA(..., transactionId){
...
log.info("Doing SubA "+transactionId);
doSubA();
}
}
Because the logging is distracting, we decided to use AOP for that.
The method doComplexTransaction(..)
could be covered with @Around(execution(FQN.doComplexTransaction(..)))
The calls doA()
, doB()
and doC()
could be refactored out to another class, so they could be covered with @Around
likewise.
But then the following problem occurs:
How to pass the transcationId (generated in one advice) between different advices?
Or more general:
How to design "transactional logging (with identifier)" across several methodcalls and objects?
Could this be done with Spring-AOP
?
My goal is to discern the different concurrent transactions in my log, that would make it easy queryable via elasticsearch et al.
Bruteforce-solution:
(similar to Steve Park's)
One idea, which I had, was generating the transactionId
in the first advice and "inject" it for further calls in proceedingJoinPoint.proceed(..., transactionId). In any further advice, I could extract the
transactionIdvia
.getArgs()and inject it in the
proceed()`-call.
But this has two downsides:
1) It is aesthetically non pleasant, or just: awkward. It's a hack, though a working one.
2) This violates several design principles, first: the principle of least astonishment. If a reviewer looks at the POJO and sees a variable passed but never "used" - thanks to AOP - he would be at least astonished.
So, yes, that is one solution, but I am looking for a better one.
TransactionAspectSupport
. It does something like what you need, although I'm not sure you can use it as-is for your use case.