package rocks.inspectit.agent.java.sdk.opentracing.propagation;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import rocks.inspectit.agent.java.sdk.opentracing.internal.TracerLogger;
import rocks.inspectit.agent.java.sdk.opentracing.internal.constants.PropagationConstants;
import rocks.inspectit.agent.java.sdk.opentracing.internal.impl.SpanContextImpl;
import rocks.inspectit.agent.java.sdk.opentracing.internal.impl.TracerLoggerWrapper;
import rocks.inspectit.agent.java.sdk.opentracing.internal.util.ConversionUtils;
/**
* Abstract {@link Propagator} that knows what is injected and extracted from the carrier.
* Implementing classes must only provide {@link #injectBaggage(Object, String, String)} and
* {@link #extractBaggage(Object)} methods, where they can deal with any needed operations as
* encoding for example.
*
* @param <C>
* type of carrier
* @author Ivan Senic
*
*/
public abstract class AbstractPropagator<C> implements Propagator<C> {
/**
* Logger of this class.
*/
private static final TracerLogger LOGGER = TracerLoggerWrapper.getTraceLogger(AbstractPropagator.class);
/**
* Injects one baggage item to the carrier. Sub-class is responsible of providing exactly this
* key/value once {@link #extractBaggage(Object)} is called, but can wrap the key/value in what
* ever they want.
*
* @param carrier
* carrier
* @param key
* key
* @param value
* value
*/
protected abstract void injectBaggage(C carrier, String key, String value);
/**
* Gets all baggage (not only tracing related) from the carrier. For example the HTTP carrier
* would here provide all headers. Subclasses can deal here with additional operations as
* encoding.
*
* @param carrier
* carrier
* @return Itarbale
*/
protected abstract Iterable<Entry<String, String>> extractBaggage(C carrier);
/**
* {@inheritDoc}
*/
@Override
public void inject(SpanContextImpl spanContext, C carrier) {
if (null == spanContext) {
return;
}
injectBaggage(carrier, PropagationConstants.SPAN_ID, ConversionUtils.toHexString(spanContext.getId()));
injectBaggage(carrier, PropagationConstants.TRACE_ID, ConversionUtils.toHexString(spanContext.getTraceId()));
Iterable<Entry<String, String>> baggageItems = spanContext.baggageItems();
if (null != baggageItems) {
for (Map.Entry<String, String> e : baggageItems) {
injectBaggage(carrier, PropagationConstants.INSPECTIT_BAGGAGE_PREFIX + e.getKey(), e.getValue());
}
}
}
/**
* {@inheritDoc}
*/
@Override
public SpanContextImpl extract(C carrier) {
Iterable<Entry<String, String>> iterable = extractBaggage(carrier);
if ((null == iterable) || (null == iterable.iterator())) {
return null;
}
Map<String, String> passedBaggage = new HashMap<String, String>();
String idFromBaggage = null;
String traceIdFromBaggage = null;
// iterate over the baggage
for (Entry<String, String> e : iterable) {
String key = e.getKey();
if (PropagationConstants.SPAN_ID.equals(key)) {
idFromBaggage = e.getValue();
} else if (PropagationConstants.TRACE_ID.equals(key)) {
traceIdFromBaggage = e.getValue();
} else if (key.startsWith(PropagationConstants.INSPECTIT_BAGGAGE_PREFIX)) {
String realKey = key.substring(PropagationConstants.INSPECTIT_BAGGAGE_PREFIX.length());
passedBaggage.put(realKey, e.getValue());
}
}
// at least span id and trace id are needed, if they are not passed return null
if (notEmpty(idFromBaggage) && notEmpty(traceIdFromBaggage)) {
try {
long id = ConversionUtils.parseHexStringSafe(idFromBaggage);
long traceId = ConversionUtils.parseHexStringSafe(traceIdFromBaggage);
return SpanContextImpl.buildExtractedContext(id, traceId, passedBaggage);
} catch (NumberFormatException e) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Failed converting span and trace id. These are expected in the hexadecimal format, but were " + idFromBaggage + " and " + traceIdFromBaggage + ".", e);
}
// ids were not parsable
return null;
}
} else {
return null;
}
}
/**
* Small utility to check if string is not empty.
*
* @param s
* String
* @return If string is not null and has at least 1 char
*/
private boolean notEmpty(String s) {
return (null != s) && !s.isEmpty();
}
}