package rocks.inspectit.agent.java.sensor.method.remote.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rocks.inspectit.agent.java.config.impl.RegisteredSensorConfig;
import rocks.inspectit.agent.java.core.ICoreService;
import rocks.inspectit.agent.java.core.IPlatformManager;
import rocks.inspectit.agent.java.hooking.IMethodHook;
import rocks.inspectit.agent.java.sdk.opentracing.internal.impl.SpanImpl;
import rocks.inspectit.agent.java.sensor.method.http.StartEndMarker;
import rocks.inspectit.agent.java.tracing.core.ClientInterceptor;
import rocks.inspectit.agent.java.tracing.core.adapter.ClientAdapterProvider;
import rocks.inspectit.agent.java.tracing.core.adapter.ClientRequestAdapter;
import rocks.inspectit.agent.java.tracing.core.adapter.ResponseAdapter;
import rocks.inspectit.agent.java.tracing.core.transformer.SpanTransformer;
import rocks.inspectit.shared.all.tracing.data.AbstractSpan;
/**
* The hook is the default implementation of remote client. The hook works with the
* {@link ClientInterceptor} in order to correctly handle client request start in the
* {@link #beforeBody(long, long, Object, Object[], RegisteredSensorConfig)} and request end in the
* {@link #secondAfterBody(ICoreService, long, long, Object, Object[], Object, RegisteredSensorConfig)}.
* <p>
* This hook measures also measures execution time.
* <p>
* The created spans will be passed to the give core service of the second after body method.
*
* @author Thomas Kluge
* @author Ivan Senic
*
*/
public class RemoteClientHook implements IMethodHook {
/**
* The logger of the class.
*/
private static final Logger LOG = LoggerFactory.getLogger(RemoteClientHook.class);
/**
* Helps us to ensure that we only execute one remote client hook for each client request on all
* remote client sensor implementations.
* <p>
* Static on purpose.
*/
private static final StartEndMarker REF_MARKER = new StartEndMarker();
/**
* {@link ClientInterceptor}.
*/
private final ClientInterceptor clientInterceptor;
/**
* {@link ClientAdapterProvider}.
*/
private final ClientAdapterProvider clientAdapterProvider;
/**
* The Platform manager.
*/
private final IPlatformManager platformManager;
/**
* The stack containing the span created by the {@link #clientInterceptor}.
*/
private final ThreadLocal<SpanImpl> spanStack = new ThreadLocal<SpanImpl>();
/**
* Default constructor.
*
* @param clientInterceptor
* Our client interceptor.
* @param clientAdapterProvider
* {@link ClientAdapterProvider}
* @param platformManager
* The Platform manager
*
*/
public RemoteClientHook(ClientInterceptor clientInterceptor, ClientAdapterProvider clientAdapterProvider, IPlatformManager platformManager) {
this.clientInterceptor = clientInterceptor;
this.clientAdapterProvider = clientAdapterProvider;
this.platformManager = platformManager;
}
/**
* {@inheritDoc}
*/
@Override
public void beforeBody(long methodId, long sensorTypeId, Object object, Object[] parameters, RegisteredSensorConfig rsc) {
if (!REF_MARKER.isMarkerSet()) {
// get requestAdapter and handle
ClientRequestAdapter<?> adapter = clientAdapterProvider.getClientRequestAdapter(object, parameters, rsc);
if (null != adapter) {
SpanImpl span = clientInterceptor.handleRequest(adapter);
if (null != span) {
spanStack.set(span);
if (LOG.isDebugEnabled()) {
LOG.debug("Remote client hook before body span " + span);
}
}
}
}
REF_MARKER.markCall();
}
/**
* {@inheritDoc}
*/
@Override
public void firstAfterBody(long methodId, long sensorTypeId, Object object, Object[] parameters, Object result, RegisteredSensorConfig rsc) {
REF_MARKER.markEndCall();
}
/**
* {@inheritDoc}
*/
@Override
public void secondAfterBody(ICoreService coreService, long methodId, long sensorTypeId, Object object, Object[] parameters, Object result, RegisteredSensorConfig rsc) {
// check if in the right(first) invocation
if (REF_MARKER.isMarkerSet() && REF_MARKER.matchesFirst()) {
// call ended, remove the marker.
REF_MARKER.remove();
// extract span from thread local
SpanImpl span = spanStack.get();
if (null != span) {
// get requestAdapter
ResponseAdapter adapter = clientAdapterProvider.getClientResponseAdapter(object, parameters, result, rsc);
// only handle if request adapter is provided
if (null != adapter) {
clientInterceptor.handleResponse(span, adapter);
spanStack.remove();
if (LOG.isDebugEnabled()) {
LOG.debug("Remote client hook after body span " + span);
}
AbstractSpan transformedSpan = SpanTransformer.transformSpan(span);
transformedSpan.setPlatformIdent(platformManager.getPlatformId());
transformedSpan.setMethodIdent(methodId);
transformedSpan.setSensorTypeIdent(sensorTypeId);
// add to core service (use span id as prefix)
coreService.addMethodSensorData(sensorTypeId, methodId, String.valueOf(transformedSpan.getSpanIdent().getId()), transformedSpan);
}
}
}
}
}