I'm using Akka with Java. I want to know is there any best practice/pattern to trace scenarios with logging in Akka environment?
Here is a very simple scenario:
- A source
Deviceactor sends astatusmessage to thePropagatoractor; - The
Propagatoractor forwards thestatusmessage to its listeners (otherDeviceactors); - Each listener (
Device) sends anackmessage to thePropagatoractor.
Base Requirements:
- Each running scenario should be distinguishable in logs.
- The scenario-initiator identifier (here is a device-id) should be presented in all logs.
Any advice for adding to requirements? Maybe the initiating message's class name!?
My approach is putting traceable info in logger's MDC: 1) introducing an interface for marking messages and 2) an Abstract class as a base class of all actors:
1- Traceable which is implemented by all (related) message classes:
public interface Traceable {
String traceId(); // An unique id (UUID) in each scenario (Req#1)
int deviceId(); // Device which initiated the scenario (Req#2)
}
2- AbstractActorWithLogging as base class of all actors, which puts traceable information in logger's MDC:
public abstract class AbstractActorWithLogging extends AbstractActor {
protected final DiagnosticLoggingAdapter logger = Logging.getLogger(this);
@Override
public void aroundReceive(PartialFunction<Object, BoxedUnit> receive, Object msg) {
try {
if (msg instanceof Traceable) logger.setMDC(extractMdc(((Traceable) msg)));
if (logger.isDebugEnabled()) logger.debug("Received: {}.", msg);
super.aroundReceive(receive, msg);
if (logger.isDebugEnabled()) logger.debug("Processed: {}.", msg);
} finally {
logger.clearMDC();
}
}
protected Map<String, Object> extractMdc(Traceable traceable) {
Map<String, Object> mdc = new HashMap<>();
mdc.put("traceId", traceable.traceId());
mdc.put("deviceId", traceable.deviceId());
return mdc;
}
}