in apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/tracing/OTelSpanBuilder.java [149:209]
public Span startSpan() {
AbstractSpanImpl<?> span;
BaggageImpl parentBaggage;
AbstractSpanImpl<?> parentSpan = null;
Context remoteContext = null;
if (parent != null) {
Span parentOtelSpan = Span.fromContext(parent);
if (parentOtelSpan.getSpanContext().isRemote()) {
remoteContext = parent;
} else if (parentOtelSpan instanceof OTelSpan) {
parentSpan = ((OTelSpan) parentOtelSpan).getInternalSpan();
}
parentBaggage = OtelBaggage.toElasticBaggage(io.opentelemetry.api.baggage.Baggage.fromContext(parent));
} else {
// when parent is not explicitly set, the currently active parent is used as fallback
parentSpan = elasticApmTracer.currentContext().getSpan();
parentBaggage = elasticApmTracer.currentContext().getBaggage();
}
if (remoteContext != null) {
PotentiallyMultiValuedMap headers = new PotentiallyMultiValuedMap(2);
W3CTraceContextPropagator.getInstance().inject(remoteContext, headers, PotentiallyMultiValuedMap::add);
span = elasticApmTracer.startChildTransaction(headers, MultiValueMapAccessor.INSTANCE, PrivilegedActionUtils.getClassLoader(getClass()), parentBaggage, epochMicros);
} else if (parentSpan == null) {
span = elasticApmTracer.startRootTransaction(PrivilegedActionUtils.getClassLoader(getClass()), parentBaggage, epochMicros);
} else {
span = elasticApmTracer.startSpan(parentSpan, parentBaggage, epochMicros);
}
if (span == null) {
return Span.getInvalid();
}
span.withName(spanName);
if (span instanceof TransactionImpl) {
TransactionImpl t = ((TransactionImpl) span);
t.setFrameworkName("OpenTelemetry API");
String otelVersion = VersionUtils.getVersion(OpenTelemetry.class, "io.opentelemetry", "opentelemetry-api");
if (otelVersion != null) {
t.setFrameworkVersion(otelVersion);
}
}
span.withOtelKind(OTelHelper.map(kind));
// With OTel API, the status (bridged to outcome) should only be explicitly set, thus we have to set and use
// user outcome to provide higher priority and avoid inferring outcome from any reported exception
span.withUserOutcome(Outcome.UNKNOWN);
// Add the links to the span
for (int i = 0; i < links.size(); i++) {
span.addSpanLink(TraceContextImpl.fromParentContext(), ((OTelSpanContext) links.get(i)).getElasticTraceContext());
}
OTelSpan otelSpan = new OTelSpan(span);
attributes.forEach((AttributeKey<?> k, Object v) -> otelSpan.setAttribute((AttributeKey<? super Object>) k, (Object) v));
return otelSpan;
}