views:

164

answers:

6

Hi, We have a system that uses threading so that it can concurrently handle different bits of functionality in parallel. We would like to find a way to tie all log entries for a particular "transaction" together. Normally, one might use 'threadName' to gather these together, but clearly that fails in a multithreaded situation.

Short of passing a 'transaction key' down through every method call, I can't see a way to tie these together. And passing a key into every single method is just ugly.

Also, we're kind of tied to Java logging, as our system is built on a modified version of it. So, I would be interested in other platforms for examples of what we might try, but switching platforms is highly unlikely.

Does anyone have any suggestions?
Thanks,
Peter

EDIT: Unfortunately, I don't have control over the creation of the threads as that's all handled by a workflow package. Otherwise, the idea of caching the ID once for each thread (on ThreadLocal maybe?) then setting that on the new threads as they are created is a good idea. I may try that anyway.

A: 

How about naming your threads to include the transaction ID? Quick and Dirty, admittedly, but it should work (until you need the thread name for something else or you start reusing threads in a thread pool).

Yishai
I didn't know you could do that, so thanks, but I'm using a workflow package, so I don't really have control over the thread names per se.
Risser
+1  A: 

You could consider creating a globally-accessible Map that maps a Thread's name to its current transaction ID. Upon beginning a new task, generate a GUID for that transaction and have the Thread register itself in the Map. Do the same for any Threads it spawns to perform the same task. Then, when you need to log something, you can simply lookup the transaction ID from the global Map, based on the current Thread's name. (A bit kludgy, but should work)

VeeArr
I like this idea, except that I don't get to see the actual generation of the thread. It's out of my hands, thanks to the workflow package.
Risser
To expand on this idea, what is being proposed here is to queue up logged events on a thread by thread basis. If at *some point* during the processing, you know the transaction id, then you can associate it with all the log events queued up.If you are generating large numbers of log events, this 'queue' might still be on the filesystem, and you use a post-processing step to convert threadId --> transactionId.
Dilum Ranatunga
A: 

If you are logging, then you must have some kind of logger object. You should have a spearate instance in each thread.

  • add a method to it called setID(String id).
  • When it is initialized in your thread, set a unique ID using the method.
  • prepend the set iD to each log entry.
Zak
A: 

A couple people have suggested answers that have the newly spawned thread somehow knowing what the transaction ID is. Unless I'm missing something, in order to get this ID into the newly spawned thread, I would have to pass it all the way down the line into the method that spawns the thread, which I'd rather not do.

I don't think you need to pass it down, but rather the code responsible for handing work to these threads needs to have the transactionID to pass. Wouldn't the work-assigner have this already?

matt b
+1  A: 

This is a perfect example for AspectJ crosscuts. If you know the methods that are being called you can put interceptors on them and bind dynamically.

This article will give you several options http://www.ibm.com/developerworks/java/library/j-logging/

Romain Hippeau
+1  A: 
leopoldkot