From 27fab55de46bfdf1642c1b56141bb47b653028bd Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 16:47:21 +0100 Subject: [PATCH 01/94] Fist working draft --- .../apm/agent/bci/ElasticApmAgent.java | 2 +- .../apm/agent/impl/ElasticApmTracer.java | 12 ++ .../elastic/apm/agent/impl/GlobalTracer.java | 12 ++ .../co/elastic/apm/agent/impl/NoopTracer.java | 16 +- .../co/elastic/apm/agent/impl/Tracer.java | 6 + .../agent/impl/transaction/AbstractSpan.java | 15 ++ .../transaction}/MultiValueMapAccessor.java | 6 +- .../agent/impl/transaction/TraceContext.java | 6 +- .../agent/impl/transaction/TraceState.java | 4 + .../agent/util/PotentiallyMultiValuedMap.java | 17 ++- .../impl/transaction/TraceContextTest.java | 1 - apm-agent-plugin-sdk/pom.xml | 8 + .../apm-opentelemetry-plugin/pom.xml | 28 ++++ .../ContextStorageInstrumentation.java | 43 ++++++ .../GlobalOpenTelemetryInstrumentation.java | 46 ++++++ .../context/ElasticOTelContext.java | 33 +++++ .../context/ElasticOTelContextStorage.java | 36 +++++ .../context/ElasticOTelScope.java | 18 +++ .../opentelemetry/context/package-info.java | 4 + .../apm/agent/opentelemetry/package-info.java | 28 ++++ .../sdk/ElasticOTelContextPropagators.java | 14 ++ .../opentelemetry/sdk/ElasticOTelSpan.java | 76 ++++++++++ .../sdk/ElasticOTelSpanBuilder.java | 130 +++++++++++++++++ .../sdk/ElasticOTelSpanContext.java | 120 +++++++++++++++ .../opentelemetry/sdk/ElasticOTelTracer.java | 18 +++ .../sdk/ElasticOTelTracerProvider.java | 24 +++ .../sdk/ElasticOpenTelemetry.java | 26 ++++ .../agent/opentelemetry/sdk/package-info.java | 4 + ...ic.apm.agent.sdk.ElasticApmInstrumentation | 2 + .../sdk/ElasticOpenTelemetryTest.java | 137 ++++++++++++++++++ apm-agent-plugins/pom.xml | 1 + elastic-apm-agent/pom.xml | 5 + 32 files changed, 884 insertions(+), 14 deletions(-) rename apm-agent-core/src/{test/java/co/elastic/apm/agent/impl => main/java/co/elastic/apm/agent/impl/transaction}/MultiValueMapAccessor.java (88%) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/pom.xml create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java index 892ffd307e..106306ff03 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java @@ -310,7 +310,7 @@ private static AgentBuilder initAgentBuilder(ElasticApmTracer tracer, Instrument for (final ElasticApmInstrumentation advice : instrumentations) { if (isIncluded(advice, coreConfiguration)) { numberOfAdvices++; - agentBuilder = applyAdvice(tracer, agentBuilder, advice, new ElementMatcher.Junction.Conjunction<>(advice.getTypeMatcher(), not(isInterface()))); + agentBuilder = applyAdvice(tracer, agentBuilder, advice, advice.getTypeMatcher()); } } logger.debug("Applied {} advices", numberOfAdvices); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index 3789428014..e7988d9eda 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -161,6 +161,12 @@ public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoa return startRootTransaction(sampler, -1, initiatingClassLoader); } + @Override + @Nullable + public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader, long epochMicro) { + return startRootTransaction(sampler, epochMicro, initiatingClassLoader); + } + @Override @Nullable public Transaction startRootTransaction(Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) { @@ -178,6 +184,12 @@ public Transaction startChildTransaction(@Nullable C headerCarrier, TextHead return startChildTransaction(headerCarrier, textHeadersGetter, sampler, -1, initiatingClassLoader); } + @Override + @Nullable + public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, @Nullable ClassLoader initiatingClassLoader, long epochMicros) { + return startChildTransaction(headerCarrier, textHeadersGetter, sampler, epochMicros, initiatingClassLoader); + } + @Override @Nullable public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, Sampler sampler, diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java index 2418c283c3..421fdc73c9 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java @@ -84,6 +84,12 @@ public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoa return tracer.startRootTransaction(initiatingClassLoader); } + @Nullable + @Override + public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader, long epochMicro) { + return tracer.startRootTransaction(initiatingClassLoader, epochMicro); + } + @Nullable public Transaction startRootTransaction(Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) { return tracer.startRootTransaction(sampler, epochMicros, initiatingClassLoader); @@ -94,6 +100,12 @@ public Transaction startChildTransaction(@Nullable C headerCarrier, TextHead return tracer.startChildTransaction(headerCarrier, textHeadersGetter, initiatingClassLoader); } + @Nullable + @Override + public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, @Nullable ClassLoader initiatingClassLoader, long epochMicros) { + return tracer.startChildTransaction(headerCarrier, textHeadersGetter, initiatingClassLoader, epochMicros); + } + @Nullable public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) { return tracer.startChildTransaction(headerCarrier, textHeadersGetter, sampler, epochMicros, initiatingClassLoader); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java index fecb117d8b..f0f73a420f 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -47,6 +47,12 @@ public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoa return null; } + @Nullable + @Override + public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader, long epochMicro) { + return null; + } + @Nullable @Override public Transaction startRootTransaction(Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) { @@ -59,6 +65,12 @@ public Transaction startChildTransaction(@Nullable C headerCarrier, TextHead return null; } + @Nullable + @Override + public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, @Nullable ClassLoader initiatingClassLoader, long epochMicros) { + return null; + } + @Nullable @Override public Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) { diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java index 90fa702bc8..54ae0c398f 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java @@ -47,6 +47,9 @@ public interface Tracer { @Nullable Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader); + @Nullable + Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader, long epochMicro); + /** * Starts a trace-root transaction with a specified sampler and start timestamp * @@ -74,6 +77,9 @@ public interface Tracer { @Nullable Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, @Nullable ClassLoader initiatingClassLoader); + @Nullable + Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter textHeadersGetter, @Nullable ClassLoader initiatingClassLoader, long epochMicros); + /** * Starts a transaction as a child of the context headers obtained through the provided {@link HeaderGetter}. * If the created transaction cannot be started as a child transaction (for example - if no parent context header is diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index 71aa78d06c..09034bebd9 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -380,6 +380,21 @@ public String captureExceptionAndGetErrorId(@Nullable Throwable t) { return tracer.captureAndReportException(getTraceContext().getClock().getEpochMicros(), t, this); } + public void addLabel(String key, @Nullable Object value) { + if (value == null) { + return; + } + if (isSampled()) { + if (value instanceof Boolean) { + addLabel(key, (Boolean) value); + } else if (value instanceof Number) { + addLabel(key, (Number) value); + } else { + getContext().addLabel(key, value.toString()); + } + } + } + public void addLabel(String key, String value) { if (isSampled()) { getContext().addLabel(key, value); diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/MultiValueMapAccessor.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/MultiValueMapAccessor.java similarity index 88% rename from apm-agent-core/src/test/java/co/elastic/apm/agent/impl/MultiValueMapAccessor.java rename to apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/MultiValueMapAccessor.java index 9caf32dc8c..e0ac734b64 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/MultiValueMapAccessor.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/MultiValueMapAccessor.java @@ -22,12 +22,8 @@ * under the License. * #L% */ -package co.elastic.apm.agent.impl; +package co.elastic.apm.agent.impl.transaction; -import co.elastic.apm.agent.impl.transaction.AbstractHeaderGetter; -import co.elastic.apm.agent.impl.transaction.HeaderRemover; -import co.elastic.apm.agent.impl.transaction.TextHeaderGetter; -import co.elastic.apm.agent.impl.transaction.TextHeaderSetter; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import javax.annotation.Nullable; diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java index 6d5921d4d1..666f3593f9 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java @@ -737,7 +737,7 @@ public ClassLoader getApplicationClassLoader() { } } - TraceState getTraceState() { + public TraceState getTraceState() { return traceState; } @@ -794,6 +794,10 @@ public boolean traceIdAndIdEquals(byte[] serialized) { return id.dataEquals(serialized, traceId.getLength()) && traceId.dataEquals(serialized, 0); } + public byte getFlags() { + return flags; + } + public interface ChildContextCreator { boolean asChildOf(TraceContext child, T parent); } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceState.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceState.java index 63602bc2b7..8ee25df97e 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceState.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceState.java @@ -69,6 +69,10 @@ public void copyFrom(TraceState other) { rewriteBuffer.setLength(0); } + public List getTracestate() { + return tracestate; + } + public void addTextHeader(String headerValue) { int elasticEntryStartIndex = headerValue.indexOf(VENDOR_PREFIX); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/util/PotentiallyMultiValuedMap.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/PotentiallyMultiValuedMap.java index 1d8b7f87a5..0593fca371 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/util/PotentiallyMultiValuedMap.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/PotentiallyMultiValuedMap.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -42,8 +42,17 @@ */ public class PotentiallyMultiValuedMap implements Recyclable { - private final List keys = new ArrayList<>(); - private final List values = new ArrayList<>(); + private final List keys; + private final List values; + + public PotentiallyMultiValuedMap() { + this(10); + } + + public PotentiallyMultiValuedMap(int initialSize) { + keys = new ArrayList<>(initialSize); + values = new ArrayList<>(initialSize); + } /** * Adds a value to this map. diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java index 677bea3467..be307123b4 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java @@ -31,7 +31,6 @@ import co.elastic.apm.agent.impl.BinaryHeaderMapAccessor; import co.elastic.apm.agent.impl.ElasticApmTracer; import co.elastic.apm.agent.impl.ElasticApmTracerBuilder; -import co.elastic.apm.agent.impl.MultiValueMapAccessor; import co.elastic.apm.agent.impl.TextHeaderMapAccessor; import co.elastic.apm.agent.impl.sampling.ConstantSampler; import co.elastic.apm.agent.impl.sampling.Sampler; diff --git a/apm-agent-plugin-sdk/pom.xml b/apm-agent-plugin-sdk/pom.xml index 9553588f5f..bcfa9ce426 100644 --- a/apm-agent-plugin-sdk/pom.xml +++ b/apm-agent-plugin-sdk/pom.xml @@ -62,6 +62,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml new file mode 100644 index 0000000000..b45531ec5f --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -0,0 +1,28 @@ + + + + apm-agent-plugins + co.elastic.apm + 1.20.1-SNAPSHOT + + 4.0.0 + + apm-opentelemetry-plugin + ${project.groupId}:${project.artifactId} + + + ${project.basedir}/../.. + 8 + 8 + + + + + io.opentelemetry + opentelemetry-api + 0.14.1 + + + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java new file mode 100644 index 0000000000..b5fdc84bb5 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -0,0 +1,43 @@ +package co.elastic.apm.agent.opentelemetry; + +import co.elastic.apm.agent.bci.TracerAwareInstrumentation; +import co.elastic.apm.agent.impl.GlobalTracer; +import co.elastic.apm.agent.opentelemetry.context.ElasticOTelContextStorage; +import co.elastic.apm.agent.sdk.advice.AssignTo; +import io.opentelemetry.context.ContextStorage; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.Collection; +import java.util.Collections; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +public class ContextStorageInstrumentation extends TracerAwareInstrumentation { + + private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.getTracerImpl()); + + @Override + public ElementMatcher getTypeMatcher() { + return named("io.opentelemetry.context.ContextStorage"); + } + + @Override + public ElementMatcher getMethodMatcher() { + return named("get").and(returns(named("io.opentelemetry.context.ContextStorage"))); + } + + @Override + public Collection getInstrumentationGroupNames() { + return Collections.singleton("opentelemetry"); + } + + @AssignTo.Return + @Advice.OnMethodExit(suppress = Throwable.class, inline = false) + public static ContextStorage onExit() { + return CONTEXT_STORAGE; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java new file mode 100644 index 0000000000..3ab896297d --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -0,0 +1,46 @@ +package co.elastic.apm.agent.opentelemetry; + +import co.elastic.apm.agent.bci.TracerAwareInstrumentation; +import co.elastic.apm.agent.impl.GlobalTracer; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class GlobalOpenTelemetryInstrumentation extends TracerAwareInstrumentation { + @Override + public ElementMatcher getTypeMatcher() { + return named("io.opentelemetry.api.GlobalOpenTelemetry"); + } + + @Override + public ElementMatcher getMethodMatcher() { + return named("get"); + } + + @Override + public Collection getInstrumentationGroupNames() { + return Collections.singleton("opentelemetry"); + } + + @Override + public boolean includeWhenInstrumentationIsDisabled() { + return true; + } + + @Advice.OnMethodEnter(suppress = Throwable.class, inline = false) + public static void onEnter(@Advice.FieldValue("globalOpenTelemetry") @Nullable OpenTelemetry globalOpenTelemetry) { + if (globalOpenTelemetry == null) { + GlobalOpenTelemetry.set(new ElasticOpenTelemetry(GlobalTracer.requireTracerImpl())); + } + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java new file mode 100644 index 0000000000..b6a1cdaead --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java @@ -0,0 +1,33 @@ +package co.elastic.apm.agent.opentelemetry.context; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +public class ElasticOTelContext implements Context { + private final Map, Object> entries; + + public ElasticOTelContext() { + this(new HashMap<>(4)); + } + + private ElasticOTelContext(Map, Object> entries) { + this.entries = entries; + } + + @Nullable + @Override + public V get(ContextKey key) { + return (V) entries.get(key); + } + + @Override + public Context with(ContextKey k1, V v1) { + Map, Object> copy = new HashMap<>(entries); + copy.put(k1, v1); + return new ElasticOTelContext(copy); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java new file mode 100644 index 0000000000..bff1795d88 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java @@ -0,0 +1,36 @@ +package co.elastic.apm.agent.opentelemetry.context; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelSpan; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextStorage; +import io.opentelemetry.context.Scope; + +import javax.annotation.Nullable; + +public class ElasticOTelContextStorage implements ContextStorage { + private final ElasticApmTracer elasticApmTracer; + + public ElasticOTelContextStorage(ElasticApmTracer elasticApmTracer) { + this.elasticApmTracer = elasticApmTracer; + } + + @Override + public Scope attach(Context toAttach) { + AbstractSpan span = ((ElasticOTelSpan)Span.fromContextOrNull(toAttach)).getInternalSpan(); + elasticApmTracer.activate(span); + return new ElasticOTelScope(span); + } + + @Nullable + @Override + public Context current() { + AbstractSpan active = elasticApmTracer.getActive(); + if (active == null) { + return null; + } + return new ElasticOTelSpan(active).storeInContext(new ElasticOTelContext()); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java new file mode 100644 index 0000000000..e213cd5c52 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java @@ -0,0 +1,18 @@ +package co.elastic.apm.agent.opentelemetry.context; + +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import io.opentelemetry.context.Scope; + +public class ElasticOTelScope implements Scope { + + private final AbstractSpan span; + + public ElasticOTelScope(AbstractSpan span) { + this.span = span; + } + + @Override + public void close() { + span.deactivate(); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java new file mode 100644 index 0000000000..99b0164729 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java @@ -0,0 +1,4 @@ +@NonnullApi +package co.elastic.apm.agent.opentelemetry.context; + +import co.elastic.apm.agent.sdk.NonnullApi; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java new file mode 100644 index 0000000000..d690ff9e9f --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java @@ -0,0 +1,28 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ +@NonnullApi +package co.elastic.apm.agent.opentelemetry; + +import co.elastic.apm.agent.sdk.NonnullApi; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java new file mode 100644 index 0000000000..f03b03f15e --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java @@ -0,0 +1,14 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; + +class ElasticOTelContextPropagators implements ContextPropagators { + public static final ContextPropagators INSTANCE = new ElasticOTelContextPropagators(); + + @Override + public TextMapPropagator getTextMapPropagator() { + return W3CTraceContextPropagator.getInstance(); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java new file mode 100644 index 0000000000..98b3518546 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -0,0 +1,76 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.StatusCode; + +import javax.annotation.Nonnull; +import java.util.concurrent.TimeUnit; + +public class ElasticOTelSpan implements Span { + private final AbstractSpan span; + + public ElasticOTelSpan(AbstractSpan span) { + this.span = span; + } + + @Override + public Span setAttribute(AttributeKey key, @Nonnull T value) { + span.addLabel(key.getKey(), value.toString()); + return this; + } + + @Override + public Span addEvent(String name, Attributes attributes) { + return this; + } + + @Override + public Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) { + return this; + } + + @Override + public Span setStatus(StatusCode statusCode, String description) { + return this; + } + + @Override + public Span recordException(Throwable exception, Attributes additionalAttributes) { + span.captureException(exception); + return this; + } + + @Override + public Span updateName(String name) { + span.withName(name); + return this; + } + + @Override + public void end() { + span.end(); + } + + @Override + public void end(long timestamp, TimeUnit unit) { + span.end(unit.toMicros(timestamp)); + } + + @Override + public SpanContext getSpanContext() { + return new ElasticOTelSpanContext(span.getTraceContext()); + } + + @Override + public boolean isRecording() { + return false; + } + + public AbstractSpan getInternalSpan() { + return span; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java new file mode 100644 index 0000000000..5d0495bfc8 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -0,0 +1,130 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; +import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +class ElasticOTelSpanBuilder implements SpanBuilder { + + private final String spanName; + private final ElasticApmTracer elasticApmTracer; + private long epochMicros = -1; + @Nullable + private AbstractSpan parent; + @Nullable + private Context remoteContext; + private final Map attributes = new HashMap<>(); + + public ElasticOTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { + this.spanName = spanName; + this.elasticApmTracer = elasticApmTracer; + this.parent = elasticApmTracer.getActive(); + } + + @Override + public SpanBuilder setParent(Context context) { + Span span = Span.fromContext(context); + if (span.getSpanContext().isRemote()) { + remoteContext = context; + } else { + parent = ((ElasticOTelSpan) span).getInternalSpan(); + } + return this; + } + + @Override + public SpanBuilder setNoParent() { + parent = null; + remoteContext = null; + return this; + } + + @Override + public SpanBuilder addLink(SpanContext spanContext) { + return this; + } + + @Override + public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { + return this; + } + + @Override + public SpanBuilder setAttribute(String key, @Nonnull String value) { + attributes.put(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, long value) { + attributes.put(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, double value) { + attributes.put(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, boolean value) { + attributes.put(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(AttributeKey key, @Nonnull T value) { + attributes.put(key.getKey(), value); + return this; + } + + @Override + public SpanBuilder setSpanKind(Span.Kind spanKind) { + return this; + } + + @Override + public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { + this.epochMicros = unit.toMicros(startTimestamp); + return this; + } + + @Override + public Span startSpan() { + AbstractSpan span; + if (remoteContext != null) { + PotentiallyMultiValuedMap headers = new PotentiallyMultiValuedMap(2); + W3CTraceContextPropagator.getInstance() + .inject(remoteContext, headers, (carrier, key, value) -> { + if (carrier != null) carrier.add(key, value); + }); + span = elasticApmTracer.startChildTransaction(headers, MultiValueMapAccessor.INSTANCE, getClass().getClassLoader(), epochMicros); + } else if (parent == null) { + span = elasticApmTracer.startRootTransaction(getClass().getClassLoader(), epochMicros); + } else { + span = elasticApmTracer.startSpan(parent, epochMicros); + } + if (span == null) { + return Span.getInvalid(); + } + span.withName(spanName); + attributes.forEach(span::addLabel); + // TODO translate well-known attributes + return new ElasticOTelSpan(span); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java new file mode 100644 index 0000000000..486e99ad5f --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java @@ -0,0 +1,120 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.transaction.TraceContext; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.api.trace.TraceStateBuilder; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +public class ElasticOTelSpanContext implements SpanContext { + private final TraceContext traceContext; + + public ElasticOTelSpanContext(TraceContext traceContext) { + this.traceContext = traceContext; + } + + @Override + public String getTraceIdAsHexString() { + return traceContext.getTraceId().toString(); + } + + @Override + public String getSpanIdAsHexString() { + return traceContext.getId().toString(); + } + + @Override + public byte getTraceFlags() { + return traceContext.getFlags(); + } + + @Override + public TraceState getTraceState() { + return new ElasticOtelTraceState(traceContext.getTraceState()); + } + + @Override + public boolean isRemote() { + return false; + } + + private static class ElasticOtelTraceState implements TraceState { + private final co.elastic.apm.agent.impl.transaction.TraceState traceState; + + public ElasticOtelTraceState(co.elastic.apm.agent.impl.transaction.TraceState traceState) { + this.traceState = traceState; + } + + @Nullable + @Override + public String get(String key) { + List tracestate = traceState.getTracestate(); + for (String ts : tracestate) { + if (ts.startsWith(key + "=")) { + return ts.substring(key.length() + 1); + } + } + return null; + } + + @Override + public int size() { + return traceState.getTracestate().size(); + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public void forEach(BiConsumer consumer) { + for (String s : traceState.getTracestate()) { + consumer.accept(s.substring(0, s.indexOf('=')), s.substring(s.indexOf('=') + 1)); + } + } + + @Override + public Map asMap() { + HashMap map = new HashMap<>(); + forEach(map::put); + return map; + } + + @Override + public TraceStateBuilder toBuilder() { + return new ElasticOTelTraceStateBuilder(traceState); + } + + private static class ElasticOTelTraceStateBuilder implements TraceStateBuilder { + private final co.elastic.apm.agent.impl.transaction.TraceState builder; + + public ElasticOTelTraceStateBuilder(co.elastic.apm.agent.impl.transaction.TraceState traceState) { + this.builder = new co.elastic.apm.agent.impl.transaction.TraceState(); + this.builder.copyFrom(traceState); + } + + @Override + public TraceStateBuilder set(String key, String value) { + builder.getTracestate().add(key + "=" + value); + return this; + } + + @Override + public TraceStateBuilder remove(String key) { + builder.getTracestate().removeIf(ts -> ts.startsWith(key + "=")); + return this; + } + + @Override + public TraceState build() { + return new ElasticOtelTraceState(builder); + } + } + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java new file mode 100644 index 0000000000..4f7182c7e9 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java @@ -0,0 +1,18 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.Tracer; + +class ElasticOTelTracer implements Tracer { + private final ElasticApmTracer elasticApmTracer; + + ElasticOTelTracer(ElasticApmTracer elasticApmTracer) { + this.elasticApmTracer = elasticApmTracer; + } + + @Override + public SpanBuilder spanBuilder(String spanName) { + return new ElasticOTelSpanBuilder(spanName, elasticApmTracer); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java new file mode 100644 index 0000000000..c637bb5542 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java @@ -0,0 +1,24 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; + +import javax.annotation.Nullable; + +class ElasticOTelTracerProvider implements TracerProvider { + private final Tracer tracer; + + ElasticOTelTracerProvider(Tracer tracer) { + this.tracer = tracer; + } + + @Override + public Tracer get(String instrumentationName) { + return get(instrumentationName, null); + } + + @Override + public Tracer get(String instrumentationName, @Nullable String instrumentationVersion) { + return this.tracer; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java new file mode 100644 index 0000000000..a4bbb6b752 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java @@ -0,0 +1,26 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; + +public class ElasticOpenTelemetry implements OpenTelemetry { + private final TracerProvider traceProvider; + private final ContextPropagators contextPropagators; + + public ElasticOpenTelemetry(ElasticApmTracer tracer) { + this.traceProvider = new ElasticOTelTracerProvider(new ElasticOTelTracer(tracer)); + this.contextPropagators = ElasticOTelContextPropagators.INSTANCE; + } + + @Override + public TracerProvider getTracerProvider() { + return this.traceProvider; + } + + @Override + public ContextPropagators getPropagators() { + return this.contextPropagators; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java new file mode 100644 index 0000000000..effe62419d --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java @@ -0,0 +1,4 @@ +@NonnullApi +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.sdk.NonnullApi; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation new file mode 100644 index 0000000000..5d6816c04b --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation @@ -0,0 +1,2 @@ +co.elastic.apm.agent.opentelemetry.GlobalOpenTelemetryInstrumentation +co.elastic.apm.agent.opentelemetry.ContextStorageInstrumentation diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java new file mode 100644 index 0000000000..239998cdca --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -0,0 +1,137 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.AbstractInstrumentationTest; +import co.elastic.apm.agent.impl.context.TransactionContext; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.TextMapPropagator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class ElasticOpenTelemetryTest extends AbstractInstrumentationTest { + + private OpenTelemetry openTelemetry; + private Tracer otelTracer; + + @BeforeEach + void setUp() { + this.openTelemetry = GlobalOpenTelemetry.get(); + otelTracer = openTelemetry.getTracer(null); + } + + @Test + void testTransaction() { + otelTracer.spanBuilder("transaction") + .startSpan() + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + } + + @Test + void testTransactionWithAttribute() { + otelTracer.spanBuilder("transaction") + .setAttribute("boolean", true) + .setAttribute("long", 42L) + .setAttribute("string", "hello") + .startSpan() + .end(); + + assertThat(reporter.getTransactions()).hasSize(1); + TransactionContext context = reporter.getFirstTransaction().getContext(); + assertThat(context.getLabel("boolean")).isEqualTo(true); + assertThat(context.getLabel("long")).isEqualTo(42L); + assertThat(context.getLabel("string")).isEqualTo("hello"); + } + + @Test + void testTransactionWithSpanManualPropagation() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + otelTracer.spanBuilder("span") + .setParent(Context.root().with(transaction)) + .startSpan() + .end(); + transaction.end(); + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getSpans()).hasSize(1); + assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + assertThat(reporter.getFirstSpan().getNameAsString()).isEqualTo("span"); + assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); + } + + @Test + void testTransactionWithSpanContextStorePropagation() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + try (Scope scope = transaction.makeCurrent()) { + otelTracer.spanBuilder("span") + .startSpan() + .end(); + } finally { + transaction.end(); + } + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getSpans()).hasSize(1); + assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + assertThat(reporter.getFirstSpan().getNameAsString()).isEqualTo("span"); + assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); + } + + @Test + void testTransactionWithRemoteParent() { + Context context = openTelemetry.getPropagators() + .getTextMapPropagator() + .extract(Context.current(), + Map.of("traceparent", "00-cafebabe16cd43dd8448eb211c80319c-deadbeef197918e1-01"), + new MapGetter()); + otelTracer.spanBuilder("transaction") + .setParent(context) + .startSpan() + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + assertThat(reporter.getFirstTransaction().getTraceContext().getTraceId().toString()).isEqualTo("cafebabe16cd43dd8448eb211c80319c"); + assertThat(reporter.getFirstTransaction().getTraceContext().getParentId().toString()).isEqualTo("deadbeef197918e1"); + } + + @Test + void testTransactionInject() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + HashMap otelHeaders = new HashMap<>(); + HashMap elasticApmHeaders = new HashMap<>(); + try (Scope scope = transaction.makeCurrent()) { + openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), otelHeaders, HashMap::put); + tracer.getActive().propagateTraceContext(elasticApmHeaders, (k, v, m) -> m.put(k, v)); + } finally { + transaction.end(); + } + assertThat(elasticApmHeaders).containsAllEntriesOf(otelHeaders); + } + + private static class MapGetter implements TextMapPropagator.Getter> { + @Override + public Iterable keys(Map carrier) { + return carrier.keySet(); + } + + @Nullable + @Override + public String get(@Nullable Map carrier, String key) { + return carrier.get(key); + } + } +} diff --git a/apm-agent-plugins/pom.xml b/apm-agent-plugins/pom.xml index 5c01e715a5..e94c4d85ad 100644 --- a/apm-agent-plugins/pom.xml +++ b/apm-agent-plugins/pom.xml @@ -55,6 +55,7 @@ apm-micrometer-plugin apm-jdk-httpclient-plugin apm-rabbitmq + apm-opentelemetry-plugin diff --git a/elastic-apm-agent/pom.xml b/elastic-apm-agent/pom.xml index d173a53d3a..2530c9f946 100644 --- a/elastic-apm-agent/pom.xml +++ b/elastic-apm-agent/pom.xml @@ -169,6 +169,11 @@ apm-okhttp-plugin ${project.version} + + ${project.groupId} + apm-opentelemetry-plugin + ${project.version} + ${project.groupId} apm-opentracing-plugin From 517e037d72ae9336f96ca4d760fed8b33989fd55 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 17:12:24 +0100 Subject: [PATCH 02/94] Lazily parse tracestate --- .../sdk/ElasticOTelSpanContext.java | 94 +++---------------- 1 file changed, 15 insertions(+), 79 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java index 486e99ad5f..f4462a9a66 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java @@ -4,12 +4,9 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.api.trace.TraceStateBuilder; +import org.stagemonitor.util.StringUtils; -import javax.annotation.Nullable; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; public class ElasticOTelSpanContext implements SpanContext { private final TraceContext traceContext; @@ -35,7 +32,20 @@ public byte getTraceFlags() { @Override public TraceState getTraceState() { - return new ElasticOtelTraceState(traceContext.getTraceState()); + // Lazily parses tracestate header. + // Our internal TraceState class doesn't parse the raw tracestate header + // as we currently don't have a use case where the agent needs to read the tracestate. + TraceStateBuilder builder = TraceState.builder(); + List tracestate = traceContext.getTraceState().getTracestate(); + for (int i = 0, size = tracestate.size(); i < size; i++) { + for (String vendorEntry : StringUtils.split(tracestate.get(i), ',')) { + String[] keyValue = StringUtils.split(vendorEntry, '='); + if (keyValue.length == 2) { + builder.set(keyValue[0], keyValue[1]); + } + } + } + return builder.build(); } @Override @@ -43,78 +53,4 @@ public boolean isRemote() { return false; } - private static class ElasticOtelTraceState implements TraceState { - private final co.elastic.apm.agent.impl.transaction.TraceState traceState; - - public ElasticOtelTraceState(co.elastic.apm.agent.impl.transaction.TraceState traceState) { - this.traceState = traceState; - } - - @Nullable - @Override - public String get(String key) { - List tracestate = traceState.getTracestate(); - for (String ts : tracestate) { - if (ts.startsWith(key + "=")) { - return ts.substring(key.length() + 1); - } - } - return null; - } - - @Override - public int size() { - return traceState.getTracestate().size(); - } - - @Override - public boolean isEmpty() { - return size() == 0; - } - - @Override - public void forEach(BiConsumer consumer) { - for (String s : traceState.getTracestate()) { - consumer.accept(s.substring(0, s.indexOf('=')), s.substring(s.indexOf('=') + 1)); - } - } - - @Override - public Map asMap() { - HashMap map = new HashMap<>(); - forEach(map::put); - return map; - } - - @Override - public TraceStateBuilder toBuilder() { - return new ElasticOTelTraceStateBuilder(traceState); - } - - private static class ElasticOTelTraceStateBuilder implements TraceStateBuilder { - private final co.elastic.apm.agent.impl.transaction.TraceState builder; - - public ElasticOTelTraceStateBuilder(co.elastic.apm.agent.impl.transaction.TraceState traceState) { - this.builder = new co.elastic.apm.agent.impl.transaction.TraceState(); - this.builder.copyFrom(traceState); - } - - @Override - public TraceStateBuilder set(String key, String value) { - builder.getTracestate().add(key + "=" + value); - return this; - } - - @Override - public TraceStateBuilder remove(String key) { - builder.getTracestate().removeIf(ts -> ts.startsWith(key + "=")); - return this; - } - - @Override - public TraceState build() { - return new ElasticOtelTraceState(builder); - } - } - } } From 605c893c02c9e11277c1ae6288e3d7cc24bf0393 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 17:37:52 +0100 Subject: [PATCH 03/94] Use built-in Context --- .../context/ElasticOTelContext.java | 33 ------------------- .../context/ElasticOTelContextStorage.java | 10 ++++-- .../sdk/ElasticOpenTelemetryTest.java | 28 ++++++++++++++++ 3 files changed, 36 insertions(+), 35 deletions(-) delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java deleted file mode 100644 index b6a1cdaead..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContext.java +++ /dev/null @@ -1,33 +0,0 @@ -package co.elastic.apm.agent.opentelemetry.context; - -import io.opentelemetry.context.Context; -import io.opentelemetry.context.ContextKey; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; - -public class ElasticOTelContext implements Context { - private final Map, Object> entries; - - public ElasticOTelContext() { - this(new HashMap<>(4)); - } - - private ElasticOTelContext(Map, Object> entries) { - this.entries = entries; - } - - @Nullable - @Override - public V get(ContextKey key) { - return (V) entries.get(key); - } - - @Override - public Context with(ContextKey k1, V v1) { - Map, Object> copy = new HashMap<>(entries); - copy.put(k1, v1); - return new ElasticOTelContext(copy); - } -} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java index bff1795d88..51f5949292 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java @@ -5,6 +5,7 @@ import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelSpan; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.Scope; @@ -19,11 +20,16 @@ public ElasticOTelContextStorage(ElasticApmTracer elasticApmTracer) { @Override public Scope attach(Context toAttach) { - AbstractSpan span = ((ElasticOTelSpan)Span.fromContextOrNull(toAttach)).getInternalSpan(); + AbstractSpan span = ((ElasticOTelSpan) Span.fromContextOrNull(toAttach)).getInternalSpan(); elasticApmTracer.activate(span); return new ElasticOTelScope(span); } + /** + * NOTE: the returned context is not the same as the one provided in {@link #attach(Context)}. + * The consequence of this is that it will not have the context keys of the original context. + * In other words, {@link Context#get(ContextKey)} will return {@code null} for any key besides the span key. + */ @Nullable @Override public Context current() { @@ -31,6 +37,6 @@ public Context current() { if (active == null) { return null; } - return new ElasticOTelSpan(active).storeInContext(new ElasticOTelContext()); + return Context.root().with(new ElasticOTelSpan(active)); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 239998cdca..1115b382f6 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -2,14 +2,17 @@ import co.elastic.apm.agent.AbstractInstrumentationTest; import co.elastic.apm.agent.impl.context.TransactionContext; +import co.elastic.apm.agent.opentelemetry.context.ElasticOTelContextStorage; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import javax.annotation.Nullable; @@ -90,6 +93,31 @@ void testTransactionWithSpanContextStorePropagation() { assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); } + /** + * Demonstrates a missing feature of this bridge: custom context entries are not propagated + * + * @see ElasticOTelContextStorage#current() + */ + @Test + @Disabled + void testPropagateCustomContextKey() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + Context context = Context.current() + .with(transaction) + .with(ContextKey.named("foo"), "bar"); + try (Scope scope = context.makeCurrent()) { + assertThat(tracer.getActive().getTraceContext().getId().toString()).isEqualTo(transaction.getSpanContext().getSpanIdAsHexString()); + // this assertion fails as context keys are not propagated + assertThat(Context.current().get(ContextKey.named("foo"))).isEqualTo("bar"); + } finally { + transaction.end(); + } + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + } + @Test void testTransactionWithRemoteParent() { Context context = openTelemetry.getPropagators() From 844f09782f2db7a1c1fe4e251ffc1f189fc0ed89 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 18:59:46 +0100 Subject: [PATCH 04/94] Translate OTel attributes to intake API --- .../agent/impl/transaction/AbstractSpan.java | 15 ------- .../apm-opentelemetry-plugin/pom.xml | 5 +++ .../opentelemetry/sdk/AttributeMapper.java | 42 +++++++++++++++++++ .../opentelemetry/sdk/ElasticOTelSpan.java | 2 +- .../sdk/ElasticOTelSpanBuilder.java | 20 ++++----- .../sdk/ElasticOpenTelemetryTest.java | 13 ++++++ 6 files changed, 69 insertions(+), 28 deletions(-) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index 09034bebd9..71aa78d06c 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -380,21 +380,6 @@ public String captureExceptionAndGetErrorId(@Nullable Throwable t) { return tracer.captureAndReportException(getTraceContext().getClock().getEpochMicros(), t, this); } - public void addLabel(String key, @Nullable Object value) { - if (value == null) { - return; - } - if (isSampled()) { - if (value instanceof Boolean) { - addLabel(key, (Boolean) value); - } else if (value instanceof Number) { - addLabel(key, (Number) value); - } else { - getContext().addLabel(key, value.toString()); - } - } - } - public void addLabel(String key, String value) { if (isSampled()) { getContext().addLabel(key, value); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index b45531ec5f..0a62ea73e1 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -24,5 +24,10 @@ opentelemetry-api 0.14.1 + + io.opentelemetry + opentelemetry-semconv + 0.14.1 + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java new file mode 100644 index 0000000000..8cc85b27ce --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java @@ -0,0 +1,42 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.context.web.ResultUtil; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.Span; +import co.elastic.apm.agent.impl.transaction.Transaction; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import javax.annotation.Nullable; + +class AttributeMapper { + + static void mapAttribute(AbstractSpan span, AttributeKey key, @Nullable Object value) { + if (value == null) { + return; + } + if (span.isSampled()) { + // TODO translate other well-known attributes + if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { + int statusCode = ((Number) value).intValue(); + if (span instanceof Transaction) { + ((Transaction) span).getContext().getResponse().withStatusCode(statusCode); + ((Transaction) span).withResult(ResultUtil.getResultByHttpStatus(statusCode)); + } else if (span instanceof Span) { + ((Span) span).getContext().getHttp().withStatusCode(statusCode); + } + } + setUnknownAttributeAsLabel(span, key, value); + } + } + + private static void setUnknownAttributeAsLabel(AbstractSpan span, AttributeKey key, Object value) { + if (value instanceof Boolean) { + span.addLabel(key.getKey(), (Boolean) value); + } else if (value instanceof Number) { + span.addLabel(key.getKey(), (Number) value); + } else { + span.addLabel(key.getKey(), value.toString()); + } + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index 98b3518546..7990f43f58 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -19,7 +19,7 @@ public ElasticOTelSpan(AbstractSpan span) { @Override public Span setAttribute(AttributeKey key, @Nonnull T value) { - span.addLabel(key.getKey(), value.toString()); + AttributeMapper.mapAttribute(span, key, value); return this; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index 5d0495bfc8..9a8536473f 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -22,12 +22,12 @@ class ElasticOTelSpanBuilder implements SpanBuilder { private final String spanName; private final ElasticApmTracer elasticApmTracer; + private final Map, Object> attributes = new HashMap<>(); private long epochMicros = -1; @Nullable private AbstractSpan parent; @Nullable private Context remoteContext; - private final Map attributes = new HashMap<>(); public ElasticOTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { this.spanName = spanName; @@ -65,31 +65,31 @@ public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { @Override public SpanBuilder setAttribute(String key, @Nonnull String value) { - attributes.put(key, value); + setAttribute(AttributeKey.stringKey(key), value); return this; } @Override public SpanBuilder setAttribute(String key, long value) { - attributes.put(key, value); + setAttribute(AttributeKey.longKey(key), value); return this; } @Override public SpanBuilder setAttribute(String key, double value) { - attributes.put(key, value); + setAttribute(AttributeKey.doubleKey(key), value); return this; } @Override public SpanBuilder setAttribute(String key, boolean value) { - attributes.put(key, value); + setAttribute(AttributeKey.booleanKey(key), value); return this; } @Override public SpanBuilder setAttribute(AttributeKey key, @Nonnull T value) { - attributes.put(key.getKey(), value); + attributes.put(key, value); return this; } @@ -109,10 +109,7 @@ public Span startSpan() { AbstractSpan span; if (remoteContext != null) { PotentiallyMultiValuedMap headers = new PotentiallyMultiValuedMap(2); - W3CTraceContextPropagator.getInstance() - .inject(remoteContext, headers, (carrier, key, value) -> { - if (carrier != null) carrier.add(key, value); - }); + W3CTraceContextPropagator.getInstance().inject(remoteContext, headers, PotentiallyMultiValuedMap::add); span = elasticApmTracer.startChildTransaction(headers, MultiValueMapAccessor.INSTANCE, getClass().getClassLoader(), epochMicros); } else if (parent == null) { span = elasticApmTracer.startRootTransaction(getClass().getClassLoader(), epochMicros); @@ -123,8 +120,7 @@ public Span startSpan() { return Span.getInvalid(); } span.withName(spanName); - attributes.forEach(span::addLabel); - // TODO translate well-known attributes + attributes.forEach((key, value) -> AttributeMapper.mapAttribute(span, key, value)); return new ElasticOTelSpan(span); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 1115b382f6..2fc8ed0c4a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -11,6 +11,7 @@ import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -29,6 +30,7 @@ class ElasticOpenTelemetryTest extends AbstractInstrumentationTest { @BeforeEach void setUp() { this.openTelemetry = GlobalOpenTelemetry.get(); + assertThat(openTelemetry).isSameAs(GlobalOpenTelemetry.get()); otelTracer = openTelemetry.getTracer(null); } @@ -41,6 +43,17 @@ void testTransaction() { assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); } + @Test + void testTransactionStatusCode() { + otelTracer.spanBuilder("transaction") + .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) + .startSpan() + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); + assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); + } + @Test void testTransactionWithAttribute() { otelTracer.spanBuilder("transaction") From 1a28319fe2d2ebc08cc7de7a3f8d65bc1c5a25af Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 19:00:07 +0100 Subject: [PATCH 05/94] Refine instrumentations --- .../ContextStorageInstrumentation.java | 2 +- .../GlobalOpenTelemetryInstrumentation.java | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index b5fdc84bb5..42d4c2002c 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -18,7 +18,7 @@ public class ContextStorageInstrumentation extends TracerAwareInstrumentation { - private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.getTracerImpl()); + private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.requireTracerImpl()); @Override public ElementMatcher getTypeMatcher() { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 3ab896297d..2c2061ab63 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -3,20 +3,22 @@ import co.elastic.apm.agent.bci.TracerAwareInstrumentation; import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; -import io.opentelemetry.api.GlobalOpenTelemetry; +import co.elastic.apm.agent.sdk.advice.AssignTo; import io.opentelemetry.api.OpenTelemetry; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -import javax.annotation.Nullable; import java.util.Collection; import java.util.Collections; import static net.bytebuddy.matcher.ElementMatchers.named; public class GlobalOpenTelemetryInstrumentation extends TracerAwareInstrumentation { + + private static final ElasticOpenTelemetry ELASTIC_OPEN_TELEMETRY = new ElasticOpenTelemetry(GlobalTracer.requireTracerImpl()); + @Override public ElementMatcher getTypeMatcher() { return named("io.opentelemetry.api.GlobalOpenTelemetry"); @@ -37,10 +39,15 @@ public boolean includeWhenInstrumentationIsDisabled() { return true; } - @Advice.OnMethodEnter(suppress = Throwable.class, inline = false) - public static void onEnter(@Advice.FieldValue("globalOpenTelemetry") @Nullable OpenTelemetry globalOpenTelemetry) { - if (globalOpenTelemetry == null) { - GlobalOpenTelemetry.set(new ElasticOpenTelemetry(GlobalTracer.requireTracerImpl())); - } + @Advice.OnMethodEnter(suppress = Throwable.class, inline = false, skipOn = Advice.OnNonDefaultValue.class) + public static boolean onEnter() { + // skips actual method and directly goes to exit advice + return true; + } + + @AssignTo.Return + @Advice.OnMethodExit(suppress = Throwable.class, inline = false) + public static OpenTelemetry onExit() { + return ELASTIC_OPEN_TELEMETRY; } } From 204bea75fa5cec5601408bc5f1e512a65046511e Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 19:04:34 +0100 Subject: [PATCH 06/94] Mark as experimental --- .../agent/opentelemetry/ContextStorageInstrumentation.java | 4 ++-- .../opentelemetry/GlobalOpenTelemetryInstrumentation.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 42d4c2002c..ec6b0f41f0 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -10,8 +10,8 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; @@ -32,7 +32,7 @@ public ElementMatcher getMethodMatcher() { @Override public Collection getInstrumentationGroupNames() { - return Collections.singleton("opentelemetry"); + return Arrays.asList("opentelemetry", "experimental"); } @AssignTo.Return diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 2c2061ab63..9cc368dd8b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -10,8 +10,8 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -31,7 +31,7 @@ public ElementMatcher getMethodMatcher() { @Override public Collection getInstrumentationGroupNames() { - return Collections.singleton("opentelemetry"); + return Arrays.asList("opentelemetry", "experimental"); } @Override From a7b65c9534e469c1626643405af924875fb748a4 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 19:15:35 +0100 Subject: [PATCH 07/94] Add enable_experimental_instrumentations option --- .../configuration/CoreConfiguration.java | 23 ++++++++-- .../test/resources/test.elasticapm.properties | 3 +- docs/configuration.asciidoc | 46 +++++++++++++++++-- .../ConfigurationExporterTest.java | 1 - 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 1280689aa0..7bc761467a 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -42,6 +42,7 @@ import org.stagemonitor.configuration.source.ConfigurationSource; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -244,7 +245,17 @@ public class CoreConfiguration extends ConfigurationOptionProvider { "NOTE: Changing this value at runtime can slow down the application temporarily.") .dynamic(true) .tags("added[1.0.0,Changing this value at runtime is possible since version 1.15.0]") - .buildWithDefault(Collections.singleton("experimental")); + .buildWithDefault(Collections.emptyList()); + + private final ConfigurationOption enableExperimentalInstrumentations = ConfigurationOption.booleanOption() + .key("enable_experimental_instrumentations") + .configurationCategory(CORE_CATEGORY) + .description("Whether to apply experimental instrumentations.\n" + + "\n" + + "NOTE: Changing this value at runtime can slow down the application temporarily.") + .dynamic(true) + .tags("added[1.21.0]") + .buildWithDefault(false); private final ConfigurationOption> unnestExceptions = ConfigurationOption .builder(new ListValueConverter<>(new WildcardMatcherValueConverter()), List.class) @@ -588,7 +599,7 @@ public boolean isInstrument() { } public List> getInstrumentationOptions() { - return Arrays.asList(instrument, traceMethods, disabledInstrumentations); + return Arrays.asList(instrument, traceMethods, disabledInstrumentations, enableExperimentalInstrumentations); } public String getServiceName() { @@ -637,7 +648,13 @@ public List getSanitizeFieldNames() { } public Collection getDisabledInstrumentations() { - return disabledInstrumentations.get(); + List disabled = new ArrayList<>(disabledInstrumentations.get()); + if (enableExperimentalInstrumentations.get()) { + disabled.remove("experimental"); + } else { + disabled.add("experimental"); + } + return disabled; } public List getUnnestExceptions() { diff --git a/apm-agent-core/src/test/resources/test.elasticapm.properties b/apm-agent-core/src/test/resources/test.elasticapm.properties index f8a14b6343..4347d96185 100644 --- a/apm-agent-core/src/test/resources/test.elasticapm.properties +++ b/apm-agent-core/src/test/resources/test.elasticapm.properties @@ -1,5 +1,4 @@ -# experimental instrumentations should be active in tests -disable_instrumentations= +enable_experimental_instrumentations=true application_packages=co.elastic.apm ship_agent_logs=false log_level=DEBUG diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index c5fe0f67e2..aa0995ad37 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -110,6 +110,7 @@ Click on a key to get more information. ** <> ** <> ** <> +** <> ** <> ** <> ** <> @@ -698,7 +699,7 @@ you should add an additional entry to this list (make sure to also include the d ==== `disable_instrumentations` (added[1.0.0,Changing this value at runtime is possible since version 1.15.0]) A list of instrumentations which should be disabled. -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `ssl-context`, `timer-task`, `urlconnection`. +Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `ssl-context`, `timer-task`, `urlconnection`. If you want to try out experimental features, set the value to an empty string. NOTE: Changing this value at runtime can slow down the application temporarily. @@ -709,7 +710,7 @@ NOTE: Changing this value at runtime can slow down the application temporarily. [options="header"] |============ | Default | Type | Dynamic -| `experimental` | Collection | true +| `` | Collection | true |============ @@ -719,6 +720,31 @@ NOTE: Changing this value at runtime can slow down the application temporarily. | `elastic.apm.disable_instrumentations` | `disable_instrumentations` | `ELASTIC_APM_DISABLE_INSTRUMENTATIONS` |============ +// This file is auto generated. Please make your changes in *Configuration.java (for example CoreConfiguration.java) and execute ConfigurationExporter +[float] +[[config-enable-experimental-instrumentations]] +==== `enable_experimental_instrumentations` (added[1.21.0]) + +Whether to apply experimental instrumentations. + +NOTE: Changing this value at runtime can slow down the application temporarily. + +<> + + +[options="header"] +|============ +| Default | Type | Dynamic +| `false` | Boolean | true +|============ + + +[options="header"] +|============ +| Java System Properties | Property file | Environment +| `elastic.apm.enable_experimental_instrumentations` | `enable_experimental_instrumentations` | `ELASTIC_APM_ENABLE_EXPERIMENTAL_INSTRUMENTATIONS` +|============ + // This file is auto generated. Please make your changes in *Configuration.java (for example CoreConfiguration.java) and execute ConfigurationExporter [float] [[config-unnest-exceptions]] @@ -2567,16 +2593,26 @@ The default unit for this option is `ms`. # sanitize_field_names=password,passwd,pwd,secret,*key,*token*,*session*,*credit*,*card*,authorization,set-cookie # A list of instrumentations which should be disabled. -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `ssl-context`, `timer-task`, `urlconnection`. +# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `ssl-context`, `timer-task`, `urlconnection`. # If you want to try out experimental features, set the value to an empty string. # # NOTE: Changing this value at runtime can slow down the application temporarily. # # This setting can be changed at runtime # Type: comma separated list -# Default value: experimental +# Default value: +# +# disable_instrumentations= + +# Whether to apply experimental instrumentations. +# +# NOTE: Changing this value at runtime can slow down the application temporarily. +# +# This setting can be changed at runtime +# Type: Boolean +# Default value: false # -# disable_instrumentations=experimental +# enable_experimental_instrumentations=false # When reporting exceptions, # un-nests the exceptions matching the wildcard pattern. diff --git a/elastic-apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java b/elastic-apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java index 20fc061621..0d90e74ed5 100644 --- a/elastic-apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java +++ b/elastic-apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java @@ -161,7 +161,6 @@ static String renderDocumentation(ConfigurationRegistry configurationRegistry) t public static String getAllInstrumentationGroupNames() { Set instrumentationGroupNames = new TreeSet<>(); - instrumentationGroupNames.add("experimental"); for (ElasticApmInstrumentation instrumentation : DependencyInjectingServiceLoader.load(ElasticApmInstrumentation.class, MockTracer.create())) { instrumentationGroupNames.addAll(instrumentation.getInstrumentationGroupNames()); } From c89b977f05995a546a491c4e7c9c0e16fc3f3448 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 22 Jan 2021 23:31:45 +0100 Subject: [PATCH 08/94] polishing --- .../GlobalOpenTelemetryInstrumentation.java | 11 ++++++-- .../context/ElasticOTelContextStorage.java | 11 +++++--- .../sdk/ElasticOTelContextPropagators.java | 14 ---------- .../opentelemetry/sdk/ElasticOTelSpan.java | 3 ++- .../sdk/ElasticOTelSpanBuilder.java | 2 +- .../sdk/ElasticOTelSpanContext.java | 2 ++ .../opentelemetry/sdk/ElasticOTelTracer.java | 4 +-- .../sdk/ElasticOTelTracerProvider.java | 4 +-- .../sdk/ElasticOpenTelemetry.java | 26 ------------------- 9 files changed, 26 insertions(+), 51 deletions(-) delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 9cc368dd8b..7f79284809 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -2,9 +2,13 @@ import co.elastic.apm.agent.bci.TracerAwareInstrumentation; import co.elastic.apm.agent.impl.GlobalTracer; -import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracer; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracerProvider; import co.elastic.apm.agent.sdk.advice.AssignTo; +import io.opentelemetry.api.DefaultOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -17,7 +21,10 @@ public class GlobalOpenTelemetryInstrumentation extends TracerAwareInstrumentation { - private static final ElasticOpenTelemetry ELASTIC_OPEN_TELEMETRY = new ElasticOpenTelemetry(GlobalTracer.requireTracerImpl()); + private static final OpenTelemetry ELASTIC_OPEN_TELEMETRY = DefaultOpenTelemetry.builder() + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .setTracerProvider(new ElasticOTelTracerProvider(new ElasticOTelTracer(GlobalTracer.requireTracerImpl()))) + .build(); @Override public ElementMatcher getTypeMatcher() { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java index 51f5949292..f322742ebf 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java @@ -20,9 +20,14 @@ public ElasticOTelContextStorage(ElasticApmTracer elasticApmTracer) { @Override public Scope attach(Context toAttach) { - AbstractSpan span = ((ElasticOTelSpan) Span.fromContextOrNull(toAttach)).getInternalSpan(); - elasticApmTracer.activate(span); - return new ElasticOTelScope(span); + Span span = Span.fromContext(toAttach); + if (span instanceof ElasticOTelSpan) { + AbstractSpan internalSpan = ((ElasticOTelSpan) span).getInternalSpan(); + elasticApmTracer.activate(internalSpan); + return new ElasticOTelScope(internalSpan); + } else { + return Scope.noop(); + } } /** diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java deleted file mode 100644 index f03b03f15e..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelContextPropagators.java +++ /dev/null @@ -1,14 +0,0 @@ -package co.elastic.apm.agent.opentelemetry.sdk; - -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.TextMapPropagator; - -class ElasticOTelContextPropagators implements ContextPropagators { - public static final ContextPropagators INSTANCE = new ElasticOTelContextPropagators(); - - @Override - public TextMapPropagator getTextMapPropagator() { - return W3CTraceContextPropagator.getInstance(); - } -} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index 7990f43f58..29e35ab9f3 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -35,6 +35,7 @@ public Span addEvent(String name, Attributes attributes, long timestamp, TimeUni @Override public Span setStatus(StatusCode statusCode, String description) { + // TODO set outcome return this; } @@ -67,7 +68,7 @@ public SpanContext getSpanContext() { @Override public boolean isRecording() { - return false; + return span.isSampled(); } public AbstractSpan getInternalSpan() { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index 9a8536473f..a838b05dcc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -40,7 +40,7 @@ public SpanBuilder setParent(Context context) { Span span = Span.fromContext(context); if (span.getSpanContext().isRemote()) { remoteContext = context; - } else { + } else if (span instanceof ElasticOTelSpan) { parent = ((ElasticOTelSpan) span).getInternalSpan(); } return this; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java index f4462a9a66..f454355974 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java @@ -50,6 +50,8 @@ public TraceState getTraceState() { @Override public boolean isRemote() { + // the elastic agent doesn't create a TraceContext for remote parents + // instead, it directly creates an entry child span given the request headers return false; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java index 4f7182c7e9..6a31ef9093 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java @@ -4,10 +4,10 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.Tracer; -class ElasticOTelTracer implements Tracer { +public class ElasticOTelTracer implements Tracer { private final ElasticApmTracer elasticApmTracer; - ElasticOTelTracer(ElasticApmTracer elasticApmTracer) { + public ElasticOTelTracer(ElasticApmTracer elasticApmTracer) { this.elasticApmTracer = elasticApmTracer; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java index c637bb5542..02ca266aaf 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java @@ -5,10 +5,10 @@ import javax.annotation.Nullable; -class ElasticOTelTracerProvider implements TracerProvider { +public class ElasticOTelTracerProvider implements TracerProvider { private final Tracer tracer; - ElasticOTelTracerProvider(Tracer tracer) { + public ElasticOTelTracerProvider(Tracer tracer) { this.tracer = tracer; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java deleted file mode 100644 index a4bbb6b752..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java +++ /dev/null @@ -1,26 +0,0 @@ -package co.elastic.apm.agent.opentelemetry.sdk; - -import co.elastic.apm.agent.impl.ElasticApmTracer; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.TracerProvider; -import io.opentelemetry.context.propagation.ContextPropagators; - -public class ElasticOpenTelemetry implements OpenTelemetry { - private final TracerProvider traceProvider; - private final ContextPropagators contextPropagators; - - public ElasticOpenTelemetry(ElasticApmTracer tracer) { - this.traceProvider = new ElasticOTelTracerProvider(new ElasticOTelTracer(tracer)); - this.contextPropagators = ElasticOTelContextPropagators.INSTANCE; - } - - @Override - public TracerProvider getTracerProvider() { - return this.traceProvider; - } - - @Override - public ContextPropagators getPropagators() { - return this.contextPropagators; - } -} From 87e84204995d4c6a2aa024c92a140e0cbf17a05f Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Sat, 23 Jan 2021 08:28:39 +0100 Subject: [PATCH 09/94] Extract advice to separate class --- .../ContextStorageInstrumentation.java | 25 ++++++++++---- .../GlobalOpenTelemetryInstrumentation.java | 34 ++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index ec6b0f41f0..476964f793 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -18,8 +18,6 @@ public class ContextStorageInstrumentation extends TracerAwareInstrumentation { - private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.requireTracerImpl()); - @Override public ElementMatcher getTypeMatcher() { return named("io.opentelemetry.context.ContextStorage"); @@ -35,9 +33,24 @@ public Collection getInstrumentationGroupNames() { return Arrays.asList("opentelemetry", "experimental"); } - @AssignTo.Return - @Advice.OnMethodExit(suppress = Throwable.class, inline = false) - public static ContextStorage onExit() { - return CONTEXT_STORAGE; + @Override + public boolean includeWhenInstrumentationIsDisabled() { + return true; + } + + @Override + public Class getAdviceClass() { + return ContextStorageAdvice.class; + } + + public static class ContextStorageAdvice { + + private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.requireTracerImpl()); + + @AssignTo.Return + @Advice.OnMethodExit(suppress = Throwable.class, inline = false) + public static ContextStorage onExit() { + return CONTEXT_STORAGE; + } } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 7f79284809..3369d3e1a0 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -21,11 +21,6 @@ public class GlobalOpenTelemetryInstrumentation extends TracerAwareInstrumentation { - private static final OpenTelemetry ELASTIC_OPEN_TELEMETRY = DefaultOpenTelemetry.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(new ElasticOTelTracerProvider(new ElasticOTelTracer(GlobalTracer.requireTracerImpl()))) - .build(); - @Override public ElementMatcher getTypeMatcher() { return named("io.opentelemetry.api.GlobalOpenTelemetry"); @@ -46,15 +41,28 @@ public boolean includeWhenInstrumentationIsDisabled() { return true; } - @Advice.OnMethodEnter(suppress = Throwable.class, inline = false, skipOn = Advice.OnNonDefaultValue.class) - public static boolean onEnter() { - // skips actual method and directly goes to exit advice - return true; + @Override + public Class getAdviceClass() { + return GlobalOpenTelemetryAdvice.class; } - @AssignTo.Return - @Advice.OnMethodExit(suppress = Throwable.class, inline = false) - public static OpenTelemetry onExit() { - return ELASTIC_OPEN_TELEMETRY; + public static class GlobalOpenTelemetryAdvice { + + private static final OpenTelemetry ELASTIC_OPEN_TELEMETRY = DefaultOpenTelemetry.builder() + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .setTracerProvider(new ElasticOTelTracerProvider(new ElasticOTelTracer(GlobalTracer.requireTracerImpl()))) + .build(); + + @Advice.OnMethodEnter(suppress = Throwable.class, inline = false, skipOn = Advice.OnNonDefaultValue.class) + public static boolean onEnter() { + // skips actual method and directly goes to exit advice + return true; + } + + @AssignTo.Return + @Advice.OnMethodExit(suppress = Throwable.class, inline = false) + public static OpenTelemetry onExit() { + return ELASTIC_OPEN_TELEMETRY; + } } } From 8f63bf1984943d0edc019b5b09205df9aca9aa88 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Sat, 23 Jan 2021 10:01:18 +0100 Subject: [PATCH 10/94] more polishing --- .../apm/agent/bci/ElasticApmAgent.java | 2 ++ .../configuration/CoreConfiguration.java | 2 +- .../apm-opentelemetry-plugin/pom.xml | 3 +++ .../ContextStorageInstrumentation.java | 24 +++++++++++++++++++ .../GlobalOpenTelemetryInstrumentation.java | 24 +++++++++++++++++++ .../context/ElasticOTelContextStorage.java | 24 +++++++++++++++++++ .../context/ElasticOTelScope.java | 24 +++++++++++++++++++ .../opentelemetry/context/package-info.java | 24 +++++++++++++++++++ .../opentelemetry/sdk/AttributeMapper.java | 24 +++++++++++++++++++ .../opentelemetry/sdk/ElasticOTelSpan.java | 24 +++++++++++++++++++ .../sdk/ElasticOTelSpanBuilder.java | 24 +++++++++++++++++++ .../sdk/ElasticOTelSpanContext.java | 24 +++++++++++++++++++ .../opentelemetry/sdk/ElasticOTelTracer.java | 24 +++++++++++++++++++ .../sdk/ElasticOTelTracerProvider.java | 24 +++++++++++++++++++ .../agent/opentelemetry/sdk/package-info.java | 24 +++++++++++++++++++ .../sdk/ElasticOpenTelemetryTest.java | 24 +++++++++++++++++++ 16 files changed, 318 insertions(+), 1 deletion(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java index 106306ff03..616f81998d 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/ElasticApmAgent.java @@ -311,6 +311,8 @@ private static AgentBuilder initAgentBuilder(ElasticApmTracer tracer, Instrument if (isIncluded(advice, coreConfiguration)) { numberOfAdvices++; agentBuilder = applyAdvice(tracer, agentBuilder, advice, advice.getTypeMatcher()); + } else { + logger.debug("Not applying excluded instrumentation {}", instrumentation.getClass().getName()); } } logger.debug("Applied {} advices", numberOfAdvices); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 7bc761467a..c34c399ce3 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -245,7 +245,7 @@ public class CoreConfiguration extends ConfigurationOptionProvider { "NOTE: Changing this value at runtime can slow down the application temporarily.") .dynamic(true) .tags("added[1.0.0,Changing this value at runtime is possible since version 1.15.0]") - .buildWithDefault(Collections.emptyList()); + .buildWithDefault(Collections.emptyList()); private final ConfigurationOption enableExperimentalInstrumentations = ConfigurationOption.booleanOption() .key("enable_experimental_instrumentations") diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 0a62ea73e1..c050b7a275 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -16,6 +16,9 @@ ${project.basedir}/../.. 8 8 + 8 + 11 + true diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 476964f793..ded049e53a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 3369d3e1a0..d24eb6b4dc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java index f322742ebf..893ec87c17 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.context; import co.elastic.apm.agent.impl.ElasticApmTracer; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java index e213cd5c52..a16426ecf7 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.context; import co.elastic.apm.agent.impl.transaction.AbstractSpan; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java index 99b0164729..1c8a61b23d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ @NonnullApi package co.elastic.apm.agent.opentelemetry.context; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java index 8cc85b27ce..8d42555a11 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.context.web.ResultUtil; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index 29e35ab9f3..7d0e55b6e9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.transaction.AbstractSpan; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index a838b05dcc..b0c3f3e670 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.ElasticApmTracer; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java index f454355974..b12c0febcc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.transaction.TraceContext; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java index 6a31ef9093..a8f1075ebc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.ElasticApmTracer; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java index 02ca266aaf..9f4e1ecded 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import io.opentelemetry.api.trace.Tracer; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java index effe62419d..102fff240d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ @NonnullApi package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 2fc8ed0c4a..ebe000d498 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.AbstractInstrumentationTest; From 9b2e48934d7e1fb0dbfe52d097a384e20edbca19 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 25 Jan 2021 08:21:29 +0100 Subject: [PATCH 11/94] Map OTel semantic convention attributes to data model --- .../apm/agent/impl/context/Destination.java | 2 +- .../opentelemetry/sdk/AttributeMapper.java | 66 ------ .../opentelemetry/sdk/ElasticOTelSpan.java | 223 +++++++++++++++++- .../sdk/ElasticOTelSpanBuilder.java | 9 +- .../sdk/ElasticOpenTelemetryTest.java | 140 ++++++++++- 5 files changed, 353 insertions(+), 87 deletions(-) delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java index 8cc6b5fd48..38a6db353c 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java @@ -193,7 +193,7 @@ public StringBuilder getName() { return name; } - public Service withType(String type) { + public Service withType(@Nullable String type) { this.type = type; return this; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java deleted file mode 100644 index 8d42555a11..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/AttributeMapper.java +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * #L% - */ -package co.elastic.apm.agent.opentelemetry.sdk; - -import co.elastic.apm.agent.impl.context.web.ResultUtil; -import co.elastic.apm.agent.impl.transaction.AbstractSpan; -import co.elastic.apm.agent.impl.transaction.Span; -import co.elastic.apm.agent.impl.transaction.Transaction; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; - -import javax.annotation.Nullable; - -class AttributeMapper { - - static void mapAttribute(AbstractSpan span, AttributeKey key, @Nullable Object value) { - if (value == null) { - return; - } - if (span.isSampled()) { - // TODO translate other well-known attributes - if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { - int statusCode = ((Number) value).intValue(); - if (span instanceof Transaction) { - ((Transaction) span).getContext().getResponse().withStatusCode(statusCode); - ((Transaction) span).withResult(ResultUtil.getResultByHttpStatus(statusCode)); - } else if (span instanceof Span) { - ((Span) span).getContext().getHttp().withStatusCode(statusCode); - } - } - setUnknownAttributeAsLabel(span, key, value); - } - } - - private static void setUnknownAttributeAsLabel(AbstractSpan span, AttributeKey key, Object value) { - if (value instanceof Boolean) { - span.addLabel(key.getKey(), (Boolean) value); - } else if (value instanceof Number) { - span.addLabel(key.getKey(), (Number) value); - } else { - span.addLabel(key.getKey(), value.toString()); - } - } -} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index 7d0e55b6e9..fd23287679 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,14 +24,25 @@ */ package co.elastic.apm.agent.opentelemetry.sdk; +import co.elastic.apm.agent.impl.context.Request; +import co.elastic.apm.agent.impl.context.Url; +import co.elastic.apm.agent.impl.context.web.ResultUtil; import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.Transaction; +import co.elastic.apm.agent.util.VersionUtils; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nonnull; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; +import java.util.Map; import java.util.concurrent.TimeUnit; public class ElasticOTelSpan implements Span { @@ -39,14 +50,23 @@ public class ElasticOTelSpan implements Span { public ElasticOTelSpan(AbstractSpan span) { this.span = span; + span.incrementReferences(); } @Override public Span setAttribute(AttributeKey key, @Nonnull T value) { - AttributeMapper.mapAttribute(span, key, value); + mapAttribute(key, value); return this; } + public void mapAttribute(AttributeKey key, Object value) { + if (span instanceof Transaction) { + mapTransactionAttributes((Transaction) span, key, value); + } else if (span instanceof Span) { + mapSpanAttributes((co.elastic.apm.agent.impl.transaction.Span) span, key, value); + } + } + @Override public Span addEvent(String name, Attributes attributes) { return this; @@ -59,6 +79,17 @@ public Span addEvent(String name, Attributes attributes, long timestamp, TimeUni @Override public Span setStatus(StatusCode statusCode, String description) { + if (span instanceof Transaction) { + Transaction t = (Transaction) span; + switch (statusCode) { + case OK: + t.withResultIfUnset("OK"); + break; + case ERROR: + t.withResultIfUnset("Error"); + break; + } + } // TODO set outcome return this; } @@ -77,9 +108,195 @@ public Span updateName(String name) { @Override public void end() { + if (span instanceof Transaction) { + onTransactionEnd(); + } else if (span instanceof Span) { + onSpanEnd(); + } span.end(); } + private void mapTransactionAttributes(Transaction t, AttributeKey key, Object value) { + Request request = t.getContext().getRequest(); + // http.* + if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { + t.getContext().getResponse().withStatusCode(((Number) value).intValue()); + t.withResult(ResultUtil.getResultByHttpStatus(((Number) value).intValue())); + } else if (key.equals(SemanticAttributes.HTTP_URL)) { + StringBuilder fullURl = request.getUrl().getFull(); + fullURl.setLength(0); + fullURl.append((String) value); + try { + URL url = new URL((String) value); + request.getUrl().withSearch(url.getQuery()); + request.getUrl().withProtocol(url.getProtocol()); + request.getUrl().withPathname(url.getPath()); + request.getUrl().withHostname(url.getHost()); + int port = url.getPort(); + port = port > 0 ? port : url.getDefaultPort(); + if (port > 0) { + request.getUrl().withPort(port); + } + } catch (MalformedURLException ignore) { + } + } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { + StringBuilder fullURl = request.getUrl().getFull(); + if (fullURl.length() == 0) { + fullURl.append((String) value); + } + } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { + request.withMethod((String) value); + } else if (key.equals(SemanticAttributes.HTTP_HOST)) { + String httpHost = (String) value; + int indexOfColon = httpHost.indexOf(':'); + if (indexOfColon > 0) { + request.getUrl().withHostname(httpHost.substring(0, indexOfColon)); + try { + request.getUrl().withPort(Integer.parseInt(httpHost.substring(indexOfColon + 1))); + } catch (NumberFormatException ignore) { + } + } else { + request.getUrl().withHostname(httpHost); + } + } else if (key.equals(SemanticAttributes.HTTP_SERVER_NAME)) { + request.getUrl().withHostname((String) value); + } else if (key.equals(SemanticAttributes.HTTP_SCHEME)) { + request.getUrl().withProtocol((String) value); + } else if (key.equals(SemanticAttributes.HTTP_ROUTE)) { + request.getUrl().withPathname((String) value); + } else if (key.equals(SemanticAttributes.HTTP_FLAVOR)) { + request.withHttpVersion((String) value); + } else if (key.equals(SemanticAttributes.HTTP_CLIENT_IP)) { + request.getHeaders().add("X-Forwarded-For", (String) value); + } else if (key.equals(SemanticAttributes.HTTP_USER_AGENT)) { + request.getHeaders().add("User-Agent", (String) value); + } else { + setAttributeAsLabel(t, key, value); + } + + } + + private void onTransactionEnd() { + Transaction t = (Transaction) span; + Request request = t.getContext().getRequest(); + if (request.hasContent()) { + t.withType("request"); + Url requestUrl = request.getUrl(); + if (requestUrl.getProtocol() == null) { + requestUrl.withProtocol("http"); + } + Iterator> iterator = span.getContext().getLabelIterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + // net.* + if (entry.getKey().equals(SemanticAttributes.NET_HOST_NAME.getKey())) { + if (requestUrl.getHostname() == null) { + requestUrl.withHostname((String) entry.getValue()); + } + } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_PORT.getKey())) { + if (requestUrl.getPort().length() == 0) { + requestUrl.withPort(((Number) entry.getValue()).intValue()); + } + } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_IP.getKey())) { + String remoteAddress = request.getSocket().getRemoteAddress(); + request.getSocket().withRemoteAddress(entry.getValue() + (remoteAddress == null ? "" : remoteAddress)); + } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_PORT.getKey())) { + String remoteAddress = request.getSocket().getRemoteAddress(); + request.getSocket().withRemoteAddress((remoteAddress == null ? "" : remoteAddress) + ":" + entry.getValue()); + } + } + // if the URL starts with / we have only captured the http.target and have to construct the full url + if (requestUrl.getFull().length() > 0 && requestUrl.getFull().charAt(0) == '/') { + String httpTarget = requestUrl.getFull().toString(); + requestUrl.getFull().setLength(0); + requestUrl + .appendToFull(requestUrl.getProtocol()) + .appendToFull("://") + .appendToFull(requestUrl.getHostname()) + .appendToFull(requestUrl.getPort().length() > 0 ? ":" + requestUrl.getPort() : "") + .appendToFull(httpTarget); + } + + } else { + t.withType("unknown"); + } + t.setFrameworkName("OpenTelemetry"); + t.setFrameworkVersion(VersionUtils.getVersion(OpenTelemetry.class, "io.opentelemetry", "opentelemetry-api")); + + } + + private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, AttributeKey key, Object value) { + co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); + + // http.* + if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { + context.getHttp().withStatusCode(((Number) value).intValue()); + } else if (key.equals(SemanticAttributes.HTTP_URL)) { + context.getHttp().withUrl((String) value); + } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { + if (context.getHttp().getUrl() == null) { + context.getHttp().withUrl((String) value); + } + } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { + context.getHttp().withMethod((String) value); + } else if (key.equals(SemanticAttributes.HTTP_HOST)) { + context.getDestination().withAddressPort((String) value); + } + // net.* + else if (key.equals(SemanticAttributes.NET_PEER_NAME)) { + context.getDestination().withAddress((String) value); + } else if (key.equals(SemanticAttributes.NET_PEER_IP)) { + if (context.getDestination().getAddress().length() == 0) { + context.getDestination().withAddress((String) value); + } + } else if (key.equals(SemanticAttributes.NET_PEER_PORT)) { + context.getDestination().withPort(((Number) value).intValue()); + } + // db.* + else if (key.equals(SemanticAttributes.DB_SYSTEM)) { + s.withType((String) value); + } else if (key.equals(SemanticAttributes.DB_NAME)) { + context.getDb().withInstance((String) value); + } else if (key.equals(SemanticAttributes.DB_STATEMENT)) { + context.getDb().withStatement((String) value); + } else if (key.equals(SemanticAttributes.DB_USER)) { + context.getDb().withUser((String) value); + } else { + setAttributeAsLabel(s, key, value); + } + } + + private void onSpanEnd() { + co.elastic.apm.agent.impl.transaction.Span s = (co.elastic.apm.agent.impl.transaction.Span) this.span; + co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); + if (context.getHttp().hasContent()) { + s.withType("external").withSubtype("http"); + } else if (context.getDb().hasContent()) { + s.withType("db").withSubtype(context.getDb().getType()); + if (s.getSubtype() != null) { + context.getDestination() + .getService() + .withName(s.getSubtype()) + .withType(s.getSubtype()); + } + } else { + s.withType("app"); + } + if (context.getDestination().getService().hasContent()) { + context.getDestination().getService().withType(s.getType()); + } + } + + private static void setAttributeAsLabel(AbstractSpan span, AttributeKey key, Object value) { + if (value instanceof Boolean) { + span.addLabel(key.getKey(), (Boolean) value); + } else if (value instanceof Number) { + span.addLabel(key.getKey(), (Number) value); + } else { + span.addLabel(key.getKey(), value.toString()); + } + } + @Override public void end(long timestamp, TimeUnit unit) { span.end(unit.toMicros(timestamp)); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index b0c3f3e670..faba3299c4 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -144,7 +144,8 @@ public Span startSpan() { return Span.getInvalid(); } span.withName(spanName); - attributes.forEach((key, value) -> AttributeMapper.mapAttribute(span, key, value)); - return new ElasticOTelSpan(span); + ElasticOTelSpan elasticOTelSpan = new ElasticOTelSpan(span); + attributes.forEach(elasticOTelSpan::mapAttribute); + return elasticOTelSpan; } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index ebe000d498..52d2940a4c 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -56,6 +56,7 @@ void setUp() { this.openTelemetry = GlobalOpenTelemetry.get(); assertThat(openTelemetry).isSameAs(GlobalOpenTelemetry.get()); otelTracer = openTelemetry.getTracer(null); + disableRecyclingValidation(); } @Test @@ -67,17 +68,6 @@ void testTransaction() { assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); } - @Test - void testTransactionStatusCode() { - otelTracer.spanBuilder("transaction") - .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) - .startSpan() - .end(); - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); - assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); - } - @Test void testTransactionWithAttribute() { otelTracer.spanBuilder("transaction") @@ -130,6 +120,24 @@ void testTransactionWithSpanContextStorePropagation() { assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); } + @Test + void testStartChildAfterEnd() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + transaction.end(); + + assertThat(reporter.getTransactions()).hasSize(1); + // simulate reporting the span + reporter.getFirstTransaction().decrementReferences(); + + try (Scope scope = transaction.makeCurrent()) { + otelTracer.spanBuilder("span") + .startSpan() + .end(); + } + assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); + } + /** * Demonstrates a missing feature of this bridge: custom context entries are not propagated * @@ -187,6 +195,112 @@ void testTransactionInject() { assertThat(elasticApmHeaders).containsAllEntriesOf(otelHeaders); } + @Test + void testTransactionSemanticConventionMappingHttpHost() { + otelTracer.spanBuilder("transaction") + .startSpan() + .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") + .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") + .setAttribute(SemanticAttributes.HTTP_HOST, "www.example.com:8080") + .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") + .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); + assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("www.example.com"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://www.example.com:8080/foo?bar"); + } + + @Test + void testTransactionSemanticConventionMappingHttpNetHostName() { + otelTracer.spanBuilder("transaction") + .startSpan() + .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") + .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") + .setAttribute(SemanticAttributes.NET_HOST_NAME, "example.com") + .setAttribute(SemanticAttributes.NET_HOST_PORT, 8080) + .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") + .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) + .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") + .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); + assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); + } + + @Test + void testTransactionSemanticConventionMappingHttpNetHostIP() { + otelTracer.spanBuilder("transaction") + .startSpan() + .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") + .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") + .setAttribute(SemanticAttributes.NET_HOST_NAME, "127.0.0.1") + .setAttribute(SemanticAttributes.NET_HOST_PORT, 8080) + .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) + .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") + .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") + .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); + assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("127.0.0.1"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://127.0.0.1:8080/foo?bar"); + } + + @Test + void testTransactionSemanticConventionMappingHttpUrl() { + otelTracer.spanBuilder("transaction") + .startSpan() + .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") + .setAttribute(SemanticAttributes.HTTP_URL, "http://example.com:8080/foo?bar") + .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) + .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) + .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") + .end(); + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); + assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); + } + + @Test + void testSpanSemanticConventionMappingHttp() { + Span transaction = otelTracer.spanBuilder("transaction") + .startSpan(); + try (Scope scope = transaction.makeCurrent()) { + otelTracer.spanBuilder("span") + .startSpan() + .end(); + } finally { + transaction.end(); + } + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getSpans()).hasSize(1); + assertThat(reporter.getFirstSpan()); + } + private static class MapGetter implements TextMapPropagator.Getter> { @Override public Iterable keys(Map carrier) { From a7899d947c50dcbca5311cd37f5ad33dc23cc663 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 25 Jan 2021 08:22:10 +0100 Subject: [PATCH 12/94] Mark spans non-discardable on context propagation --- .../sdk/ElasticOTelTextMapPropagator.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java new file mode 100644 index 0000000000..66783676e5 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java @@ -0,0 +1,33 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapPropagator; + +import javax.annotation.Nullable; +import java.util.Collection; + +public class ElasticOTelTextMapPropagator implements TextMapPropagator { + + private static final TextMapPropagator W3C_PROPAGATOR = W3CTraceContextPropagator.getInstance(); + + @Override + public Collection fields() { + return W3C_PROPAGATOR.fields(); + } + + @Override + public void inject(Context context, @Nullable C carrier, Setter setter) { + Span span = Span.fromContext(context); + if (span instanceof ElasticOTelSpan) { + ((ElasticOTelSpan) span).getInternalSpan().setNonDiscardable(); + } + W3C_PROPAGATOR.inject(context, carrier, setter); + } + + @Override + public Context extract(Context context, @Nullable C carrier, Getter getter) { + return W3C_PROPAGATOR.extract(context, carrier, getter); + } +} From 56594eb5b68b4b5010e1271e16f6086d4366b228 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 25 Jan 2021 08:40:17 +0100 Subject: [PATCH 13/94] Remove construction of URL fields that are filled on APM Server --- .../opentelemetry/sdk/ElasticOTelSpan.java | 27 ------------------- .../sdk/ElasticOpenTelemetryTest.java | 11 ++++---- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index fd23287679..cd0e5a1218 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -39,8 +39,6 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nonnull; -import java.net.MalformedURLException; -import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -126,19 +124,6 @@ private void mapTransactionAttributes(Transaction t, AttributeKey key, Object StringBuilder fullURl = request.getUrl().getFull(); fullURl.setLength(0); fullURl.append((String) value); - try { - URL url = new URL((String) value); - request.getUrl().withSearch(url.getQuery()); - request.getUrl().withProtocol(url.getProtocol()); - request.getUrl().withPathname(url.getPath()); - request.getUrl().withHostname(url.getHost()); - int port = url.getPort(); - port = port > 0 ? port : url.getDefaultPort(); - if (port > 0) { - request.getUrl().withPort(port); - } - } catch (MalformedURLException ignore) { - } } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { StringBuilder fullURl = request.getUrl().getFull(); if (fullURl.length() == 0) { @@ -205,18 +190,6 @@ private void onTransactionEnd() { request.getSocket().withRemoteAddress((remoteAddress == null ? "" : remoteAddress) + ":" + entry.getValue()); } } - // if the URL starts with / we have only captured the http.target and have to construct the full url - if (requestUrl.getFull().length() > 0 && requestUrl.getFull().charAt(0) == '/') { - String httpTarget = requestUrl.getFull().toString(); - requestUrl.getFull().setLength(0); - requestUrl - .appendToFull(requestUrl.getProtocol()) - .appendToFull("://") - .appendToFull(requestUrl.getHostname()) - .appendToFull(requestUrl.getPort().length() > 0 ? ":" + requestUrl.getPort() : "") - .appendToFull(httpTarget); - } - } else { t.withType("unknown"); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 52d2940a4c..4cc9d70be0 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -212,7 +212,7 @@ void testTransactionSemanticConventionMappingHttpHost() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("www.example.com"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://www.example.com:8080/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); } @Test @@ -236,7 +236,7 @@ void testTransactionSemanticConventionMappingHttpNetHostName() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); } @Test @@ -260,7 +260,7 @@ void testTransactionSemanticConventionMappingHttpNetHostIP() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("127.0.0.1"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://127.0.0.1:8080/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); } @Test @@ -268,6 +268,7 @@ void testTransactionSemanticConventionMappingHttpUrl() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") + .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") .setAttribute(SemanticAttributes.HTTP_URL, "http://example.com:8080/foo?bar") .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) @@ -278,8 +279,8 @@ void testTransactionSemanticConventionMappingHttpUrl() { assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isNull(); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEmpty(); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); } From ca4e5a6135b3ee3cf54a6c3352e85f9560f8e7da Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 25 Jan 2021 09:40:04 +0100 Subject: [PATCH 14/94] Add license headers --- .../sdk/ElasticOTelTextMapPropagator.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java index 66783676e5..c348b0f92a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java @@ -1,3 +1,27 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ package co.elastic.apm.agent.opentelemetry.sdk; import io.opentelemetry.api.trace.Span; From 31c5b9765610bef8988a22f4103b06a1afdda537 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 25 Jan 2021 09:40:16 +0100 Subject: [PATCH 15/94] Revert "Remove construction of URL fields that are filled on APM Server" This reverts commit 56594eb5b68b4b5010e1271e16f6086d4366b228. --- .../opentelemetry/sdk/ElasticOTelSpan.java | 27 +++++++++++++++++++ .../sdk/ElasticOpenTelemetryTest.java | 11 ++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index cd0e5a1218..fd23287679 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -39,6 +39,8 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nonnull; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -124,6 +126,19 @@ private void mapTransactionAttributes(Transaction t, AttributeKey key, Object StringBuilder fullURl = request.getUrl().getFull(); fullURl.setLength(0); fullURl.append((String) value); + try { + URL url = new URL((String) value); + request.getUrl().withSearch(url.getQuery()); + request.getUrl().withProtocol(url.getProtocol()); + request.getUrl().withPathname(url.getPath()); + request.getUrl().withHostname(url.getHost()); + int port = url.getPort(); + port = port > 0 ? port : url.getDefaultPort(); + if (port > 0) { + request.getUrl().withPort(port); + } + } catch (MalformedURLException ignore) { + } } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { StringBuilder fullURl = request.getUrl().getFull(); if (fullURl.length() == 0) { @@ -190,6 +205,18 @@ private void onTransactionEnd() { request.getSocket().withRemoteAddress((remoteAddress == null ? "" : remoteAddress) + ":" + entry.getValue()); } } + // if the URL starts with / we have only captured the http.target and have to construct the full url + if (requestUrl.getFull().length() > 0 && requestUrl.getFull().charAt(0) == '/') { + String httpTarget = requestUrl.getFull().toString(); + requestUrl.getFull().setLength(0); + requestUrl + .appendToFull(requestUrl.getProtocol()) + .appendToFull("://") + .appendToFull(requestUrl.getHostname()) + .appendToFull(requestUrl.getPort().length() > 0 ? ":" + requestUrl.getPort() : "") + .appendToFull(httpTarget); + } + } else { t.withType("unknown"); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 4cc9d70be0..52d2940a4c 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -212,7 +212,7 @@ void testTransactionSemanticConventionMappingHttpHost() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("www.example.com"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://www.example.com:8080/foo?bar"); } @Test @@ -236,7 +236,7 @@ void testTransactionSemanticConventionMappingHttpNetHostName() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); } @Test @@ -260,7 +260,7 @@ void testTransactionSemanticConventionMappingHttpNetHostIP() { assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("127.0.0.1"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("/foo?bar"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://127.0.0.1:8080/foo?bar"); } @Test @@ -268,7 +268,6 @@ void testTransactionSemanticConventionMappingHttpUrl() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") - .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") .setAttribute(SemanticAttributes.HTTP_URL, "http://example.com:8080/foo?bar") .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) @@ -279,8 +278,8 @@ void testTransactionSemanticConventionMappingHttpUrl() { assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isNull(); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEmpty(); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); + assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort().toString()).isEqualTo("8080"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); } From f04c94fa5d9da91fdbbde3bd1503594d519d6203 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Tue, 26 Jan 2021 10:09:30 +0100 Subject: [PATCH 16/94] Map destination details of external spans --- .../elastic/apm/agent/impl/context/Http.java | 22 +- .../elastic/apm/agent/impl/context/Url.java | 41 ++- .../report/serialize/DslJsonSerializer.java | 2 +- .../apm-opentelemetry-plugin/pom.xml | 5 + .../opentelemetry/sdk/ElasticOTelSpan.java | 247 +++++++++++------- .../sdk/ElasticOpenTelemetryTest.java | 52 +++- 6 files changed, 258 insertions(+), 111 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java index a23c98f246..c72da48432 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -35,8 +35,7 @@ public class Http implements Recyclable { /** * URL used by this HTTP outgoing span */ - @Nullable - private String url; + private final Url url = new Url(); /** * HTTP method used by this HTTP outgoing span @@ -54,6 +53,10 @@ public class Http implements Recyclable { */ @Nullable public String getUrl() { + return url.getFull().toString(); + } + + public Url getUrlObject() { return url; } @@ -71,7 +74,10 @@ public int getStatusCode() { */ public Http withUrl(@Nullable String url) { if (url != null) { - this.url = sanitize(url); + String sanitized = sanitize(url); + if (sanitized != null) { + this.url.appendToFull(sanitized); + } } return this; } @@ -106,19 +112,19 @@ public Http withStatusCode(int statusCode) { @Override public void resetState() { - url = null; + url.resetState(); method = null; statusCode = 0; } public boolean hasContent() { - return url != null || + return url.hasContent() || method != null || statusCode > 0; } public void copyFrom(Http other) { - url = other.url; + url.copyFrom(other.url); method = other.method; statusCode = other.statusCode; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java index edb705c7c1..27ef1d1a29 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,6 +27,7 @@ import co.elastic.apm.agent.objectpool.Recyclable; import javax.annotation.Nullable; +import java.net.URL; /** @@ -114,6 +115,16 @@ public StringBuilder getPort() { return port; } + public int getPortAsInt() { + if (port.length() > 0) { + try { + return Integer.parseInt(port, 0, port.length(), 10); + } catch (NumberFormatException ignore) { + } + } + return -1; + } + /** * The port of the request, e.g. '443' */ @@ -154,6 +165,32 @@ public Url withSearch(@Nullable String search) { return this; } + public void fillFromFullUrl(URL url) { + if (protocol == null) protocol = url.getProtocol(); + if (hostname == null) hostname = url.getHost(); + if (pathname == null) pathname = url.getPath(); + if (search == null) search = url.getQuery(); + int port = url.getPort(); + port = port > 0 ? port : url.getDefaultPort(); + if (port > 0) { + withPort(port); + } + } + + public void fillFullUrl() { + if (full.length() > 0 || hostname == null) { + return; + } + full.append(protocol != null ? protocol : "http") + .append("://") + .append(hostname) + .append(port.length() > 0 ? ":" : "") + .append(port.length() > 0 ? port : "") + .append(pathname != null ? pathname : "") + .append(search != null ? "?" : "") + .append(search != null ? search : ""); + } + @Override public void resetState() { protocol = null; diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java index 8415df1c0d..795d16c53a 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java @@ -871,7 +871,7 @@ private void serializeHttpContext(final Http http) { if (statusCode > 0) { writeField("status_code", http.getStatusCode()); } - writeLastField("url", http.getUrl()); + writeLastField("url", http.getUrlObject().getFull()); jw.writeByte(OBJECT_END); jw.writeByte(COMMA); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index c050b7a275..55ce9ed6ca 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -32,5 +32,10 @@ opentelemetry-semconv 0.14.1 + + ${project.groupId} + apm-httpclient-core + ${project.version} + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index fd23287679..40b57af05b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -24,6 +24,9 @@ */ package co.elastic.apm.agent.opentelemetry.sdk; +import co.elastic.apm.agent.http.client.HttpClientHelper; +import co.elastic.apm.agent.impl.context.AbstractContext; +import co.elastic.apm.agent.impl.context.Destination; import co.elastic.apm.agent.impl.context.Request; import co.elastic.apm.agent.impl.context.Url; import co.elastic.apm.agent.impl.context.web.ResultUtil; @@ -39,6 +42,7 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; @@ -62,7 +66,7 @@ public Span setAttribute(AttributeKey key, @Nonnull T value) { public void mapAttribute(AttributeKey key, Object value) { if (span instanceof Transaction) { mapTransactionAttributes((Transaction) span, key, value); - } else if (span instanceof Span) { + } else if (span instanceof co.elastic.apm.agent.impl.transaction.Span) { mapSpanAttributes((co.elastic.apm.agent.impl.transaction.Span) span, key, value); } } @@ -109,61 +113,24 @@ public Span updateName(String name) { @Override public void end() { if (span instanceof Transaction) { - onTransactionEnd(); - } else if (span instanceof Span) { - onSpanEnd(); + onTransactionEnd((Transaction) span); + } else if (span instanceof co.elastic.apm.agent.impl.transaction.Span) { + onSpanEnd((co.elastic.apm.agent.impl.transaction.Span) span); } span.end(); } private void mapTransactionAttributes(Transaction t, AttributeKey key, Object value) { Request request = t.getContext().getRequest(); + Url url = request.getUrl(); // http.* if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { t.getContext().getResponse().withStatusCode(((Number) value).intValue()); t.withResult(ResultUtil.getResultByHttpStatus(((Number) value).intValue())); - } else if (key.equals(SemanticAttributes.HTTP_URL)) { - StringBuilder fullURl = request.getUrl().getFull(); - fullURl.setLength(0); - fullURl.append((String) value); - try { - URL url = new URL((String) value); - request.getUrl().withSearch(url.getQuery()); - request.getUrl().withProtocol(url.getProtocol()); - request.getUrl().withPathname(url.getPath()); - request.getUrl().withHostname(url.getHost()); - int port = url.getPort(); - port = port > 0 ? port : url.getDefaultPort(); - if (port > 0) { - request.getUrl().withPort(port); - } - } catch (MalformedURLException ignore) { - } - } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { - StringBuilder fullURl = request.getUrl().getFull(); - if (fullURl.length() == 0) { - fullURl.append((String) value); - } + } else if (mapHttpUrlAttributes(key, value, url)) { + // successfully mapped inside mapHttpUrlAttributes } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { request.withMethod((String) value); - } else if (key.equals(SemanticAttributes.HTTP_HOST)) { - String httpHost = (String) value; - int indexOfColon = httpHost.indexOf(':'); - if (indexOfColon > 0) { - request.getUrl().withHostname(httpHost.substring(0, indexOfColon)); - try { - request.getUrl().withPort(Integer.parseInt(httpHost.substring(indexOfColon + 1))); - } catch (NumberFormatException ignore) { - } - } else { - request.getUrl().withHostname(httpHost); - } - } else if (key.equals(SemanticAttributes.HTTP_SERVER_NAME)) { - request.getUrl().withHostname((String) value); - } else if (key.equals(SemanticAttributes.HTTP_SCHEME)) { - request.getUrl().withProtocol((String) value); - } else if (key.equals(SemanticAttributes.HTTP_ROUTE)) { - request.getUrl().withPathname((String) value); } else if (key.equals(SemanticAttributes.HTTP_FLAVOR)) { request.withHttpVersion((String) value); } else if (key.equals(SemanticAttributes.HTTP_CLIENT_IP)) { @@ -173,50 +140,26 @@ private void mapTransactionAttributes(Transaction t, AttributeKey key, Object } else { setAttributeAsLabel(t, key, value); } - } - private void onTransactionEnd() { - Transaction t = (Transaction) span; + private void onTransactionEnd(Transaction t) { Request request = t.getContext().getRequest(); if (request.hasContent()) { t.withType("request"); - Url requestUrl = request.getUrl(); - if (requestUrl.getProtocol() == null) { - requestUrl.withProtocol("http"); - } - Iterator> iterator = span.getContext().getLabelIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - // net.* - if (entry.getKey().equals(SemanticAttributes.NET_HOST_NAME.getKey())) { - if (requestUrl.getHostname() == null) { - requestUrl.withHostname((String) entry.getValue()); + Url url = request.getUrl(); + captureNetHostUrlAttributes(url, span.getContext()); + request.getSocket().withRemoteAddress(getClientRemoteAddress(span.getContext())); + if (url.hasContent()) { + StringBuilder fullUrl = url.getFull(); + if (fullUrl.length() > 0) { + try { + url.fillFromFullUrl(new URL(fullUrl.toString())); + } catch (MalformedURLException ignore) { } - } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_PORT.getKey())) { - if (requestUrl.getPort().length() == 0) { - requestUrl.withPort(((Number) entry.getValue()).intValue()); - } - } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_IP.getKey())) { - String remoteAddress = request.getSocket().getRemoteAddress(); - request.getSocket().withRemoteAddress(entry.getValue() + (remoteAddress == null ? "" : remoteAddress)); - } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_PORT.getKey())) { - String remoteAddress = request.getSocket().getRemoteAddress(); - request.getSocket().withRemoteAddress((remoteAddress == null ? "" : remoteAddress) + ":" + entry.getValue()); + } else { + url.fillFullUrl(); } } - // if the URL starts with / we have only captured the http.target and have to construct the full url - if (requestUrl.getFull().length() > 0 && requestUrl.getFull().charAt(0) == '/') { - String httpTarget = requestUrl.getFull().toString(); - requestUrl.getFull().setLength(0); - requestUrl - .appendToFull(requestUrl.getProtocol()) - .appendToFull("://") - .appendToFull(requestUrl.getHostname()) - .appendToFull(requestUrl.getPort().length() > 0 ? ":" + requestUrl.getPort() : "") - .appendToFull(httpTarget); - } - } else { t.withType("unknown"); } @@ -225,22 +168,36 @@ private void onTransactionEnd() { } + @Nullable + public String getClientRemoteAddress(AbstractContext context) { + String netPeerIp = null; + Long netPeerPort = null; + Iterator> iterator = context.getLabelIterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + // net.* + if (entry.getKey().equals(SemanticAttributes.NET_PEER_IP.getKey())) { + netPeerIp = (String) entry.getValue(); + } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_PORT.getKey())) { + netPeerPort = (Long) entry.getValue(); + } + } + if (netPeerIp != null && netPeerPort != null) { + return netPeerIp + ":" + netPeerPort; + } + return null; + } + private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, AttributeKey key, Object value) { co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); // http.* - if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { + if (mapHttpUrlAttributes(key, value, context.getHttp().getUrlObject())) { + // successfully mapped inside mapHttpUrlAttributes + } else if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { context.getHttp().withStatusCode(((Number) value).intValue()); - } else if (key.equals(SemanticAttributes.HTTP_URL)) { - context.getHttp().withUrl((String) value); - } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { - if (context.getHttp().getUrl() == null) { - context.getHttp().withUrl((String) value); - } } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { context.getHttp().withMethod((String) value); - } else if (key.equals(SemanticAttributes.HTTP_HOST)) { - context.getDestination().withAddressPort((String) value); } // net.* else if (key.equals(SemanticAttributes.NET_PEER_NAME)) { @@ -266,24 +223,124 @@ else if (key.equals(SemanticAttributes.DB_SYSTEM)) { } } - private void onSpanEnd() { - co.elastic.apm.agent.impl.transaction.Span s = (co.elastic.apm.agent.impl.transaction.Span) this.span; + private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); + Destination destination = context.getDestination(); if (context.getHttp().hasContent()) { s.withType("external").withSubtype("http"); + Url url = context.getHttp().getUrlObject(); + if (context.getDestination().getAddress().length() > 0) { + url.withHostname(context.getDestination().getAddress().toString()); + } + if (context.getDestination().getPort() > 0) { + url.withPort(context.getDestination().getPort()); + } + // The full url is the only thing we report on spans. + // Instrumentations may not set the full url but only it's components (see mapHttpUrlAttributes) + url.fillFullUrl(); + if (url.getProtocol() == null || url.getHostname() == null) { + try { + // We also need the different pieces of the url in order to determine the destination details + url.fillFromFullUrl(new URL(url.getFull().toString())); + } catch (MalformedURLException ignore) { + } + } + HttpClientHelper.setDestinationServiceDetails(s, url.getProtocol(), url.getHostname(), url.getPortAsInt()); } else if (context.getDb().hasContent()) { s.withType("db").withSubtype(context.getDb().getType()); if (s.getSubtype() != null) { - context.getDestination() + destination .getService() .withName(s.getSubtype()) - .withType(s.getSubtype()); + .withResource(s.getSubtype()) + .withType(s.getType()); } } else { s.withType("app"); + if (destination.getService().hasContent()) { + destination.getService().withType(s.getType()); + } + } + } + + /** + * Only one of the following is required per OpenTelemetry's semantic conventions: + * + * Client: + * - http.url + * - http.scheme, http.host, http.target + * - http.scheme, net.peer.name, net.peer.port, http.target + * - http.scheme, net.peer.ip, net.peer.port, http.target + * + * Server: + * - http.url + * - http.scheme, http.host, http.target + * - http.scheme, http.server_name, net.host.port, http.target + * - http.scheme, net.host.name, net.host.port, http.target + * + * The net.* fields are captured on span/transaction end because by the time they are set, + * we don't necessarily know whether the span represents an http operation + */ + private boolean mapHttpUrlAttributes(AttributeKey key, Object value, Url url) { + if (key.equals(SemanticAttributes.HTTP_URL)) { + StringBuilder fullURl = url.getFull(); + fullURl.setLength(0); + fullURl.append((String) value); + } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { + String httpTarget = (String) value; + int indexOfQuery = httpTarget.indexOf('?'); + if (indexOfQuery > 0) { + url.withPathname(httpTarget.substring(0, indexOfQuery)); + url.withSearch(httpTarget.substring(Math.min(indexOfQuery + 1, httpTarget.length()))); + } + } else if (key.equals(SemanticAttributes.HTTP_HOST)) { + String httpHost = (String) value; + int indexOfColon = httpHost.indexOf(':'); + if (indexOfColon > 0) { + url.withHostname(httpHost.substring(0, indexOfColon)); + try { + url.withPort(Integer.parseInt(httpHost.substring(indexOfColon + 1))); + } catch (NumberFormatException ignore) { + } + } else { + url.withHostname(httpHost); + } + } else if (key.equals(SemanticAttributes.HTTP_SERVER_NAME)) { + url.withHostname((String) value); + } else if (key.equals(SemanticAttributes.HTTP_SCHEME)) { + url.withProtocol((String) value); + } else if (key.equals(SemanticAttributes.HTTP_ROUTE)) { + url.withPathname((String) value); + } else { + return false; + } + return true; + } + + /** + * these properties may have been set before we know it's an http request, that's why this capture is called on span end + */ + private void captureNetHostUrlAttributes(Url url, AbstractContext context) { + if (url.getHostname() != null && url.getPort().length() > 0) { + return; } - if (context.getDestination().getService().hasContent()) { - context.getDestination().getService().withType(s.getType()); + Iterator> iterator = context.getLabelIterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + // net.* + if (entry.getKey().equals(SemanticAttributes.NET_HOST_NAME.getKey())) { + if (url.getHostname() == null) { + url.withHostname((String) entry.getValue()); + } + } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_IP.getKey())) { + if (url.getHostname() == null) { + url.withHostname((String) entry.getValue()); + } + } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_PORT.getKey())) { + if (url.getPort().length() == 0) { + url.withPort(((Number) entry.getValue()).intValue()); + } + } } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 52d2940a4c..ef244a19d7 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -43,6 +43,7 @@ import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; @@ -285,20 +286,61 @@ void testTransactionSemanticConventionMappingHttpUrl() { } @Test - void testSpanSemanticConventionMappingHttp() { + void testSpanSemanticConventionMappingHttpUrl() { + testSpanSemanticConventionMappingHttpHelper(span -> span.setAttribute(SemanticAttributes.HTTP_URL, "http://example.com/foo?bar")); + } + + @Test + void testSpanSemanticConventionMappingHttpHost() { + testSpanSemanticConventionMappingHttpHelper(span -> { + span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); + span.setAttribute(SemanticAttributes.HTTP_HOST, "example.com"); + span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + }); + } + + @Test + void testSpanSemanticConventionMappingHttpPeerName() { + testSpanSemanticConventionMappingHttpHelper(span -> { + span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); + span.setAttribute(SemanticAttributes.NET_PEER_IP, "192.0.2.5"); + span.setAttribute(SemanticAttributes.NET_PEER_NAME, "example.com"); + span.setAttribute(SemanticAttributes.NET_PEER_PORT, 80); + span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + }); + } + + @Test + void testSpanSemanticConventionMappingHttpPeerIp() { + testSpanSemanticConventionMappingHttpHelper(span -> { + span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); + span.setAttribute(SemanticAttributes.NET_PEER_IP, "example.com"); + span.setAttribute(SemanticAttributes.NET_PEER_PORT, 80); + span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + }); + } + + void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); try (Scope scope = transaction.makeCurrent()) { - otelTracer.spanBuilder("span") - .startSpan() - .end(); + Span span = otelTracer.spanBuilder("span") + .startSpan(); + spanConsumer.accept(span); + span.end(); } finally { transaction.end(); } assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getFirstSpan()); + assertThat(reporter.getFirstSpan().getContext().getDestination().getPort()).isEqualTo(80); + assertThat(reporter.getFirstSpan().getContext().getHttp().getUrl()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); + assertThat(reporter.getFirstSpan().getContext().getDestination().getAddress().toString()).isEqualTo("example.com"); + assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getName().toString()).isEqualTo("http://example.com"); + assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getResource().toString()).isEqualTo("example.com:80"); + assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getType()).isEqualTo("external"); + reporter.resetWithoutRecycling(); } private static class MapGetter implements TextMapPropagator.Getter> { From 1d72e4a8e5a1f67f2fea8d3ff171556b47673c03 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Tue, 26 Jan 2021 10:36:56 +0100 Subject: [PATCH 17/94] Avoid calling method that's @since Java 9 --- .../src/main/java/co/elastic/apm/agent/impl/context/Url.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java index 27ef1d1a29..dbd54c699f 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java @@ -118,7 +118,7 @@ public StringBuilder getPort() { public int getPortAsInt() { if (port.length() > 0) { try { - return Integer.parseInt(port, 0, port.length(), 10); + return Integer.parseInt(port.toString()); } catch (NumberFormatException ignore) { } } From 316c65b58479113e977695f5c424cb41370814f8 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Wed, 27 Jan 2021 11:06:32 +0100 Subject: [PATCH 18/94] Fix packaging and shading --- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 1 + .../opentelemetry/sdk/ElasticOpenTelemetryTest.java | 1 + elastic-apm-agent/pom.xml | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 55ce9ed6ca..f90323f92b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -26,6 +26,7 @@ io.opentelemetry opentelemetry-api 0.14.1 + provided io.opentelemetry diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index ef244a19d7..56d7469d6e 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -156,6 +156,7 @@ void testPropagateCustomContextKey() { assertThat(tracer.getActive().getTraceContext().getId().toString()).isEqualTo(transaction.getSpanContext().getSpanIdAsHexString()); // this assertion fails as context keys are not propagated assertThat(Context.current().get(ContextKey.named("foo"))).isEqualTo("bar"); + Span.current().setAttribute("foo", "bar"); } finally { transaction.end(); } diff --git a/elastic-apm-agent/pom.xml b/elastic-apm-agent/pom.xml index 2530c9f946..d1bcf8b32d 100644 --- a/elastic-apm-agent/pom.xml +++ b/elastic-apm-agent/pom.xml @@ -345,6 +345,12 @@ org/HdrHistogram/WriterReaderPhaser.class + + io.opentelemetry:* + + io/opentelemetry/semconv/** + + @@ -413,6 +419,11 @@ org.HdrHistogram co.elastic.apm.agent.shaded.HdrHistogram + + + io.opentelemetry.semconv + co.elastic.apm.agent.shaded.opentelemetry.semconv + From 4bf7349f38bc878c715429c00a1c8b9bc3242d4d Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 29 Jan 2021 11:04:28 +0100 Subject: [PATCH 19/94] Add docs --- docs/apis.asciidoc | 25 +++++ docs/index.asciidoc | 3 +- docs/opentelemetry.asciidoc | 182 ++++++++++++++++++++++++++++++++++++ docs/opentracing.asciidoc | 22 ++--- docs/public-api.asciidoc | 88 ++++++++--------- 5 files changed, 263 insertions(+), 57 deletions(-) create mode 100644 docs/apis.asciidoc create mode 100644 docs/opentelemetry.asciidoc diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc new file mode 100644 index 0000000000..8ec329af1c --- /dev/null +++ b/docs/apis.asciidoc @@ -0,0 +1,25 @@ +ifdef::env-github[] +NOTE: For the best reading experience, +please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] +endif::[] + +[[apis]] +== Programmatic APIs + +There are three different ways enhance the out-of-the-box instrumentation of the Java agent with manual instrumentation: + +. <> + + A simple and stable API that is most native to the agent. + Contains annotations to declaratively create spans. +. <> + + A vendor neutral API. + If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. + Be aware that the API of 0.x versions is not stable. + In this version, breaking changes are frequently introduced which means you may have to adapt your instrumentation code when updating. +. <> + + A vendor neutral API that is discontinued in favor of OpenTelemetry. + + +include::./public-api.asciidoc[] +include::./opentelemetry.asciidoc[] +include::./opentracing.asciidoc[] diff --git a/docs/index.asciidoc b/docs/index.asciidoc index cfc996129f..25a2bf9252 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -16,9 +16,8 @@ include::./intro.asciidoc[Introduction] include::./setup.asciidoc[Set up the agent] include::./supported-technologies.asciidoc[Supported Technologies] include::./configuration.asciidoc[Configuration] -include::./public-api.asciidoc[API documentation] +include::./apis.asciidoc[Programmatic APIs] include::./metrics.asciidoc[Metrics] -include::./opentracing.asciidoc[OpenTracing API documentation] include::./log-correlation.asciidoc[Log correlation] include::./method-monitoring.asciidoc[Java method monitoring] include::./tuning-and-overhead.asciidoc[Tuning and Overhead considerations] diff --git a/docs/opentelemetry.asciidoc b/docs/opentelemetry.asciidoc new file mode 100644 index 0000000000..28d0f27c6b --- /dev/null +++ b/docs/opentelemetry.asciidoc @@ -0,0 +1,182 @@ +ifdef::env-github[] +NOTE: For the best reading experience, +please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] +endif::[] + +[[opentelementry-bridge]] +=== OpenTelemetry bridge + +NOTE: The OpenTelemetry bridge is currently experimental. +To enable it, set <> to `true`. + +The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, +using the OpenTelemetry API. +In other words, +it translates the calls to the OpenTelemetry API to Elastic APM and thus allows for reusing existing instrumentation. + +The first span of a service will be converted to an Elastic APM +{apm-overview-ref-v}/transactions.html[`Transaction`], +subsequent spans are mapped to Elastic APM +{apm-overview-ref-v}/transaction-spans.html[`Span`]. + +[float] +[[otel-operation-modes]] +==== Operation Modes + +This bridge allows for different operation modes in combination with the Elastic APM `javaagent` + +Noop:: ++ +-- +If the `javaagent` is not specified, the bridge is in noop mode and does not actually record and report spans. +-- + +Mix and Match:: ++ +-- +If you want to leverage the auto instrumentation of Elastic APM, +but also want to create custom spans or use the OpenTelemetry API to add custom tags to the spans created by Elastic APM, +you can just do that. +The OpenTelemetry bridge and the standard Elastic APM API interact seamlessly. +-- + +Manual instrumentation:: ++ +-- +If you don't want Elastic APM to auto-instrument known frameworks, +but instead only rely on manual instrumentation, +disable the auto instrumentation setting the configuration option <> to `false`. +-- + +[float] +[[otel-getting-started]] +==== Getting started +The first step in getting started with the OpenTelemetry API bridge is to declare a dependency to the API: + +[source,xml] +.pom.xml +---- + + io.opentelemetry + opentelemetry-api + ${version.opentelemetry} + +---- + +[source,groovy] +.build.gradle +---- +compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" +---- + +[float] +[[otel-init-tracer]] +==== Initialize tracer + +There's no separate dependency needed for the bridge itself. +The Java agent hooks into `GlobalOpenTelemetry` to return it's own implementation of `OpenTelemetry` +that is connected to the internal tracer of the agent. + +[source,java] +---- +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Tracer; + +OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); +Tracer tracer = openTelemetry.getTracer(""); + +---- + +To disable that behavior, +and to rely on the standard discovery mechanism of `GlobalOpenTelemetry`, +you can set <> to `opentelemetry`. + +[float] +[[otel-set-attribute]] +==== Add custom metadata to a span + +If you like the spans created by the Elastic APM Java agent's auto-instrumentation, +but you want to add a custom label, +you can use the OpenTelemetry API to get ahold of the current span and call `setAttribute`: + +[source,java] +---- +Span.current().setAttribute("foo", "bar"); +---- + +[float] +[[otel-create-transaction-span]] +==== Create a child of the active span + +This is an example for adding a custom span to the span created by the Java agent's auto-instrumentation. + +[source,java] +---- +// if there's an active span, it will implicitly be the parent +// in case there's no parent, the custom span will become a Elastic APM transaction +Span custom = tracer.spanBuilder("my custom span").startSpan(); +// making your child the current one makes the Java agent aware of this span +// if the agent creates spans in the context of myTracedMethod() (such as outgoing requests), +// they'll be added as a child of your custom span +try (Scope scope = custom.makeCurrent()) { + myTracedMethod(); +} catch (Exception e) { + custom.recordException(e); + throw e; +} finally { + custom.end(); +} +---- + +To learn more about the OpenTelemetry API, +head over do https://opentelemetry.io/docs/java/manual_instrumentation/[their documentation]. + +[float] +[[otel-elastic-apm-tags]] +==== Elastic APM specific tags +Elastic APM defines some tags which are not included in the OpenTelemetry API but are relevant in the context of Elastic APM. + +- `type` - sets the type of the transaction/span, + for example `request`, `ext` or `db` +- `subtype` - sets the subtype of the span, + for example `http`, `mysql` or `jsf` +- `action` - sets the action related to a span, + for example `query`, `execute` or `render` +- `user.id` - sets the user id, + appears in the "User" tab in the transaction details in the Elastic APM app +- `user.email` - sets the user email, + appears in the "User" tab in the transaction details in the Elastic APM app +- `user.username` - sets the user name, + appears in the "User" tab in the transaction details in the Elastic APM app +- `result` - sets the result of the transaction. Overrides the default value of `success`. + If the `error` tag is set to `true`, the default value is `error`. + Setting `http.status_code` to `200`, for example, implicitly sets the result to `HTTP 2xx` if not explicitly set otherwise. + +[float] +[[otel-caveats]] +==== Caveats +Not all features of the OpenTelemetry API are supported. + +[float] +[[otel-propagation]] +===== In process context propagation +Entries that are added to the current context, +`Context.current().with(...).makeCurrent()` cannot be retrieved via `Context.current().get(...)`. + +[float] +[[otel-references]] +===== Span References +The `SpanBuilder#addLink` method is currently not supported. +Spans can only have a single parent (`SpanBuilder#setParent`) + +[float] +[[otel-baggage]] +===== Baggage +Propagating baggage within or outside the process is not supported. +Baggage items are silently dropped. + +[float] +[[otel-events]] +===== Events +Events are silently dropped, for example `Span.current().addEvent("my event")`. diff --git a/docs/opentracing.asciidoc b/docs/opentracing.asciidoc index 3220e9a910..7b6c8f8bea 100644 --- a/docs/opentracing.asciidoc +++ b/docs/opentracing.asciidoc @@ -4,11 +4,11 @@ please view this documentation at https://www.elastic.co/guide/en/apm/agent/java endif::[] [[opentracing-bridge]] -== Elastic APM OpenTracing bridge +=== OpenTracing bridge NOTE: Latest supported OpenTracing version: 0.33 (as of agent and OpenTracing-bridge version 1.9.0) -The Elastic APM OpenTracing bridge allows to create Elastic APM `Transactions` and `Spans`, +The Elastic APM OpenTracing bridge allows creating Elastic APM `Transactions` and `Spans`, using the OpenTracing API. In other words, it translates the calls to the OpenTracing API to Elastic APM and thus allows for reusing existing instrumentation. @@ -20,7 +20,7 @@ subsequent spans are mapped to Elastic APM [float] [[operation-modes]] -=== Operation Modes +==== Operation Modes This bridge allows for different operation modes in combination with the Elastic APM `javaagent` @@ -49,7 +49,7 @@ disable the auto instrumentation setting the configuration option <> on how to customize the current transaction. @@ -69,7 +69,7 @@ See <> on how to achieve that. [float] [[api-current-span]] -==== `Span currentSpan()` +===== `Span currentSpan()` Returns the currently active span or transaction. See <> on how to customize the current span. @@ -95,7 +95,7 @@ See <> on how to achieve that. [float] [[api-start-transaction]] -==== `Transaction startTransaction()` +===== `Transaction startTransaction()` Use this method to create a custom transaction. @@ -128,7 +128,7 @@ See <> on how to achieve tha [float] [[api-start-transaction-with-remote-parent-header]] -==== `Transaction startTransactionWithRemoteParent(HeaderExtractor)` added[1.3.0] +===== `Transaction startTransactionWithRemoteParent(HeaderExtractor)` added[1.3.0] Similar to <> but creates this transaction as the child of a remote parent. * `headerExtractor`: a functional interface which receives a header name and returns the first header with that name @@ -159,7 +159,7 @@ NOTE: If the protocol supports multi-value headers, use <> but creates this transaction as the child of a remote parent. @@ -194,7 +194,7 @@ NOTE: If the protocol does not support multi-value headers, use <>, otherwise [float] [[api-capture-transaction]] -==== `@CaptureTransaction` +===== `@CaptureTransaction` Annotating a method with `@CaptureTransaction` creates a transaction for that method. Note that this only works when there is no active transaction on the same thread. @@ -219,7 +219,7 @@ and <> [float] [[api-capture-span]] -==== `@CaptureSpan` +===== `@CaptureSpan` Annotating a method with `@CaptureSpan` creates a span as the child of the currently active span or transaction (<>). @@ -238,7 +238,7 @@ See <>, <>, <> method. [float] [[api-set-name]] -==== `Transaction setName(String name)` +===== `Transaction setName(String name)` Override the name of the current transaction. For supported frameworks, the transaction name is determined automatically, @@ -296,7 +296,7 @@ transaction.setName("My Transaction"); [float] [[api-transaction-set-type]] -==== `Transaction setType(String type)` +===== `Transaction setType(String type)` Sets the type of the transaction. There’s a special type called `request`, which is used by the agent for the transactions automatically created when an incoming HTTP request is detected. @@ -312,7 +312,7 @@ transaction.setType(Transaction.TYPE_REQUEST); [float] [[api-transaction-add-tag]] -==== `Transaction setLabel(String key, value)` added[1.5.0 as `addLabel`,Number and boolean labels require APM Server 6.7] +===== `Transaction setLabel(String key, value)` added[1.5.0 as `addLabel`,Number and boolean labels require APM Server 6.7] Labels are used to add *indexed* information to transactions, spans, and errors. Indexed means the data is searchable and aggregatable in Elasticsearch. Multiple labels can be defined with different key-value pairs. @@ -342,7 +342,7 @@ transaction.setLabel("foo", "bar"); [float] [[api-transaction-add-custom-context]] -==== `Transaction addCustomContext(String key, value)` added[1.7.0] +===== `Transaction addCustomContext(String key, value)` added[1.7.0] Custom context is used to add non-indexed, custom contextual information to transactions. Non-indexed means the data is not searchable or aggregatable in Elasticsearch, @@ -362,7 +362,7 @@ transaction.addCustomContext("foo", "bar"); [float] [[api-transaction-set-user]] -==== `Transaction setUser(String id, String email, String username)` +===== `Transaction setUser(String id, String email, String username)` Call this to enrich collected performance data and errors with information about the user/client. This method can be called at any point during the request/response life cycle (i.e. while a transaction is active). The given context will be added to the active transaction. @@ -382,12 +382,12 @@ transaction.setUser(user.getId(), user.getEmail(), user.getUsername()); [float] [[api-transaction-capture-exception]] -==== `String captureException(Exception e)` +===== `String captureException(Exception e)` Captures an exception and reports it to the APM server. Since version 1.14.0 - returns the id of reported error. [float] [[api-transaction-get-id]] -==== `String getId()` +===== `String getId()` Returns the id of this transaction (never `null`) If this transaction represents a noop, @@ -395,7 +395,7 @@ this method returns an empty string. [float] [[api-transaction-get-trace-id]] -==== `String getTraceId()` +===== `String getTraceId()` Returns the trace-id of this transaction. The trace-id is consistent across all transactions and spans which belong to the same logical trace, @@ -406,7 +406,7 @@ this method returns an empty string. [float] [[api-ensure-parent-id]] -==== `String ensureParentId()` +===== `String ensureParentId()` If the transaction does not have a parent-ID yet, calling this method generates a new ID, sets it as the parent-ID of this transaction, @@ -441,7 +441,7 @@ See the {apm-rum-ref}[JavaScript RUM agent documentation] for more information. [float] [[api-transaction-start-span-with-type]] -==== `Span startSpan(String type, String subtype, String action)` +===== `Span startSpan(String type, String subtype, String action)` Start and return a new span with a type, a subtype and an action, as a child of this transaction. The type, subtype and action strings are used to group similar spans together, with different resolution. @@ -476,7 +476,7 @@ See <> on how to achieve that. [float] [[api-transaction-start-span]] -==== `Span startSpan()` +===== `Span startSpan()` Start and return a new custom span with no type as a child of this transaction. It is important to call <> when the span has ended. @@ -502,7 +502,7 @@ See <> on how to achieve that. [float] [[api-transaction-set-result]] -==== `Transaction setResult(String result)` +===== `Transaction setResult(String result)` A string describing the result of the transaction. This is typically the HTTP status code, or e.g. "success" for a background task @@ -510,14 +510,14 @@ This is typically the HTTP status code, or e.g. "success" for a background task [float] [[api-transaction-set-start-timestamp]] -==== `Transaction setStartTimestamp(long epochMicros)` added[1.5.0] +===== `Transaction setStartTimestamp(long epochMicros)` added[1.5.0] Sets the start timestamp of this event. * `epochMicros`: the timestamp of when this event started, in microseconds (µs) since epoch [float] [[api-transaction-end]] -==== `void end()` +===== `void end()` Ends the transaction and schedules it to be reported to the APM Server. It is illegal to call any methods on a transaction instance which has already ended. This also includes this method and <>. @@ -530,7 +530,7 @@ transaction.end(); [float] [[api-transaction-end-timestamp]] -==== `void end(long epochMicros)` added[1.5.0] +===== `void end(long epochMicros)` added[1.5.0] Ends the transaction and schedules it to be reported to the APM Server. It is illegal to call any methods on a transaction instance which has already ended. This also includes this method and <>. @@ -546,7 +546,7 @@ transaction.end(System.currentTimeMillis() * 1000); [float] [[api-transaction-activate]] -==== `Scope activate()` +===== `Scope activate()` Makes this span the active span on the current thread until `Scope#close()` has been called. Scopes should only be used in try-with-resource statements in order to make sure the `Scope#close()` method is called in all circumstances. @@ -575,12 +575,12 @@ NOTE: <> and `Scope#close()` have to be called on the [float] [[api-transaction-is-sampled]] -==== `boolean isSampled()` +===== `boolean isSampled()` Returns true if this transaction is recorded and sent to the APM Server [float] [[api-transaction-inject-trace-headers]] -==== `void injectTraceHeaders(HeaderInjector headerInjector)` added[1.3.0] +===== `void injectTraceHeaders(HeaderInjector headerInjector)` added[1.3.0] * `headerInjector`: tells the agent how to inject a header into the request object @@ -617,7 +617,7 @@ public Response onOutgoingRequest(Request request) throws Exception { //---------------------------- [float] [[api-span]] -=== Span API +==== Span API //---------------------------- A span contains information about a specific code path, executed as part of a transaction. @@ -630,7 +630,7 @@ See <> on how to get a reference of the current span. [float] [[api-span-set-name]] -==== `Span setName(String name)` +===== `Span setName(String name)` Override the name of the current span. Example: @@ -644,7 +644,7 @@ span.setName("SELECT FROM customer"); [float] [[api-span-add-tag]] -==== `Span setLabel(String key, value)` added[1.5.0 as `addLabel`] +===== `Span setLabel(String key, value)` added[1.5.0 as `addLabel`] A flat mapping of user-defined labels with string, number or boolean values. NOTE: In version 6.x, labels are stored under `context.tags` in Elasticsearch. @@ -666,12 +666,12 @@ span.setLabel("foo", "bar"); [float] [[api-span-capture-exception]] -==== `String captureException(Exception e)` +===== `String captureException(Exception e)` Captures an exception and reports it to the APM server. Since version 1.14.0 - returns the id of reported error. [float] [[api-span-get-id]] -==== `String getId()` +===== `String getId()` Returns the id of this span (never `null`) If this span represents a noop, @@ -679,7 +679,7 @@ this method returns an empty string. [float] [[api-span-get-trace-id]] -==== `String getTraceId()` +===== `String getTraceId()` Returns the trace-ID of this span. The trace-ID is consistent across all transactions and spans which belong to the same logical trace, @@ -690,7 +690,7 @@ this method returns an empty string. [float] [[api-span-set-start-timestamp]] -==== `Span setStartTimestamp(long epochMicros)` added[1.5.0] +===== `Span setStartTimestamp(long epochMicros)` added[1.5.0] Sets the start timestamp of this event. * `epochMicros`: the timestamp of when this event started, in microseconds (µs) since epoch @@ -698,14 +698,14 @@ Sets the start timestamp of this event. [float] [[api-span-end]] -==== `void end()` +===== `void end()` Ends the span and schedules it to be reported to the APM Server. It is illegal to call any methods on a span instance which has already ended. This also includes this method and <>. [float] [[api-span-end-timestamp]] -==== `void end(long epochMicros)` added[1.5.0] +===== `void end(long epochMicros)` added[1.5.0] Ends the span and schedules it to be reported to the APM Server. It is illegal to call any methods on a span instance which has already ended. This also includes this method and <>. @@ -721,7 +721,7 @@ span.end(System.currentTimeMillis() * 1000); [float] [[api-span-start-span-with-type]] -==== `Span startSpan(String type, String subtype, String action)` +===== `Span startSpan(String type, String subtype, String action)` Start and return a new span with a type, a subtype and an action, as a child of this transaction. The type, subtype and action strings are used to group similar spans together, with different resolution. @@ -756,7 +756,7 @@ See <> on how to achieve that. [float] [[api-span-start-span]] -==== `Span startSpan()` +===== `Span startSpan()` Start and return a new custom span with no type as a child of this transaction. It is important to call <> when the span has ended. @@ -782,7 +782,7 @@ See <> on how to achieve that. [float] [[api-span-activate]] -==== `Scope activate()` +===== `Scope activate()` Makes this span the active span on the current thread until `Scope#close()` has been called. Scopes should only be used in try-with-resource statements in order to make sure the `Scope#close()` method is called in all circumstances. @@ -813,12 +813,12 @@ and the <> method. [float] [[api-span-is-sampled]] -==== `boolean isSampled()` +===== `boolean isSampled()` Returns true if this span is recorded and sent to the APM Server [float] [[api-span-inject-trace-headers]] -==== `void injectTraceHeaders(HeaderInjector headerInjector)` added[1.3.0] +===== `void injectTraceHeaders(HeaderInjector headerInjector)` added[1.3.0] * `headerInjector`: tells the agent how to inject a header into the request object From 083d297237f3ae0237ebd8c257fd833b41536504 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 29 Jan 2021 11:06:08 +0100 Subject: [PATCH 20/94] Add changelog --- CHANGELOG.asciidoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index f83f6ce96a..c35f7301b2 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -20,6 +20,19 @@ endif::[] === Unreleased +[[release-notes-1.21.0]] +==== 1.21.0 - YYYY/MM/DD + +[float] +===== Breaking changes + +[float] +===== Features +* OpenTelemetry bridge: <> + +[float] +===== Bug fixes + [[release-notes-1.20.1]] ==== 1.20.1 - YYYY/MM/DD From 5465c38f8f4a066db46742582a212a022f438967 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 29 Jan 2021 11:39:38 +0100 Subject: [PATCH 21/94] Document when OTel bridge has been added --- docs/opentelemetry.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/opentelemetry.asciidoc b/docs/opentelemetry.asciidoc index 28d0f27c6b..5e23e3c7ce 100644 --- a/docs/opentelemetry.asciidoc +++ b/docs/opentelemetry.asciidoc @@ -6,7 +6,7 @@ endif::[] [[opentelementry-bridge]] === OpenTelemetry bridge -NOTE: The OpenTelemetry bridge is currently experimental. +NOTE: Added as experimental in 1.21.0. To enable it, set <> to `true`. The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, From 970e4259fd9e9f29e0b380445800c8a5e96d98c4 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 29 Jan 2021 15:23:11 +0100 Subject: [PATCH 22/94] Update to OTel 0.15.0 and test older versions too Also makes sure that only versions starting with 1.14.0 are instrumented --- .github/dependabot.yml | 1 + .../bci/bytebuddy/CustomElementMatchers.java | 27 +++++++- .../agent/TestClassWithDependencyRunner.java | 21 ++++--- .../apm-opentelemetry-plugin/pom.xml | 17 +++++- .../AbstractOpenTelemetryInstrumentation.java | 53 ++++++++++++++++ .../ContextStorageInstrumentation.java | 20 +----- .../GlobalOpenTelemetryInstrumentation.java | 20 +----- .../sdk/ElasticOpenTelemetryTest.java | 50 +++++++-------- .../apm-opentelemetry-test/pom.xml | 47 ++++++++++++++ .../opentelemetry/OpenTelemetryVersionIT.java | 61 +++++++++++++++++++ apm-agent-plugins/pom.xml | 1 + 11 files changed, 249 insertions(+), 69 deletions(-) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java create mode 100644 apm-agent-plugins/apm-opentelemetry-test/pom.xml create mode 100644 apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5553f5c0c7..d15abc06f9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -27,3 +27,4 @@ updates: - dependency-name: "net.bytebuddy:*" - dependency-name: "org.ow2.asm:asm-tree" - dependency-name: "com.blogspot.mydailyjava:weak-lock-free" + - dependency-name: "io.opentelemetry:opentelemetry-api" diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/bytebuddy/CustomElementMatchers.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/bytebuddy/CustomElementMatchers.java index d3b691ead1..6358ec1965 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/bytebuddy/CustomElementMatchers.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/bytebuddy/CustomElementMatchers.java @@ -125,6 +125,14 @@ private static boolean canLoadClass(@Nullable ClassLoader target, String classNa * @return an LTE SemVer matcher */ public static ElementMatcher.Junction implementationVersionLte(final String version) { + return implementationVersion(version, Matcher.LTE); + } + + public static ElementMatcher.Junction implementationVersionGte(final String version) { + return implementationVersion(version, Matcher.GTE); + } + + private static ElementMatcher.Junction implementationVersion(final String version, final Matcher matcher) { return new ElementMatcher.Junction.AbstractBase() { /** * Returns true if the implementation version read from the manifest file referenced by the given @@ -141,7 +149,7 @@ public boolean matches(@Nullable ProtectionDomain protectionDomain) { Version pdVersion = readImplementationVersionFromManifest(protectionDomain); Version limitVersion = Version.of(version); if (pdVersion != null) { - return pdVersion.compareTo(limitVersion) <= 0; + return matcher.match(pdVersion, limitVersion); } } catch (Exception e) { logger.info("Cannot read implementation version based on ProtectionDomain. This should not affect " + @@ -153,6 +161,23 @@ public boolean matches(@Nullable ProtectionDomain protectionDomain) { }; } + private enum Matcher { + LTE { + @Override + > boolean match(T c1, T c2) { + return c1.compareTo(c2) <= 0; + } + }, + GTE { + @Override + > boolean match(T c1, T c2) { + return c1.compareTo(c2) >= 0; + + } + }; + abstract > boolean match(T c1, T c2); + } + @Nullable private static Version readImplementationVersionFromManifest(@Nullable ProtectionDomain protectionDomain) throws IOException, URISyntaxException { Version version = null; diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/TestClassWithDependencyRunner.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/TestClassWithDependencyRunner.java index c374c46a5f..80e4cf5c27 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/TestClassWithDependencyRunner.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/TestClassWithDependencyRunner.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -74,14 +74,18 @@ public TestClassWithDependencyRunner(String groupId, String artifactId, String v } public TestClassWithDependencyRunner(List dependencies, Class testClass, Class... classesReferencingDependency) throws Exception { + this(dependencies, testClass.getName(), Arrays.stream(classesReferencingDependency).map(Class::getName).toArray(String[]::new)); + } + + public TestClassWithDependencyRunner(List dependencies, String testClass, String... classesReferencingDependency) throws Exception { List urls = resolveArtifacts(dependencies); - List> classesToExport = new ArrayList<>(); + List classesToExport = new ArrayList<>(); classesToExport.add(testClass); classesToExport.addAll(Arrays.asList(classesReferencingDependency)); urls.add(exportToTempJarFile(classesToExport)); URLClassLoader testClassLoader = new ChildFirstURLClassLoader(urls); - testRunner = new BlockJUnit4ClassRunner(testClassLoader.loadClass(testClass.getName())); + testRunner = new BlockJUnit4ClassRunner(testClassLoader.loadClass(testClass)); classLoader = new WeakReference<>(testClassLoader); } @@ -105,14 +109,15 @@ public void assertClassLoaderIsGCed() { assertThat(classLoader.get()).isNull(); } - private static URL exportToTempJarFile(List> classes) throws IOException { + private static URL exportToTempJarFile(List classes) throws IOException { File tempTestJar = File.createTempFile("temp-test", ".jar"); tempTestJar.deleteOnExit(); try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(tempTestJar))) { - for (Class clazz : classes) { - InputStream inputStream = clazz.getResourceAsStream('/' + clazz.getName().replace('.', '/') + ".class"); + for (String clazz : classes) { + String resourceName = clazz.replace('.', '/') + ".class"; + InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourceName); try (inputStream) { - jarOutputStream.putNextEntry(new JarEntry(clazz.getName().replace('.', '/') + ".class")); + jarOutputStream.putNextEntry(new JarEntry(resourceName)); byte[] buffer = new byte[1024]; int index; while ((index = inputStream.read(buffer)) != -1) { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index f90323f92b..f2e2852fab 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -25,7 +25,7 @@ io.opentelemetry opentelemetry-api - 0.14.1 + 0.15.0 provided @@ -39,4 +39,19 @@ ${project.version} + + + + + maven-jar-plugin + + + + test-jar + + + + + + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java new file mode 100644 index 0000000000..ba76d1da8c --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java @@ -0,0 +1,53 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ +package co.elastic.apm.agent.opentelemetry; + +import co.elastic.apm.agent.bci.TracerAwareInstrumentation; +import net.bytebuddy.matcher.ElementMatcher; + +import java.security.ProtectionDomain; +import java.util.Arrays; +import java.util.Collection; + +import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.implementationVersionGte; + +public abstract class AbstractOpenTelemetryInstrumentation extends TracerAwareInstrumentation { + + @Override + public final ElementMatcher.Junction getProtectionDomainPostFilter() { + return implementationVersionGte("0.14.0"); + } + + @Override + public final boolean includeWhenInstrumentationIsDisabled() { + return true; + } + + + @Override + public final Collection getInstrumentationGroupNames() { + return Arrays.asList("opentelemetry", "experimental"); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index ded049e53a..e0add1a314 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,7 +24,6 @@ */ package co.elastic.apm.agent.opentelemetry; -import co.elastic.apm.agent.bci.TracerAwareInstrumentation; import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.context.ElasticOTelContextStorage; import co.elastic.apm.agent.sdk.advice.AssignTo; @@ -34,13 +33,10 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -import java.util.Arrays; -import java.util.Collection; - import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; -public class ContextStorageInstrumentation extends TracerAwareInstrumentation { +public class ContextStorageInstrumentation extends AbstractOpenTelemetryInstrumentation { @Override public ElementMatcher getTypeMatcher() { @@ -52,16 +48,6 @@ public ElementMatcher getMethodMatcher() { return named("get").and(returns(named("io.opentelemetry.context.ContextStorage"))); } - @Override - public Collection getInstrumentationGroupNames() { - return Arrays.asList("opentelemetry", "experimental"); - } - - @Override - public boolean includeWhenInstrumentationIsDisabled() { - return true; - } - @Override public Class getAdviceClass() { return ContextStorageAdvice.class; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index d24eb6b4dc..0c62efdf37 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,7 +24,6 @@ */ package co.elastic.apm.agent.opentelemetry; -import co.elastic.apm.agent.bci.TracerAwareInstrumentation; import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracer; import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracerProvider; @@ -38,12 +37,9 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -import java.util.Arrays; -import java.util.Collection; - import static net.bytebuddy.matcher.ElementMatchers.named; -public class GlobalOpenTelemetryInstrumentation extends TracerAwareInstrumentation { +public class GlobalOpenTelemetryInstrumentation extends AbstractOpenTelemetryInstrumentation { @Override public ElementMatcher getTypeMatcher() { @@ -55,16 +51,6 @@ public ElementMatcher getMethodMatcher() { return named("get"); } - @Override - public Collection getInstrumentationGroupNames() { - return Arrays.asList("opentelemetry", "experimental"); - } - - @Override - public boolean includeWhenInstrumentationIsDisabled() { - return true; - } - @Override public Class getAdviceClass() { return GlobalOpenTelemetryAdvice.class; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 56d7469d6e..29ba52fea9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -36,9 +36,9 @@ import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; import javax.annotation.Nullable; import java.util.HashMap; @@ -47,13 +47,13 @@ import static org.assertj.core.api.Assertions.assertThat; -class ElasticOpenTelemetryTest extends AbstractInstrumentationTest { +public class ElasticOpenTelemetryTest extends AbstractInstrumentationTest { private OpenTelemetry openTelemetry; private Tracer otelTracer; - @BeforeEach - void setUp() { + @Before + public void setUp() { this.openTelemetry = GlobalOpenTelemetry.get(); assertThat(openTelemetry).isSameAs(GlobalOpenTelemetry.get()); otelTracer = openTelemetry.getTracer(null); @@ -61,7 +61,7 @@ void setUp() { } @Test - void testTransaction() { + public void testTransaction() { otelTracer.spanBuilder("transaction") .startSpan() .end(); @@ -70,7 +70,7 @@ void testTransaction() { } @Test - void testTransactionWithAttribute() { + public void testTransactionWithAttribute() { otelTracer.spanBuilder("transaction") .setAttribute("boolean", true) .setAttribute("long", 42L) @@ -86,7 +86,7 @@ void testTransactionWithAttribute() { } @Test - void testTransactionWithSpanManualPropagation() { + public void testTransactionWithSpanManualPropagation() { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); otelTracer.spanBuilder("span") @@ -103,7 +103,7 @@ void testTransactionWithSpanManualPropagation() { } @Test - void testTransactionWithSpanContextStorePropagation() { + public void testTransactionWithSpanContextStorePropagation() { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); try (Scope scope = transaction.makeCurrent()) { @@ -122,7 +122,7 @@ void testTransactionWithSpanContextStorePropagation() { } @Test - void testStartChildAfterEnd() { + public void testStartChildAfterEnd() { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); transaction.end(); @@ -145,8 +145,8 @@ void testStartChildAfterEnd() { * @see ElasticOTelContextStorage#current() */ @Test - @Disabled - void testPropagateCustomContextKey() { + @Ignore + public void testPropagateCustomContextKey() { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); Context context = Context.current() @@ -166,7 +166,7 @@ void testPropagateCustomContextKey() { } @Test - void testTransactionWithRemoteParent() { + public void testTransactionWithRemoteParent() { Context context = openTelemetry.getPropagators() .getTextMapPropagator() .extract(Context.current(), @@ -183,7 +183,7 @@ void testTransactionWithRemoteParent() { } @Test - void testTransactionInject() { + public void testTransactionInject() { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); HashMap otelHeaders = new HashMap<>(); @@ -198,7 +198,7 @@ void testTransactionInject() { } @Test - void testTransactionSemanticConventionMappingHttpHost() { + public void testTransactionSemanticConventionMappingHttpHost() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") @@ -218,7 +218,7 @@ void testTransactionSemanticConventionMappingHttpHost() { } @Test - void testTransactionSemanticConventionMappingHttpNetHostName() { + public void testTransactionSemanticConventionMappingHttpNetHostName() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") @@ -242,7 +242,7 @@ void testTransactionSemanticConventionMappingHttpNetHostName() { } @Test - void testTransactionSemanticConventionMappingHttpNetHostIP() { + public void testTransactionSemanticConventionMappingHttpNetHostIP() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") @@ -266,7 +266,7 @@ void testTransactionSemanticConventionMappingHttpNetHostIP() { } @Test - void testTransactionSemanticConventionMappingHttpUrl() { + public void testTransactionSemanticConventionMappingHttpUrl() { otelTracer.spanBuilder("transaction") .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") @@ -287,12 +287,12 @@ void testTransactionSemanticConventionMappingHttpUrl() { } @Test - void testSpanSemanticConventionMappingHttpUrl() { + public void testSpanSemanticConventionMappingHttpUrl() { testSpanSemanticConventionMappingHttpHelper(span -> span.setAttribute(SemanticAttributes.HTTP_URL, "http://example.com/foo?bar")); } @Test - void testSpanSemanticConventionMappingHttpHost() { + public void testSpanSemanticConventionMappingHttpHost() { testSpanSemanticConventionMappingHttpHelper(span -> { span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); span.setAttribute(SemanticAttributes.HTTP_HOST, "example.com"); @@ -301,7 +301,7 @@ void testSpanSemanticConventionMappingHttpHost() { } @Test - void testSpanSemanticConventionMappingHttpPeerName() { + public void testSpanSemanticConventionMappingHttpPeerName() { testSpanSemanticConventionMappingHttpHelper(span -> { span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); span.setAttribute(SemanticAttributes.NET_PEER_IP, "192.0.2.5"); @@ -312,7 +312,7 @@ void testSpanSemanticConventionMappingHttpPeerName() { } @Test - void testSpanSemanticConventionMappingHttpPeerIp() { + public void testSpanSemanticConventionMappingHttpPeerIp() { testSpanSemanticConventionMappingHttpHelper(span -> { span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); span.setAttribute(SemanticAttributes.NET_PEER_IP, "example.com"); @@ -321,7 +321,7 @@ void testSpanSemanticConventionMappingHttpPeerIp() { }); } - void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { + public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); try (Scope scope = transaction.makeCurrent()) { @@ -344,7 +344,7 @@ void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { reporter.resetWithoutRecycling(); } - private static class MapGetter implements TextMapPropagator.Getter> { + public static class MapGetter implements TextMapPropagator.Getter> { @Override public Iterable keys(Map carrier) { return carrier.keySet(); diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry-test/pom.xml new file mode 100644 index 0000000000..fa8a80d912 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-test/pom.xml @@ -0,0 +1,47 @@ + + + + apm-agent-plugins + co.elastic.apm + 1.20.1-SNAPSHOT + + 4.0.0 + + ${project.groupId}:${project.artifactId} + apm-opentelemetry-test + + + ${project.basedir}/../.. + + + + + ${project.groupId} + apm-opentelemetry-plugin + test-jar + ${project.version} + test + + + io.opentelemetry + * + + + + + ${project.groupId} + apm-opentelemetry-plugin + ${project.version} + test + + + io.opentelemetry + * + + + + + + diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java new file mode 100644 index 0000000000..75e79c5d42 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -0,0 +1,61 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2021 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ +package co.elastic.apm.opentelemetry; + +import co.elastic.apm.agent.TestClassWithDependencyRunner; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.List; + +@RunWith(Parameterized.class) +public class OpenTelemetryVersionIT { + private final TestClassWithDependencyRunner runner; + + public OpenTelemetryVersionIT(String version) throws Exception { + List dependencies = List.of( + "io.opentelemetry:opentelemetry-api:" + version, + "io.opentelemetry:opentelemetry-context:" + version, + "io.opentelemetry:opentelemetry-semconv:0.14.1"); + runner = new TestClassWithDependencyRunner(dependencies, + "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest", + "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest$MapGetter"); + } + + @Parameterized.Parameters(name= "{0}") + public static Iterable data() { + return Arrays.asList(new Object[][]{ + {"0.15.0"}, + {"0.14.1"}, + }); + } + + @Test + public void testVersions() throws Exception { + runner.run(); + } +} diff --git a/apm-agent-plugins/pom.xml b/apm-agent-plugins/pom.xml index e94c4d85ad..7ce8408e7f 100644 --- a/apm-agent-plugins/pom.xml +++ b/apm-agent-plugins/pom.xml @@ -56,6 +56,7 @@ apm-jdk-httpclient-plugin apm-rabbitmq apm-opentelemetry-plugin + apm-opentelemetry-test From 233179d9418f1299450c7b0ce1a2b92053a9fe61 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Wed, 3 Feb 2021 11:38:58 +0100 Subject: [PATCH 23/94] Implement review suggestions --- CHANGELOG.asciidoc | 2 +- .../elastic/apm/agent/impl/context/Destination.java | 2 +- .../java/co/elastic/apm/agent/impl/context/Http.java | 4 ++-- .../apm/agent/report/serialize/DslJsonSerializer.java | 2 +- .../AbstractEsClientInstrumentationTest.java | 2 +- .../apm/agent/http/client/HttpClientHelperTest.java | 10 +++++----- .../AbstractHttpClientInstrumentationTest.java | 11 +++++------ .../apm/agent/opentelemetry/sdk/ElasticOTelSpan.java | 8 ++++---- .../opentelemetry/sdk/ElasticOpenTelemetryTest.java | 2 +- .../resttemplate/SprintRestTemplateIntegration.java | 2 +- docs/opentelemetry.asciidoc | 4 ++-- docs/opentracing.asciidoc | 4 ++-- 12 files changed, 26 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index e1ff513b93..ea87ec078e 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -28,7 +28,7 @@ endif::[] https://github.com/elastic/apm/blob/master/specs/agents/metadata.md#cloud-provider-metadata[spec] for details. By default, the agent will try to automatically detect the cloud provider on startup, but this can be configured through the <> config option - {pull}1599[#1599] -* OpenTelemetry bridge: <> +* OpenTelemetry bridge (experimental): <> [float] ===== Bug fixes diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java index 38a6db353c..8cc6b5fd48 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Destination.java @@ -193,7 +193,7 @@ public StringBuilder getName() { return name; } - public Service withType(@Nullable String type) { + public Service withType(String type) { this.type = type; return this; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java index c72da48432..8a6e779900 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Http.java @@ -52,11 +52,11 @@ public class Http implements Recyclable { * URL used for the outgoing HTTP call */ @Nullable - public String getUrl() { + public String getFullUrl() { return url.getFull().toString(); } - public Url getUrlObject() { + public Url getUrl() { return url; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java index 9ffa41098f..37d32786f1 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java @@ -960,7 +960,7 @@ private void serializeHttpContext(final Http http) { if (statusCode > 0) { writeField("status_code", http.getStatusCode()); } - writeLastField("url", http.getUrlObject().getFull()); + writeLastField("url", http.getUrl().getFull()); jw.writeByte(OBJECT_END); jw.writeByte(COMMA); } diff --git a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/src/test/java/co/elastic/apm/agent/es/restclient/AbstractEsClientInstrumentationTest.java b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/src/test/java/co/elastic/apm/agent/es/restclient/AbstractEsClientInstrumentationTest.java index c5df95e0d4..99a888c532 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/src/test/java/co/elastic/apm/agent/es/restclient/AbstractEsClientInstrumentationTest.java +++ b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/src/test/java/co/elastic/apm/agent/es/restclient/AbstractEsClientInstrumentationTest.java @@ -130,7 +130,7 @@ private void validateHttpContextContent(Http http, int statusCode, String method assertThat(http).isNotNull(); assertThat(http.getMethod()).isEqualTo(method); assertThat(http.getStatusCode()).isEqualTo(statusCode); - assertThat(http.getUrl()).isEqualTo("http://" + container.getHttpHostAddress()); + assertThat(http.getFullUrl()).isEqualTo("http://" + container.getHttpHostAddress()); } protected void validateSpanContentAfterIndexCreateRequest() { diff --git a/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/http/client/HttpClientHelperTest.java b/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/http/client/HttpClientHelperTest.java index 9ad5b9827b..aef9e349f3 100644 --- a/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/http/client/HttpClientHelperTest.java +++ b/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/http/client/HttpClientHelperTest.java @@ -59,7 +59,7 @@ void testNonDefaultPort() throws URISyntaxException { .end(); assertThat(reporter.getSpans()).hasSize(1); Span httpSpan = reporter.getFirstSpan(); - assertThat(httpSpan.getContext().getHttp().getUrl()).isEqualTo("http://testing.local:1234/path?query"); + assertThat(httpSpan.getContext().getHttp().getFullUrl()).isEqualTo("http://testing.local:1234/path?query"); Destination destination = httpSpan.getContext().getDestination(); assertThat(destination.getService().getName().toString()).isEqualTo("http://testing.local:1234"); assertThat(destination.getService().getResource().toString()).isEqualTo("testing.local:1234"); @@ -74,7 +74,7 @@ void testDefaultExplicitPort() throws URISyntaxException { .end(); assertThat(reporter.getSpans()).hasSize(1); Span httpSpan = reporter.getFirstSpan(); - assertThat(httpSpan.getContext().getHttp().getUrl()).isEqualTo("https://www.elastic.co:443/products/apm"); + assertThat(httpSpan.getContext().getHttp().getFullUrl()).isEqualTo("https://www.elastic.co:443/products/apm"); Destination destination = httpSpan.getContext().getDestination(); assertThat(destination.getService().getName().toString()).isEqualTo("https://www.elastic.co"); assertThat(destination.getService().getResource().toString()).isEqualTo("www.elastic.co:443"); @@ -89,7 +89,7 @@ void testDefaultImplicitPort() throws URISyntaxException { .end(); assertThat(reporter.getSpans()).hasSize(1); Span httpSpan = reporter.getFirstSpan(); - assertThat(httpSpan.getContext().getHttp().getUrl()).isEqualTo("https://www.elastic.co/products/apm"); + assertThat(httpSpan.getContext().getHttp().getFullUrl()).isEqualTo("https://www.elastic.co/products/apm"); Destination destination = httpSpan.getContext().getDestination(); assertThat(destination.getService().getName().toString()).isEqualTo("https://www.elastic.co"); assertThat(destination.getService().getResource().toString()).isEqualTo("www.elastic.co:443"); @@ -104,7 +104,7 @@ void testDefaultImplicitPortWithIpv4() throws URISyntaxException { .end(); assertThat(reporter.getSpans()).hasSize(1); Span httpSpan = reporter.getFirstSpan(); - assertThat(httpSpan.getContext().getHttp().getUrl()).isEqualTo("https://151.101.114.217/index.html"); + assertThat(httpSpan.getContext().getHttp().getFullUrl()).isEqualTo("https://151.101.114.217/index.html"); Destination destination = httpSpan.getContext().getDestination(); assertThat(destination.getService().getName().toString()).isEqualTo("https://151.101.114.217"); assertThat(destination.getService().getResource().toString()).isEqualTo("151.101.114.217:443"); @@ -119,7 +119,7 @@ void testDefaultImplicitPortWithIpv6() throws URISyntaxException { .end(); assertThat(reporter.getSpans()).hasSize(1); Span httpSpan = reporter.getFirstSpan(); - assertThat(httpSpan.getContext().getHttp().getUrl()).isEqualTo("http://[2001:db8:a0b:12f0::1]/index.html"); + assertThat(httpSpan.getContext().getHttp().getFullUrl()).isEqualTo("http://[2001:db8:a0b:12f0::1]/index.html"); Destination destination = httpSpan.getContext().getDestination(); assertThat(destination.getService().getName().toString()).isEqualTo("http://[2001:db8:a0b:12f0::1]"); assertThat(destination.getService().getResource().toString()).isEqualTo("[2001:db8:a0b:12f0::1]:80"); diff --git a/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/httpclient/AbstractHttpClientInstrumentationTest.java b/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/httpclient/AbstractHttpClientInstrumentationTest.java index 9157fc7b3d..c24408fe83 100644 --- a/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/httpclient/AbstractHttpClientInstrumentationTest.java +++ b/apm-agent-plugins/apm-httpclient-core/src/test/java/co/elastic/apm/agent/httpclient/AbstractHttpClientInstrumentationTest.java @@ -51,7 +51,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.any; import static com.github.tomakehurst.wiremock.client.WireMock.anyRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.seeOther; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; @@ -137,7 +136,7 @@ protected void verifyHttpSpan(String scheme, String host, int port, String path) assertThat(reporter.getSpans()).hasSize(1); Span span = reporter.getSpans().get(0); String baseUrl = scheme + "://" + host + ":" + port; - assertThat(span.getContext().getHttp().getUrl()).isEqualTo(baseUrl + path); + assertThat(span.getContext().getHttp().getFullUrl()).isEqualTo(baseUrl + path); assertThat(span.getContext().getHttp().getStatusCode()).isEqualTo(200); assertThat(span.getType()).isEqualTo("external"); assertThat(span.getSubtype()).isEqualTo("http"); @@ -172,7 +171,7 @@ public void testNonExistingHttpCall() { assertThat(reporter.getFirstSpan(500)).isNotNull(); assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getSpans().get(0).getContext().getHttp().getUrl()).isEqualTo(getBaseUrl() + path); + assertThat(reporter.getSpans().get(0).getContext().getHttp().getFullUrl()).isEqualTo(getBaseUrl() + path); assertThat(reporter.getSpans().get(0).getContext().getHttp().getStatusCode()).isEqualTo(404); } @@ -183,7 +182,7 @@ public void testErrorHttpCall() { assertThat(reporter.getFirstSpan(500)).isNotNull(); assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getSpans().get(0).getContext().getHttp().getUrl()).isEqualTo(getBaseUrl() + path); + assertThat(reporter.getSpans().get(0).getContext().getHttp().getFullUrl()).isEqualTo(getBaseUrl() + path); assertThat(reporter.getSpans().get(0).getContext().getHttp().getStatusCode()).isEqualTo(515); } @@ -194,7 +193,7 @@ public void testHttpCallRedirect() { assertThat(reporter.getFirstSpan(500)).isNotNull(); assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getSpans().get(0).getContext().getHttp().getUrl()).isEqualTo(getBaseUrl() + path); + assertThat(reporter.getSpans().get(0).getContext().getHttp().getFullUrl()).isEqualTo(getBaseUrl() + path); assertThat(reporter.getSpans().get(0).getContext().getHttp().getStatusCode()).isEqualTo(200); verifyTraceContextHeaders(reporter.getFirstSpan(), "/redirect"); @@ -215,7 +214,7 @@ public void testHttpCallCircularRedirect() { assertThat(reporter.getErrors()).hasSize(1); assertThat(reporter.getFirstError().getException()).isNotNull(); assertThat(reporter.getFirstError().getException().getClass()).isNotNull(); - assertThat(reporter.getSpans().get(0).getContext().getHttp().getUrl()).isEqualTo(getBaseUrl() + path); + assertThat(reporter.getSpans().get(0).getContext().getHttp().getFullUrl()).isEqualTo(getBaseUrl() + path); verifyTraceContextHeaders(reporter.getFirstSpan(), "/circular-redirect"); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index 40b57af05b..b1f7443c27 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -192,7 +192,7 @@ private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, Att co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); // http.* - if (mapHttpUrlAttributes(key, value, context.getHttp().getUrlObject())) { + if (mapHttpUrlAttributes(key, value, context.getHttp().getUrl())) { // successfully mapped inside mapHttpUrlAttributes } else if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { context.getHttp().withStatusCode(((Number) value).intValue()); @@ -228,7 +228,7 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { Destination destination = context.getDestination(); if (context.getHttp().hasContent()) { s.withType("external").withSubtype("http"); - Url url = context.getHttp().getUrlObject(); + Url url = context.getHttp().getUrl(); if (context.getDestination().getAddress().length() > 0) { url.withHostname(context.getDestination().getAddress().toString()); } @@ -253,12 +253,12 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { .getService() .withName(s.getSubtype()) .withResource(s.getSubtype()) - .withType(s.getType()); + .withType("db"); } } else { s.withType("app"); if (destination.getService().hasContent()) { - destination.getService().withType(s.getType()); + destination.getService().withType("app"); } } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 29ba52fea9..7b280ba26d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -336,7 +336,7 @@ public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsu assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getSpans()).hasSize(1); assertThat(reporter.getFirstSpan().getContext().getDestination().getPort()).isEqualTo(80); - assertThat(reporter.getFirstSpan().getContext().getHttp().getUrl()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); + assertThat(reporter.getFirstSpan().getContext().getHttp().getFullUrl()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); assertThat(reporter.getFirstSpan().getContext().getDestination().getAddress().toString()).isEqualTo("example.com"); assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getName().toString()).isEqualTo("http://example.com"); assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getResource().toString()).isEqualTo("example.com:80"); diff --git a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/src/test/java/co/elastic/apm/agent/resttemplate/SprintRestTemplateIntegration.java b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/src/test/java/co/elastic/apm/agent/resttemplate/SprintRestTemplateIntegration.java index 17011391bb..e587656133 100644 --- a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/src/test/java/co/elastic/apm/agent/resttemplate/SprintRestTemplateIntegration.java +++ b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/src/test/java/co/elastic/apm/agent/resttemplate/SprintRestTemplateIntegration.java @@ -92,7 +92,7 @@ public void getRoot() { Span span = reporter.getFirstSpan(); Http http = span.getContext().getHttp(); assertThat(http.getMethod()).isEqualTo("GET"); - assertThat(http.getUrl()).isEqualTo(url); + assertThat(http.getFullUrl()).isEqualTo(url); } } } diff --git a/docs/opentelemetry.asciidoc b/docs/opentelemetry.asciidoc index 5e23e3c7ce..e0e4094b99 100644 --- a/docs/opentelemetry.asciidoc +++ b/docs/opentelemetry.asciidoc @@ -23,12 +23,12 @@ subsequent spans are mapped to Elastic APM [[otel-operation-modes]] ==== Operation Modes -This bridge allows for different operation modes in combination with the Elastic APM `javaagent` +This bridge allows for different operation modes in combination with the Elastic APM agent Noop:: + -- -If the `javaagent` is not specified, the bridge is in noop mode and does not actually record and report spans. +If the agent is not installed, the bridge is in noop mode and does not actually record and report spans. -- Mix and Match:: diff --git a/docs/opentracing.asciidoc b/docs/opentracing.asciidoc index 7b6c8f8bea..ad4ad1d47a 100644 --- a/docs/opentracing.asciidoc +++ b/docs/opentracing.asciidoc @@ -22,12 +22,12 @@ subsequent spans are mapped to Elastic APM [[operation-modes]] ==== Operation Modes -This bridge allows for different operation modes in combination with the Elastic APM `javaagent` +This bridge allows for different operation modes in combination with the Elastic APM agent Noop:: + -- -If the `javaagent` is not specified, the bridge is in noop mode and does not actually record and report spans. +If the agent is not installed, the bridge is in noop mode and does not actually record and report spans. -- Mix and Match:: From a85d5f4d74aff854b38aeef5297d13b9ac793438 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 5 Feb 2021 11:52:17 +0100 Subject: [PATCH 24/94] Bubble up operation modes to apis.asciidoc --- ...blic-api.asciidoc => api-elastic.asciidoc} | 0 ...ry.asciidoc => api-opentelemetry.asciidoc} | 41 ++++------------- ...cing.asciidoc => api-opentracing.asciidoc} | 45 ++++--------------- docs/apis.asciidoc | 39 +++++++++++++--- 4 files changed, 51 insertions(+), 74 deletions(-) rename docs/{public-api.asciidoc => api-elastic.asciidoc} (100%) rename docs/{opentelemetry.asciidoc => api-opentelemetry.asciidoc} (82%) rename docs/{opentracing.asciidoc => api-opentracing.asciidoc} (77%) diff --git a/docs/public-api.asciidoc b/docs/api-elastic.asciidoc similarity index 100% rename from docs/public-api.asciidoc rename to docs/api-elastic.asciidoc diff --git a/docs/opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc similarity index 82% rename from docs/opentelemetry.asciidoc rename to docs/api-opentelemetry.asciidoc index e0e4094b99..14ceeb39c2 100644 --- a/docs/opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -19,35 +19,6 @@ The first span of a service will be converted to an Elastic APM subsequent spans are mapped to Elastic APM {apm-overview-ref-v}/transaction-spans.html[`Span`]. -[float] -[[otel-operation-modes]] -==== Operation Modes - -This bridge allows for different operation modes in combination with the Elastic APM agent - -Noop:: -+ --- -If the agent is not installed, the bridge is in noop mode and does not actually record and report spans. --- - -Mix and Match:: -+ --- -If you want to leverage the auto instrumentation of Elastic APM, -but also want to create custom spans or use the OpenTelemetry API to add custom tags to the spans created by Elastic APM, -you can just do that. -The OpenTelemetry bridge and the standard Elastic APM API interact seamlessly. --- - -Manual instrumentation:: -+ --- -If you don't want Elastic APM to auto-instrument known frameworks, -but instead only rely on manual instrumentation, -disable the auto instrumentation setting the configuration option <> to `false`. --- - [float] [[otel-getting-started]] ==== Getting started @@ -69,6 +40,8 @@ The first step in getting started with the OpenTelemetry API bridge is to declar compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" ---- +The minimum required OpenTelemetry version is 0.14.1. + [float] [[otel-init-tracer]] ==== Initialize tracer @@ -132,10 +105,13 @@ try (Scope scope = custom.makeCurrent()) { To learn more about the OpenTelemetry API, head over do https://opentelemetry.io/docs/java/manual_instrumentation/[their documentation]. + +//// +TODO implement Elastic APM specific attributes [float] -[[otel-elastic-apm-tags]] -==== Elastic APM specific tags -Elastic APM defines some tags which are not included in the OpenTelemetry API but are relevant in the context of Elastic APM. +[[otel-elastic-apm-attributes]] +==== Elastic APM specific attributes +Elastic APM defines some attributes which are not included in OpenTelemetry's semantic conventionsAPI but are relevant in the context of Elastic APM. - `type` - sets the type of the transaction/span, for example `request`, `ext` or `db` @@ -152,6 +128,7 @@ Elastic APM defines some tags which are not included in the OpenTelemetry API bu - `result` - sets the result of the transaction. Overrides the default value of `success`. If the `error` tag is set to `true`, the default value is `error`. Setting `http.status_code` to `200`, for example, implicitly sets the result to `HTTP 2xx` if not explicitly set otherwise. +//// [float] [[otel-caveats]] diff --git a/docs/opentracing.asciidoc b/docs/api-opentracing.asciidoc similarity index 77% rename from docs/opentracing.asciidoc rename to docs/api-opentracing.asciidoc index ad4ad1d47a..49f38f8959 100644 --- a/docs/opentracing.asciidoc +++ b/docs/api-opentracing.asciidoc @@ -6,7 +6,8 @@ endif::[] [[opentracing-bridge]] === OpenTracing bridge -NOTE: Latest supported OpenTracing version: 0.33 (as of agent and OpenTracing-bridge version 1.9.0) +NOTE: OpenTracing is discontinued in favor of OpenTelemetry. Consider using the <> instead. + +Latest supported OpenTracing version: 0.33 (as of agent and OpenTracing-bridge version 1.9.0) The Elastic APM OpenTracing bridge allows creating Elastic APM `Transactions` and `Spans`, using the OpenTracing API. @@ -18,37 +19,9 @@ The first span of a service will be converted to an Elastic APM subsequent spans are mapped to Elastic APM {apm-overview-ref-v}/transaction-spans.html[`Span`]. -[float] -[[operation-modes]] -==== Operation Modes - -This bridge allows for different operation modes in combination with the Elastic APM agent - -Noop:: -+ --- -If the agent is not installed, the bridge is in noop mode and does not actually record and report spans. --- - -Mix and Match:: -+ --- -If you want to leverage the auto instrumentation of Elastic APM, -but also want do create custom spans or use the OpenTracing API to add custom tags to the spans created by Elastic APM, -you can just do that. -The OpenTracing bridge and the standard Elastic APM API interact seamlessly. --- - -Manual instrumentation:: -+ --- -If you don't want Elastic APM to auto-instrument known frameworks, -but instead only rely on manual instrumentation, -disable the auto instrumentation setting the configuration option <> to `false`. --- [float] -[[getting-started]] +[[opentracing-getting-started]] ==== Getting started The first step in getting started with the OpenTracing API bridge is to declare a dependency to the API: @@ -88,7 +61,7 @@ Tracer tracer = new ElasticApmTracer(); [float] -[[elastic-apm-tags]] +[[opentracing-elastic-apm-tags]] ==== Elastic APM specific tags Elastic APM defines some tags which are not included in the OpenTracing API but are relevant in the context of Elastic APM. @@ -110,31 +83,31 @@ Elastic APM defines some tags which are not included in the OpenTracing API but Setting `http.status_code` to `200`, for example, implicitly sets the result to `HTTP 2xx` if not explicitly set otherwise. [float] -[[unsupported]] +[[opentracing-unsupported]] ==== Caveats Not all features of the OpenTracing API are supported. [float] -[[propagation]] +[[opentracing-propagation]] ===== Context propagation This bridge only supports the formats `Format.Builtin.TEXT_MAP` and `Format.Builtin.HTTP_HEADERS`. `Format.Builtin.BINARY` is currently not supported. [float] -[[references]] +[[opentracing-references]] ===== Span References Currently, this bridge only supports `child_of` references. Other references, like `follows_from` are not supported yet. [float] -[[baggage]] +[[opentracing-baggage]] ===== Baggage The `Span.setBaggageItem(String, String)` method is not supported. Baggage items are silently dropped. [float] -[[logs]] +[[opentracing-logs]] ===== Logs Only exception logging is supported. Logging an Exception on the OpenTracing span will create an Elastic APM diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc index 8ec329af1c..137b556886 100644 --- a/docs/apis.asciidoc +++ b/docs/apis.asciidoc @@ -13,13 +13,40 @@ There are three different ways enhance the out-of-the-box instrumentation of the Contains annotations to declaratively create spans. . <> + A vendor neutral API. - If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. - Be aware that the API of 0.x versions is not stable. - In this version, breaking changes are frequently introduced which means you may have to adapt your instrumentation code when updating. + If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. + + Be aware that the API is not stable if you are using non GA (0.x) versions. + In non GA versions, breaking changes are frequently introduced which means you may have to adapt your instrumentation code when updating. . <> + A vendor neutral API that is discontinued in favor of OpenTelemetry. +[float] +[[apis-operation-modes]] +== Operation Modes -include::./public-api.asciidoc[] -include::./opentelemetry.asciidoc[] -include::./opentracing.asciidoc[] +All APIs allow for different operation modes in combination with the Elastic APM agent + +Noop:: ++ +-- +If the agent is not installed, the APIs are in noop mode and do not actually record and report spans. +-- + +Mix and Match:: ++ +-- +If you want to leverage the auto instrumentation of Elastic APM, +but also want to create custom spans or use the API to add custom labels to the spans created by Elastic APM, +you can just do that. +-- + +Manual instrumentation:: ++ +-- +If you don't want Elastic APM to auto-instrument known frameworks, +but instead only rely on manual instrumentation, +disable the auto instrumentation setting the configuration option <> to `false`. +-- + +include::./api-elastic.asciidoc[] +include::./api-opentelemetry.asciidoc[] +include::./api-opentracing.asciidoc[] From b4f69e65c3f946fcdfdfa26182990a2af5deac96 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 5 Feb 2021 12:12:30 +0100 Subject: [PATCH 25/94] Log warning once if unsupported APIs are used --- .../elastic/apm/agent/util/LoggerUtils.java | 427 ++++++++++++++++++ .../apm/agent/util/LoggerUtilsTest.java | 23 + .../opentelemetry/sdk/ElasticOTelSpan.java | 7 + .../sdk/ElasticOTelSpanBuilder.java | 7 + 4 files changed, 464 insertions(+) create mode 100644 apm-agent-core/src/main/java/co/elastic/apm/agent/util/LoggerUtils.java create mode 100644 apm-agent-core/src/test/java/co/elastic/apm/agent/util/LoggerUtilsTest.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/util/LoggerUtils.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/LoggerUtils.java new file mode 100644 index 0000000000..65f33ea6ae --- /dev/null +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/LoggerUtils.java @@ -0,0 +1,427 @@ +package co.elastic.apm.agent.util; + +import org.slf4j.Logger; +import org.slf4j.Marker; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class LoggerUtils { + + public static Logger logOnce(Logger logger) { + return new LogOnceLogger(logger); + } + + private static class LogOnceLogger implements Logger { + private final Logger delegate; + private final AtomicBoolean alreadyLogged = new AtomicBoolean(false); + + private LogOnceLogger(Logger delegate) { + this.delegate = delegate; + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public boolean isTraceEnabled() { + return delegate.isTraceEnabled(); + } + + @Override + public void trace(String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(msg); + } + } + + @Override + public void trace(String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(format, arg); + } + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(format, arg1, arg2); + } + } + + @Override + public void trace(String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(format, arguments); + } + } + + @Override + public void trace(String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(msg, t); + } + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return delegate.isTraceEnabled(marker); + } + + @Override + public void trace(Marker marker, String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(marker, msg); + } + } + + @Override + public void trace(Marker marker, String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(marker, format, arg); + } + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(marker, format, arg1, arg2); + } + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(marker, format, argArray); + } + } + + @Override + public void trace(Marker marker, String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.trace(marker, msg, t); + } + } + + @Override + public boolean isDebugEnabled() { + return delegate.isDebugEnabled(); + } + + @Override + public void debug(String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(msg); + } + } + + @Override + public void debug(String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(format, arg); + } + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(format, arg1, arg2); + } + } + + @Override + public void debug(String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(format, arguments); + } + } + + @Override + public void debug(String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(msg, t); + } + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return delegate.isDebugEnabled(marker); + } + + @Override + public void debug(Marker marker, String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(marker, msg); + } + } + + @Override + public void debug(Marker marker, String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(marker, format, arg); + } + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(marker, format, arg1, arg2); + } + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(marker, format, arguments); + } + } + + @Override + public void debug(Marker marker, String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.debug(marker, msg, t); + } + } + + @Override + public boolean isInfoEnabled() { + return delegate.isInfoEnabled(); + } + + @Override + public void info(String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(msg); + } + } + + @Override + public void info(String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(format, arg); + } + } + + @Override + public void info(String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(format, arg1, arg2); + } + } + + @Override + public void info(String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(format, arguments); + } + } + + @Override + public void info(String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(msg, t); + } + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return delegate.isInfoEnabled(marker); + } + + @Override + public void info(Marker marker, String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(marker, msg); + } + } + + @Override + public void info(Marker marker, String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(marker, format, arg); + } + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(marker, format, arg1, arg2); + } + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(marker, format, arguments); + } + } + + @Override + public void info(Marker marker, String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.info(marker, msg, t); + } + } + + @Override + public boolean isWarnEnabled() { + return delegate.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(msg); + } + } + + @Override + public void warn(String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(format, arg); + } + } + + @Override + public void warn(String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(format, arguments); + } + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(format, arg1, arg2); + } + } + + @Override + public void warn(String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(msg, t); + } + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return delegate.isWarnEnabled(marker); + } + + @Override + public void warn(Marker marker, String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(marker, msg); + } + } + + @Override + public void warn(Marker marker, String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(marker, format, arg); + } + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(marker, format, arg1, arg2); + } + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(marker, format, arguments); + } + } + + @Override + public void warn(Marker marker, String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.warn(marker, msg, t); + } + } + + @Override + public boolean isErrorEnabled() { + return delegate.isErrorEnabled(); + } + + @Override + public void error(String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(msg); + } + } + + @Override + public void error(String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(format, arg); + } + } + + @Override + public void error(String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(format, arg1, arg2); + } + } + + @Override + public void error(String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(format, arguments); + } + } + + @Override + public void error(String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(msg, t); + } + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return delegate.isErrorEnabled(marker); + } + + @Override + public void error(Marker marker, String msg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(marker, msg); + } + } + + @Override + public void error(Marker marker, String format, Object arg) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(marker, format, arg); + } + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(marker, format, arg1, arg2); + } + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(marker, format, arguments); + } + } + + @Override + public void error(Marker marker, String msg, Throwable t) { + if (alreadyLogged.compareAndSet(false, true)) { + delegate.error(marker, msg, t); + } + } + } +} diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/util/LoggerUtilsTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/util/LoggerUtilsTest.java new file mode 100644 index 0000000000..e5f4ff85f5 --- /dev/null +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/util/LoggerUtilsTest.java @@ -0,0 +1,23 @@ +package co.elastic.apm.agent.util; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +class LoggerUtilsTest { + + @Test + void testLogOnce() { + Logger mock = mock(Logger.class); + Logger logger = LoggerUtils.logOnce(mock); + + logger.info("once"); + logger.warn("twice"); + + verify(mock).info("once"); + verifyNoMoreInteractions(mock); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java index b1f7443c27..d278939ff1 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java @@ -32,6 +32,7 @@ import co.elastic.apm.agent.impl.context.web.ResultUtil; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.Transaction; +import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.VersionUtils; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; @@ -40,6 +41,8 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -50,6 +53,8 @@ import java.util.concurrent.TimeUnit; public class ElasticOTelSpan implements Span { + private static final Logger eventLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(ElasticOTelSpan.class)); + private final AbstractSpan span; public ElasticOTelSpan(AbstractSpan span) { @@ -73,11 +78,13 @@ public void mapAttribute(AttributeKey key, Object value) { @Override public Span addEvent(String name, Attributes attributes) { + eventLogger.warn("The addEvent API is not supported at the moment"); return this; } @Override public Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) { + eventLogger.warn("The addEvent API is not supported at the moment"); return this; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index faba3299c4..e62764f81c 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -27,6 +27,7 @@ import co.elastic.apm.agent.impl.ElasticApmTracer; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; +import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; @@ -35,6 +36,8 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -44,6 +47,8 @@ class ElasticOTelSpanBuilder implements SpanBuilder { + private static final Logger addLinkLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(ElasticOTelSpanBuilder.class)); + private final String spanName; private final ElasticApmTracer elasticApmTracer; private final Map, Object> attributes = new HashMap<>(); @@ -79,11 +84,13 @@ public SpanBuilder setNoParent() { @Override public SpanBuilder addLink(SpanContext spanContext) { + addLinkLogger.warn("The addLink API is not supported at the moment"); return this; } @Override public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { + addLinkLogger.warn("The addLink API is not supported at the moment"); return this; } From 430ca09c271436e1f2629e927b25eeccc18256c0 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Thu, 11 Feb 2021 14:28:31 +0100 Subject: [PATCH 26/94] Be more clear about what is and what's not supported --- docs/api-opentelemetry.asciidoc | 15 +++++++++++++++ docs/apis.asciidoc | 4 +--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 14ceeb39c2..8b57336f5b 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -14,6 +14,12 @@ using the OpenTelemetry API. In other words, it translates the calls to the OpenTelemetry API to Elastic APM and thus allows for reusing existing instrumentation. +NOTE: While manual instrumentations using the OpenTelemetry API can be adapted to the Elastic APM Java agent, it's not possible to use the instrumentations from +https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] in the context of the Elastic APM Java agent. + +However, you can use https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] (aka the OpenTelementry Java agent) +and send the data to APM Server. +See the {apm-overview-ref-v}/open-telemetry-elastic.html[OpenTelemetry integration docs] for more details. + The first span of a service will be converted to an Elastic APM {apm-overview-ref-v}/transactions.html[`Transaction`], subsequent spans are mapped to Elastic APM @@ -42,6 +48,9 @@ compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" The minimum required OpenTelemetry version is 0.14.1. +NOTE: Be aware that non GA (0.x) versions of the OpenTelemetry API are not stable and don't guarantee backward compatibility. +This means that you may have to adapt your instrumentation code when updating to newer versions. + [float] [[otel-init-tracer]] ==== Initialize tracer @@ -135,6 +144,12 @@ Elastic APM defines some attributes which are not included in OpenTelemetry's se ==== Caveats Not all features of the OpenTelemetry API are supported. +[float] +[[otel-metrics]] +===== Metrics +This bridge only supports the tracing API. +The Metrics API is currently not supported. + [float] [[otel-propagation]] ===== In process context propagation diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc index 137b556886..7804ee5cd2 100644 --- a/docs/apis.asciidoc +++ b/docs/apis.asciidoc @@ -4,7 +4,7 @@ please view this documentation at https://www.elastic.co/guide/en/apm/agent/java endif::[] [[apis]] -== Programmatic APIs +== Tracing APIs There are three different ways enhance the out-of-the-box instrumentation of the Java agent with manual instrumentation: @@ -14,8 +14,6 @@ There are three different ways enhance the out-of-the-box instrumentation of the . <> + A vendor neutral API. If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. + - Be aware that the API is not stable if you are using non GA (0.x) versions. - In non GA versions, breaking changes are frequently introduced which means you may have to adapt your instrumentation code when updating. . <> + A vendor neutral API that is discontinued in favor of OpenTelemetry. From 39f086c5ada64fea9370cf0e6c9651f43e4d7044 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Thu, 11 Feb 2021 15:03:37 +0100 Subject: [PATCH 27/94] Update and require OTel 0.16.0 --- .../apm-opentelemetry-plugin/pom.xml | 8 ++++-- .../AbstractOpenTelemetryInstrumentation.java | 2 +- .../GlobalOpenTelemetryInstrumentation.java | 11 ++------ .../sdk/ElasticOTelSpanBuilder.java | 3 +- .../sdk/ElasticOTelSpanContext.java | 13 +++++---- .../sdk/ElasticOpenTelemetry.java | 28 +++++++++++++++++++ .../sdk/ElasticOpenTelemetryTest.java | 2 +- .../opentelemetry/OpenTelemetryVersionIT.java | 5 ++-- docs/api-opentelemetry.asciidoc | 5 +--- 9 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index f2e2852fab..56d93c9897 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -25,13 +25,17 @@ io.opentelemetry opentelemetry-api - 0.15.0 + + 0.16.0 provided io.opentelemetry opentelemetry-semconv - 0.14.1 + 0.16.0-alpha ${project.groupId} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java index ba76d1da8c..7c1ccc1488 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java @@ -37,7 +37,7 @@ public abstract class AbstractOpenTelemetryInstrumentation extends TracerAwareIn @Override public final ElementMatcher.Junction getProtectionDomainPostFilter() { - return implementationVersionGte("0.14.0"); + return implementationVersionGte("0.16.0"); } @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 0c62efdf37..a8c27a52a8 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -25,13 +25,9 @@ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.impl.GlobalTracer; -import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracer; -import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelTracerProvider; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; import co.elastic.apm.agent.sdk.advice.AssignTo; -import io.opentelemetry.api.DefaultOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.propagation.ContextPropagators; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -58,10 +54,7 @@ public Class getAdviceClass() { public static class GlobalOpenTelemetryAdvice { - private static final OpenTelemetry ELASTIC_OPEN_TELEMETRY = DefaultOpenTelemetry.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(new ElasticOTelTracerProvider(new ElasticOTelTracer(GlobalTracer.requireTracerImpl()))) - .build(); + private static final OpenTelemetry ELASTIC_OPEN_TELEMETRY = new ElasticOpenTelemetry(GlobalTracer.requireTracerImpl()); @Advice.OnMethodEnter(suppress = Throwable.class, inline = false, skipOn = Advice.OnNonDefaultValue.class) public static boolean onEnter() { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java index e62764f81c..20658a2507 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java @@ -34,6 +34,7 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; import org.slf4j.Logger; @@ -125,7 +126,7 @@ public SpanBuilder setAttribute(AttributeKey key, @Nonnull T value) { } @Override - public SpanBuilder setSpanKind(Span.Kind spanKind) { + public SpanBuilder setSpanKind(SpanKind spanKind) { return this; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java index b12c0febcc..ed6c7b60ff 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,6 +26,7 @@ import co.elastic.apm.agent.impl.transaction.TraceContext; import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.api.trace.TraceStateBuilder; import org.stagemonitor.util.StringUtils; @@ -40,18 +41,18 @@ public ElasticOTelSpanContext(TraceContext traceContext) { } @Override - public String getTraceIdAsHexString() { + public String getTraceId() { return traceContext.getTraceId().toString(); } @Override - public String getSpanIdAsHexString() { + public String getSpanId() { return traceContext.getId().toString(); } @Override - public byte getTraceFlags() { - return traceContext.getFlags(); + public TraceFlags getTraceFlags() { + return TraceFlags.fromByte(traceContext.getFlags()); } @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java new file mode 100644 index 0000000000..c00a1fb699 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java @@ -0,0 +1,28 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; + +public class ElasticOpenTelemetry implements OpenTelemetry { + + private final ContextPropagators contextPropagators; + private final ElasticOTelTracerProvider elasticOTelTracerProvider; + + public ElasticOpenTelemetry(ElasticApmTracer tracer) { + elasticOTelTracerProvider = new ElasticOTelTracerProvider(new ElasticOTelTracer(tracer)); + contextPropagators = ContextPropagators.create(W3CTraceContextPropagator.getInstance()); + } + + @Override + public TracerProvider getTracerProvider() { + return elasticOTelTracerProvider; + } + + @Override + public ContextPropagators getPropagators() { + return contextPropagators; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 7b280ba26d..67908cfec5 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -153,7 +153,7 @@ public void testPropagateCustomContextKey() { .with(transaction) .with(ContextKey.named("foo"), "bar"); try (Scope scope = context.makeCurrent()) { - assertThat(tracer.getActive().getTraceContext().getId().toString()).isEqualTo(transaction.getSpanContext().getSpanIdAsHexString()); + assertThat(tracer.getActive().getTraceContext().getId().toString()).isEqualTo(transaction.getSpanContext().getSpanId()); // this assertion fails as context keys are not propagated assertThat(Context.current().get(ContextKey.named("foo"))).isEqualTo("bar"); Span.current().setAttribute("foo", "bar"); diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 75e79c5d42..2b65eaf445 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -40,7 +40,7 @@ public OpenTelemetryVersionIT(String version) throws Exception { List dependencies = List.of( "io.opentelemetry:opentelemetry-api:" + version, "io.opentelemetry:opentelemetry-context:" + version, - "io.opentelemetry:opentelemetry-semconv:0.14.1"); + "io.opentelemetry:opentelemetry-semconv:0.16.0-alpha"); runner = new TestClassWithDependencyRunner(dependencies, "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest", "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest$MapGetter"); @@ -49,8 +49,7 @@ public OpenTelemetryVersionIT(String version) throws Exception { @Parameterized.Parameters(name= "{0}") public static Iterable data() { return Arrays.asList(new Object[][]{ - {"0.15.0"}, - {"0.14.1"}, + {"0.16.0"}, }); } diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 8b57336f5b..a6626821ee 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -46,10 +46,7 @@ The first step in getting started with the OpenTelemetry API bridge is to declar compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" ---- -The minimum required OpenTelemetry version is 0.14.1. - -NOTE: Be aware that non GA (0.x) versions of the OpenTelemetry API are not stable and don't guarantee backward compatibility. -This means that you may have to adapt your instrumentation code when updating to newer versions. +The minimum required OpenTelemetry version is 0.16.0. [float] [[otel-init-tracer]] From 02cbb452fa937982cbcef409e899016bd6919e6a Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Thu, 11 Feb 2021 15:06:15 +0100 Subject: [PATCH 28/94] Remove smurf naming convention --- .../ContextStorageInstrumentation.java | 4 ++-- ...extStorage.java => OTelContextStorage.java} | 18 +++++++++--------- .../{ElasticOTelScope.java => OTelScope.java} | 8 ++++---- .../sdk/ElasticOpenTelemetry.java | 6 +++--- .../{ElasticOTelSpan.java => OTelSpan.java} | 8 ++++---- ...elSpanBuilder.java => OTelSpanBuilder.java} | 16 ++++++++-------- ...elSpanContext.java => OTelSpanContext.java} | 4 ++-- ...pagator.java => OTelTextMapPropagator.java} | 10 +++++----- ...{ElasticOTelTracer.java => OTelTracer.java} | 10 +++++----- ...erProvider.java => OTelTracerProvider.java} | 8 ++++---- .../sdk/ElasticOpenTelemetryTest.java | 4 ++-- 11 files changed, 48 insertions(+), 48 deletions(-) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/{ElasticOTelContextStorage.java => OTelContextStorage.java} (82%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/{ElasticOTelScope.java => OTelScope.java} (91%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelSpan.java => OTelSpan.java} (98%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelSpanBuilder.java => OTelSpanBuilder.java} (91%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelSpanContext.java => OTelSpanContext.java} (95%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelTextMapPropagator.java => OTelTextMapPropagator.java} (89%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelTracer.java => OTelTracer.java} (86%) rename apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/{ElasticOTelTracerProvider.java => OTelTracerProvider.java} (91%) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index e0add1a314..550c49c144 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -25,7 +25,7 @@ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.impl.GlobalTracer; -import co.elastic.apm.agent.opentelemetry.context.ElasticOTelContextStorage; +import co.elastic.apm.agent.opentelemetry.context.OTelContextStorage; import co.elastic.apm.agent.sdk.advice.AssignTo; import io.opentelemetry.context.ContextStorage; import net.bytebuddy.asm.Advice; @@ -55,7 +55,7 @@ public Class getAdviceClass() { public static class ContextStorageAdvice { - private static final ElasticOTelContextStorage CONTEXT_STORAGE = new ElasticOTelContextStorage(GlobalTracer.requireTracerImpl()); + private static final OTelContextStorage CONTEXT_STORAGE = new OTelContextStorage(GlobalTracer.requireTracerImpl()); @AssignTo.Return @Advice.OnMethodExit(suppress = Throwable.class, inline = false) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java similarity index 82% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index 893ec87c17..b59a7ae1ab 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,7 +26,7 @@ import co.elastic.apm.agent.impl.ElasticApmTracer; import co.elastic.apm.agent.impl.transaction.AbstractSpan; -import co.elastic.apm.agent.opentelemetry.sdk.ElasticOTelSpan; +import co.elastic.apm.agent.opentelemetry.sdk.OTelSpan; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextKey; @@ -35,20 +35,20 @@ import javax.annotation.Nullable; -public class ElasticOTelContextStorage implements ContextStorage { +public class OTelContextStorage implements ContextStorage { private final ElasticApmTracer elasticApmTracer; - public ElasticOTelContextStorage(ElasticApmTracer elasticApmTracer) { + public OTelContextStorage(ElasticApmTracer elasticApmTracer) { this.elasticApmTracer = elasticApmTracer; } @Override public Scope attach(Context toAttach) { Span span = Span.fromContext(toAttach); - if (span instanceof ElasticOTelSpan) { - AbstractSpan internalSpan = ((ElasticOTelSpan) span).getInternalSpan(); + if (span instanceof OTelSpan) { + AbstractSpan internalSpan = ((OTelSpan) span).getInternalSpan(); elasticApmTracer.activate(internalSpan); - return new ElasticOTelScope(internalSpan); + return new OTelScope(internalSpan); } else { return Scope.noop(); } @@ -66,6 +66,6 @@ public Context current() { if (active == null) { return null; } - return Context.root().with(new ElasticOTelSpan(active)); + return Context.root().with(new OTelSpan(active)); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java similarity index 91% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java index a16426ecf7..7d914c54ea 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/ElasticOTelScope.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,11 +27,11 @@ import co.elastic.apm.agent.impl.transaction.AbstractSpan; import io.opentelemetry.context.Scope; -public class ElasticOTelScope implements Scope { +public class OTelScope implements Scope { private final AbstractSpan span; - public ElasticOTelScope(AbstractSpan span) { + public OTelScope(AbstractSpan span) { this.span = span; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java index c00a1fb699..ef120eb77a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java @@ -9,16 +9,16 @@ public class ElasticOpenTelemetry implements OpenTelemetry { private final ContextPropagators contextPropagators; - private final ElasticOTelTracerProvider elasticOTelTracerProvider; + private final TracerProvider tracerProvider; public ElasticOpenTelemetry(ElasticApmTracer tracer) { - elasticOTelTracerProvider = new ElasticOTelTracerProvider(new ElasticOTelTracer(tracer)); + tracerProvider = new OTelTracerProvider(new OTelTracer(tracer)); contextPropagators = ContextPropagators.create(W3CTraceContextPropagator.getInstance()); } @Override public TracerProvider getTracerProvider() { - return elasticOTelTracerProvider; + return tracerProvider; } @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java similarity index 98% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index d278939ff1..2692d89588 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -52,12 +52,12 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -public class ElasticOTelSpan implements Span { - private static final Logger eventLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(ElasticOTelSpan.class)); +public class OTelSpan implements Span { + private static final Logger eventLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(OTelSpan.class)); private final AbstractSpan span; - public ElasticOTelSpan(AbstractSpan span) { + public OTelSpan(AbstractSpan span) { this.span = span; span.incrementReferences(); } @@ -368,7 +368,7 @@ public void end(long timestamp, TimeUnit unit) { @Override public SpanContext getSpanContext() { - return new ElasticOTelSpanContext(span.getTraceContext()); + return new OTelSpanContext(span.getTraceContext()); } @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java similarity index 91% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 20658a2507..2fdbe24a31 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -46,9 +46,9 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -class ElasticOTelSpanBuilder implements SpanBuilder { +class OTelSpanBuilder implements SpanBuilder { - private static final Logger addLinkLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(ElasticOTelSpanBuilder.class)); + private static final Logger addLinkLogger = LoggerUtils.logOnce(LoggerFactory.getLogger(OTelSpanBuilder.class)); private final String spanName; private final ElasticApmTracer elasticApmTracer; @@ -59,7 +59,7 @@ class ElasticOTelSpanBuilder implements SpanBuilder { @Nullable private Context remoteContext; - public ElasticOTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { + public OTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { this.spanName = spanName; this.elasticApmTracer = elasticApmTracer; this.parent = elasticApmTracer.getActive(); @@ -70,8 +70,8 @@ public SpanBuilder setParent(Context context) { Span span = Span.fromContext(context); if (span.getSpanContext().isRemote()) { remoteContext = context; - } else if (span instanceof ElasticOTelSpan) { - parent = ((ElasticOTelSpan) span).getInternalSpan(); + } else if (span instanceof OTelSpan) { + parent = ((OTelSpan) span).getInternalSpan(); } return this; } @@ -152,8 +152,8 @@ public Span startSpan() { return Span.getInvalid(); } span.withName(spanName); - ElasticOTelSpan elasticOTelSpan = new ElasticOTelSpan(span); - attributes.forEach(elasticOTelSpan::mapAttribute); - return elasticOTelSpan; + OTelSpan otelSpan = new OTelSpan(span); + attributes.forEach(otelSpan::mapAttribute); + return otelSpan; } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java similarity index 95% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java index ed6c7b60ff..3738f85f4e 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java @@ -33,10 +33,10 @@ import java.util.List; -public class ElasticOTelSpanContext implements SpanContext { +public class OTelSpanContext implements SpanContext { private final TraceContext traceContext; - public ElasticOTelSpanContext(TraceContext traceContext) { + public OTelSpanContext(TraceContext traceContext) { this.traceContext = traceContext; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java similarity index 89% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java index c348b0f92a..0f87f7ecf9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTextMapPropagator.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -32,7 +32,7 @@ import javax.annotation.Nullable; import java.util.Collection; -public class ElasticOTelTextMapPropagator implements TextMapPropagator { +public class OTelTextMapPropagator implements TextMapPropagator { private static final TextMapPropagator W3C_PROPAGATOR = W3CTraceContextPropagator.getInstance(); @@ -44,8 +44,8 @@ public Collection fields() { @Override public void inject(Context context, @Nullable C carrier, Setter setter) { Span span = Span.fromContext(context); - if (span instanceof ElasticOTelSpan) { - ((ElasticOTelSpan) span).getInternalSpan().setNonDiscardable(); + if (span instanceof OTelSpan) { + ((OTelSpan) span).getInternalSpan().setNonDiscardable(); } W3C_PROPAGATOR.inject(context, carrier, setter); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java similarity index 86% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java index a8f1075ebc..35ae25c4b4 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracer.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,15 +28,15 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.Tracer; -public class ElasticOTelTracer implements Tracer { +public class OTelTracer implements Tracer { private final ElasticApmTracer elasticApmTracer; - public ElasticOTelTracer(ElasticApmTracer elasticApmTracer) { + public OTelTracer(ElasticApmTracer elasticApmTracer) { this.elasticApmTracer = elasticApmTracer; } @Override public SpanBuilder spanBuilder(String spanName) { - return new ElasticOTelSpanBuilder(spanName, elasticApmTracer); + return new OTelSpanBuilder(spanName, elasticApmTracer); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java similarity index 91% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java rename to apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java index 9f4e1ecded..82218a350d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOTelTracerProvider.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -29,10 +29,10 @@ import javax.annotation.Nullable; -public class ElasticOTelTracerProvider implements TracerProvider { +public class OTelTracerProvider implements TracerProvider { private final Tracer tracer; - public ElasticOTelTracerProvider(Tracer tracer) { + public OTelTracerProvider(Tracer tracer) { this.tracer = tracer; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 67908cfec5..7e9b9e4536 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -26,7 +26,7 @@ import co.elastic.apm.agent.AbstractInstrumentationTest; import co.elastic.apm.agent.impl.context.TransactionContext; -import co.elastic.apm.agent.opentelemetry.context.ElasticOTelContextStorage; +import co.elastic.apm.agent.opentelemetry.context.OTelContextStorage; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; @@ -142,7 +142,7 @@ public void testStartChildAfterEnd() { /** * Demonstrates a missing feature of this bridge: custom context entries are not propagated * - * @see ElasticOTelContextStorage#current() + * @see OTelContextStorage#current() */ @Test @Ignore From 4ff5c4ff3b01161fa87f179facc1330d0340fe86 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Thu, 11 Feb 2021 15:20:46 +0100 Subject: [PATCH 29/94] Set outcome --- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 2 +- .../apm/agent/opentelemetry/sdk/OTelSpan.java | 13 ++++++++++++- apm-agent-plugins/apm-opentelemetry-test/pom.xml | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 56d93c9897..bad16a57d3 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.20.1-SNAPSHOT + 1.21.1-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 2692d89588..9941c765f3 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -31,6 +31,7 @@ import co.elastic.apm.agent.impl.context.Url; import co.elastic.apm.agent.impl.context.web.ResultUtil; import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.VersionUtils; @@ -101,7 +102,17 @@ public Span setStatus(StatusCode statusCode, String description) { break; } } - // TODO set outcome + switch (statusCode) { + case ERROR: + span.withOutcome(Outcome.FAILURE); + break; + case OK: + span.withOutcome(Outcome.SUCCESS); + break; + case UNSET: + span.withOutcome(Outcome.UNKNOWN); + break; + } return this; } diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry-test/pom.xml index fa8a80d912..ebc87812d0 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-test/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.20.1-SNAPSHOT + 1.21.1-SNAPSHOT 4.0.0 From d8f37df7efefe9a8e82e8602bb8a0db4b52331b8 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Tue, 2 Mar 2021 08:58:31 +0100 Subject: [PATCH 30/94] Update to otel 1.0.0 --- CHANGELOG.asciidoc | 2 +- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 4 ++-- .../AbstractOpenTelemetryInstrumentation.java | 8 +++----- .../apm/agent/opentelemetry/sdk/OTelSpanContext.java | 2 +- .../agent/opentelemetry/sdk/OTelTextMapPropagator.java | 6 ++++-- .../agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java | 4 ++-- .../elastic/apm/opentelemetry/OpenTelemetryVersionIT.java | 6 ++++-- docs/api-opentelemetry.asciidoc | 4 ++-- docs/apis.asciidoc | 2 +- 9 files changed, 20 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index b8951b810c..16a3ccc317 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -36,6 +36,7 @@ to assist with such efforts. * The <> option is now dynamic * Flushing internal and micrometer metrics before the agent shuts down - {pull}1658[#1658] * Support for OkHttp 4.4+ - {pull}1672[#1672] +* OpenTelemetry tracer API bridge (experimental): <> [float] ===== Bug fixes @@ -70,7 +71,6 @@ https://github.com/elastic/apm/blob/master/specs/agents/metadata.md#cloud-provid By default, the agent will try to automatically detect the cloud provider on startup, but this can be configured through the <> config option - {pull}1599[#1599] * Add span & transaction `outcome` field to improve error rate calculations - {pull}1613[#1613] -* OpenTelemetry tracer API bridge (experimental): <> [float] ===== Bug fixes diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index bad16a57d3..65a3325bbd 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -29,13 +29,13 @@ when updating the version, add the old version to OpenTelemetryVersionIT to make sure we're compatible with both the old and the new version --> - 0.16.0 + 1.0.0 provided io.opentelemetry opentelemetry-semconv - 0.16.0-alpha + 1.0.0-alpha ${project.groupId} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java index 7c1ccc1488..dad194f06d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java @@ -25,19 +25,17 @@ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; +import co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers; import net.bytebuddy.matcher.ElementMatcher; -import java.security.ProtectionDomain; import java.util.Arrays; import java.util.Collection; -import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.implementationVersionGte; - public abstract class AbstractOpenTelemetryInstrumentation extends TracerAwareInstrumentation { @Override - public final ElementMatcher.Junction getProtectionDomainPostFilter() { - return implementationVersionGte("0.16.0"); + public final ElementMatcher.Junction getClassLoaderMatcher() { + return CustomElementMatchers.classLoaderCanLoadClass("io.opentelemetry.context.propagation.TextMapSetter"); } @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java index 3738f85f4e..c1b16b1903 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java @@ -66,7 +66,7 @@ public TraceState getTraceState() { for (String vendorEntry : StringUtils.split(tracestate.get(i), ',')) { String[] keyValue = StringUtils.split(vendorEntry, '='); if (keyValue.length == 2) { - builder.set(keyValue[0], keyValue[1]); + builder.put(keyValue[0], keyValue[1]); } } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java index 0f87f7ecf9..0230910dc9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java @@ -27,7 +27,9 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapSetter; import javax.annotation.Nullable; import java.util.Collection; @@ -42,7 +44,7 @@ public Collection fields() { } @Override - public void inject(Context context, @Nullable C carrier, Setter setter) { + public void inject(Context context, @Nullable C carrier, TextMapSetter setter) { Span span = Span.fromContext(context); if (span instanceof OTelSpan) { ((OTelSpan) span).getInternalSpan().setNonDiscardable(); @@ -51,7 +53,7 @@ public void inject(Context context, @Nullable C carrier, Setter setter) { } @Override - public Context extract(Context context, @Nullable C carrier, Getter getter) { + public Context extract(Context context, @Nullable C carrier, TextMapGetter getter) { return W3C_PROPAGATOR.extract(context, carrier, getter); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 7e9b9e4536..6dae495b1b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -34,7 +34,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import org.junit.Before; import org.junit.Ignore; @@ -344,7 +344,7 @@ public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsu reporter.resetWithoutRecycling(); } - public static class MapGetter implements TextMapPropagator.Getter> { + public static class MapGetter implements TextMapGetter> { @Override public Iterable keys(Map carrier) { return carrier.keySet(); diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 2b65eaf445..8af8f5ac8c 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -40,7 +40,7 @@ public OpenTelemetryVersionIT(String version) throws Exception { List dependencies = List.of( "io.opentelemetry:opentelemetry-api:" + version, "io.opentelemetry:opentelemetry-context:" + version, - "io.opentelemetry:opentelemetry-semconv:0.16.0-alpha"); + "io.opentelemetry:opentelemetry-semconv:1.0.0-alpha"); runner = new TestClassWithDependencyRunner(dependencies, "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest", "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest$MapGetter"); @@ -49,7 +49,9 @@ public OpenTelemetryVersionIT(String version) throws Exception { @Parameterized.Parameters(name= "{0}") public static Iterable data() { return Arrays.asList(new Object[][]{ - {"0.16.0"}, + {"0.17.0"}, + {"0.17.1"}, + {"1.0.0"}, }); } diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index a6626821ee..9466dfdb1e 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -6,7 +6,7 @@ endif::[] [[opentelementry-bridge]] === OpenTelemetry bridge -NOTE: Added as experimental in 1.21.0. +NOTE: Added as experimental in 1.22.0. To enable it, set <> to `true`. The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, @@ -46,7 +46,7 @@ The first step in getting started with the OpenTelemetry API bridge is to declar compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" ---- -The minimum required OpenTelemetry version is 0.16.0. +The minimum required OpenTelemetry version is 0.17.0. [float] [[otel-init-tracer]] diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc index 7804ee5cd2..28c77f3301 100644 --- a/docs/apis.asciidoc +++ b/docs/apis.asciidoc @@ -13,7 +13,7 @@ There are three different ways enhance the out-of-the-box instrumentation of the Contains annotations to declaratively create spans. . <> + A vendor neutral API. - If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. + + If you plan to do a lot of manual instrumentation and want to reduce vendor lock-in this is probably what you're looking for. . <> + A vendor neutral API that is discontinued in favor of OpenTelemetry. From 21c8002ab576af6a58856da33faffc19f1168003 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 14 Jun 2021 21:15:35 +0200 Subject: [PATCH 31/94] fix advice class names --- .../apm/agent/opentelemetry/ContextStorageInstrumentation.java | 2 +- .../agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 90b0e481a2..59b6da8b23 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -50,7 +50,7 @@ public ElementMatcher getMethodMatcher() { @Override public String getAdviceClassName() { - return "co.elastic.apm.agent.opentelemetry.ContextStorageInstrumentation.ContextStorageAdvice"; + return "co.elastic.apm.agent.opentelemetry.ContextStorageInstrumentation$ContextStorageAdvice"; } public static class ContextStorageAdvice { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 5462e25749..a3e395003b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -49,7 +49,7 @@ public ElementMatcher getMethodMatcher() { @Override public String getAdviceClassName() { - return "co.elastic.apm.agent.opentelemetry.GlobalOpenTelemetryInstrumentation.GlobalOpenTelemetryAdvice"; + return "co.elastic.apm.agent.opentelemetry.GlobalOpenTelemetryInstrumentation$GlobalOpenTelemetryAdvice"; } public static class GlobalOpenTelemetryAdvice { From 6faddb1ff0ef84827fc9b9fdf04a4e2942ce2d71 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 15 Jun 2021 09:52:07 +0200 Subject: [PATCH 32/94] fix url test --- .../java/co/elastic/apm/agent/impl/context/Url.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java index 94ba897c96..b7aaa8f4cd 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java @@ -203,9 +203,13 @@ public void fillFullUrl() { } full.append(protocol != null ? protocol : "http") .append("://") - .append(hostname) - .append(port > 0 ? port : "") - .append(pathname != null ? pathname : "") + .append(hostname); + + if (port > 0) { + full.append(":").append(port); + } + + full.append(pathname != null ? pathname : "") .append(search != null ? "?" : "") .append(search != null ? search : ""); } From 27ebcfdb04b5a3839db464f71664acbdab9d6a0e Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 19 Aug 2021 15:57:01 +0200 Subject: [PATCH 33/94] post-merge update --- .../elastic/apm/agent/impl/context/Url.java | 2 - .../AbstractOpenTelemetryInstrumentation.java | 8 +--- .../ContextStorageInstrumentation.java | 8 +--- .../GlobalOpenTelemetryInstrumentation.java | 8 +--- .../context/OTelContextStorage.java | 8 +--- .../opentelemetry/context/OTelScope.java | 8 +--- .../opentelemetry/context/package-info.java | 8 +--- .../apm/agent/opentelemetry/package-info.java | 8 +--- .../sdk/ElasticOpenTelemetry.java | 8 +--- .../apm/agent/opentelemetry/sdk/OTelSpan.java | 42 ++++--------------- .../opentelemetry/sdk/OTelSpanBuilder.java | 8 +--- .../opentelemetry/sdk/OTelSpanContext.java | 8 +--- .../sdk/OTelTextMapPropagator.java | 8 +--- .../agent/opentelemetry/sdk/OTelTracer.java | 8 +--- .../opentelemetry/sdk/OTelTracerProvider.java | 8 +--- .../agent/opentelemetry/sdk/package-info.java | 8 +--- .../sdk/ElasticOpenTelemetryTest.java | 11 +---- 17 files changed, 23 insertions(+), 144 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java index 5a0b29b889..9e145167ea 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java @@ -89,8 +89,6 @@ public StringBuilder getFull() { /** * Updates full URL from current state of {@literal this}. Must be called after all other Url fields are set. - * - * @return url */ private void updateFull() { // inspired by org.apache.catalina.connector.Request.getRequestURL diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java index dad194f06d..0492594875 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 59b6da8b23..736c2fe77a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index a3e395003b..9f8d9ef979 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index b59a7ae1ab..f89061c7e9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.context; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java index 7d914c54ea..9972705a77 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.context; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java index 0b9a4b4bf2..e4ee3b911b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ @NonnullApi package co.elastic.apm.agent.opentelemetry.context; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java index 3b86c825fa..245461a82d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ @NonnullApi package co.elastic.apm.agent.opentelemetry; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java index 1c228ba56a..afc86a3867 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index f0dcdbde0d..fe583cc967 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; @@ -47,8 +41,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.net.MalformedURLException; -import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -167,17 +159,6 @@ private void onTransactionEnd(Transaction t) { Url url = request.getUrl(); captureNetHostUrlAttributes(url, span.getContext()); request.getSocket().withRemoteAddress(getClientRemoteAddress(span.getContext())); - if (url.hasContent()) { - StringBuilder fullUrl = url.getFull(); - if (fullUrl.length() > 0) { - try { - url.fillFromFullUrl(new URL(fullUrl.toString())); - } catch (MalformedURLException ignore) { - } - } else { - url.fillFullUrl(); - } - } } else { t.withType("unknown"); } @@ -210,7 +191,7 @@ private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, Att co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); // http.* - if (mapHttpUrlAttributes(key, value, context.getHttp().getUrl())) { + if (mapHttpUrlAttributes(key, value, context.getHttp().getInternalUrl())) { // successfully mapped inside mapHttpUrlAttributes } else if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { context.getHttp().withStatusCode(((Number) value).intValue()); @@ -246,23 +227,14 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { Destination destination = context.getDestination(); if (context.getHttp().hasContent()) { s.withType("external").withSubtype("http"); - Url url = context.getHttp().getUrl(); + Url url = context.getHttp().getInternalUrl(); if (context.getDestination().getAddress().length() > 0) { url.withHostname(context.getDestination().getAddress().toString()); } if (context.getDestination().getPort() > 0) { url.withPort(context.getDestination().getPort()); } - // The full url is the only thing we report on spans. - // Instrumentations may not set the full url but only it's components (see mapHttpUrlAttributes) - url.fillFullUrl(); - if (url.getProtocol() == null || url.getHostname() == null) { - try { - // We also need the different pieces of the url in order to determine the destination details - url.fillFromFullUrl(new URL(url.getFull().toString())); - } catch (MalformedURLException ignore) { - } - } + HttpClientHelper.setDestinationServiceDetails(s, url.getProtocol(), url.getHostname(), url.getPort()); } else if (context.getDb().hasContent()) { s.withType("db").withSubtype(context.getDb().getType()); @@ -301,9 +273,9 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { */ private boolean mapHttpUrlAttributes(AttributeKey key, Object value, Url url) { if (key.equals(SemanticAttributes.HTTP_URL)) { - StringBuilder fullURl = url.getFull(); - fullURl.setLength(0); - fullURl.append((String) value); + url.withFull((String) value); + // ensure other fields or URL are populated through parsing + url.parseAndFillFromFull(); } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { String httpTarget = (String) value; int indexOfQuery = httpTarget.indexOf('?'); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 2fdbe24a31..f9a3f0f52a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java index c1b16b1903..15f5c99eb7 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java index 0230910dc9..fe175fccd0 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java index 35ae25c4b4..db800afc1b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java index 82218a350d..c7595e6ff3 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java index bb36c4380c..b524bcacb2 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ @NonnullApi package co.elastic.apm.agent.opentelemetry.sdk; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 88125ef196..750a369b6b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.agent.opentelemetry.sdk; @@ -336,11 +330,10 @@ public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsu assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getSpans()).hasSize(1); assertThat(reporter.getFirstSpan().getContext().getDestination().getPort()).isEqualTo(80); - assertThat(reporter.getFirstSpan().getContext().getHttp()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); + assertThat(reporter.getFirstSpan().getContext().getHttp().getUrl().toString()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); assertThat(reporter.getFirstSpan().getContext().getDestination().getAddress().toString()).isEqualTo("example.com"); assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getName().toString()).isEqualTo("http://example.com"); assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getResource().toString()).isEqualTo("example.com:80"); - assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getType()).isEqualTo("external"); reporter.resetWithoutRecycling(); } From 28dd7d53c3f2b31b10b92968cc91f0c317dc5006 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 20 Aug 2021 10:48:00 +0200 Subject: [PATCH 34/94] add missing ivy test dependency --- apm-agent-plugins/apm-opentelemetry-test/pom.xml | 5 +++++ .../elastic/apm/opentelemetry/OpenTelemetryVersionIT.java | 8 +------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry-test/pom.xml index ab6d57dedf..3a9f65e97c 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-test/pom.xml @@ -42,6 +42,11 @@ + + org.apache.ivy + ivy + test + diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 8af8f5ac8c..fdc613ef90 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -1,9 +1,4 @@ -/*- - * #%L - * Elastic APM Java agent - * %% - * Copyright (C) 2018 - 2021 Elastic and contributors - * %% +/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright @@ -20,7 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * #L% */ package co.elastic.apm.opentelemetry; From d021714b37625bf7ef1a8d3936515c3d6725f339 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 20 Aug 2021 10:50:19 +0200 Subject: [PATCH 35/94] test versions 1.0.x->1.5.0 --- .../apm/opentelemetry/OpenTelemetryVersionIT.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index fdc613ef90..b478aea84d 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -34,7 +34,7 @@ public OpenTelemetryVersionIT(String version) throws Exception { List dependencies = List.of( "io.opentelemetry:opentelemetry-api:" + version, "io.opentelemetry:opentelemetry-context:" + version, - "io.opentelemetry:opentelemetry-semconv:1.0.0-alpha"); + "io.opentelemetry:opentelemetry-semconv:" + version + "-alpha"); runner = new TestClassWithDependencyRunner(dependencies, "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest", "co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest$MapGetter"); @@ -43,9 +43,12 @@ public OpenTelemetryVersionIT(String version) throws Exception { @Parameterized.Parameters(name= "{0}") public static Iterable data() { return Arrays.asList(new Object[][]{ - {"0.17.0"}, - {"0.17.1"}, - {"1.0.0"}, + {"1.0.1"}, + {"1.1.0"}, + {"1.2.0"}, + {"1.3.0"}, + {"1.4.1"}, + {"1.5.0"}, }); } From 81daba234f967a6e301a1e2b1918d26192c853dd Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 20 Aug 2021 15:10:03 +0200 Subject: [PATCH 36/94] add few tests for coverage --- .../apm-opentelemetry-plugin/pom.xml | 7 +++++-- .../sdk/ElasticOpenTelemetryTest.java | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 08c8f19f03..5b8c140338 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -19,6 +19,8 @@ 8 11 true + + 1.0.0 @@ -29,13 +31,14 @@ when updating the version, add the old version to OpenTelemetryVersionIT to make sure we're compatible with both the old and the new version --> - 1.0.0 + ${version.opentelemetry} provided io.opentelemetry opentelemetry-semconv - 1.0.0-alpha + ${version.opentelemetry}-alpha + provided ${project.groupId} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 750a369b6b..2b21ec4d6c 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -35,6 +35,8 @@ import org.junit.Test; import javax.annotation.Nullable; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -68,6 +70,7 @@ public void testTransactionWithAttribute() { otelTracer.spanBuilder("transaction") .setAttribute("boolean", true) .setAttribute("long", 42L) + .setAttribute("double", 73D) .setAttribute("string", "hello") .startSpan() .end(); @@ -76,6 +79,7 @@ public void testTransactionWithAttribute() { TransactionContext context = reporter.getFirstTransaction().getContext(); assertThat(context.getLabel("boolean")).isEqualTo(true); assertThat(context.getLabel("long")).isEqualTo(42L); + assertThat(context.getLabel("double")).isEqualTo(73D); assertThat(context.getLabel("string")).isEqualTo("hello"); } @@ -191,6 +195,23 @@ public void testTransactionInject() { assertThat(elasticApmHeaders).containsAllEntriesOf(otelHeaders); } + @Test + public void setStartTimestamp() { + + Instant transactionStart = Instant.now(); + + otelTracer.spanBuilder("transaction") + .setStartTimestamp(transactionStart) + .startSpan() + .end(); + + long transactionStartMicros = ChronoUnit.MICROS.between(Instant.EPOCH, transactionStart); + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getFirstTransaction().getTimestamp()).isEqualTo(transactionStartMicros); + + } + @Test public void testTransactionSemanticConventionMappingHttpHost() { otelTracer.spanBuilder("transaction") From fe86a0ab01a8e9540a57470e89a0aa3b3189c738 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 20 Aug 2021 15:28:29 +0200 Subject: [PATCH 37/94] fix doc release version --- docs/api-opentelemetry.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 9466dfdb1e..365e4f7486 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -6,7 +6,7 @@ endif::[] [[opentelementry-bridge]] === OpenTelemetry bridge -NOTE: Added as experimental in 1.22.0. +NOTE: Added as experimental in 1.26.0. To enable it, set <> to `true`. The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, From fe0501cd7639c99aa2cf84bd85d8d0b96b75deb1 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 20 Aug 2021 15:48:15 +0200 Subject: [PATCH 38/94] update docs --- docs/configuration.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index d70015393d..2a1b79cf25 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -713,7 +713,7 @@ you should add an additional entry to this list (make sure to also include the d ==== `disable_instrumentations` (added[1.0.0,Changing this value at runtime is possible since version 1.15.0]) A list of instrumentations which should be disabled. -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. +Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. For version `1.25.0` and later, use <> to enable experimental instrumentations. NOTE: Changing this value at runtime can slow down the application temporarily. @@ -2913,7 +2913,7 @@ The default unit for this option is `ms`. # sanitize_field_names=password,passwd,pwd,secret,*key,*token*,*session*,*credit*,*card*,authorization,set-cookie # A list of instrumentations which should be disabled. -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. +# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `bootdelegation`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. # For version `1.25.0` and later, use <> to enable experimental instrumentations. # # NOTE: Changing this value at runtime can slow down the application temporarily. From a29681322ba9d6d9dadb3f199a6afcba2d5cdb8d Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Sep 2021 15:02:36 +0200 Subject: [PATCH 39/94] introduce ElasticContext to rule them all --- .../apm/agent/impl/ElasticApmTracer.java | 110 ++++++++++++------ .../agent/impl/transaction/AbstractSpan.java | 14 ++- .../impl/transaction/ElasticContext.java | 59 ++++++++++ 3 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index bdb776e597..f6202ca773 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -28,6 +28,7 @@ import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.BinaryHeaderGetter; +import co.elastic.apm.agent.impl.transaction.ElasticContext; import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.TextHeaderGetter; import co.elastic.apm.agent.impl.transaction.TraceContext; @@ -81,13 +82,13 @@ public class ElasticApmTracer implements Tracer { private final ObjectPool errorPool; private final Reporter reporter; private final ObjectPoolFactory objectPoolFactory; - // Maintains a stack of all the activated spans + // Maintains a stack of all the activated spans/contexts // This way its easy to retrieve the bottom of the stack (the transaction) // Also, the caller does not have to keep a reference to the previously active span, as that is maintained by the stack - private final ThreadLocal>> activeStack = new ThreadLocal>>() { + private final ThreadLocal>> activeStack = new ThreadLocal>>() { @Override - protected Deque> initialValue() { - return new ArrayDeque>(); + protected Deque> initialValue() { + return new ArrayDeque>(); } }; @@ -250,7 +251,7 @@ private Transaction createTransaction() { @Override @Nullable public Transaction currentTransaction() { - final AbstractSpan bottomOfStack = activeStack.get().peekLast(); + final ElasticContext bottomOfStack = activeStack.get().peekLast(); return bottomOfStack != null ? bottomOfStack.getTransaction() : null; } @@ -467,6 +468,12 @@ public ObjectPoolFactory getObjectPoolFactory() { @Override @Nullable public AbstractSpan getActive() { + ElasticContext active = activeStack.get().peek(); + return active != null ? active.getSpan() : null; + } + + @Nullable + public ElasticContext getActiveContext() { return activeStack.get().peek(); } @@ -671,54 +678,81 @@ public T getLifecycleListener(Class listenerClass) { return null; } - public void activate(AbstractSpan span) { + @Nullable + public ElasticContext currentContext() { + return activeStack.get().peek(); + } + + public void activate(ElasticContext context) { if (logger.isDebugEnabled()) { - logger.debug("Activating {} on thread {}", span, Thread.currentThread().getId()); - } - span.incrementReferences(); - List activationListeners = getActivationListeners(); - for (int i = 0, size = activationListeners.size(); i < size; i++) { - try { - activationListeners.get(i).beforeActivate(span); - } catch (Error e) { - throw e; - } catch (Throwable t) { - logger.warn("Exception while calling {}#beforeActivate", activationListeners.get(i).getClass().getSimpleName(), t); + logger.debug("Activating {} on thread {}", context, Thread.currentThread().getId()); + } + + ElasticContext currentContext = currentContext(); + ElasticContext newContext = context; + + AbstractSpan span = context.getSpan(); + if (span != null) { + span.incrementReferences(); + triggerActivationListeners(span, true); + } else if(currentContext != null) { + // when there is no span attached to the context we are attaching to but there is one in the current + // context, we just propagate to the context that will be activated. + span = currentContext.getSpan(); + if (span != null) { + newContext = context.withActiveSpan(span); } } - activeStack.get().push(span); + + activeStack.get().push(newContext); } - public void deactivate(AbstractSpan span) { + public void deactivate(ElasticContext context) { if (logger.isDebugEnabled()) { - logger.debug("Deactivating {} on thread {}", span, Thread.currentThread().getId()); + logger.debug("Deactivating {} on thread {}", context, Thread.currentThread().getId()); } + ElasticContext activeContext = activeStack.get().poll(); + AbstractSpan span = null; try { - final Deque> stack = activeStack.get(); - assertIsActive(span, stack.poll()); - List activationListeners = getActivationListeners(); - for (int i = 0, size = activationListeners.size(); i < size; i++) { - try { - // `this` is guaranteed to not be recycled yet as the reference count is only decremented after this method has executed - activationListeners.get(i).afterDeactivate(span); - } catch (Error e) { - throw e; - } catch (Throwable t) { - logger.warn("Exception while calling {}#afterDeactivate", activationListeners.get(i).getClass().getSimpleName(), t); - } + assertIsActive(context, activeContext); + span = context.getSpan(); + + if (null != span) { + triggerActivationListeners(span, false); } } finally { - span.decrementReferences(); + if (null != span) { + span.decrementReferences(); + } } } - private void assertIsActive(AbstractSpan span, @Nullable AbstractSpan currentlyActive) { - if (span != currentlyActive) { - logger.warn("Deactivating a span ({}) which is not the currently active span ({}). " + - "This can happen when not properly deactivating a previous span.", span, currentlyActive); + private void assertIsActive(ElasticContext context, @Nullable ElasticContext currentlyActive) { + if (context != currentlyActive) { + logger.warn("Deactivating a context ({}) which is not the currently active one ({}). " + + "This can happen when not properly deactivating a previous span or context.", context, currentlyActive); if (assertionsEnabled) { - throw new AssertionError("Deactivating a span that is not the active one"); + throw new AssertionError("Deactivating a context that is not the active one"); + } + } + } + + private void triggerActivationListeners(AbstractSpan span, boolean isActivate) { + List activationListeners = getActivationListeners(); + for (int i = 0, size = activationListeners.size(); i < size; i++) { + ActivationListener listener = activationListeners.get(i); + try { + if (isActivate) { + listener.beforeActivate(span); + } else { + // `this` is guaranteed to not be recycled yet as the reference count is only decremented after this method has executed + listener.afterDeactivate(span); + } + } catch (Error e) { + throw e; + } catch (Throwable t) { + logger.warn("Exception while calling {}#{}", listener.getClass().getSimpleName(), isActivate ? "beforeActivate" : "afterDeactivate", t); } } } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index a11771520e..d94e688d65 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -34,7 +34,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -public abstract class AbstractSpan> implements Recyclable { +public abstract class AbstractSpan> implements Recyclable, ElasticContext { public static final int PRIO_USER_SUPPLIED = 1000; public static final int PRIO_HIGH_LEVEL_FRAMEWORK = 100; public static final int PRIO_METHOD_SIGNATURE = 100; @@ -133,9 +133,6 @@ public boolean isDiscarded() { return discardRequested && getTraceContext().isDiscardable(); } - @Nullable - public abstract Transaction getTransaction(); - private static class ChildDurationTimer implements Recyclable { private AtomicInteger activeChildren = new AtomicInteger(); @@ -648,4 +645,13 @@ public T withUserOutcome(Outcome outcome) { return thiz(); } + @Override + public ElasticContext withActiveSpan(AbstractSpan span) { + return this; + } + + @Override + public AbstractSpan getSpan() { + return this; + } } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java new file mode 100644 index 0000000000..6e320f13bf --- /dev/null +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package co.elastic.apm.agent.impl.transaction; + +import javax.annotation.Nullable; + +public interface ElasticContext> { + + /** + * Makes the context active + * + * @return this + */ + T activate(); + + /** + * Deactivates context + * + * @return this + */ + T deactivate(); + + /** + * Adds a span as active within context. Might return a different context instance if required, for example + * when the context implementation is immutable and thus can't be modified. + * + * @param span span to add to the context + * @return context with activated span + */ + ElasticContext withActiveSpan(AbstractSpan span); + + /** + * @return the span/transaction that is associated to this context, {@literal null} if there is none + */ + @Nullable + AbstractSpan getSpan(); + + /** + * @return transaction associated to this context, {@literal null} if there is none + */ + @Nullable + Transaction getTransaction(); +} From ac1d10f6bb13c1f734cb462ce57d3eb04f4e44af Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Sep 2021 12:29:42 +0200 Subject: [PATCH 40/94] bridge otel root context --- .../apm/agent/impl/ElasticApmTracer.java | 23 +- .../agent/impl/transaction/AbstractSpan.java | 17 +- .../impl/transaction/ElasticContext.java | 9 + .../ArrayBasedContextInstrumentation.java | 58 ++++ .../context/OTelContextStorage.java | 67 ++-- .../opentelemetry/context/OTelScope.java | 36 -- .../opentelemetry/sdk/OTelBridgeContext.java | 143 ++++++++ .../apm/agent/opentelemetry/sdk/OTelSpan.java | 5 + ...ic.apm.agent.sdk.ElasticApmInstrumentation | 1 + .../sdk/ElasticOpenTelemetryTest.java | 326 ++++++++++++++++-- 10 files changed, 589 insertions(+), 96 deletions(-) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index f6202ca773..0fd83a7118 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -707,15 +707,34 @@ public void activate(ElasticContext context) { activeStack.get().push(newContext); } + public Scope activateInScope(final ElasticContext context) { + // already in scope + if (getActiveContext() == context) { + return Scope.NoopScope.INSTANCE; + } + context.activate(); + return new Scope() { + @Override + public void close() { + context.deactivate(); + } + }; + } + public void deactivate(ElasticContext context) { if (logger.isDebugEnabled()) { logger.debug("Deactivating {} on thread {}", context, Thread.currentThread().getId()); } ElasticContext activeContext = activeStack.get().poll(); - AbstractSpan span = null; + AbstractSpan span = context.getSpan(); + + if (activeContext != context && context == span) { + // when context has been upgraded, we need to deactivate the original span + activeContext = context; + } + try { assertIsActive(context, activeContext); - span = context.getSpan(); if (null != span) { triggerActivationListeners(span, false); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index d94e688d65..636c2f1978 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -473,28 +473,21 @@ private boolean hasChildId(Id spanId) { return false; } + @Override public T activate() { tracer.activate(this); return (T) this; } + @Override public T deactivate() { tracer.deactivate(this); return (T) this; } + @Override public Scope activateInScope() { - // already in scope - if (tracer.getActive() == this) { - return Scope.NoopScope.INSTANCE; - } - activate(); - return new Scope() { - @Override - public void close() { - deactivate(); - } - }; + return tracer.activateInScope(this); } /** @@ -647,6 +640,8 @@ public T withUserOutcome(Outcome outcome) { @Override public ElasticContext withActiveSpan(AbstractSpan span) { + // for internal spans the active span is only stored implicitly in the stack, hence we have no requirement + // to have any other kind of context storage. return this; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java index 6e320f13bf..4aa2cbb228 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java @@ -18,6 +18,8 @@ */ package co.elastic.apm.agent.impl.transaction; +import co.elastic.apm.agent.impl.Scope; + import javax.annotation.Nullable; public interface ElasticContext> { @@ -36,6 +38,13 @@ public interface ElasticContext> { */ T deactivate(); + /** + * Activates context in a scope + * + * @return active scope that will deactivate context when closed + */ + Scope activateInScope(); + /** * Adds a span as active within context. Might return a different context instance if required, for example * when the context implementation is immutable and thus can't be modified. diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java new file mode 100644 index 0000000000..4d2fb42a46 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java @@ -0,0 +1,58 @@ +package co.elastic.apm.agent.opentelemetry; + +import co.elastic.apm.agent.impl.GlobalTracer; +import co.elastic.apm.agent.opentelemetry.sdk.OTelBridgeContext; +import co.elastic.apm.agent.sdk.advice.AssignTo; +import io.opentelemetry.context.Context; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import javax.annotation.Nullable; + +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +/** + * Instruments {@code io.opentelemetry.context.ArrayBasedContext#root()} to capture original context root + * and allow relying ot the provided context implementation for key/value storage in context + */ +public class ArrayBasedContextInstrumentation extends AbstractOpenTelemetryInstrumentation { + + @Override + public ElementMatcher getTypeMatcher() { + return named("io.opentelemetry.context.ArrayBasedContext"); + } + + @Override + public ElementMatcher getMethodMatcher() { + return named("root") + .and(isStatic()) + .and(returns(hasSuperType(named("io.opentelemetry.context.Context")))) + .and(takesNoArguments()); + } + + @Override + public String getAdviceClassName() { + return "co.elastic.apm.agent.opentelemetry.ArrayBasedContextInstrumentation$RootAdvice"; + } + + public static class RootAdvice { + + @Nullable + @AssignTo.Return + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class, inline = false) + public static Context onExit(@Advice.Return @Nullable Context returnValue) { + + if (returnValue == null) { + return null; + } + + return OTelBridgeContext.bridgeRootContext(GlobalTracer.requireTracerImpl(), returnValue); + } + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index f89061c7e9..af9581a37b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -20,46 +20,71 @@ import co.elastic.apm.agent.impl.ElasticApmTracer; import co.elastic.apm.agent.impl.transaction.AbstractSpan; -import co.elastic.apm.agent.opentelemetry.sdk.OTelSpan; -import io.opentelemetry.api.trace.Span; +import co.elastic.apm.agent.impl.transaction.ElasticContext; +import co.elastic.apm.agent.opentelemetry.sdk.OTelBridgeContext; import io.opentelemetry.context.Context; -import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.Scope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; public class OTelContextStorage implements ContextStorage { - private final ElasticApmTracer elasticApmTracer; - public OTelContextStorage(ElasticApmTracer elasticApmTracer) { - this.elasticApmTracer = elasticApmTracer; + private static final Logger logger = LoggerFactory.getLogger(OTelContextStorage.class); + + private final ElasticApmTracer tracer; + + public OTelContextStorage(ElasticApmTracer tracer) { + this.tracer = tracer; } @Override - public Scope attach(Context toAttach) { - Span span = Span.fromContext(toAttach); - if (span instanceof OTelSpan) { - AbstractSpan internalSpan = ((OTelSpan) span).getInternalSpan(); - elasticApmTracer.activate(internalSpan); - return new OTelScope(internalSpan); - } else { + public Scope attach(@Nullable Context toAttach) { + if (toAttach == null) { + // no context to attach + return Scope.noop(); + } + + if (toAttach == tracer.currentContext()) { + // already active return Scope.noop(); } + + if (!(toAttach instanceof OTelBridgeContext)) { + throw new IllegalStateException("unexpected context type "+ toAttach.getClass().getName()); + } + OTelBridgeContext bridgeContext = (OTelBridgeContext)toAttach; + + tracer.activate(bridgeContext); + return bridgeContext; } - /** - * NOTE: the returned context is not the same as the one provided in {@link #attach(Context)}. - * The consequence of this is that it will not have the context keys of the original context. - * In other words, {@link Context#get(ContextKey)} will return {@code null} for any key besides the span key. - */ @Nullable @Override public Context current() { - AbstractSpan active = elasticApmTracer.getActive(); - if (active == null) { + ElasticContext current = tracer.currentContext(); + if (current == null) { return null; } - return Context.root().with(new OTelSpan(active)); + + if (current instanceof OTelBridgeContext) { + return (Context) current; + } + + if (!(current instanceof AbstractSpan)) { + throw new IllegalStateException("unexpected context type to upgrade: " + current.getClass().getName()); + } + + logger.debug("upgrading active context {} to a bridged context", current); + + tracer.deactivate(current); + OTelBridgeContext upgradedContext = OTelBridgeContext.wrapElasticActiveSpan(tracer, (AbstractSpan) current); + tracer.activate(upgradedContext); + + logger.debug("active context upgraded to {}", upgradedContext); + + return upgradedContext; } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java deleted file mode 100644 index 9972705a77..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelScope.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package co.elastic.apm.agent.opentelemetry.context; - -import co.elastic.apm.agent.impl.transaction.AbstractSpan; -import io.opentelemetry.context.Scope; - -public class OTelScope implements Scope { - - private final AbstractSpan span; - - public OTelScope(AbstractSpan span) { - this.span = span; - } - - @Override - public void close() { - span.deactivate(); - } -} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java new file mode 100644 index 0000000000..2e0120c9de --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -0,0 +1,143 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.ElasticApmTracer; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.ElasticContext; +import co.elastic.apm.agent.impl.transaction.Transaction; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; +import io.opentelemetry.context.Scope; + +import javax.annotation.Nullable; + +public class OTelBridgeContext implements ElasticContext, Context, Scope { + + /** + * Original root context as returned by {@link Context#root()} before instrumentation. + */ + @Nullable + private static volatile Context originalRootContext; + + /** + * Bridged root context that will be returned by {@link Context#root()} after instrumentation + */ + @Nullable + private static volatile OTelBridgeContext root; + + /** + * OTel context used for key/value storage + */ + private Context otelContext; + + private final ElasticApmTracer tracer; + + private OTelBridgeContext(ElasticApmTracer tracer, Context otelContext) { + this.tracer = tracer; + this.otelContext = otelContext; + } + + /** + * Captures the original root context and setup the bridged root if required + * + * @param tracer tracer + * @param originalRoot original OTel root context + * @return bridged context + */ + public static OTelBridgeContext bridgeRootContext(ElasticApmTracer tracer, Context originalRoot) { + if (root != null) { + return root; + } + + synchronized (OTelBridgeContext.class) { + originalRootContext = originalRoot; + root = new OTelBridgeContext(tracer, originalRoot); + } + return root; + } + + public static OTelBridgeContext wrapElasticActiveSpan(ElasticApmTracer tracer, AbstractSpan span) { + OTelSpan otelSpan = new OTelSpan(span); + return new OTelBridgeContext(tracer, originalRootContext.with(otelSpan)); + } + + @Override + public OTelBridgeContext activate() { + tracer.activate(this); + return this; + } + + @Override + public co.elastic.apm.agent.impl.Scope activateInScope() { + return tracer.activateInScope(this); + } + + @Override + public OTelBridgeContext withActiveSpan(AbstractSpan span) { + // otel context is immutable, thus we have to create new bridged context here + return new OTelBridgeContext(tracer, otelContext.with(new OTelSpan(span))); + } + + @Override + public OTelBridgeContext deactivate() { + tracer.deactivate(this); + return this; + } + + @Nullable + @Override + public AbstractSpan getSpan() { + // get otel span from context + Span span = Span.fromContext(otelContext); + if (span instanceof OTelSpan) { + return ((OTelSpan) span).getInternalSpan(); + } + return null; + } + + @Nullable + @Override + public Transaction getTransaction() { + AbstractSpan span = getSpan(); + return span != null ? span.getTransaction() : null; + } + + @Nullable + @Override + public V get(ContextKey key) { + return otelContext.get(key); + } + + @Override + public Context with(ContextKey key, V value) { + return new OTelBridgeContext(tracer, otelContext.with(key, value)); + } + + @Override + public void close() { + deactivate(); + } + + @Override + public String toString() { + return "OTelBridgeContext[" + otelContext + "]"; + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index fe583cc967..4a09e18503 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -362,4 +362,9 @@ public boolean isRecording() { public AbstractSpan getInternalSpan() { return span; } + + @Override + public String toString() { + return "OtelSpan[" + span + "]"; + } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation index 5d6816c04b..784affed33 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation @@ -1,2 +1,3 @@ co.elastic.apm.agent.opentelemetry.GlobalOpenTelemetryInstrumentation co.elastic.apm.agent.opentelemetry.ContextStorageInstrumentation +co.elastic.apm.agent.opentelemetry.ArrayBasedContextInstrumentation diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 2b21ec4d6c..7ed0ab5c9a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -20,6 +20,9 @@ import co.elastic.apm.agent.AbstractInstrumentationTest; import co.elastic.apm.agent.impl.context.TransactionContext; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.ElasticContext; +import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.opentelemetry.context.OTelContextStorage; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; @@ -30,6 +33,7 @@ import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -56,6 +60,16 @@ public void setUp() { disableRecyclingValidation(); } + @Before + public void before(){ + checkNoContext(); + } + + @After + public void after(){ + checkNoContext(); + } + @Test public void testTransaction() { otelTracer.spanBuilder("transaction") @@ -137,32 +151,6 @@ public void testStartChildAfterEnd() { assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); } - /** - * Demonstrates a missing feature of this bridge: custom context entries are not propagated - * - * @see OTelContextStorage#current() - */ - @Test - @Ignore - public void testPropagateCustomContextKey() { - Span transaction = otelTracer.spanBuilder("transaction") - .startSpan(); - Context context = Context.current() - .with(transaction) - .with(ContextKey.named("foo"), "bar"); - try (Scope scope = context.makeCurrent()) { - assertThat(tracer.getActive().getTraceContext().getId().toString()).isEqualTo(transaction.getSpanContext().getSpanId()); - // this assertion fails as context keys are not propagated - assertThat(Context.current().get(ContextKey.named("foo"))).isEqualTo("bar"); - Span.current().setAttribute("foo", "bar"); - } finally { - transaction.end(); - } - - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); - } - @Test public void testTransactionWithRemoteParent() { Context context = openTelemetry.getPropagators() @@ -209,7 +197,293 @@ public void setStartTimestamp() { assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getFirstTransaction().getTimestamp()).isEqualTo(transactionStartMicros); + } + + @Test + public void otelBridgedRootContext() { + checkBridgedContext(Context.root()); + + assertThat(Context.root()) + .describedAs("wrapped root context should be current") + .isSameAs(Context.current()); + } + + public ElasticContext checkBridgedContext(Context context) { + assertThat(context).isInstanceOf(ElasticContext.class); + + // we have to check classs name as the wrapper class is loaded in the plugin CL and it also loadable from + // the current CL, thus making class equality not work as expected + assertThat(context.getClass().getName()) + .describedAs("root context should be wrapped") + .doesNotStartWith("io.opentelemetry"); + + return (ElasticContext)context; + } + + @Test + public void otelContextStoreAndRetrieve() { + Span span = otelTracer.spanBuilder("span").startSpan(); + + checkNoContext(); + + ContextKey key1 = ContextKey.named("key1"); + Context context1 = Context.current().with(key1, "value1"); + assertThat(context1.get(key1)).isEqualTo("value1"); + + ContextKey key2 = ContextKey.named("key2"); + + try (Scope scope1 = context1.makeCurrent()) { + checkCurrentContext(context1, "first context should be active"); + checkCurrentContextKey(key1, "value1"); + + Context context2 = context1.with(key2, "value2"); + try(Scope scope2 = context2.makeCurrent()){ + checkCurrentContext(context2, "second context should be active"); + checkCurrentContextKey(key1, "value1"); + checkCurrentContextKey(key2, "value2"); + + try (Scope spanScope = span.makeCurrent()) { + assertThat(Context.current()) + .describedAs("span context should have its own context") + .isNotSameAs(context2) + .isNotSameAs(context1); + checkCurrentContextKey(key1, "value1"); + checkCurrentContextKey(key2, "value2"); + } finally { + span.end(); + } + checkCurrentContext(context2, "second context should be restored"); + } + + assertThat(context1.get(key2)) + .describedAs("context should be immutable") + .isNull(); + + checkCurrentContext(context1, "context should be restored"); + } + + checkNoContext(); + + } + + private static void checkCurrentContext(Context expected, String assertMsg) { + assertThat(Context.current()) + .describedAs(assertMsg) + .isSameAs(expected); + + assertThat(expected) + .describedAs("otel context should also be an elastic context") + .isInstanceOf(ElasticContext.class); + + assertThat(tracer.currentContext()) + .describedAs(assertMsg) + .isSameAs(expected); + } + + @Test + public void otelContextRetrieveByKeyReferenceOnly() { + ContextKey key = ContextKey.named("key"); + Context contextWithKey = Context.current().with(key, "value"); + assertThat(contextWithKey.get(key)).isEqualTo("value"); + + String valueWithSameNameKey = contextWithKey.get(ContextKey.named("key")); + assertThat(valueWithSameNameKey) + .describedAs("only key reference should allow to get values in context") + .isNull(); + } + + @Test + public void otelContextRootIdempotent() { + assertThat(Context.root()) + .describedAs("multiple calls to Context.root() should return the same value") + .isSameAs(Context.root()); + } + + @Test + public void otelContextCurrentIdempotent() { + + // create a non-root context by adding a value + ContextKey key = ContextKey.named("key"); + Context context = Context.current().with(key, "value"); + + try (Scope scope = context.makeCurrent()) { + assertThat(context).isNotSameAs(Context.root()); + checkCurrentContext(context, "multiple calls to Context.current() should return the same value"); + checkCurrentContextKey(key, "value"); + } + + assertThat(Context.current().get(key)).isNull(); + } + + @Test + public void otelContextMakeCurrentMoreThanOnce() { + ContextKey key = ContextKey.named("key"); + Context context = Context.current().with(key, "value"); + + try (Scope scope1 = context.makeCurrent()) { + assertThat(scope1).isNotSameAs(Scope.noop()); + checkCurrentContext(context, "first activation should activate context"); + + // here the context is expected to remain the same as it is not modified (we don't add any value to it) + try (Scope scope2 = context.makeCurrent()) { + checkCurrentContext(context, "double activation should keep the same context"); + assertThat(scope2) + .describedAs("nested scope should be noop as context remains the same") + .isSameAs(Scope.noop()); + } + } + } + + @Test + public void contextActivationFromElastic() { + ContextKey key = ContextKey.named("key"); + + Context context = Context.root().with(key, "value"); + ElasticContext bridgedContext = checkBridgedContext(context); + + // activate context from elastic API using a bridged context + try (co.elastic.apm.agent.impl.Scope scope = bridgedContext.activateInScope()) { + + checkCurrentContext(context, "elastic and otel contexts should be the same"); + + checkCurrentContextKey(key, "value"); + + } + } + + + @Test + public void contextActivationFromOtel() { + + ContextKey key = ContextKey.named("key"); + Context context = Context.root().with(key, "value"); + + checkBridgedContext(context); + + // activate context from Otel API + try (Scope scope = context.makeCurrent()) { + + checkCurrentContext(context, "elastic and otel contexts should be the same"); + + checkCurrentContextKey(key, "value"); + } + + } + + private void checkCurrentContextKey(ContextKey key, String expectedValue) { + Context current = Context.current(); + assertThat(current.get(key)) + .describedAs("context %s should contain %s=%s",current, key, expectedValue) + .isEqualTo(expectedValue); + } + + private void checkNoContext() { + assertThat(tracer.currentContext()) + .describedAs("no active elastic context is expected") + .isNull(); + assertThat(Context.current()) + .describedAs("no active otel context is expected") + .isSameAs(Context.root()) + .isNotNull(); + } + + @Test + public void otelStateWithActiveElasticTransaction() { + + Transaction transaction = startTestRootTransaction(); + + try { + assertThat(tracer.currentContext()).isSameAs(transaction); + + assertThat(Context.current()) + .describedAs("current otel context should have elastic span as active") + .isNotSameAs(Context.root()); + + assertThat(Span.current()) + .describedAs("elastic span should appear visible in current context") + .isNotNull(); + + assertThat(tracer.currentContext()) + .describedAs("current context should have been upgraded to otel context") + .isNotNull() + .isNotSameAs(transaction); + + assertThat(tracer.currentTransaction()) + .isSameAs(tracer.currentContext().getSpan()) + .isSameAs(transaction); + } finally { + // this must transparently deactivate the upgraded context + transaction.deactivate().end(); + } + } + + @Test + public void otelSpanOverActiveElasticTransaction() { + Transaction transaction = startTestRootTransaction(); + + String spanId; + try { + + Span otelSpan = openTelemetry.getTracer("test") + .spanBuilder("otel span") + .startSpan(); + + try (Scope scope = otelSpan.makeCurrent()) { + spanId = Span.current().getSpanContext().getSpanId(); + } + + otelSpan.end(); + + } finally { + transaction.deactivate().end(); + } + + assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); + assertThat(reporter.getFirstTransaction()).isSameAs(transaction); + + assertThat(reporter.getNumReportedSpans()).isEqualTo(1); + AbstractSpan reportedSpan = reporter.getFirstSpan().getSpan(); + assertThat(reportedSpan).isNotNull(); + assertThat(reportedSpan.getNameAsString()).isEqualTo("otel span"); + assertThat(reportedSpan.getTraceContext().getId().toString()).isEqualTo(spanId); + assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())); + } + + @Test + public void elasticSpanOverOtelSpan() { + // create and activate an otel span which should create a transaction + // create and activate an elastic span + + Span otelSpan = openTelemetry.getTracer("test") + .spanBuilder("otel transaction") + .startSpan(); + + Transaction transaction; + try (Scope scope = otelSpan.makeCurrent()) { + + transaction = tracer.currentTransaction(); + assertThat(transaction).isNotNull(); + + co.elastic.apm.agent.impl.transaction.Span elasticSpan = transaction.createSpan(); + try (co.elastic.apm.agent.impl.Scope elasticScope = elasticSpan.activateInScope()) { + assertThat(tracer.getActiveSpan()).isNotNull(); + tracer.getActiveSpan().withName("elastic span"); + } finally { + elasticSpan.end(); + } + } finally { + otelSpan.end(); + } + + assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); + assertThat(reporter.getFirstTransaction()).isSameAs(transaction); + assertThat(transaction.getNameAsString()).isEqualTo("otel transaction"); + assertThat(reporter.getNumReportedSpans()).isEqualTo(1); + AbstractSpan reportedSpan = reporter.getFirstSpan().getSpan(); + assertThat(reportedSpan).isNotNull(); + assertThat(reportedSpan.getNameAsString()).isEqualTo("elastic span"); + assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())); } @Test From de91e3f4f6ca9f0deda36893bc3ab402dbb0737e Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Sep 2021 12:44:55 +0200 Subject: [PATCH 41/94] code cleanup --- .../sdk/ElasticOpenTelemetryTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 7ed0ab5c9a..6e2194ce9a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -23,7 +23,6 @@ import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.ElasticContext; import co.elastic.apm.agent.impl.transaction.Transaction; -import co.elastic.apm.agent.opentelemetry.context.OTelContextStorage; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; @@ -35,7 +34,6 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import javax.annotation.Nullable; @@ -61,12 +59,12 @@ public void setUp() { } @Before - public void before(){ + public void before() { checkNoContext(); } @After - public void after(){ + public void after() { checkNoContext(); } @@ -217,7 +215,7 @@ public ElasticContext checkBridgedContext(Context context) { .describedAs("root context should be wrapped") .doesNotStartWith("io.opentelemetry"); - return (ElasticContext)context; + return (ElasticContext) context; } @Test @@ -237,7 +235,7 @@ public void otelContextStoreAndRetrieve() { checkCurrentContextKey(key1, "value1"); Context context2 = context1.with(key2, "value2"); - try(Scope scope2 = context2.makeCurrent()){ + try (Scope scope2 = context2.makeCurrent()) { checkCurrentContext(context2, "second context should be active"); checkCurrentContextKey(key1, "value1"); checkCurrentContextKey(key2, "value2"); @@ -373,7 +371,7 @@ public void contextActivationFromOtel() { private void checkCurrentContextKey(ContextKey key, String expectedValue) { Context current = Context.current(); assertThat(current.get(key)) - .describedAs("context %s should contain %s=%s",current, key, expectedValue) + .describedAs("context %s should contain %s=%s", current, key, expectedValue) .isEqualTo(expectedValue); } @@ -483,7 +481,7 @@ public void elasticSpanOverOtelSpan() { AbstractSpan reportedSpan = reporter.getFirstSpan().getSpan(); assertThat(reportedSpan).isNotNull(); assertThat(reportedSpan.getNameAsString()).isEqualTo("elastic span"); - assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())); + assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())).isTrue(); } @Test From 2db9716daa1d4abd3734b8d6890398b9139a653f Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Sep 2021 13:15:18 +0200 Subject: [PATCH 42/94] code cleanup + update test to 1.6.0 --- .../sdk/ElasticOpenTelemetryTest.java | 14 ++++++++------ .../apm/opentelemetry/OpenTelemetryVersionIT.java | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 6e2194ce9a..ffa8c7a68d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -55,17 +55,19 @@ public void setUp() { this.openTelemetry = GlobalOpenTelemetry.get(); assertThat(openTelemetry).isSameAs(GlobalOpenTelemetry.get()); otelTracer = openTelemetry.getTracer(null); + + // otel spans are not recycled for now disableRecyclingValidation(); } @Before public void before() { - checkNoContext(); + checkNoActiveContext(); } @After public void after() { - checkNoContext(); + checkNoActiveContext(); } @Test @@ -222,7 +224,7 @@ public ElasticContext checkBridgedContext(Context context) { public void otelContextStoreAndRetrieve() { Span span = otelTracer.spanBuilder("span").startSpan(); - checkNoContext(); + checkNoActiveContext(); ContextKey key1 = ContextKey.named("key1"); Context context1 = Context.current().with(key1, "value1"); @@ -260,7 +262,7 @@ public void otelContextStoreAndRetrieve() { checkCurrentContext(context1, "context should be restored"); } - checkNoContext(); + checkNoActiveContext(); } @@ -375,7 +377,7 @@ private void checkCurrentContextKey(ContextKey key, String expectedValue .isEqualTo(expectedValue); } - private void checkNoContext() { + private void checkNoActiveContext() { assertThat(tracer.currentContext()) .describedAs("no active elastic context is expected") .isNull(); @@ -444,7 +446,7 @@ public void otelSpanOverActiveElasticTransaction() { assertThat(reportedSpan).isNotNull(); assertThat(reportedSpan.getNameAsString()).isEqualTo("otel span"); assertThat(reportedSpan.getTraceContext().getId().toString()).isEqualTo(spanId); - assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())); + assertThat(reportedSpan.getTraceContext().isChildOf(transaction.getTraceContext())).isTrue(); } @Test diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index b478aea84d..39a55c2733 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -49,6 +49,7 @@ public static Iterable data() { {"1.3.0"}, {"1.4.1"}, {"1.5.0"}, + {"1.6.0"}, }); } From 717d51f01033806caa6e293a921e794461141c18 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Sep 2021 15:37:44 +0200 Subject: [PATCH 43/94] add missing license header --- .../ArrayBasedContextInstrumentation.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java index 4d2fb42a46..323c127a52 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package co.elastic.apm.agent.opentelemetry; import co.elastic.apm.agent.impl.GlobalTracer; From 1b0804b0803e6b19b7890c7d7ab0d0896deac852 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 15 Sep 2021 09:31:24 +0200 Subject: [PATCH 44/94] minor tweaks --- .../java/co/elastic/apm/agent/impl/ElasticApmTracer.java | 5 +++++ .../agent/opentelemetry/ContextStorageInstrumentation.java | 3 +++ .../agent/opentelemetry/context/OTelContextStorage.java | 7 +++++-- .../apm/agent/opentelemetry/sdk/OTelBridgeContext.java | 7 +++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index 74b439b524..ec224b47e5 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -713,6 +713,11 @@ public Scope activateInScope(final ElasticContext context) { return Scope.NoopScope.INSTANCE; } context.activate(); + + if (context instanceof Scope) { + // we can take shortcut and avoid creating a separate object + return (Scope) context; + } return new Scope() { @Override public void close() { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 736c2fe77a..213827fbef 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -30,6 +30,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; +/** + * Instruments {@link ContextStorage#get()} + */ public class ContextStorageInstrumentation extends AbstractOpenTelemetryInstrumentation { @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index af9581a37b..6fb6d64998 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -53,9 +53,12 @@ public Scope attach(@Nullable Context toAttach) { } if (!(toAttach instanceof OTelBridgeContext)) { - throw new IllegalStateException("unexpected context type "+ toAttach.getClass().getName()); + // likely to be triggered when trying to activate a context created before agent attachment and + // instrumentation. + logger.debug("unexpected context type for attachment {}", toAttach.getClass().getName()); + return Scope.noop(); } - OTelBridgeContext bridgeContext = (OTelBridgeContext)toAttach; + OTelBridgeContext bridgeContext = (OTelBridgeContext) toAttach; tracer.activate(bridgeContext); return bridgeContext; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index 2e0120c9de..2d61f1afdc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -74,6 +74,13 @@ public static OTelBridgeContext bridgeRootContext(ElasticApmTracer tracer, Conte return root; } + /** + * Bridges an active elastic span to an active OTel span context + * + * @param tracer tracer + * @param span elastic span + * @return bridged context + */ public static OTelBridgeContext wrapElasticActiveSpan(ElasticApmTracer tracer, AbstractSpan span) { OTelSpan otelSpan = new OTelSpan(span); return new OTelBridgeContext(tracer, originalRootContext.with(otelSpan)); From b86d00e4bce5797258b3e5ab948443825e36565f Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 21 Sep 2021 10:05:51 +0200 Subject: [PATCH 45/94] fix doc update test fail msg --- .../apm/agent/configuration/ConfigurationExporterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java b/apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java index 12aecc7897..ce1ec0d087 100644 --- a/apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java +++ b/apm-agent/src/test/java/co/elastic/apm/agent/configuration/ConfigurationExporterTest.java @@ -111,7 +111,7 @@ void testGeneratedConfigurationDocsAreUpToDate() throws IOException, TemplateExc assertThat(renderedDocumentation) .withFailMessage("The rendered configuration documentation (/docs/configuration.asciidoc) is not up-to-date.\n" + "If you see this error on CI, it means you have to execute the tests locally " + - "(./mvnw clean test -pl elastic-apm-agent -am -DfailIfNoTests=false -Dtest=ConfigurationExporterTest) " + + "(./mvnw clean test -pl apm-agent -am -DfailIfNoTests=false -Dtest=ConfigurationExporterTest) " + "which will update the rendered docs.\n" + "If you see this error while running the tests locally, there's nothing more to do - the rendered docs have been updated. " + "When you execute this test the next time, it will not fail anymore.") From 5c77c00082c2f391371a7bc61560a6cee49cd020 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 25 Oct 2021 14:43:20 +0200 Subject: [PATCH 46/94] add span kind + wip on shared spec --- .../agent/impl/transaction/AbstractSpan.java | 24 ++ .../agent/impl/transaction/OTelSpanKind.java | 12 + .../test/java/specs/BaseStepDefinitions.java | 23 ++ .../java/specs/OutcomeStepsDefinitions.java | 19 +- .../src/test/java/specs/RunCucumberTest.java | 2 +- ...OutcomeState.java => SpecTracerState.java} | 4 +- .../specs/OutcomeGrpcStepsDefinitions.java | 4 +- .../apm-opentelemetry-plugin/pom.xml | 19 ++ .../ArrayBasedContextInstrumentation.java | 2 +- .../GlobalOpenTelemetryInstrumentation.java | 4 + .../opentelemetry/sdk/OTelBridgeContext.java | 4 + .../apm/agent/opentelemetry/sdk/OTelSpan.java | 16 +- .../opentelemetry/sdk/OTelSpanBuilder.java | 10 + .../sdk/ElasticOpenTelemetryTest.java | 6 +- .../opentelemetry/sdk/OTelInferenceTest.java | 175 +++++++++++ .../opentelemetry/sdk/OTelSpanKindTest.java | 20 ++ .../java/specs/OTelBridgeCucumberTest.java | 11 + .../specs/OTelBridgeStepsDefinitions.java | 279 ++++++++++++++++++ 18 files changed, 608 insertions(+), 26 deletions(-) create mode 100644 apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java rename apm-agent-core/src/test/java/specs/{OutcomeState.java => SpecTracerState.java} (97%) create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java create mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index 9ca484b880..38eebaf4e2 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -30,6 +30,8 @@ import org.slf4j.LoggerFactory; import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -105,6 +107,11 @@ public abstract class AbstractSpan> implements Recycla private boolean hasCapturedExceptions; + @Nullable + private OTelSpanKind otelKind = null; + + private Map otelAttributes = new HashMap<>(); + public int getReferenceCount() { return references.get(); } @@ -353,6 +360,8 @@ public void resetState() { outcome = null; userOutcome = null; hasCapturedExceptions = false; + otelKind = null; + otelAttributes.clear(); } public Span createSpan() { @@ -664,4 +673,19 @@ public ElasticContext withActiveSpan(AbstractSpan span) { public AbstractSpan getSpan() { return this; } + + public T withOtelKind(OTelSpanKind kind) { + this.otelKind = kind; + return thiz(); + } + + @Nullable + public OTelSpanKind getOtelKind() { + return otelKind; + } + + public Map getOtelAttributes() { + return otelAttributes; + } + } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java new file mode 100644 index 0000000000..ad84b75cd8 --- /dev/null +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java @@ -0,0 +1,12 @@ +package co.elastic.apm.agent.impl.transaction; + +/** + * Mirrors OpenTelemetry span kind + */ +public enum OTelSpanKind { + INTERNAL, + SERVER, + CLIENT, + PRODUCER, + CONSUMER +} diff --git a/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java b/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java index a78c39ba48..bc5d1f9c38 100644 --- a/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java +++ b/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java @@ -20,10 +20,33 @@ import io.cucumber.java.en.Given; +import static org.assertj.core.api.Assertions.assertThat; + public class BaseStepDefinitions { + private final SpecTracerState state; + @Given("an agent") public void initAgent() { // not used, use before/after hooks instead for init & cleanup } + + public BaseStepDefinitions(SpecTracerState state) { + this.state = state; + } + + @Given("an active transaction") + public void startTransaction() { + assertThat(state.getTransaction()).isNull(); + + state.startTransaction(); + } + + @Given("an active span") + public void startSpan() { + // spans can't exist outside a transaction, thus we have to create it if not explicitly asked to + state.startRootTransactionIfRequired(); + + state.startSpan(); + } } diff --git a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java index 1423343d6c..fcad21e680 100644 --- a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java +++ b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java @@ -32,27 +32,12 @@ public class OutcomeStepsDefinitions { - private final OutcomeState state; + private final SpecTracerState state; - public OutcomeStepsDefinitions(OutcomeState state) { + public OutcomeStepsDefinitions(SpecTracerState state) { this.state = state; } - @Given("an active transaction") - public void startTransaction() { - assertThat(state.getTransaction()).isNull(); - - state.startTransaction(); - } - - @Given("an active span") - public void startSpan() { - // spans can't exist outside of a transaction, thus we have to create it if not explicitly asked to - state.startRootTransactionIfRequired(); - - state.startSpan(); - } - @Then("{} outcome is {string}") public void thenOutcomeIs(String context, String outcome) { checkOutcome(context.equals("span") ? state.getSpan() : state.getTransaction(), outcome); diff --git a/apm-agent-core/src/test/java/specs/RunCucumberTest.java b/apm-agent-core/src/test/java/specs/RunCucumberTest.java index cb7a6dac20..c82af05854 100644 --- a/apm-agent-core/src/test/java/specs/RunCucumberTest.java +++ b/apm-agent-core/src/test/java/specs/RunCucumberTest.java @@ -23,6 +23,6 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) -@CucumberOptions(strict = true, plugin = {"pretty"}, tags = "not @grpc") +@CucumberOptions(strict = true, plugin = {"pretty"}, tags = "not @grpc and not @opentelemetry-bridge") public class RunCucumberTest { } diff --git a/apm-agent-core/src/test/java/specs/OutcomeState.java b/apm-agent-core/src/test/java/specs/SpecTracerState.java similarity index 97% rename from apm-agent-core/src/test/java/specs/OutcomeState.java rename to apm-agent-core/src/test/java/specs/SpecTracerState.java index 92aeed9753..0007d78f10 100644 --- a/apm-agent-core/src/test/java/specs/OutcomeState.java +++ b/apm-agent-core/src/test/java/specs/SpecTracerState.java @@ -25,13 +25,13 @@ import static org.assertj.core.api.Assertions.assertThat; -public class OutcomeState { +public class SpecTracerState { private final ElasticApmTracer tracer; private Transaction transaction; private Span span; - public OutcomeState() { + public SpecTracerState() { tracer = MockTracer.createRealTracer(); } diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java index 980032cb5f..f05e57d0aa 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java +++ b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java @@ -27,9 +27,9 @@ public class OutcomeGrpcStepsDefinitions { - private final OutcomeState state; + private final SpecTracerState state; - public OutcomeGrpcStepsDefinitions(OutcomeState state) { + public OutcomeGrpcStepsDefinitions(SpecTracerState state) { this.state = state; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 8cea9a1ab5..3bc39ccad8 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -45,6 +45,25 @@ apm-httpclient-core ${project.version} + + + io.cucumber + cucumber-java + ${version.cucumber} + test + + + io.cucumber + cucumber-junit + ${version.cucumber} + test + + + io.cucumber + cucumber-picocontainer + ${version.cucumber} + test + diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java index 323c127a52..59fd4d88c6 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java @@ -37,7 +37,7 @@ /** * Instruments {@code io.opentelemetry.context.ArrayBasedContext#root()} to capture original context root - * and allow relying ot the provided context implementation for key/value storage in context + * and allows relying on the provided context implementation for key/value storage in context */ public class ArrayBasedContextInstrumentation extends AbstractOpenTelemetryInstrumentation { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index 9f8d9ef979..d629220ace 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -21,6 +21,7 @@ import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; import co.elastic.apm.agent.sdk.advice.AssignTo; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -29,6 +30,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; +/** + * Instruments {@link GlobalOpenTelemetry#get()} + */ public class GlobalOpenTelemetryInstrumentation extends AbstractOpenTelemetryInstrumentation { @Override diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index 2d61f1afdc..cad80f0f9a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -127,6 +127,8 @@ public Transaction getTransaction() { return span != null ? span.getTransaction() : null; } + // OTel context implementation + @Nullable @Override public V get(ContextKey key) { @@ -138,6 +140,8 @@ public Context with(ContextKey key, V value) { return new OTelBridgeContext(tracer, otelContext.with(key, value)); } + // OTel scope implementation + @Override public void close() { deactivate(); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 4a09e18503..0f12d3468d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -25,6 +25,7 @@ import co.elastic.apm.agent.impl.context.Url; import co.elastic.apm.agent.impl.context.web.ResultUtil; import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.util.LoggerUtils; @@ -57,6 +58,7 @@ public OTelSpan(AbstractSpan span) { @Override public Span setAttribute(AttributeKey key, @Nonnull T value) { + span.getOtelAttributes().put(key.getKey(), value); mapAttribute(key, value); return this; } @@ -64,7 +66,7 @@ public Span setAttribute(AttributeKey key, @Nonnull T value) { public void mapAttribute(AttributeKey key, Object value) { if (span instanceof Transaction) { mapTransactionAttributes((Transaction) span, key, value); - } else if (span instanceof co.elastic.apm.agent.impl.transaction.Span) { + } else { mapSpanAttributes((co.elastic.apm.agent.impl.transaction.Span) span, key, value); } } @@ -133,6 +135,7 @@ public void end() { private void mapTransactionAttributes(Transaction t, AttributeKey key, Object value) { Request request = t.getContext().getRequest(); Url url = request.getUrl(); + // http.* if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { t.getContext().getResponse().withStatusCode(((Number) value).intValue()); @@ -190,6 +193,17 @@ public String getClientRemoteAddress(AbstractContext context) { private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, AttributeKey key, Object value) { co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); + if (OTelSpanKind.CLIENT == span.getOtelKind()) { + // HTTP client span + if (key.equals(SemanticAttributes.HTTP_URL) || key.equals(SemanticAttributes.HTTP_SCHEME) || key.getKey().startsWith("http.")) { + s.withType("external").withSubtype("http"); + } + if (key.equals(SemanticAttributes.DB_SYSTEM)) { + s.withType("db").withSubtype((String) value); + } + } + + // http.* if (mapHttpUrlAttributes(key, value, context.getHttp().getInternalUrl())) { // successfully mapped inside mapHttpUrlAttributes diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index f9a3f0f52a..dfce606db9 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -21,6 +21,7 @@ import co.elastic.apm.agent.impl.ElasticApmTracer; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import io.opentelemetry.api.common.AttributeKey; @@ -53,6 +54,9 @@ class OTelSpanBuilder implements SpanBuilder { @Nullable private Context remoteContext; + @Nullable + private SpanKind kind; + public OTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { this.spanName = spanName; this.elasticApmTracer = elasticApmTracer; @@ -121,6 +125,7 @@ public SpanBuilder setAttribute(AttributeKey key, @Nonnull T value) { @Override public SpanBuilder setSpanKind(SpanKind spanKind) { + kind = spanKind; return this; } @@ -146,8 +151,13 @@ public Span startSpan() { return Span.getInvalid(); } span.withName(spanName); + if (kind != null) { + span.withOtelKind(OTelSpanKind.valueOf(kind.name())); + } OTelSpan otelSpan = new OTelSpan(span); attributes.forEach(otelSpan::mapAttribute); + otelSpan.inferAttributes(); return otelSpan; } + } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index ffa8c7a68d..ffcf175931 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -109,7 +109,9 @@ public void testTransactionWithSpanManualPropagation() { assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + Transaction reportedTransaction = reporter.getFirstTransaction(); + assertThat(reportedTransaction.getNameAsString()).isEqualTo("transaction"); + assertThat(reporter.getFirstSpan().getNameAsString()).isEqualTo("span"); assertThat(reporter.getFirstSpan().isChildOf(reporter.getFirstTransaction())).isTrue(); } @@ -211,7 +213,7 @@ public void otelBridgedRootContext() { public ElasticContext checkBridgedContext(Context context) { assertThat(context).isInstanceOf(ElasticContext.class); - // we have to check classs name as the wrapper class is loaded in the plugin CL and it also loadable from + // we have to check class name as the wrapper class is loaded in the plugin CL and it is also loadable from // the current CL, thus making class equality not work as expected assertThat(context.getClass().getName()) .describedAs("root context should be wrapped") diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java new file mode 100644 index 0000000000..a2b76394bf --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java @@ -0,0 +1,175 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.AbstractInstrumentationTest; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.Transaction; +import com.fasterxml.jackson.databind.JsonNode; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import specs.TestJsonSpec; + +import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.Locale; +import java.util.Optional; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OTelInferenceTest extends AbstractInstrumentationTest { + + private OpenTelemetry otel; + private Tracer otelTracer; + + @BeforeEach + void setUp() { + this.otel = GlobalOpenTelemetry.get(); + assertThat(otel).isSameAs(GlobalOpenTelemetry.get()); + otelTracer = otel.getTracer(null); + + // otel spans are not recycled for now + disableRecyclingValidation(); + } + + @ParameterizedTest + @MethodSource("getTestCases") + void runTest(JsonNode testCase) { + + String description = textAttribute(testCase, "description_message"); + boolean createSpan = textAttribute(testCase, "object_to_create").equals("span"); + + JsonNode jsonOtelSpan = testCase.get("otel_span"); + + SpanKind kind = SpanKind.valueOf(textAttribute(jsonOtelSpan, "kind").toUpperCase(Locale.ROOT)); + + JsonNode jsonAttributes = jsonOtelSpan.get("attributes"); + + String expectedType = textAttribute(testCase, "expected_type"); + String expectedSubType = optionalTextAttribute(testCase, "expected_subtype"); + String expectedResource = optionalTextAttribute(testCase, "expected_resource"); + + if (!createSpan) { + assertThat(expectedSubType) + .describedAs("subtype should not be set for transactions") + .isNull(); + assertThat(expectedResource) + .describedAs("resource should not be set for transactions") + .isNull(); + } + + AbstractSpan elasticSpan; + + if (createSpan) { + testSpan(description, kind, jsonAttributes); + + assertThat(reporter.getNumReportedSpans()).isEqualTo(1); + assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); + + elasticSpan = reporter.getFirstSpan(); + + assertThat(elasticSpan).isInstanceOf(co.elastic.apm.agent.impl.transaction.Span.class); + co.elastic.apm.agent.impl.transaction.Span span = (co.elastic.apm.agent.impl.transaction.Span) elasticSpan; + + assertThat(span.getType()) + .isEqualTo(expectedType); + + assertThat(span.getSubtype()) + .isEqualTo(expectedSubType); + + if(expectedResource != null){ + assertThat(span.getContext().getDestination().getService().getResource().toString()) + .isEqualTo(expectedResource); + } + + } else { + testTransaction(description, kind, jsonAttributes); + + assertThat(reporter.getNumReportedSpans()).isEqualTo(0); + assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); + + elasticSpan = reporter.getFirstTransaction(); + + assertThat(elasticSpan).isNotNull(); + + assertThat(elasticSpan).isInstanceOf(Transaction.class); + Transaction transaction = (Transaction) elasticSpan; + + + + assertThat(transaction.getType()) + .isEqualTo(expectedType); + } + + } + + private Span testTransaction(String description, SpanKind kind, JsonNode attributes) { + Span span = startOtelSpan(String.format("transaction %s", description), kind); + applyOtelAttributes(span, attributes); + span.end(); + return span; + } + + private Span testSpan(String description, SpanKind kind, JsonNode attributes) { + Span transactionSpan = startOtelSpan(String.format("parent transaction for %s", description), SpanKind.SERVER); + Span spanSpan = startOtelSpan(String.format("span %s", description), kind); + applyOtelAttributes(spanSpan, attributes); + spanSpan.end(); + transactionSpan.end(); + return spanSpan; + } + + private Span startOtelSpan(String name, SpanKind kind) { + return otelTracer.spanBuilder(name) + .setSpanKind(kind) + .startSpan(); + } + + private void applyOtelAttributes(Span span, JsonNode attributes) { + attributes.fields() + .forEachRemaining(e -> { + JsonNode jsonValue = e.getValue(); + if (jsonValue.isBoolean()) { + span.setAttribute(e.getKey(), jsonValue.asBoolean()); + } else if (jsonValue.isNumber()) { + span.setAttribute(e.getKey(), jsonValue.asLong()); + } else if (jsonValue.isTextual()) { + span.setAttribute(e.getKey(), jsonValue.asText()); + } else { + throw new IllegalStateException(); + } + }); + } + + private static String textAttribute(JsonNode json, String name) { + return Optional.ofNullable(json.get(name)) + .map(JsonNode::asText) + .orElseThrow(()-> new IllegalStateException("missing mandatory attribute " + name)); + } + + @Nullable + private static String optionalTextAttribute(JsonNode json, String name) { + return Optional.ofNullable(json.get(name)) + .map(v -> v.isNull() ? null : v.asText()) + .orElse(null); + } + + private static Stream> getTestCases() { + Iterator iterator = TestJsonSpec.getJson("otel_bridge_inference.json").iterator(); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) + .map(test -> { + String description = test.get("description_message").asText(); + assertThat(description).isNotNull().isNotEmpty(); + return Named.of(description, test); + }); + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java new file mode 100644 index 0000000000..4cdfb7dce0 --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java @@ -0,0 +1,20 @@ +package co.elastic.apm.agent.opentelemetry.sdk; + +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; +import io.opentelemetry.api.trace.SpanKind; +import org.junit.jupiter.api.Test; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OTelSpanKindTest { + + @Test + void checkSpanKindMapping() { + assertThat(Stream.of(OTelSpanKind.values()).map(Enum::name).collect(Collectors.toSet())) + .containsExactlyElementsOf(Stream.of(SpanKind.values()).map(Enum::name).collect(Collectors.toSet())); + + } +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java new file mode 100644 index 0000000000..664d730b0d --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java @@ -0,0 +1,11 @@ +package specs; + +import io.cucumber.junit.Cucumber; +import io.cucumber.junit.CucumberOptions; +import org.junit.runner.RunWith; + +@RunWith(Cucumber.class) +@CucumberOptions(strict = true, plugin = {"pretty"}, tags = "@opentelemetry-bridge and @wip") +public class OTelBridgeCucumberTest { + +} diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java new file mode 100644 index 0000000000..0cdfe497bb --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java @@ -0,0 +1,279 @@ +package specs; + +import co.elastic.apm.agent.impl.Scope; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; +import co.elastic.apm.agent.impl.transaction.Span; +import co.elastic.apm.agent.impl.transaction.TraceContext; +import co.elastic.apm.agent.impl.transaction.Transaction; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; +import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetryTest; +import co.elastic.apm.agent.opentelemetry.sdk.OTelSpan; +import io.cucumber.java.Before; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OTelBridgeStepsDefinitions { + + private static final String REMOTE_PARENT_TRACE_ID = "cafebabe16cd43dd8448eb211c80319c"; + private static final String REMOTE_PARENT_ID = "deadbeef197918e1"; + + private final ElasticOpenTelemetry otel; + + // state will contain the Elastic state when created before OTel + // this is required for shared steps definitions like 'an active transaction' + private final SpecTracerState state; + + private OTelSpan otelSpan; + private boolean isOtelSpanEnded; + + private Map otelSpanAttributes; + + private Context localParentContext = null; + + public OTelBridgeStepsDefinitions(SpecTracerState state) { + this.state = state; + this.otel = new ElasticOpenTelemetry(state.getTracer()); + } + + @Before + public void resetState() { + this.otelSpan = null; + this.localParentContext = null; + this.otelSpanAttributes = new HashMap<>(); + this.isOtelSpanEnded = false; + } + + // creating elastic span or transaction from OTel span + + @Given("OTel span is created with remote context as parent") + public void createOTelSpanWithRemoteContext() { + otelSpan = (OTelSpan) otel.getTracer("") + .spanBuilder("otel span") + .setParent(getRemoteContext()) + .startSpan(); + + assertThat(otelSpan.getSpanContext().getTraceId()).isEqualTo(REMOTE_PARENT_TRACE_ID); + } + + @Then("Elastic bridged transaction has remote context as parent") + public void bridgedTransactionWithRemoteContextParent() { + TraceContext traceContext = getBridgedTransaction().getTraceContext(); + assertThat(traceContext.isRoot()).isFalse(); + assertThat(traceContext.getParentId().toString()).isEqualTo(REMOTE_PARENT_ID); + assertThat(traceContext.getTraceId().toString()).isEqualTo(REMOTE_PARENT_TRACE_ID); + } + + private Context getRemoteContext(){ + return otel.getPropagators() + .getTextMapPropagator() + .extract(Context.current(), + Map.of("traceparent", String.format("00-%s-%s-01", REMOTE_PARENT_TRACE_ID, REMOTE_PARENT_ID), + "tracestate", "k=v"), + new ElasticOpenTelemetryTest.MapGetter()); + } + + @Given("OTel span is created without parent") + public void createOTelSpanWithoutParent(){ + otelSpan = (OTelSpan) otel.getTracer("") + .spanBuilder("otel span") + .setNoParent() // redundant, but makes it explicit + .startSpan(); + } + + @Then("Elastic bridged transaction is a root transaction") + public void bridgedTransactionIsRootTransaction() { + TraceContext traceContext = getBridgedTransaction().getTraceContext(); + assertThat(traceContext.isRoot()).isTrue(); + } + + @Given("OTel span is created with local context as parent") + public void createOTelSpanWithLocalParent() { + localParentContext = Context.root().with(otel.getTracer("").spanBuilder("parent").startSpan()); + + otelSpan = (OTelSpan) otel.getTracer("") + .spanBuilder("otel span") + .setParent(localParentContext) + .startSpan(); + + } + + @Then("Elastic bridged span has local context as parent") + public void bridgedSpanHasLocalParent() { + assertThat(localParentContext).isNotNull(); + + SpanContext otelParentContext = io.opentelemetry.api.trace.Span.fromContext(localParentContext).getSpanContext(); + + TraceContext bridgedSpanContext = getBridgedSpan().getTraceContext(); + assertThat(bridgedSpanContext.getTraceId().toString()).isEqualTo(otelParentContext.getTraceId()); + assertThat(bridgedSpanContext.getParentId().toString()).isEqualTo(otelParentContext.getSpanId()); + } + + // OTel span kind mapping for spans & transactions + + @Given("OTel span is created with kind {string}") + public void otelSpanIsCreatedWithKind(String kind) { + // we have to use a parent transaction as we are creating a span + // the parent transaction is created by another step definition, thus we reuse the existing state + Transaction parentTransaction = state.getTransaction(); + + Function createSpanWithKind = k -> { + SpanBuilder spanBuilder = otel.getTracer("") + .spanBuilder("span") + .setSpanKind(SpanKind.valueOf(k)); + return (OTelSpan) spanBuilder.startSpan(); + }; + + if( parentTransaction != null){ + // creating a span as a child of existing transaction + try (Scope scope = parentTransaction.activateInScope()) { + this.otelSpan = createSpanWithKind.apply(kind); + } + } else { + // creating a root transaction + this.otelSpan = createSpanWithKind.apply(kind); + } + + } + + @Given("OTel span has following attributes") + public void otelSpanAttributes(io.cucumber.datatable.DataTable table) { + table.cells().forEach(r -> { + String key = r.get(0); + String stringValue = r.get(1); + if (stringValue != null) { + AttributeKey attributeKey = lookupKey(key); + + Object valueAsObject; + switch (attributeKey.getType()) { + case LONG: + Long longValue = Long.parseLong(stringValue); + otelSpan.setAttribute(attributeKey, longValue); + valueAsObject = longValue; + break; + case BOOLEAN: + Boolean booleanValue = Boolean.parseBoolean(stringValue); + otelSpan.setAttribute(attributeKey, booleanValue); + valueAsObject = booleanValue; + break; + default: + otelSpan.setAttribute(key, stringValue); + valueAsObject = stringValue; + } + otelSpanAttributes.put(key, valueAsObject); + } + }); + } + + private static AttributeKey lookupKey(String name) { + switch (name) { + case "http.url": + return SemanticAttributes.HTTP_URL; + case "http.scheme": + return SemanticAttributes.HTTP_SCHEME; + case "http.host": + return SemanticAttributes.HTTP_HOST; + case "net.peer.name": + return SemanticAttributes.NET_PEER_NAME; + case "net.peer.ip": + return SemanticAttributes.NET_PEER_IP; + case "net.peer.port": + return SemanticAttributes.NET_PEER_PORT; + case "db.system": + return SemanticAttributes.DB_SYSTEM; + default: + throw new IllegalArgumentException("unknown key for name " + name); + } + } + + @Then("Elastic bridged (transaction|span) OTel kind is {string}") + public void bridgeObjectKind(String kind){ + assertThat(getBridgedAbstractSpan().getOtelKind()) + .isEqualTo(OTelSpanKind.valueOf(kind)); + } + + @Then("Elastic bridged object is a span") + public void bridgeObjectTypeSpan() { + getBridgedSpan(); + } + + @Then("Elastic bridged object is a transaction") + public void bridgeObjectTypeTransaction() { + getBridgedTransaction(); + } + + @Then("Elastic bridged (transaction|span) type is {string}") + public void bridgeObjectType(String expected) { + AbstractSpan bridgedObject = getBridgedAbstractSpan(); + String type; + if (bridgedObject instanceof Transaction) { + type = ((Transaction) bridgedObject).getType(); + } else { + type = ((Span) bridgedObject).getType(); + } + + assertThat(type).isEqualTo(expected); + } + + @Then("Elastic bridged span subtype is {string}") + public void bridgeObjectSubtype(String expected) { + assertThat(getBridgedSpan().getSubtype()).isEqualTo(expected); + } + + @Then("Elastic bridged span OTel attributes are copied as-is") + public void bridgeObjectOTelAttributesCheck() { + assertThat(otelSpan.getInternalSpan().getOtelAttributes()) + .containsExactlyEntriesOf(otelSpanAttributes); + } + + @Then("Elastic bridged span destination resource is not set") + public void bridgeObjectDestinationResourceNotSet() { + assertThat(getDestinationResource()).isEmpty(); + } + + @Then("Elastic bridged span destination resource is set to {string}") + public void bridgeObjectDestinationResource(String expected) { + assertThat(getDestinationResource()).isEqualTo(expected); + } + + private String getDestinationResource() { + return getBridgedSpan().getContext().getDestination().getService().getResource().toString(); + } + + private AbstractSpan getBridgedAbstractSpan() { + return getBridgedObject(AbstractSpan.class); + } + + private Transaction getBridgedTransaction() { + return getBridgedObject(Transaction.class); + } + + private Span getBridgedSpan() { + return getBridgedObject(Span.class); + } + + private > T getBridgedObject(Class expectedType) { + // span should be ended lazily on first access as part of the mapping is performed when ending the span + if (!isOtelSpanEnded) { + otelSpan.end(); + isOtelSpanEnded = true; + } + + AbstractSpan internalSpan = otelSpan.getInternalSpan(); + assertThat(internalSpan).isInstanceOf(expectedType); + return expectedType.cast(internalSpan); + } + +} From 214ae74f60f19d15338774088ac39ee1de52618d Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 25 Oct 2021 14:44:57 +0200 Subject: [PATCH 47/94] add wip gherkin spec --- .../test/resources/specs/otel_bridge.feature | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 apm-agent-core/src/test/resources/specs/otel_bridge.feature diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature new file mode 100644 index 0000000000..0d9134e2ee --- /dev/null +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -0,0 +1,119 @@ +@opentelemetry-bridge +Feature: OpenTelemetry bridge + + # --- Creating Elastic span or transaction from OTel span + + Sceario: Create transaction from OTel span with remote context + Given an agent + And OTel span is created with remote context as parent + Then Elastic bridged object is a transaction + Then Elastic bridged transaction has remote context as parent + + Scenario: Create root transaction from OTel span without parent + Given an agent + And OTel span is created without parent + Then Elastic bridged object is a transaction + Then Elastic bridged transaction is a root transaction + + Scenario: Create span from OTel span + Given an agent + And OTel span is created with local context as parent + Then Elastic bridged object is a span + Then Elastic bridged span has local context as parent + + # --- OTel span kind mapping for spans & transactions + + Scenario Outline: OTel span kind is transmitted as-is for spans + Given an agent + And an active transaction + And OTel span is created with kind "" + Then Elastic bridged object is a span + Then Elastic bridged span OTel kind is "" + Examples: + | kind | + | INTERNAL | + | SERVER | + | CLIENT | + | PRODUCER | + | CONSUMER | + + Scenario Outline: OTel span kind is transmitted as-is for transactions + Given an agent + And OTel span is created with kind "" + Then Elastic bridged object is a transaction + Then Elastic bridged transaction OTel kind is "" + Examples: + | kind | + | INTERNAL | + | SERVER | + | CLIENT | + | PRODUCER | + | CONSUMER | + + + # --- span type, subtype and action inference from OTel attributes + + # --- HTTP client + + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client + @wip + Scenario Outline: HTTP client [ ] + Given an agent + And an active transaction + And OTel span is created with kind 'CLIENT' + And OTel span has following attributes + | http.url | | + | http.scheme | | + | http.host | | + | net.peer.ip | | + | net.peer.name | | + | net.peer.port | | + Then Elastic bridged span type is 'external' + Then Elastic bridged span subtype is 'http' + Then Elastic bridged span OTel attributes are copied as-is + Then Elastic bridged span destination resource is set to "" + Examples: + | http.url | http.scheme | http.host | net.peer.ip | net.peer.name | net.peer.port | resource | + | https://testing.invalid:8443/ | | | | | | testing.invalid:8443 | + | https://testing.invalid/ | | | | | | testing.invalid | + | http://testing.invalid/ | | | | | | testing.invalid | + | | http | testing.invalid | | | | testing.invalid | + | | https | testing.invalid | 127.0.0.1 | | | testing.invalid | + | | http | | 127.0.0.1 | | 81 | 127.0.0.1:81 | + | | https | | 127.0.0.1 | | 445 | 127.0.0.1:445 | + | | http | | 127.0.0.1 | host1 | 445 | host1:445 | + | | https | | 127.0.0.1 | host2 | 445 | host2:445 | + + # --- DB client + + @wip + @db-client + Scenario Outline: DB client [ ] + Given an agent + And an active transaction + And OTel span is created with kind 'CLIENT' + And OTel span has following attributes + | db.system | | + | net.peer.ip | | + | net.peer.name | | + | net.peer.port | | + Then Elastic bridged span type is 'db' + Then Elastic bridged span subtype is "" + Then Elastic bridged span OTel attributes are copied as-is + Then Elastic bridged span destination resource is set to "" + Examples: + | db.system | net.peer.ip | net.peer.name | net.peer.port | resource | + | mysql | | | | mysql:3306 | + | oracle | | oracledb | | oracledb:1521 | + | oracle | 127.0.0.1 | | | 127.0.0.1:1521 | + | mysql | 127.0.0.1 | dbserver | 3307 | dbserver:3307 | + + + # --- Messaging producer (client span emitting a message) + + # --- RPC client + + + # --- TODO : Messaging + + From 86e5b1cccde80db7e9caa7df08783dca95ba19fb Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 25 Oct 2021 14:55:05 +0200 Subject: [PATCH 48/94] add missing file headers --- .../agent/impl/transaction/OTelSpanKind.java | 18 ++++++++++++++++++ .../latest/testapp/generated/HelloGrpc.java | 2 +- .../opentelemetry/sdk/OTelInferenceTest.java | 18 ++++++++++++++++++ .../opentelemetry/sdk/OTelSpanKindTest.java | 18 ++++++++++++++++++ .../java/specs/OTelBridgeCucumberTest.java | 18 ++++++++++++++++++ .../java/specs/OTelBridgeStepsDefinitions.java | 18 ++++++++++++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java index ad84b75cd8..1193891586 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/OTelSpanKind.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package co.elastic.apm.agent.impl.transaction; /** diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/src/test/java/co/elastic/apm/agent/grpc/latest/testapp/generated/HelloGrpc.java b/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/src/test/java/co/elastic/apm/agent/grpc/latest/testapp/generated/HelloGrpc.java index 9f0da2dc0a..b87b46aeb5 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/src/test/java/co/elastic/apm/agent/grpc/latest/testapp/generated/HelloGrpc.java +++ b/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/src/test/java/co/elastic/apm/agent/grpc/latest/testapp/generated/HelloGrpc.java @@ -23,7 +23,7 @@ /** */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.40.1)", + value = "by gRPC proto compiler (version 1.41.0)", comments = "Source: rpc.proto") @io.grpc.stub.annotations.GrpcGenerated public final class HelloGrpc { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java index a2b76394bf..b02246918e 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.AbstractInstrumentationTest; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java index 4cdfb7dce0..ad6c14da33 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.impl.transaction.OTelSpanKind; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java index 664d730b0d..2d9abaf329 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package specs; import io.cucumber.junit.Cucumber; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java index 0cdfe497bb..b3b8e980ef 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java @@ -1,3 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package specs; import co.elastic.apm.agent.impl.Scope; From f0629cce867ecaac205e9928700e7d800f5c54a4 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 25 Oct 2021 21:43:05 +0200 Subject: [PATCH 49/94] wip http + db span mapping --- .../test/resources/specs/otel_bridge.feature | 19 ++- .../apm/agent/opentelemetry/sdk/OTelSpan.java | 121 ++++++++++++++---- .../java/specs/OTelBridgeCucumberTest.java | 2 +- .../specs/OTelBridgeStepsDefinitions.java | 4 +- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index 0d9134e2ee..8c30af0093 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -3,7 +3,7 @@ Feature: OpenTelemetry bridge # --- Creating Elastic span or transaction from OTel span - Sceario: Create transaction from OTel span with remote context + Scenario: Create transaction from OTel span with remote context Given an agent And OTel span is created with remote context as parent Then Elastic bridged object is a transaction @@ -56,7 +56,6 @@ Feature: OpenTelemetry bridge # --- HTTP client # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client - @wip Scenario Outline: HTTP client [ ] Given an agent And an active transaction @@ -75,10 +74,10 @@ Feature: OpenTelemetry bridge Examples: | http.url | http.scheme | http.host | net.peer.ip | net.peer.name | net.peer.port | resource | | https://testing.invalid:8443/ | | | | | | testing.invalid:8443 | - | https://testing.invalid/ | | | | | | testing.invalid | - | http://testing.invalid/ | | | | | | testing.invalid | - | | http | testing.invalid | | | | testing.invalid | - | | https | testing.invalid | 127.0.0.1 | | | testing.invalid | + | https://[::1]/ | | | | | | [::1]:443 | + | http://testing.invalid/ | | | | | | testing.invalid:80 | + | | http | testing.invalid | | | | testing.invalid:80 | + | | https | testing.invalid | 127.0.0.1 | | | testing.invalid:443 | | | http | | 127.0.0.1 | | 81 | 127.0.0.1:81 | | | https | | 127.0.0.1 | | 445 | 127.0.0.1:445 | | | http | | 127.0.0.1 | host1 | 445 | host1:445 | @@ -86,8 +85,6 @@ Feature: OpenTelemetry bridge # --- DB client - @wip - @db-client Scenario Outline: DB client [ ] Given an agent And an active transaction @@ -103,9 +100,9 @@ Feature: OpenTelemetry bridge Then Elastic bridged span destination resource is set to "" Examples: | db.system | net.peer.ip | net.peer.name | net.peer.port | resource | - | mysql | | | | mysql:3306 | - | oracle | | oracledb | | oracledb:1521 | - | oracle | 127.0.0.1 | | | 127.0.0.1:1521 | + | mysql | | | | mysql | + | oracle | | oracledb | | oracledb | + | oracle | 127.0.0.1 | | | 127.0.0.1 | | mysql | 127.0.0.1 | dbserver | 3307 | dbserver:3307 | diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 0f12d3468d..4c38811cd6 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -18,9 +18,7 @@ */ package co.elastic.apm.agent.opentelemetry.sdk; -import co.elastic.apm.agent.http.client.HttpClientHelper; import co.elastic.apm.agent.impl.context.AbstractContext; -import co.elastic.apm.agent.impl.context.Destination; import co.elastic.apm.agent.impl.context.Request; import co.elastic.apm.agent.impl.context.Url; import co.elastic.apm.agent.impl.context.web.ResultUtil; @@ -237,34 +235,111 @@ else if (key.equals(SemanticAttributes.DB_SYSTEM)) { } private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { - co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); - Destination destination = context.getDestination(); - if (context.getHttp().hasContent()) { + + Map attributes = s.getOtelAttributes(); + + String type = null; + String subType = null; + StringBuilder destinationResource = s.getContext().getDestination().getService().getResource(); + + String netPeerIp = (String) attributes.get("net.peer.ip"); + String netPeerName = (String) attributes.get("net.peer.name"); + Long port = (Long) attributes.get("net.peer.port"); + if (null != port && port < 0) { + port = null; + } + + String netPeer = netPeerName != null ? netPeerName : netPeerIp; + + String httpUrl = (String) attributes.get("http.url"); + String httpScheme = (String) attributes.get("http.scheme"); + String dbSystem = (String) attributes.get("db.system"); + String messagingSystem = (String) attributes.get("messaging.system"); + if (null != dbSystem) { + type = "db"; + subType = dbSystem; + destinationResource.append(netPeer != null ? netPeer : dbSystem); + } else if (messagingSystem != null) { + type = "messaging"; + subType = messagingSystem; + String messagingDestination = (String) attributes.get("messaging.destination"); + if (messagingDestination != null) { + destinationResource.append(messagingSystem).append('/').append(messagingDestination); + port = null; // skip appending port when destination is known + } else { + destinationResource.append(netPeer != null ? netPeer : messagingSystem); + } + } else if (httpUrl != null || httpScheme != null) { + type = "external"; + subType = "http"; s.withType("external").withSubtype("http"); - Url url = context.getHttp().getInternalUrl(); - if (context.getDestination().getAddress().length() > 0) { - url.withHostname(context.getDestination().getAddress().toString()); + + String httpHost = (String) attributes.get("http.host"); + if (null == httpHost) { + httpHost = netPeer; } - if (context.getDestination().getPort() > 0) { - url.withPort(context.getDestination().getPort()); + if (httpHost == null && httpUrl != null) { + // use HTTP context internal for temp parsing without extra allocation + Url internalUrl = s.getContext().getHttp().getInternalUrl(); + internalUrl.withFull(httpUrl); + httpHost = internalUrl.getHostname(); + port = (long) internalUrl.getPort(); + internalUrl.resetState(); } - HttpClientHelper.setDestinationServiceDetails(s, url.getProtocol(), url.getHostname(), url.getPort()); - } else if (context.getDb().hasContent()) { - s.withType("db").withSubtype(context.getDb().getType()); - if (s.getSubtype() != null) { - destination - .getService() - .withName(s.getSubtype()) - .withResource(s.getSubtype()) - .withType("db"); + if (httpHost != null) { + destinationResource.append(httpHost); } - } else { - s.withType("app"); - if (destination.getService().hasContent()) { - destination.getService().withType("app"); + + if (port == null) { + if ("http".equals(httpScheme)) { + port = 80L; + } else if ("https".equals(httpScheme)) { + port = 443L; + } } + } else { + } + + if (port != null) { + destinationResource.append(':').append(port); } + + s.withType(type).withSubtype(subType); + + +// co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); +// Destination destination = context.getDestination(); +// if (context.getHttp().hasContent()) { +// s.withType("external").withSubtype("http"); +// Url url = context.getHttp().getInternalUrl(); +// if (context.getDestination().getAddress().length() > 0) { +// url.withHostname(context.getDestination().getAddress().toString()); +// } +// if (context.getDestination().getPort() > 0) { +// url.withPort(context.getDestination().getPort()); +// } +// +// HttpClientHelper.setDestinationServiceDetails(s, url.getProtocol(), url.getHostname(), url.getPort()); +// } else if (context.getDb().hasContent()) { +// s.withType("db").withSubtype(context.getDb().getType()); +// if (s.getSubtype() != null) { +// destination +// .getService() +// .withName(s.getSubtype()) +// .withResource(s.getSubtype()) +// .withType("db"); +// } +//// } else { +//// s.withType("app"); +//// if (destination.getService().hasContent()) { +//// destination.getService().withType("app"); +//// } +// } + } + + private void getResource() { + } /** diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java index 2d9abaf329..64d83a3bce 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java @@ -23,7 +23,7 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) -@CucumberOptions(strict = true, plugin = {"pretty"}, tags = "@opentelemetry-bridge and @wip") +@CucumberOptions(strict = true, plugin = {"pretty"}, tags = "@opentelemetry-bridge") public class OTelBridgeCucumberTest { } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java index b3b8e980ef..031b014f96 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java @@ -263,7 +263,9 @@ public void bridgeObjectDestinationResourceNotSet() { @Then("Elastic bridged span destination resource is set to {string}") public void bridgeObjectDestinationResource(String expected) { - assertThat(getDestinationResource()).isEqualTo(expected); + assertThat(getDestinationResource()) + .describedAs("destination resource expected for otel attributes: %s", getBridgedSpan().getOtelAttributes()) + .isEqualTo(expected); } private String getDestinationResource() { From 73f29a3b04335fa68ac88dc3eb45408929dd0314 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 26 Oct 2021 17:18:25 +0200 Subject: [PATCH 50/94] finalize 1st tep of bridge --- .../elastic/apm/agent/impl/context/Url.java | 2 +- .../test/resources/specs/otel_bridge.feature | 126 +++++-- .../apm/agent/opentelemetry/sdk/OTelSpan.java | 324 ++++-------------- .../opentelemetry/sdk/OTelSpanBuilder.java | 3 +- .../specs/OTelBridgeStepsDefinitions.java | 15 + 5 files changed, 193 insertions(+), 277 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java index 9e145167ea..7b82da35e4 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/context/Url.java @@ -260,7 +260,7 @@ public void parseAndFillFromFull() { } } - private static int normalizePort(int port, @Nullable String protocol) { + public static int normalizePort(int port, @Nullable String protocol) { int portValue = port; if (portValue < 0 && protocol != null) { // Work around java.net.URL bug diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index 8c30af0093..aebfdc4ed2 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -23,25 +23,28 @@ Feature: OpenTelemetry bridge # --- OTel span kind mapping for spans & transactions - Scenario Outline: OTel span kind is transmitted as-is for spans + Scenario Outline: OTel span kind for spans & default span type & subtype Given an agent And an active transaction And OTel span is created with kind "" Then Elastic bridged object is a span Then Elastic bridged span OTel kind is "" + Then Elastic bridged span type is "" + Then Elastic bridged span subtype is "" Examples: - | kind | - | INTERNAL | - | SERVER | - | CLIENT | - | PRODUCER | - | CONSUMER | - - Scenario Outline: OTel span kind is transmitted as-is for transactions + | kind | default_type | default_subtype | + | INTERNAL | app | internal | + | SERVER | custom | | + | CLIENT | custom | | + | PRODUCER | custom | | + | CONSUMER | custom | | + + Scenario Outline: OTel span kind for transactions & default transaction type Given an agent And OTel span is created with kind "" Then Elastic bridged object is a transaction Then Elastic bridged transaction OTel kind is "" + Then Elastic bridged transaction type is 'custom' Examples: | kind | | INTERNAL | @@ -50,11 +53,24 @@ Feature: OpenTelemetry bridge | PRODUCER | | CONSUMER | - # --- span type, subtype and action inference from OTel attributes - # --- HTTP client + # --- HTTP server + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-server + Scenario Outline: HTTP server [ ] + Given an agent + And OTel span is created with kind 'SERVER' + And OTel span has following attributes + | http.url | | + | http.scheme | | + Then Elastic bridged object is a transaction + Then Elastic bridged transaction type is "request" + Examples: + | http.url | http.scheme | + | http://testing.invalid/ | | + | | http | + # --- HTTP client # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client Scenario Outline: HTTP client [ ] Given an agent @@ -84,13 +100,14 @@ Feature: OpenTelemetry bridge | | https | | 127.0.0.1 | host2 | 445 | host2:445 | # --- DB client - + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md Scenario Outline: DB client [ ] Given an agent And an active transaction And OTel span is created with kind 'CLIENT' And OTel span has following attributes | db.system | | + | db.name | | | net.peer.ip | | | net.peer.name | | | net.peer.port | | @@ -99,18 +116,85 @@ Feature: OpenTelemetry bridge Then Elastic bridged span OTel attributes are copied as-is Then Elastic bridged span destination resource is set to "" Examples: - | db.system | net.peer.ip | net.peer.name | net.peer.port | resource | - | mysql | | | | mysql | - | oracle | | oracledb | | oracledb | - | oracle | 127.0.0.1 | | | 127.0.0.1 | - | mysql | 127.0.0.1 | dbserver | 3307 | dbserver:3307 | - + | db.system | db.name | net.peer.ip | net.peer.name | net.peer.port | resource | + | mysql | | | | | mysql | + | oracle | | | oracledb | | oracledb | + | oracle | | 127.0.0.1 | | | 127.0.0.1 | + | mysql | | 127.0.0.1 | dbserver | 3307 | dbserver:3307 | + | mysql | myDb | | | | mysql/myDb | + | oracle | myDb | | oracledb | | oracledb/myDb | + | oracle | myDb | 127.0.0.1 | | | 127.0.0.1/myDb | + | mysql | myDb | 127.0.0.1 | dbserver | 3307 | dbserver:3307/myDb | + + # --- Messaging consumer (transaction consuming/receiving a message) + + Scenario: + Given an agent + And an active transaction + And OTel span is created with kind 'CONSUMER' + And OTel span has following attributes + | messaging.system | anything | + Then Elastic bridged transaction type is 'messaging' # --- Messaging producer (client span emitting a message) + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md + Scenario Outline: Messaging producer [ ] + Given an agent + And an active transaction + And OTel span is created with kind 'PRODUCER' + And OTel span has following attributes + | messaging.system | | + | messaging.destination | | + | messaging.url | | + | net.peer.ip | | + | net.peer.name | | + | net.peer.port | | + Then Elastic bridged span type is 'messaging' + Then Elastic bridged span subtype is "" + Then Elastic bridged span OTel attributes are copied as-is + Then Elastic bridged span destination resource is set to "" + Examples: + | messaging.system | messaging.destination | messaging.url | net.peer.ip | net.peer.name | net.peer.port | resource | + | rabbitmq | | amqp://carrot:4444/q1 | | | | carrot:4444 | + | rabbitmq | | | 127.0.0.1 | carrot-server | 7777 | carrot-server:7777 | + | rabbitmq | | | | carrot-server | | carrot-server | + | rabbitmq | | | 127.0.0.1 | | | 127.0.0.1 | + | rabbitmq | myQueue | amqp://carrot:4444/q1 | | | | carrot:4444/myQueue | + | rabbitmq | myQueue | | 127.0.0.1 | carrot-server | 7777 | carrot-server:7777/myQueue | + | rabbitmq | myQueue | | | carrot-server | | carrot-server/myQueue | + | rabbitmq | myQueue | | 127.0.0.1 | | | 127.0.0.1/myQueue | # --- RPC client - - - # --- TODO : Messaging + Scenario Outline: RPC client [ ] + Given an agent + And an active transaction + And OTel span is created with kind 'CLIENT' + And OTel span has following attributes + | rpc.system | | + | rpc.service | | + | net.peer.ip | | + | net.peer.name | | + | net.peer.port | | + Then Elastic bridged span type is 'external' + Then Elastic bridged span subtype is "" + Then Elastic bridged span OTel attributes are copied as-is + Then Elastic bridged span destination resource is set to "" + Examples: + | rpc.system | rpc.service | net.peer.ip | net.peer.name | net.peer.port | resource | + | grpc | | | | | grpc | + | grpc | myService | | | | grpc/myService | + | grpc | myService | | rpc-server | | rpc-server/myService | + | grpc | myService | 127.0.0.1 | rpc-server | | rpc-server/myService | + | grpc | | 127.0.0.1 | rpc-server | 7777 | rpc-server:7777 | + | grpc | myService | 127.0.0.1 | rpc-server | 7777 | rpc-server:7777/myService | + | grpc | myService | 127.0.0.1 | | 7777 | 127.0.0.1:7777/myService | + + # --- RPC server + Scenario: RPC server + Given an agent + And OTel span is created with kind 'SERVER' + And OTel span has following attributes + | rpc.system | grpc | + Then Elastic bridged transaction type is 'request' diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 4c38811cd6..a9f1481b41 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -18,10 +18,7 @@ */ package co.elastic.apm.agent.opentelemetry.sdk; -import co.elastic.apm.agent.impl.context.AbstractContext; -import co.elastic.apm.agent.impl.context.Request; import co.elastic.apm.agent.impl.context.Url; -import co.elastic.apm.agent.impl.context.web.ResultUtil; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; @@ -34,13 +31,13 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Iterator; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -57,18 +54,9 @@ public OTelSpan(AbstractSpan span) { @Override public Span setAttribute(AttributeKey key, @Nonnull T value) { span.getOtelAttributes().put(key.getKey(), value); - mapAttribute(key, value); return this; } - public void mapAttribute(AttributeKey key, Object value) { - if (span instanceof Transaction) { - mapTransactionAttributes((Transaction) span, key, value); - } else { - mapSpanAttributes((co.elastic.apm.agent.impl.transaction.Span) span, key, value); - } - } - @Override public Span addEvent(String name, Attributes attributes) { eventLogger.warn("The addEvent API is not supported at the moment"); @@ -130,108 +118,25 @@ public void end() { span.end(); } - private void mapTransactionAttributes(Transaction t, AttributeKey key, Object value) { - Request request = t.getContext().getRequest(); - Url url = request.getUrl(); - - // http.* - if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { - t.getContext().getResponse().withStatusCode(((Number) value).intValue()); - t.withResult(ResultUtil.getResultByHttpStatus(((Number) value).intValue())); - } else if (mapHttpUrlAttributes(key, value, url)) { - // successfully mapped inside mapHttpUrlAttributes - } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { - request.withMethod((String) value); - } else if (key.equals(SemanticAttributes.HTTP_FLAVOR)) { - request.withHttpVersion((String) value); - } else if (key.equals(SemanticAttributes.HTTP_CLIENT_IP)) { - request.getHeaders().add("X-Forwarded-For", (String) value); - } else if (key.equals(SemanticAttributes.HTTP_USER_AGENT)) { - request.getHeaders().add("User-Agent", (String) value); - } else { - setAttributeAsLabel(t, key, value); - } - } private void onTransactionEnd(Transaction t) { - Request request = t.getContext().getRequest(); - if (request.hasContent()) { - t.withType("request"); - Url url = request.getUrl(); - captureNetHostUrlAttributes(url, span.getContext()); - request.getSocket().withRemoteAddress(getClientRemoteAddress(span.getContext())); - } else { - t.withType("unknown"); - } - t.setFrameworkName("OpenTelemetry"); - t.setFrameworkVersion(VersionUtils.getVersion(OpenTelemetry.class, "io.opentelemetry", "opentelemetry-api")); - - } - @Nullable - public String getClientRemoteAddress(AbstractContext context) { - String netPeerIp = null; - Long netPeerPort = null; - Iterator> iterator = context.getLabelIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - // net.* - if (entry.getKey().equals(SemanticAttributes.NET_PEER_IP.getKey())) { - netPeerIp = (String) entry.getValue(); - } else if (entry.getKey().equals(SemanticAttributes.NET_PEER_PORT.getKey())) { - netPeerPort = (Long) entry.getValue(); - } + Map attributes = span.getOtelAttributes(); + boolean isRpc = attributes.containsKey("rpc.system"); + boolean isHttp = attributes.containsKey("http.url") || attributes.containsKey("http.scheme"); + boolean isMessaging = attributes.containsKey("messaging.system"); + String type = "custom"; + if (span.getOtelKind() == OTelSpanKind.SERVER && (isRpc || isHttp)) { + type = "request"; } - if (netPeerIp != null && netPeerPort != null) { - return netPeerIp + ":" + netPeerPort; - } - return null; - } - - private void mapSpanAttributes(co.elastic.apm.agent.impl.transaction.Span s, AttributeKey key, Object value) { - co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); - - if (OTelSpanKind.CLIENT == span.getOtelKind()) { - // HTTP client span - if (key.equals(SemanticAttributes.HTTP_URL) || key.equals(SemanticAttributes.HTTP_SCHEME) || key.getKey().startsWith("http.")) { - s.withType("external").withSubtype("http"); - } - if (key.equals(SemanticAttributes.DB_SYSTEM)) { - s.withType("db").withSubtype((String) value); - } + if (span.getOtelKind() == OTelSpanKind.CONSUMER && isMessaging) { + type = "messaging"; } + t.withType(type); - // http.* - if (mapHttpUrlAttributes(key, value, context.getHttp().getInternalUrl())) { - // successfully mapped inside mapHttpUrlAttributes - } else if (key.equals(SemanticAttributes.HTTP_STATUS_CODE)) { - context.getHttp().withStatusCode(((Number) value).intValue()); - } else if (key.equals(SemanticAttributes.HTTP_METHOD)) { - context.getHttp().withMethod((String) value); - } - // net.* - else if (key.equals(SemanticAttributes.NET_PEER_NAME)) { - context.getDestination().withAddress((String) value); - } else if (key.equals(SemanticAttributes.NET_PEER_IP)) { - if (context.getDestination().getAddress().length() == 0) { - context.getDestination().withAddress((String) value); - } - } else if (key.equals(SemanticAttributes.NET_PEER_PORT)) { - context.getDestination().withPort(((Number) value).intValue()); - } - // db.* - else if (key.equals(SemanticAttributes.DB_SYSTEM)) { - s.withType((String) value); - } else if (key.equals(SemanticAttributes.DB_NAME)) { - context.getDb().withInstance((String) value); - } else if (key.equals(SemanticAttributes.DB_STATEMENT)) { - context.getDb().withStatement((String) value); - } else if (key.equals(SemanticAttributes.DB_USER)) { - context.getDb().withUser((String) value); - } else { - setAttributeAsLabel(s, key, value); - } + t.setFrameworkName("OpenTelemetry"); + t.setFrameworkVersion(VersionUtils.getVersion(OpenTelemetry.class, "io.opentelemetry", "opentelemetry-api")); } private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { @@ -244,9 +149,10 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { String netPeerIp = (String) attributes.get("net.peer.ip"); String netPeerName = (String) attributes.get("net.peer.name"); - Long port = (Long) attributes.get("net.peer.port"); - if (null != port && port < 0) { - port = null; + Long netPortLong = (Long) attributes.get("net.peer.port"); + int netPort = -1; + if (null != netPortLong && netPortLong > 0L) { + netPort = netPortLong.intValue(); } String netPeer = netPeerName != null ? netPeerName : netPeerIp; @@ -255,20 +161,30 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { String httpScheme = (String) attributes.get("http.scheme"); String dbSystem = (String) attributes.get("db.system"); String messagingSystem = (String) attributes.get("messaging.system"); + String rpcSystem = (String) attributes.get("rpc.system"); if (null != dbSystem) { type = "db"; subType = dbSystem; - destinationResource.append(netPeer != null ? netPeer : dbSystem); + String dbName = (String) attributes.get("db.name"); + setSpanResource(destinationResource, netPeer, netPort, dbSystem, dbName); } else if (messagingSystem != null) { type = "messaging"; subType = messagingSystem; String messagingDestination = (String) attributes.get("messaging.destination"); - if (messagingDestination != null) { - destinationResource.append(messagingSystem).append('/').append(messagingDestination); - port = null; // skip appending port when destination is known - } else { - destinationResource.append(netPeer != null ? netPeer : messagingSystem); + URI messagingUri = parseURI((String) attributes.get("messaging.url")); + + if (netPeer == null && messagingUri != null) { + netPeer = messagingUri.getHost(); + netPort = messagingUri.getPort(); } + setSpanResource(destinationResource, netPeer, netPort, messagingSystem, messagingDestination); + } else if (rpcSystem != null) { + type = "external"; + subType = rpcSystem; + String service = (String) attributes.get("rpc.service"); + + setSpanResource(destinationResource, netPeer, netPort, rpcSystem, service); + } else if (httpUrl != null || httpScheme != null) { type = "external"; subType = "http"; @@ -279,157 +195,59 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { httpHost = netPeer; } if (httpHost == null && httpUrl != null) { - // use HTTP context internal for temp parsing without extra allocation - Url internalUrl = s.getContext().getHttp().getInternalUrl(); - internalUrl.withFull(httpUrl); - httpHost = internalUrl.getHostname(); - port = (long) internalUrl.getPort(); - internalUrl.resetState(); + URI httpUri = parseURI(httpUrl); + if (httpUri != null) { + httpHost = httpUri.getHost(); + netPort = httpUri.getPort(); + httpScheme = httpUri.getScheme(); + } } - if (httpHost != null) { - destinationResource.append(httpHost); - } + netPort = Url.normalizePort(netPort, httpScheme); - if (port == null) { - if ("http".equals(httpScheme)) { - port = 80L; - } else if ("https".equals(httpScheme)) { - port = 443L; - } - } - } else { + setSpanResource(destinationResource, httpHost, netPort, null, null); } - if (port != null) { - destinationResource.append(':').append(port); + if (type == null && s.getOtelKind() == OTelSpanKind.INTERNAL) { + type = "app"; + subType = "internal"; } s.withType(type).withSubtype(subType); - - -// co.elastic.apm.agent.impl.context.SpanContext context = s.getContext(); -// Destination destination = context.getDestination(); -// if (context.getHttp().hasContent()) { -// s.withType("external").withSubtype("http"); -// Url url = context.getHttp().getInternalUrl(); -// if (context.getDestination().getAddress().length() > 0) { -// url.withHostname(context.getDestination().getAddress().toString()); -// } -// if (context.getDestination().getPort() > 0) { -// url.withPort(context.getDestination().getPort()); -// } -// -// HttpClientHelper.setDestinationServiceDetails(s, url.getProtocol(), url.getHostname(), url.getPort()); -// } else if (context.getDb().hasContent()) { -// s.withType("db").withSubtype(context.getDb().getType()); -// if (s.getSubtype() != null) { -// destination -// .getService() -// .withName(s.getSubtype()) -// .withResource(s.getSubtype()) -// .withType("db"); -// } -//// } else { -//// s.withType("app"); -//// if (destination.getService().hasContent()) { -//// destination.getService().withType("app"); -//// } -// } - } - - private void getResource() { - } - /** - * Only one of the following is required per OpenTelemetry's semantic conventions: - *

- * Client: - * - http.url - * - http.scheme, http.host, http.target - * - http.scheme, net.peer.name, net.peer.port, http.target - * - http.scheme, net.peer.ip, net.peer.port, http.target - *

- * Server: - * - http.url - * - http.scheme, http.host, http.target - * - http.scheme, http.server_name, net.host.port, http.target - * - http.scheme, net.host.name, net.host.port, http.target - *

- * The net.* fields are captured on span/transaction end because by the time they are set, - * we don't necessarily know whether the span represents an http operation - */ - private boolean mapHttpUrlAttributes(AttributeKey key, Object value, Url url) { - if (key.equals(SemanticAttributes.HTTP_URL)) { - url.withFull((String) value); - // ensure other fields or URL are populated through parsing - url.parseAndFillFromFull(); - } else if (key.equals(SemanticAttributes.HTTP_TARGET)) { - String httpTarget = (String) value; - int indexOfQuery = httpTarget.indexOf('?'); - if (indexOfQuery > 0) { - url.withPathname(httpTarget.substring(0, indexOfQuery)); - url.withSearch(httpTarget.substring(Math.min(indexOfQuery + 1, httpTarget.length()))); - } - } else if (key.equals(SemanticAttributes.HTTP_HOST)) { - String httpHost = (String) value; - int indexOfColon = httpHost.indexOf(':'); - if (indexOfColon > 0) { - url.withHostname(httpHost.substring(0, indexOfColon)); - try { - url.withPort(Integer.parseInt(httpHost.substring(indexOfColon + 1))); - } catch (NumberFormatException ignore) { - } - } else { - url.withHostname(httpHost); - } - } else if (key.equals(SemanticAttributes.HTTP_SERVER_NAME)) { - url.withHostname((String) value); - } else if (key.equals(SemanticAttributes.HTTP_SCHEME)) { - url.withProtocol((String) value); - } else if (key.equals(SemanticAttributes.HTTP_ROUTE)) { - url.withPathname((String) value); - } else { - return false; + @Nullable + private static URI parseURI(@Nullable String s) { + if (null == s) { + return null; + } + try { + return new URI(s); + } catch (URISyntaxException e) { + return null; } - return true; } - /** - * these properties may have been set before we know it's an http request, that's why this capture is called on span end - */ - private void captureNetHostUrlAttributes(Url url, AbstractContext context) { - if (url.getHostname() != null && url.getPort() > 0) { - return; - } - Iterator> iterator = context.getLabelIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - // net.* - if (entry.getKey().equals(SemanticAttributes.NET_HOST_NAME.getKey())) { - if (url.getHostname() == null) { - url.withHostname((String) entry.getValue()); - } - } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_IP.getKey())) { - if (url.getHostname() == null) { - url.withHostname((String) entry.getValue()); - } - } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_PORT.getKey())) { - if (url.getPort() <= 0) { - url.withPort(((Number) entry.getValue()).intValue()); - } + private static void setSpanResource(StringBuilder resource, + @Nullable String netPeer, + int netPort, + @Nullable String system, + @Nullable String suffix) { + + boolean allowSuffix = false; + if (netPeer == null && system != null) { + resource.append(system); + allowSuffix = true; + } else if (netPeer != null) { + resource.append(netPeer); + allowSuffix = true; + if (netPort > 0) { + resource.append(':').append(netPort); } } - } - private static void setAttributeAsLabel(AbstractSpan span, AttributeKey key, Object value) { - if (value instanceof Boolean) { - span.addLabel(key.getKey(), (Boolean) value); - } else if (value instanceof Number) { - span.addLabel(key.getKey(), (Number) value); - } else { - span.addLabel(key.getKey(), value.toString()); + if (allowSuffix && suffix != null) { + resource.append('/').append(suffix); } } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index dfce606db9..0686260b63 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -155,8 +155,7 @@ public Span startSpan() { span.withOtelKind(OTelSpanKind.valueOf(kind.name())); } OTelSpan otelSpan = new OTelSpan(span); - attributes.forEach(otelSpan::mapAttribute); - otelSpan.inferAttributes(); + attributes.forEach((AttributeKey k, Object v) -> otelSpan.setAttribute((AttributeKey) k, (Object) v)); return otelSpan; } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java index 031b014f96..8d7264bd44 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java @@ -211,6 +211,18 @@ private static AttributeKey lookupKey(String name) { return SemanticAttributes.NET_PEER_PORT; case "db.system": return SemanticAttributes.DB_SYSTEM; + case "db.name": + return SemanticAttributes.DB_NAME; + case "messaging.system": + return SemanticAttributes.MESSAGING_SYSTEM; + case "messaging.url": + return SemanticAttributes.MESSAGING_URL; + case "messaging.destination": + return SemanticAttributes.MESSAGING_DESTINATION; + case "rpc.system": + return SemanticAttributes.RPC_SYSTEM; + case "rpc.service": + return SemanticAttributes.RPC_SERVICE; default: throw new IllegalArgumentException("unknown key for name " + name); } @@ -247,6 +259,9 @@ public void bridgeObjectType(String expected) { @Then("Elastic bridged span subtype is {string}") public void bridgeObjectSubtype(String expected) { + if (expected.isEmpty()) { + expected = null; + } assertThat(getBridgedSpan().getSubtype()).isEqualTo(expected); } From 5bc47b2f30b7c8360a52e37c7b902a0c81848850 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 26 Oct 2021 18:07:23 +0200 Subject: [PATCH 51/94] minor cleanup --- apm-agent-core/src/test/resources/specs/otel_bridge.feature | 4 +++- .../java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index aebfdc4ed2..77a0c33eec 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -127,7 +127,7 @@ Feature: OpenTelemetry bridge | mysql | myDb | 127.0.0.1 | dbserver | 3307 | dbserver:3307/myDb | # --- Messaging consumer (transaction consuming/receiving a message) - + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md Scenario: Given an agent And an active transaction @@ -165,6 +165,7 @@ Feature: OpenTelemetry bridge | rabbitmq | myQueue | | 127.0.0.1 | | | 127.0.0.1/myQueue | # --- RPC client + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md Scenario Outline: RPC client [ ] Given an agent And an active transaction @@ -190,6 +191,7 @@ Feature: OpenTelemetry bridge | grpc | myService | 127.0.0.1 | | 7777 | 127.0.0.1:7777/myService | # --- RPC server + # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md Scenario: RPC server Given an agent And OTel span is created with kind 'SERVER' diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index a9f1481b41..dd9aeac761 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -128,8 +128,7 @@ private void onTransactionEnd(Transaction t) { String type = "custom"; if (span.getOtelKind() == OTelSpanKind.SERVER && (isRpc || isHttp)) { type = "request"; - } - if (span.getOtelKind() == OTelSpanKind.CONSUMER && isMessaging) { + } else if (span.getOtelKind() == OTelSpanKind.CONSUMER && isMessaging) { type = "messaging"; } @@ -188,7 +187,6 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { } else if (httpUrl != null || httpScheme != null) { type = "external"; subType = "http"; - s.withType("external").withSubtype("http"); String httpHost = (String) attributes.get("http.host"); if (null == httpHost) { From a2d6da8849ce01f85ab3c48fa5e16a49c029df88 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 2 Nov 2021 14:03:20 +0100 Subject: [PATCH 52/94] replace 'custom' with 'unknown' for bridge --- .../src/test/resources/specs/otel_bridge.feature | 10 +++++----- .../elastic/apm/agent/opentelemetry/sdk/OTelSpan.java | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index 77a0c33eec..01f8451064 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -34,17 +34,17 @@ Feature: OpenTelemetry bridge Examples: | kind | default_type | default_subtype | | INTERNAL | app | internal | - | SERVER | custom | | - | CLIENT | custom | | - | PRODUCER | custom | | - | CONSUMER | custom | | + | SERVER | unknown | | + | CLIENT | unknown | | + | PRODUCER | unknown | | + | CONSUMER | unknown | | Scenario Outline: OTel span kind for transactions & default transaction type Given an agent And OTel span is created with kind "" Then Elastic bridged object is a transaction Then Elastic bridged transaction OTel kind is "" - Then Elastic bridged transaction type is 'custom' + Then Elastic bridged transaction type is 'unknown' Examples: | kind | | INTERNAL | diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index dd9aeac761..4ebd325693 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -125,7 +125,7 @@ private void onTransactionEnd(Transaction t) { boolean isRpc = attributes.containsKey("rpc.system"); boolean isHttp = attributes.containsKey("http.url") || attributes.containsKey("http.scheme"); boolean isMessaging = attributes.containsKey("messaging.system"); - String type = "custom"; + String type = "unknown"; if (span.getOtelKind() == OTelSpanKind.SERVER && (isRpc || isHttp)) { type = "request"; } else if (span.getOtelKind() == OTelSpanKind.CONSUMER && isMessaging) { @@ -206,9 +206,12 @@ private void onSpanEnd(co.elastic.apm.agent.impl.transaction.Span s) { setSpanResource(destinationResource, httpHost, netPort, null, null); } - if (type == null && s.getOtelKind() == OTelSpanKind.INTERNAL) { - type = "app"; - subType = "internal"; + if (type == null) { + type = "unknown"; + if (s.getOtelKind() == OTelSpanKind.INTERNAL) { + type = "app"; + subType = "internal"; + } } s.withType(type).withSubtype(subType); From 9fd61a0b0a5b163a6c9d6212807fe0dce1810737 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 2 Nov 2021 14:07:54 +0100 Subject: [PATCH 53/94] update json spec for span type/subtype --- apm-agent-core/src/test/resources/json-specs/span_types.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apm-agent-core/src/test/resources/json-specs/span_types.json b/apm-agent-core/src/test/resources/json-specs/span_types.json index b60c3730d2..c44258e10f 100644 --- a/apm-agent-core/src/test/resources/json-specs/span_types.json +++ b/apm-agent-core/src/test/resources/json-specs/span_types.json @@ -313,6 +313,10 @@ ], "allow_unlisted_subtype": true }, + "unknown": { + "__description": "For bridged spans that can't be mapped to known type/subtype", + "allow_null_subtype": true + }, "websocket": { "__description": "Websockets", "subtypes": { From 8b13a40f111d36d013f0ad4c7fc6898b7f5ad806 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Wed, 1 Dec 2021 13:35:11 +0100 Subject: [PATCH 54/94] Use AssignReturned annotations --- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 2 +- .../agent/opentelemetry/ArrayBasedContextInstrumentation.java | 3 +-- .../apm/agent/opentelemetry/ContextStorageInstrumentation.java | 3 +-- .../opentelemetry/GlobalOpenTelemetryInstrumentation.java | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 3bc39ccad8..085c2619c6 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.26.1-SNAPSHOT + 1.27.1-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java index 59fd4d88c6..798e48574d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java @@ -20,7 +20,6 @@ import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.sdk.OTelBridgeContext; -import co.elastic.apm.agent.sdk.advice.AssignTo; import io.opentelemetry.context.Context; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -62,7 +61,7 @@ public String getAdviceClassName() { public static class RootAdvice { @Nullable - @AssignTo.Return + @Advice.AssignReturned.ToReturned @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class, inline = false) public static Context onExit(@Advice.Return @Nullable Context returnValue) { diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java index 213827fbef..5ff64f53a5 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java @@ -20,7 +20,6 @@ import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.context.OTelContextStorage; -import co.elastic.apm.agent.sdk.advice.AssignTo; import io.opentelemetry.context.ContextStorage; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -54,7 +53,7 @@ public static class ContextStorageAdvice { private static final OTelContextStorage CONTEXT_STORAGE = new OTelContextStorage(GlobalTracer.requireTracerImpl()); - @AssignTo.Return + @Advice.AssignReturned.ToReturned @Advice.OnMethodExit(suppress = Throwable.class, inline = false) public static ContextStorage onExit() { return CONTEXT_STORAGE; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java index d629220ace..94a620f519 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java @@ -20,7 +20,6 @@ import co.elastic.apm.agent.impl.GlobalTracer; import co.elastic.apm.agent.opentelemetry.sdk.ElasticOpenTelemetry; -import co.elastic.apm.agent.sdk.advice.AssignTo; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import net.bytebuddy.asm.Advice; @@ -60,7 +59,7 @@ public static boolean onEnter() { return true; } - @AssignTo.Return + @Advice.AssignReturned.ToReturned @Advice.OnMethodExit(suppress = Throwable.class, inline = false) public static OpenTelemetry onExit() { return ELASTIC_OPEN_TELEMETRY; From bcbfef725ff452c194eea913c10c5ad549ab6c61 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Wed, 1 Dec 2021 13:36:52 +0100 Subject: [PATCH 55/94] Fix parent project version --- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 085c2619c6..23e4535342 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.27.1-SNAPSHOT + 1.27.2-SNAPSHOT 4.0.0 From c058bb2cfa1a6885cc8cb2d5487d7b9a22e53d67 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 6 Dec 2021 13:56:35 +0100 Subject: [PATCH 56/94] wip main cucumber tasks --- .../test/java/specs/BaseStepDefinitions.java | 24 +++++++++++- .../java/specs/OutcomeStepsDefinitions.java | 38 +++++++++---------- .../src/test/java/specs/SpecTracerState.java | 23 +++++------ .../specs/OutcomeGrpcStepsDefinitions.java | 2 +- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java b/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java index bc5d1f9c38..4f769721a7 100644 --- a/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java +++ b/apm-agent-core/src/test/java/specs/BaseStepDefinitions.java @@ -18,6 +18,8 @@ */ package specs; +import co.elastic.apm.agent.impl.transaction.Transaction; +import io.cucumber.java.ParameterType; import io.cucumber.java.en.Given; import static org.assertj.core.api.Assertions.assertThat; @@ -38,8 +40,9 @@ public BaseStepDefinitions(SpecTracerState state) { @Given("an active transaction") public void startTransaction() { assertThat(state.getTransaction()).isNull(); - - state.startTransaction(); + Transaction transaction = state.startRootTransaction(); + assertThat(transaction).isNotNull(); + assertThat(state.getTransaction()).isSameAs(transaction); } @Given("an active span") @@ -49,4 +52,21 @@ public void startSpan() { state.startSpan(); } + + @Given("the span ends") + public void endSpan() { + assertThat(state.getSpan()).isNotNull(); + state.getSpan().end(); + } + + @Given("the transaction ends") + public void endTransaction() { + assertThat(state.getTransaction()).isNotNull(); + state.getTransaction().end(); + } + + @ParameterType("transaction|span") + public String contextType(String contextType) { + return contextType; + } } diff --git a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java index fcad21e680..dc3fc33a28 100644 --- a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java +++ b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java @@ -23,6 +23,7 @@ import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.Transaction; +import io.cucumber.java.ParameterType; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; @@ -38,35 +39,35 @@ public OutcomeStepsDefinitions(SpecTracerState state) { this.state = state; } - @Then("{} outcome is {string}") + @Then("{contextType} outcome is {string}") public void thenOutcomeIs(String context, String outcome) { - checkOutcome(context.equals("span") ? state.getSpan() : state.getTransaction(), outcome); + checkOutcome(context.equals("span") ? state.getSpan() : state.getTransaction(), fromString(outcome)); } - @Then("user sets {} outcome to {string}") + @Then("user sets {contextType} outcome to {string}") public void userSetOutcome(String context, String outcome) { - setUserOutcome(getContext(context), outcome); + setUserOutcome(getContext(context), fromString(outcome)); } - @Then("{} terminates with outcome {string}") + @Then("{contextType} terminates with outcome {string}") public void terminatesWithOutcome(String context, String outcome) { - endWithOutcome(getContext(context), outcome); + endWithOutcome(getContext(context), fromString(outcome)); } - @Given("{} terminates with an error") + @Given("{contextType} terminates with an error") public void terminatesWithError(String context) { getContext(context) .captureException(new Throwable()) .end(); } - @Given("{} terminates without error") + @Given("{contextType} terminates without error") public void terminatesWithoutError(String context) { getContext(context).end(); } - AbstractSpan getContext(String context) { - return context.equals("span") ? state.getSpan() : state.getTransaction(); + private AbstractSpan getContext(String contextType) { + return contextType.equals("span") ? state.getSpan() : state.getTransaction(); } // HTTP spans & transactions mapping @@ -84,7 +85,7 @@ public void httpSpanWithStatus(int code) { @Given("an HTTP transaction with {int} response code") public void httpTransactionWithStatus(int code) { - Transaction transaction = state.startTransaction(); + Transaction transaction = state.startRootTransaction(); transaction.withName(String.format("HTTP transaction status = %d", code)); transaction.withOutcome(ResultUtil.getOutcomeByHttpServerStatus(code)).end(); @@ -92,27 +93,26 @@ public void httpTransactionWithStatus(int code) { // utilities - static void endWithOutcome(AbstractSpan context, String outcome) { + static void endWithOutcome(AbstractSpan context, Outcome outcome) { assertThat(context).isNotNull(); - context.withOutcome(fromString(outcome)) + context.withOutcome(outcome) .end(); } - static void setUserOutcome(AbstractSpan context, String outcome) { + static void setUserOutcome(AbstractSpan context, Outcome outcome) { assertThat(context).isNotNull(); - context.withUserOutcome(fromString(outcome)); + context.withUserOutcome(outcome); } - static void checkOutcome(AbstractSpan context, String outcome) { + static void checkOutcome(AbstractSpan context, Outcome outcome) { assertThat(context).isNotNull(); assertThat(context.getOutcome()) .describedAs("expected outcome = %s for context = %s", outcome, context) - .isEqualTo(fromString(outcome)); + .isEqualTo(outcome); } - static Outcome fromString(String outcome) { + private static Outcome fromString(String outcome) { return Outcome.valueOf(outcome.toUpperCase(Locale.ROOT)); } - } diff --git a/apm-agent-core/src/test/java/specs/SpecTracerState.java b/apm-agent-core/src/test/java/specs/SpecTracerState.java index 0007d78f10..b10b5e40ab 100644 --- a/apm-agent-core/src/test/java/specs/SpecTracerState.java +++ b/apm-agent-core/src/test/java/specs/SpecTracerState.java @@ -23,11 +23,14 @@ import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.Transaction; +import javax.annotation.Nullable; + import static org.assertj.core.api.Assertions.assertThat; public class SpecTracerState { private final ElasticApmTracer tracer; + private Transaction transaction; private Span span; @@ -41,37 +44,35 @@ public ElasticApmTracer getTracer() { public void startRootTransactionIfRequired() { if (transaction == null) { - startTransaction(); + startRootTransaction(); } } - public Transaction startTransaction() { - assertThat(transaction) - .describedAs("transaction already set") + public Transaction startRootTransaction() { // TODO : rename to startRootTransaction + assertThat(tracer.getActiveContext()) + .describedAs("context should be empty when starting transaction") .isNull(); - transaction = tracer.startRootTransaction(getClass().getClassLoader()); + transaction = tracer.startRootTransaction(getClass().getClassLoader()); return transaction; } - public Span startSpan() { - assertThat(span) - .describedAs("span already set b") - .isNull(); - + Transaction transaction = getTransaction(); assertThat(transaction) - .describedAs("transaction required to create span") + .describedAs("active transaction required to create span") .isNotNull(); span = transaction.createSpan(); return span; } + @Nullable public Transaction getTransaction() { return transaction; } + @Nullable public Span getSpan() { return span; } diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java index f05e57d0aa..d1dc63cb9f 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java +++ b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/specs/OutcomeGrpcStepsDefinitions.java @@ -45,7 +45,7 @@ public void grpcSpan(String grpcStatus) { @Given("a gRPC transaction with {string} status") public void grpcTransaction(String grpcStatus) { - state.startTransaction() + state.startRootTransaction() .withName(String.format("gRPC transaction %s", grpcStatus)) .withOutcome(getOutcome(grpcStatus, GrpcHelper::toServerOutcome)); } From ab10fbef53927d577d1fe861ec1d35df4b2f5f91 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 6 Dec 2021 16:05:33 +0100 Subject: [PATCH 57/94] infer on otel span end + basic outcome mapping --- .../java/specs/OutcomeStepsDefinitions.java | 2 +- .../test/resources/specs/otel_bridge.feature | 47 ++++++++++- .../apm-micrometer-plugin/pom.xml | 4 +- .../apm-opentelemetry-plugin/pom.xml | 7 +- .../sdk/ElasticOpenTelemetryTest.java | 32 ++++++++ .../specs/OTelBridgeStepsDefinitions.java | 79 +++++++++++++------ 6 files changed, 136 insertions(+), 35 deletions(-) diff --git a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java index 73b9e58bbf..f7fa511955 100644 --- a/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java +++ b/apm-agent-core/src/test/java/specs/OutcomeStepsDefinitions.java @@ -93,7 +93,7 @@ static void checkOutcome(AbstractSpan context, Outcome outcome) { .isEqualTo(outcome); } - private static Outcome fromString(String outcome) { + static Outcome fromString(String outcome) { return Outcome.valueOf(outcome.toUpperCase(Locale.ROOT)); } diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index 01f8451064..7130345ae6 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -3,21 +3,26 @@ Feature: OpenTelemetry bridge # --- Creating Elastic span or transaction from OTel span + @wip Scenario: Create transaction from OTel span with remote context Given an agent And OTel span is created with remote context as parent Then Elastic bridged object is a transaction Then Elastic bridged transaction has remote context as parent + @wip Scenario: Create root transaction from OTel span without parent Given an agent And OTel span is created without parent + And OTel span ends Then Elastic bridged object is a transaction Then Elastic bridged transaction is a root transaction + @wip Scenario: Create span from OTel span Given an agent And OTel span is created with local context as parent + And OTel span ends Then Elastic bridged object is a span Then Elastic bridged span has local context as parent @@ -27,6 +32,7 @@ Feature: OpenTelemetry bridge Given an agent And an active transaction And OTel span is created with kind "" + And OTel span ends Then Elastic bridged object is a span Then Elastic bridged span OTel kind is "" Then Elastic bridged span type is "" @@ -42,6 +48,7 @@ Feature: OpenTelemetry bridge Scenario Outline: OTel span kind for transactions & default transaction type Given an agent And OTel span is created with kind "" + And OTel span ends Then Elastic bridged object is a transaction Then Elastic bridged transaction OTel kind is "" Then Elastic bridged transaction type is 'unknown' @@ -53,6 +60,35 @@ Feature: OpenTelemetry bridge | PRODUCER | | CONSUMER | + # OTel span status mapping for spans & transactions + + Scenario Outline: OTel span mapping with status for transactions + Given an agent + And OTel span is created with kind 'SERVER' + And OTel span status set to "" + And OTel span ends + Then Elastic bridged object is a transaction + Then Elastic bridged transaction outcome is "" + Examples: + | status | outcome | + | unset | unknown | + | ok | success | + | error | failure | + + Scenario Outline: OTel span mapping with status for spans + Given an agent + Given an active transaction + And OTel span is created with kind 'INTERNAL' + And OTel span status set to "" + And OTel span ends + Then Elastic bridged object is a span + Then Elastic bridged span outcome is "" + Examples: + | status | outcome | + | unset | unknown | + | ok | success | + | error | failure | + # --- span type, subtype and action inference from OTel attributes # --- HTTP server @@ -63,6 +99,7 @@ Feature: OpenTelemetry bridge And OTel span has following attributes | http.url | | | http.scheme | | + And OTel span ends Then Elastic bridged object is a transaction Then Elastic bridged transaction type is "request" Examples: @@ -83,6 +120,7 @@ Feature: OpenTelemetry bridge | net.peer.ip | | | net.peer.name | | | net.peer.port | | + And OTel span ends Then Elastic bridged span type is 'external' Then Elastic bridged span subtype is 'http' Then Elastic bridged span OTel attributes are copied as-is @@ -111,6 +149,7 @@ Feature: OpenTelemetry bridge | net.peer.ip | | | net.peer.name | | | net.peer.port | | + And OTel span ends Then Elastic bridged span type is 'db' Then Elastic bridged span subtype is "" Then Elastic bridged span OTel attributes are copied as-is @@ -128,12 +167,12 @@ Feature: OpenTelemetry bridge # --- Messaging consumer (transaction consuming/receiving a message) # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md - Scenario: + Scenario: Messaging consumer Given an agent - And an active transaction And OTel span is created with kind 'CONSUMER' And OTel span has following attributes | messaging.system | anything | + And OTel span ends Then Elastic bridged transaction type is 'messaging' # --- Messaging producer (client span emitting a message) @@ -149,6 +188,7 @@ Feature: OpenTelemetry bridge | net.peer.ip | | | net.peer.name | | | net.peer.port | | + And OTel span ends Then Elastic bridged span type is 'messaging' Then Elastic bridged span subtype is "" Then Elastic bridged span OTel attributes are copied as-is @@ -176,6 +216,7 @@ Feature: OpenTelemetry bridge | net.peer.ip | | | net.peer.name | | | net.peer.port | | + And OTel span ends Then Elastic bridged span type is 'external' Then Elastic bridged span subtype is "" Then Elastic bridged span OTel attributes are copied as-is @@ -197,6 +238,6 @@ Feature: OpenTelemetry bridge And OTel span is created with kind 'SERVER' And OTel span has following attributes | rpc.system | grpc | + And OTel span ends Then Elastic bridged transaction type is 'request' - diff --git a/apm-agent-plugins/apm-micrometer-plugin/pom.xml b/apm-agent-plugins/apm-micrometer-plugin/pom.xml index aab053598c..490b5b48b1 100644 --- a/apm-agent-plugins/apm-micrometer-plugin/pom.xml +++ b/apm-agent-plugins/apm-micrometer-plugin/pom.xml @@ -14,8 +14,8 @@ ${project.basedir}/../.. - 8 - 8 + 11 + 11 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 23e4535342..2eee39c6d7 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -14,9 +14,9 @@ ${project.basedir}/../.. - 8 - 8 - 8 + 11 + 11 + 11 11 true @@ -46,6 +46,7 @@ ${project.version} + io.cucumber cucumber-java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index ffcf175931..5050733367 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -22,6 +22,7 @@ import co.elastic.apm.agent.impl.context.TransactionContext; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.ElasticContext; +import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Transaction; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; @@ -612,6 +613,37 @@ public void testSpanSemanticConventionMappingHttpPeerIp() { }); } + @Test + public void reportError() { + Exception error = new IllegalStateException(); + + Span span; + Span transaction = otelTracer.spanBuilder("transaction with error") + .startSpan() + .recordException(error); + try (Scope scope = transaction.makeCurrent()) { + otelTracer.spanBuilder("span with error") + .startSpan() + .recordException(error) + .end(); + } finally { + transaction.end(); + } + + assertThat(reporter.getTransactions()).hasSize(1); + assertThat(reporter.getSpans()).hasSize(1); + + assertThat(reporter.getErrors()).hasSize(2); + + assertThat(reporter.getFirstTransaction().getOutcome()) + .describedAs("recording an exception in transaction should not alter outcome") + .isEqualTo(Outcome.SUCCESS); + assertThat(reporter.getFirstSpan().getOutcome()) + .describedAs("recording an exception in span should not alter outcome") + .isEqualTo(Outcome.SUCCESS); + + } + public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { Span transaction = otelTracer.spanBuilder("transaction") .startSpan(); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java index 21bb02d0a8..f380a6668a 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java @@ -34,10 +34,13 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Context; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import javax.annotation.Nullable; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.function.Function; @@ -48,14 +51,15 @@ public class OTelBridgeStepsDefinitions { private static final String REMOTE_PARENT_TRACE_ID = "cafebabe16cd43dd8448eb211c80319c"; private static final String REMOTE_PARENT_ID = "deadbeef197918e1"; - private final ElasticOpenTelemetry otel; + // due to lazy-init access to this should use getOtel() + @Nullable + private ElasticOpenTelemetry otel; // state will contain the Elastic state when created before OTel // this is required for shared steps definitions like 'an active transaction' private final ScenarioState state; private OTelSpan otelSpan; - private boolean isOtelSpanEnded; private Map otelSpanAttributes; @@ -63,7 +67,6 @@ public class OTelBridgeStepsDefinitions { public OTelBridgeStepsDefinitions(ScenarioState state) { this.state = state; - this.otel = new ElasticOpenTelemetry(state.getTracer()); } @Before @@ -71,14 +74,21 @@ public void resetState() { this.otelSpan = null; this.localParentContext = null; this.otelSpanAttributes = new HashMap<>(); - this.isOtelSpanEnded = false; + } + + private ElasticOpenTelemetry getOtel() { + // lazily initialize OTel as the tracer state from scenario state + if (otel == null) { + otel = new ElasticOpenTelemetry(state.getTracer()); + } + return otel; } // creating elastic span or transaction from OTel span @Given("OTel span is created with remote context as parent") public void createOTelSpanWithRemoteContext() { - otelSpan = (OTelSpan) otel.getTracer("") + otelSpan = (OTelSpan) getOtel().getTracer("") .spanBuilder("otel span") .setParent(getRemoteContext()) .startSpan(); @@ -95,7 +105,7 @@ public void bridgedTransactionWithRemoteContextParent() { } private Context getRemoteContext(){ - return otel.getPropagators() + return getOtel().getPropagators() .getTextMapPropagator() .extract(Context.current(), Map.of("traceparent", String.format("00-%s-%s-01", REMOTE_PARENT_TRACE_ID, REMOTE_PARENT_ID), @@ -105,7 +115,7 @@ private Context getRemoteContext(){ @Given("OTel span is created without parent") public void createOTelSpanWithoutParent(){ - otelSpan = (OTelSpan) otel.getTracer("") + otelSpan = (OTelSpan) getOtel().getTracer("") .spanBuilder("otel span") .setNoParent() // redundant, but makes it explicit .startSpan(); @@ -119,9 +129,9 @@ public void bridgedTransactionIsRootTransaction() { @Given("OTel span is created with local context as parent") public void createOTelSpanWithLocalParent() { - localParentContext = Context.root().with(otel.getTracer("").spanBuilder("parent").startSpan()); + localParentContext = Context.root().with(getOtel().getTracer("").spanBuilder("parent").startSpan()); - otelSpan = (OTelSpan) otel.getTracer("") + otelSpan = (OTelSpan) getOtel().getTracer("") .spanBuilder("otel span") .setParent(localParentContext) .startSpan(); @@ -148,7 +158,7 @@ public void otelSpanIsCreatedWithKind(String kind) { Transaction parentTransaction = state.getTransaction(); Function createSpanWithKind = k -> { - SpanBuilder spanBuilder = otel.getTracer("") + SpanBuilder spanBuilder = getOtel().getTracer("") .spanBuilder("span") .setSpanKind(SpanKind.valueOf(k)); return (OTelSpan) spanBuilder.startSpan(); @@ -234,23 +244,29 @@ public void bridgeObjectKind(String kind){ .isEqualTo(OTelSpanKind.valueOf(kind)); } - @Then("Elastic bridged object is a span") - public void bridgeObjectTypeSpan() { - getBridgedSpan(); - } - - @Then("Elastic bridged object is a transaction") - public void bridgeObjectTypeTransaction() { - getBridgedTransaction(); + @Then("Elastic bridged object is a {contextType}") + public void bridgeSpanType(String type) { + switch (type) { + case "span": + getBridgedSpan(); + break; + case "transaction": + getBridgedTransaction(); + break; + default: + throw new IllegalArgumentException("unknown type " + type); + } } - @Then("Elastic bridged (transaction|span) type is {string}") - public void bridgeObjectType(String expected) { + @Then("Elastic bridged {contextType} type is {string}") + public void bridgeObjectType(String contextType, String expected) { AbstractSpan bridgedObject = getBridgedAbstractSpan(); String type; if (bridgedObject instanceof Transaction) { + assertThat(contextType).isEqualTo("transaction"); type = ((Transaction) bridgedObject).getType(); } else { + assertThat(contextType).isEqualTo("span"); type = ((Span) bridgedObject).getType(); } @@ -283,6 +299,23 @@ public void bridgeObjectDestinationResource(String expected) { .isEqualTo(expected); } + @Then("Elastic bridged {contextType} outcome is {string}") + public void bridgedObjectOutcome(String ignoredContextType, String outcome) { + assertThat(otelSpan.getInternalSpan().getOutcome()) + .isEqualTo(OutcomeStepsDefinitions.fromString(outcome)); + + } + + @Then("OTel span status set to {string}") + public void setOtelSpanStatus(String status){ + otelSpan.setStatus(StatusCode.valueOf(status.toUpperCase(Locale.ROOT))); + } + + @Given("OTel span ends") + public void otelSpanEnds() { + otelSpan.end(); + } + private String getDestinationResource() { return getBridgedSpan().getContext().getDestination().getService().getResource().toString(); } @@ -300,12 +333,6 @@ private Span getBridgedSpan() { } private > T getBridgedObject(Class expectedType) { - // span should be ended lazily on first access as part of the mapping is performed when ending the span - if (!isOtelSpanEnded) { - otelSpan.end(); - isOtelSpanEnded = true; - } - AbstractSpan internalSpan = otelSpan.getInternalSpan(); assertThat(internalSpan).isInstanceOf(expectedType); return expectedType.cast(internalSpan); From e38ce0a535e297b4fa649dc4a53835feb550b394 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 6 Dec 2021 16:40:11 +0100 Subject: [PATCH 58/94] pom cleanup --- apm-agent-plugins/apm-micrometer-plugin/pom.xml | 4 ++-- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apm-agent-plugins/apm-micrometer-plugin/pom.xml b/apm-agent-plugins/apm-micrometer-plugin/pom.xml index 490b5b48b1..aab053598c 100644 --- a/apm-agent-plugins/apm-micrometer-plugin/pom.xml +++ b/apm-agent-plugins/apm-micrometer-plugin/pom.xml @@ -14,8 +14,8 @@ ${project.basedir}/../.. - 11 - 11 + 8 + 8 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 2eee39c6d7..d644b11d7e 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -14,10 +14,8 @@ ${project.basedir}/../.. - 11 - 11 - 11 - 11 + 8 + 8 true 1.0.0 From dde7cd6da1a33d3ec1d2e9655ab1def734132355 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 10:43:52 +0100 Subject: [PATCH 59/94] code cleanup --- .../agent/impl/transaction/AbstractSpan.java | 2 +- .../test/resources/specs/otel_bridge.feature | 3 - .../opentelemetry/sdk/OTelInferenceTest.java | 193 ------------------ 3 files changed, 1 insertion(+), 197 deletions(-) delete mode 100644 apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java index 38eebaf4e2..cf63d71594 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java @@ -110,7 +110,7 @@ public abstract class AbstractSpan> implements Recycla @Nullable private OTelSpanKind otelKind = null; - private Map otelAttributes = new HashMap<>(); + private final Map otelAttributes = new HashMap<>(); public int getReferenceCount() { return references.get(); diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index 7130345ae6..fe3bcce7df 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -3,14 +3,12 @@ Feature: OpenTelemetry bridge # --- Creating Elastic span or transaction from OTel span - @wip Scenario: Create transaction from OTel span with remote context Given an agent And OTel span is created with remote context as parent Then Elastic bridged object is a transaction Then Elastic bridged transaction has remote context as parent - @wip Scenario: Create root transaction from OTel span without parent Given an agent And OTel span is created without parent @@ -18,7 +16,6 @@ Feature: OpenTelemetry bridge Then Elastic bridged object is a transaction Then Elastic bridged transaction is a root transaction - @wip Scenario: Create span from OTel span Given an agent And OTel span is created with local context as parent diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java deleted file mode 100644 index b02246918e..0000000000 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelInferenceTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package co.elastic.apm.agent.opentelemetry.sdk; - -import co.elastic.apm.agent.AbstractInstrumentationTest; -import co.elastic.apm.agent.impl.transaction.AbstractSpan; -import co.elastic.apm.agent.impl.transaction.Transaction; -import com.fasterxml.jackson.databind.JsonNode; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.Tracer; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Named; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import specs.TestJsonSpec; - -import javax.annotation.Nullable; -import java.util.Iterator; -import java.util.Locale; -import java.util.Optional; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import static org.assertj.core.api.Assertions.assertThat; - -public class OTelInferenceTest extends AbstractInstrumentationTest { - - private OpenTelemetry otel; - private Tracer otelTracer; - - @BeforeEach - void setUp() { - this.otel = GlobalOpenTelemetry.get(); - assertThat(otel).isSameAs(GlobalOpenTelemetry.get()); - otelTracer = otel.getTracer(null); - - // otel spans are not recycled for now - disableRecyclingValidation(); - } - - @ParameterizedTest - @MethodSource("getTestCases") - void runTest(JsonNode testCase) { - - String description = textAttribute(testCase, "description_message"); - boolean createSpan = textAttribute(testCase, "object_to_create").equals("span"); - - JsonNode jsonOtelSpan = testCase.get("otel_span"); - - SpanKind kind = SpanKind.valueOf(textAttribute(jsonOtelSpan, "kind").toUpperCase(Locale.ROOT)); - - JsonNode jsonAttributes = jsonOtelSpan.get("attributes"); - - String expectedType = textAttribute(testCase, "expected_type"); - String expectedSubType = optionalTextAttribute(testCase, "expected_subtype"); - String expectedResource = optionalTextAttribute(testCase, "expected_resource"); - - if (!createSpan) { - assertThat(expectedSubType) - .describedAs("subtype should not be set for transactions") - .isNull(); - assertThat(expectedResource) - .describedAs("resource should not be set for transactions") - .isNull(); - } - - AbstractSpan elasticSpan; - - if (createSpan) { - testSpan(description, kind, jsonAttributes); - - assertThat(reporter.getNumReportedSpans()).isEqualTo(1); - assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); - - elasticSpan = reporter.getFirstSpan(); - - assertThat(elasticSpan).isInstanceOf(co.elastic.apm.agent.impl.transaction.Span.class); - co.elastic.apm.agent.impl.transaction.Span span = (co.elastic.apm.agent.impl.transaction.Span) elasticSpan; - - assertThat(span.getType()) - .isEqualTo(expectedType); - - assertThat(span.getSubtype()) - .isEqualTo(expectedSubType); - - if(expectedResource != null){ - assertThat(span.getContext().getDestination().getService().getResource().toString()) - .isEqualTo(expectedResource); - } - - } else { - testTransaction(description, kind, jsonAttributes); - - assertThat(reporter.getNumReportedSpans()).isEqualTo(0); - assertThat(reporter.getNumReportedTransactions()).isEqualTo(1); - - elasticSpan = reporter.getFirstTransaction(); - - assertThat(elasticSpan).isNotNull(); - - assertThat(elasticSpan).isInstanceOf(Transaction.class); - Transaction transaction = (Transaction) elasticSpan; - - - - assertThat(transaction.getType()) - .isEqualTo(expectedType); - } - - } - - private Span testTransaction(String description, SpanKind kind, JsonNode attributes) { - Span span = startOtelSpan(String.format("transaction %s", description), kind); - applyOtelAttributes(span, attributes); - span.end(); - return span; - } - - private Span testSpan(String description, SpanKind kind, JsonNode attributes) { - Span transactionSpan = startOtelSpan(String.format("parent transaction for %s", description), SpanKind.SERVER); - Span spanSpan = startOtelSpan(String.format("span %s", description), kind); - applyOtelAttributes(spanSpan, attributes); - spanSpan.end(); - transactionSpan.end(); - return spanSpan; - } - - private Span startOtelSpan(String name, SpanKind kind) { - return otelTracer.spanBuilder(name) - .setSpanKind(kind) - .startSpan(); - } - - private void applyOtelAttributes(Span span, JsonNode attributes) { - attributes.fields() - .forEachRemaining(e -> { - JsonNode jsonValue = e.getValue(); - if (jsonValue.isBoolean()) { - span.setAttribute(e.getKey(), jsonValue.asBoolean()); - } else if (jsonValue.isNumber()) { - span.setAttribute(e.getKey(), jsonValue.asLong()); - } else if (jsonValue.isTextual()) { - span.setAttribute(e.getKey(), jsonValue.asText()); - } else { - throw new IllegalStateException(); - } - }); - } - - private static String textAttribute(JsonNode json, String name) { - return Optional.ofNullable(json.get(name)) - .map(JsonNode::asText) - .orElseThrow(()-> new IllegalStateException("missing mandatory attribute " + name)); - } - - @Nullable - private static String optionalTextAttribute(JsonNode json, String name) { - return Optional.ofNullable(json.get(name)) - .map(v -> v.isNull() ? null : v.asText()) - .orElse(null); - } - - private static Stream> getTestCases() { - Iterator iterator = TestJsonSpec.getJson("otel_bridge_inference.json").iterator(); - return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) - .map(test -> { - String description = test.get("description_message").asText(); - assertThat(description).isNotNull().isNotEmpty(); - return Named.of(description, test); - }); - } -} From fccfd52b80d52b51f93b6e3a1ec6e62527a4cfe2 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 10:45:10 +0100 Subject: [PATCH 60/94] set outcome for otel spans --- .../apm/agent/opentelemetry/sdk/OTelSpan.java | 6 +- .../opentelemetry/sdk/OTelSpanBuilder.java | 6 + .../sdk/ElasticOpenTelemetryTest.java | 189 +++++------------- .../opentelemetry/OpenTelemetryVersionIT.java | 3 + 4 files changed, 61 insertions(+), 143 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 4ebd325693..33b92fef10 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -84,13 +84,13 @@ public Span setStatus(StatusCode statusCode, String description) { } switch (statusCode) { case ERROR: - span.withOutcome(Outcome.FAILURE); + span.withUserOutcome(Outcome.FAILURE); break; case OK: - span.withOutcome(Outcome.SUCCESS); + span.withUserOutcome(Outcome.SUCCESS); break; case UNSET: - span.withOutcome(Outcome.UNKNOWN); + span.withUserOutcome(Outcome.UNKNOWN); break; } return this; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 0686260b63..cf0aefaabe 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -22,6 +22,7 @@ import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; import co.elastic.apm.agent.impl.transaction.OTelSpanKind; +import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import io.opentelemetry.api.common.AttributeKey; @@ -154,6 +155,11 @@ public Span startSpan() { if (kind != null) { span.withOtelKind(OTelSpanKind.valueOf(kind.name())); } + + // 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); + OTelSpan otelSpan = new OTelSpan(span); attributes.forEach((AttributeKey k, Object v) -> otelSpan.setAttribute((AttributeKey) k, (Object) v)); return otelSpan; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 5050733367..d98fcd9fff 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -19,7 +19,6 @@ package co.elastic.apm.agent.opentelemetry.sdk; import co.elastic.apm.agent.AbstractInstrumentationTest; -import co.elastic.apm.agent.impl.context.TransactionContext; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.ElasticContext; import co.elastic.apm.agent.impl.transaction.Outcome; @@ -27,6 +26,8 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextKey; @@ -59,6 +60,9 @@ public void setUp() { // otel spans are not recycled for now disableRecyclingValidation(); + + // otel spans should have unknown outcome by default unless explicitly set through API + reporter.disableCheckUnknownOutcome(); } @Before @@ -91,11 +95,12 @@ public void testTransactionWithAttribute() { .end(); assertThat(reporter.getTransactions()).hasSize(1); - TransactionContext context = reporter.getFirstTransaction().getContext(); - assertThat(context.getLabel("boolean")).isEqualTo(true); - assertThat(context.getLabel("long")).isEqualTo(42L); - assertThat(context.getLabel("double")).isEqualTo(73D); - assertThat(context.getLabel("string")).isEqualTo("hello"); + Transaction transaction = reporter.getFirstTransaction(); + + assertThat(transaction.getOtelAttributes().get("boolean")).isEqualTo(true); + assertThat(transaction.getOtelAttributes().get("long")).isEqualTo(42L); + assertThat(transaction.getOtelAttributes().get("double")).isEqualTo(73D); + assertThat(transaction.getOtelAttributes().get("string")).isEqualTo("hello"); } @Test @@ -490,76 +495,8 @@ public void elasticSpanOverOtelSpan() { } @Test - public void testTransactionSemanticConventionMappingHttpHost() { - otelTracer.spanBuilder("transaction") - .startSpan() - .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") - .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") - .setAttribute(SemanticAttributes.HTTP_HOST, "www.example.com:8080") - .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") - .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) - .end(); - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); - assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("www.example.com"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort()).isEqualTo(8080); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://www.example.com:8080/foo?bar"); - } - - @Test - public void testTransactionSemanticConventionMappingHttpNetHostName() { - otelTracer.spanBuilder("transaction") - .startSpan() - .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") - .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") - .setAttribute(SemanticAttributes.NET_HOST_NAME, "example.com") - .setAttribute(SemanticAttributes.NET_HOST_PORT, 8080) - .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") - .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) - .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") - .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) - .end(); - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); - assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort()).isEqualTo(8080); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); - } - - @Test - public void testTransactionSemanticConventionMappingHttpNetHostIP() { - otelTracer.spanBuilder("transaction") - .startSpan() - .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") - .setAttribute(SemanticAttributes.HTTP_SCHEME, "http") - .setAttribute(SemanticAttributes.NET_HOST_NAME, "127.0.0.1") - .setAttribute(SemanticAttributes.NET_HOST_PORT, 8080) - .setAttribute(SemanticAttributes.NET_PEER_PORT, 123456) - .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") - .setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar") - .setAttribute(SemanticAttributes.HTTP_STATUS_CODE, 200L) - .end(); - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); - assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("127.0.0.1"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort()).isEqualTo(8080); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://127.0.0.1:8080/foo?bar"); - } - - @Test - public void testTransactionSemanticConventionMappingHttpUrl() { - otelTracer.spanBuilder("transaction") + public void testOTelSpanAttributesCopiedAsIs() { + otelTracer.spanBuilder("transaction").setSpanKind(SpanKind.SERVER) .startSpan() .setAttribute(SemanticAttributes.HTTP_METHOD, "GET") .setAttribute(SemanticAttributes.HTTP_URL, "http://example.com:8080/foo?bar") @@ -568,64 +505,59 @@ public void testTransactionSemanticConventionMappingHttpUrl() { .setAttribute(SemanticAttributes.NET_PEER_IP, "192.168.178.1") .end(); assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("HTTP 2xx"); - assertThat(reporter.getFirstTransaction().getContext().getResponse().getStatusCode()).isEqualTo(200); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getMethod()).isEqualTo("GET"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getProtocol()).isEqualTo("http"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getHostname()).isEqualTo("example.com"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getPort()).isEqualTo(8080); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getSocket().getRemoteAddress()).isEqualTo("192.168.178.1:123456"); - assertThat(reporter.getFirstTransaction().getContext().getRequest().getUrl().getFull().toString()).isEqualTo("http://example.com:8080/foo?bar"); + + checkOTelAttributes(reporter.getFirstTransaction(), Map.of( + SemanticAttributes.HTTP_METHOD.getKey(), "GET", + SemanticAttributes.HTTP_URL.getKey(), "http://example.com:8080/foo?bar", + SemanticAttributes.HTTP_STATUS_CODE.getKey(), 200L, + SemanticAttributes.NET_PEER_PORT.getKey(), 123456L, + SemanticAttributes.NET_PEER_IP.getKey(), "192.168.178.1" + )); } - @Test - public void testSpanSemanticConventionMappingHttpUrl() { - testSpanSemanticConventionMappingHttpHelper(span -> span.setAttribute(SemanticAttributes.HTTP_URL, "http://example.com/foo?bar")); + private static void checkOTelAttributes(AbstractSpan context, Map expected) { + assertThat(context.getOtelAttributes()) + .containsAllEntriesOf(expected) + .hasSameSizeAs(expected); } @Test - public void testSpanSemanticConventionMappingHttpHost() { - testSpanSemanticConventionMappingHttpHelper(span -> { - span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); - span.setAttribute(SemanticAttributes.HTTP_HOST, "example.com"); - span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + public void reportErrorKeepsUnknownOutcome() { + checkReportError(Outcome.UNKNOWN, span -> { + span.recordException(new IllegalStateException()); }); } @Test - public void testSpanSemanticConventionMappingHttpPeerName() { - testSpanSemanticConventionMappingHttpHelper(span -> { - span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); - span.setAttribute(SemanticAttributes.NET_PEER_IP, "192.0.2.5"); - span.setAttribute(SemanticAttributes.NET_PEER_NAME, "example.com"); - span.setAttribute(SemanticAttributes.NET_PEER_PORT, 80); - span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + public void reportErrorAndSetStatusOk() { + checkReportError(Outcome.SUCCESS, span -> { + span.setStatus(StatusCode.OK); + span.recordException(new IllegalStateException()); }); } @Test - public void testSpanSemanticConventionMappingHttpPeerIp() { - testSpanSemanticConventionMappingHttpHelper(span -> { - span.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); - span.setAttribute(SemanticAttributes.NET_PEER_IP, "example.com"); - span.setAttribute(SemanticAttributes.NET_PEER_PORT, 80); - span.setAttribute(SemanticAttributes.HTTP_TARGET, "/foo?bar"); + public void reportErrorAndSetStatusError() { + checkReportError(Outcome.FAILURE, span -> { + span.recordException(new IllegalStateException()); + span.setStatus(StatusCode.ERROR); }); } - @Test - public void reportError() { - Exception error = new IllegalStateException(); + private void checkReportError(Outcome expectedOutcome, Consumer actions) { - Span span; Span transaction = otelTracer.spanBuilder("transaction with error") - .startSpan() - .recordException(error); + .startSpan(); + try (Scope scope = transaction.makeCurrent()) { - otelTracer.spanBuilder("span with error") - .startSpan() - .recordException(error) - .end(); + actions.accept(transaction); + + Span span = otelTracer.spanBuilder("span with error") + .startSpan(); + + actions.accept(span); + + span.end(); } finally { transaction.end(); } @@ -637,33 +569,10 @@ public void reportError() { assertThat(reporter.getFirstTransaction().getOutcome()) .describedAs("recording an exception in transaction should not alter outcome") - .isEqualTo(Outcome.SUCCESS); + .isEqualTo(expectedOutcome); assertThat(reporter.getFirstSpan().getOutcome()) .describedAs("recording an exception in span should not alter outcome") - .isEqualTo(Outcome.SUCCESS); - - } - - public void testSpanSemanticConventionMappingHttpHelper(Consumer spanConsumer) { - Span transaction = otelTracer.spanBuilder("transaction") - .startSpan(); - try (Scope scope = transaction.makeCurrent()) { - Span span = otelTracer.spanBuilder("span") - .startSpan(); - spanConsumer.accept(span); - span.end(); - } finally { - transaction.end(); - } - - assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getSpans()).hasSize(1); - assertThat(reporter.getFirstSpan().getContext().getDestination().getPort()).isEqualTo(80); - assertThat(reporter.getFirstSpan().getContext().getHttp().getUrl().toString()).isIn("http://example.com/foo?bar", "http://example.com:80/foo?bar"); - assertThat(reporter.getFirstSpan().getContext().getDestination().getAddress().toString()).isEqualTo("example.com"); - assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getName().toString()).isEqualTo("http://example.com"); - assertThat(reporter.getFirstSpan().getContext().getDestination().getService().getResource().toString()).isEqualTo("example.com:80"); - reporter.resetWithoutRecycling(); + .isEqualTo(expectedOutcome); } public static class MapGetter implements TextMapGetter> { diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 39a55c2733..95f2fe9f42 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -50,6 +50,9 @@ public static Iterable data() { {"1.4.1"}, {"1.5.0"}, {"1.6.0"}, + {"1.7.0"}, + {"1.8.0"}, + {"1.9.0"}, }); } From 4c5341fde313f2cf1e8df4c7f1d3a8a046aca353 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 11:45:06 +0100 Subject: [PATCH 61/94] fix tests --- .../co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java | 1 + .../agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java | 5 ++++- apm-agent-plugins/apm-opentelemetry-test/pom.xml | 2 +- .../co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java | 3 +-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 33b92fef10..81bd328fbc 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -115,6 +115,7 @@ public void end() { } else if (span instanceof co.elastic.apm.agent.impl.transaction.Span) { onSpanEnd((co.elastic.apm.agent.impl.transaction.Span) span); } + span.end(); } diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index d98fcd9fff..2c4c489080 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -199,7 +199,10 @@ public void setStartTimestamp() { otelTracer.spanBuilder("transaction") .setStartTimestamp(transactionStart) .startSpan() - .end(); + // for test reliability we have to provide explicit end time + // otherwise since OTel time is in nano-seconds and stored in micro-seconds there are not-so rare cases + // where the computed duration appears negative. + .end(transactionStart); long transactionStartMicros = ChronoUnit.MICROS.between(Instant.EPOCH, transactionStart); diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry-test/pom.xml index bbabb75f6c..6714e3f8f4 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-test/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.26.1-SNAPSHOT + 1.27.2-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 95f2fe9f42..893e5a974b 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -50,8 +50,7 @@ public static Iterable data() { {"1.4.1"}, {"1.5.0"}, {"1.6.0"}, - {"1.7.0"}, - {"1.8.0"}, + {"1.7.1"}, {"1.9.0"}, }); } From d08186b5fde4d8d55eb8919b97c5f8a1e1af924f Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 11:59:31 +0100 Subject: [PATCH 62/94] do not infer outcome from lack of exception --- apm-agent-core/src/test/resources/specs/otel_bridge.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apm-agent-core/src/test/resources/specs/otel_bridge.feature b/apm-agent-core/src/test/resources/specs/otel_bridge.feature index fe3bcce7df..5579e6ad42 100644 --- a/apm-agent-core/src/test/resources/specs/otel_bridge.feature +++ b/apm-agent-core/src/test/resources/specs/otel_bridge.feature @@ -15,6 +15,8 @@ Feature: OpenTelemetry bridge And OTel span ends Then Elastic bridged object is a transaction Then Elastic bridged transaction is a root transaction + # outcome should not be inferred from the lack/presence of errors + Then Elastic bridged transaction outcome is "unknown" Scenario: Create span from OTel span Given an agent @@ -22,6 +24,8 @@ Feature: OpenTelemetry bridge And OTel span ends Then Elastic bridged object is a span Then Elastic bridged span has local context as parent + # outcome should not be inferred from the lack/presence of errors + Then Elastic bridged span outcome is "unknown" # --- OTel span kind mapping for spans & transactions From 5f4ce601d35a5524dd02f3efbca353236bf1b622 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 13:24:13 +0100 Subject: [PATCH 63/94] fix documentation --- docs/configuration.asciidoc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 97281c7f72..aa9c0517d7 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -716,11 +716,7 @@ you should add an additional entry to this list (make sure to also include the d ==== `disable_instrumentations` (added[1.0.0,Changing this value at runtime is possible since version 1.15.0]) A list of instrumentations which should be disabled. -<<<<<<< HEAD -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. -======= -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. ->>>>>>> master +Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. For version `1.25.0` and later, use <> to enable experimental instrumentations. NOTE: Changing this value at runtime can slow down the application temporarily. @@ -2972,7 +2968,7 @@ The default unit for this option is `ms`. # sanitize_field_names=password,passwd,pwd,secret,*key,*token*,*session*,*credit*,*card*,authorization,set-cookie # A list of instrumentations which should be disabled. -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. +# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. # For version `1.25.0` and later, use <> to enable experimental instrumentations. # # NOTE: Changing this value at runtime can slow down the application temporarily. From 0ecdddecdf0aee84d3c9e77a9f930fc53edfc5b6 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 14:22:17 +0100 Subject: [PATCH 64/94] fix/cleanup documentation --- docs/api-opentelemetry.asciidoc | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 365e4f7486..efc6e297e7 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -6,7 +6,7 @@ endif::[] [[opentelementry-bridge]] === OpenTelemetry bridge -NOTE: Added as experimental in 1.26.0. +NOTE: Added as experimental in 1.29.0. To enable it, set <> to `true`. The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, @@ -111,31 +111,6 @@ try (Scope scope = custom.makeCurrent()) { To learn more about the OpenTelemetry API, head over do https://opentelemetry.io/docs/java/manual_instrumentation/[their documentation]. - -//// -TODO implement Elastic APM specific attributes -[float] -[[otel-elastic-apm-attributes]] -==== Elastic APM specific attributes -Elastic APM defines some attributes which are not included in OpenTelemetry's semantic conventionsAPI but are relevant in the context of Elastic APM. - -- `type` - sets the type of the transaction/span, - for example `request`, `ext` or `db` -- `subtype` - sets the subtype of the span, - for example `http`, `mysql` or `jsf` -- `action` - sets the action related to a span, - for example `query`, `execute` or `render` -- `user.id` - sets the user id, - appears in the "User" tab in the transaction details in the Elastic APM app -- `user.email` - sets the user email, - appears in the "User" tab in the transaction details in the Elastic APM app -- `user.username` - sets the user name, - appears in the "User" tab in the transaction details in the Elastic APM app -- `result` - sets the result of the transaction. Overrides the default value of `success`. - If the `error` tag is set to `true`, the default value is `error`. - Setting `http.status_code` to `200`, for example, implicitly sets the result to `HTTP 2xx` if not explicitly set otherwise. -//// - [float] [[otel-caveats]] ==== Caveats From 8951c3019674f6b70686d272b53d18ac34949356 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 7 Dec 2021 15:31:47 +0100 Subject: [PATCH 65/94] update changelog --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index d62b3a9a33..84b342e547 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -25,6 +25,7 @@ endif::[] [float] ===== Features +* Add experimental OpenTelemetry API bridge - {pull}1631[#1631] [float] ===== Bug fixes From 805b21d0ac0db27b1089c67bf6301b1388024c69 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 7 Feb 2022 11:36:25 +0100 Subject: [PATCH 66/94] fix sdk logger change --- apm-agent-plugins/apm-opentelemetry-plugin/pom.xml | 2 +- .../java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java | 4 ++-- .../elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java | 4 ++-- apm-agent-plugins/apm-opentelemetry-test/pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml index 492f1ff96a..33b524d5b1 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.28.1-SNAPSHOT + 1.28.5-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java index 81bd328fbc..8113a5ade2 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java @@ -23,6 +23,8 @@ import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Transaction; +import co.elastic.apm.agent.sdk.logging.Logger; +import co.elastic.apm.agent.sdk.logging.LoggerFactory; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.VersionUtils; import io.opentelemetry.api.OpenTelemetry; @@ -31,8 +33,6 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index cf0aefaabe..9b0ecb83ea 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -23,6 +23,8 @@ import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; +import co.elastic.apm.agent.sdk.logging.Logger; +import co.elastic.apm.agent.sdk.logging.LoggerFactory; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import io.opentelemetry.api.common.AttributeKey; @@ -33,8 +35,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry-test/pom.xml index 42e6f03424..c04eada0ad 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry-test/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.28.1-SNAPSHOT + 1.28.5-SNAPSHOT 4.0.0 From 6ec3ac38ee7a5d9f1c52a4d10f0de8f451d5b29f Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 7 Feb 2022 12:17:49 +0100 Subject: [PATCH 67/94] add latest versions for test coverage --- .../co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java index 893e5a974b..90436cb3d2 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java +++ b/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java @@ -52,6 +52,8 @@ public static Iterable data() { {"1.6.0"}, {"1.7.1"}, {"1.9.0"}, + {"1.10.1"}, + {"1.11.0"} }); } From a318c61d66b29f8a87eb0c9b451e2c3fba4e28a1 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 7 Feb 2022 14:23:43 +0100 Subject: [PATCH 68/94] update generated doc --- docs/configuration.asciidoc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 4fc1868ebf..4f2e13f23c 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -759,7 +759,7 @@ you should add an additional entry to this list (make sure to also include the d ==== `enable_instrumentations` (added[1.28.0]) A list of instrumentations which should be selectively enabled. -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. +Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. When set to non-empty value, only listed instrumentations will be enabled if they are not disabled through <> or <>. When not set or empty (default), all instrumentations enabled by default will be enabled unless they are disabled through <> or <>. @@ -787,11 +787,7 @@ NOTE: Changing this value at runtime can slow down the application temporarily. ==== `disable_instrumentations` (added[1.0.0,Changing this value at runtime is possible since version 1.15.0]) A list of instrumentations which should be disabled. -<<<<<<< HEAD -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. -======= -Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> e3ec8c0dce03bb52743efe60b9e0a9c56a88b286 +Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. For version `1.25.0` and later, use <> to enable experimental instrumentations. NOTE: Changing this value at runtime can slow down the application temporarily. @@ -3084,7 +3080,7 @@ The default unit for this option is `ms`. # sanitize_field_names=password,passwd,pwd,secret,*key,*token*,*session*,*credit*,*card*,*auth*,set-cookie # A list of instrumentations which should be selectively enabled. -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. +# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. # When set to non-empty value, only listed instrumentations will be enabled if they are not disabled through <> or <>. # When not set or empty (default), all instrumentations enabled by default will be enabled unless they are disabled through <> or <>. # @@ -3097,11 +3093,7 @@ The default unit for this option is `ms`. # enable_instrumentations= # A list of instrumentations which should be disabled. -<<<<<<< HEAD -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `javalin`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`. -======= -# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> e3ec8c0dce03bb52743efe60b9e0a9c56a88b286 +# Valid options are `annotations`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. # For version `1.25.0` and later, use <> to enable experimental instrumentations. # # NOTE: Changing this value at runtime can slow down the application temporarily. From a10814de0b8dd8972c90926df2e8b2d781a9e429 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 7 Feb 2022 14:31:38 +0100 Subject: [PATCH 69/94] compile agent sdk for java 7 --- apm-agent-plugin-sdk/pom.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apm-agent-plugin-sdk/pom.xml b/apm-agent-plugin-sdk/pom.xml index a1f8fc8355..508298849e 100644 --- a/apm-agent-plugin-sdk/pom.xml +++ b/apm-agent-plugin-sdk/pom.xml @@ -51,14 +51,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - From fc5c5e2402f9d312323a6348be838f3daa31d322 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 7 Feb 2022 16:45:18 +0100 Subject: [PATCH 70/94] fix doc links --- docs/api-opentelemetry.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index efc6e297e7..4e448b5643 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -18,12 +18,12 @@ NOTE: While manual instrumentations using the OpenTelemetry API can be adapted t https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] in the context of the Elastic APM Java agent. + However, you can use https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] (aka the OpenTelementry Java agent) and send the data to APM Server. -See the {apm-overview-ref-v}/open-telemetry-elastic.html[OpenTelemetry integration docs] for more details. +See the {apm-overview-ref-v}/open-telemetry.html[OpenTelemetry integration docs] for more details. The first span of a service will be converted to an Elastic APM -{apm-overview-ref-v}/transactions.html[`Transaction`], +{apm-overview-ref-v}/data-model-transactions.html[`Transaction`], subsequent spans are mapped to Elastic APM -{apm-overview-ref-v}/transaction-spans.html[`Span`]. +{apm-overview-ref-v}/data-model-spans.html[`Span`]. [float] [[otel-getting-started]] From 64b393b3b6b2de2d14ddb9b2f6e93a7c59d8a9e6 Mon Sep 17 00:00:00 2001 From: SylvainJuge Date: Tue, 8 Feb 2022 08:54:53 +0100 Subject: [PATCH 71/94] Apply suggestions from code review (docs links) Co-authored-by: Brandon Morelli --- docs/api-opentelemetry.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 4e448b5643..51027149d3 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -18,12 +18,12 @@ NOTE: While manual instrumentations using the OpenTelemetry API can be adapted t https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] in the context of the Elastic APM Java agent. + However, you can use https://github.com/open-telemetry/opentelemetry-java-instrumentation[opentelemetry-java-instrumentation] (aka the OpenTelementry Java agent) and send the data to APM Server. -See the {apm-overview-ref-v}/open-telemetry.html[OpenTelemetry integration docs] for more details. +See the {apm-guide-ref}/open-telemetry.html[OpenTelemetry integration docs] for more details. The first span of a service will be converted to an Elastic APM -{apm-overview-ref-v}/data-model-transactions.html[`Transaction`], +{apm-guide-ref}/data-model-transactions.html[`Transaction`], subsequent spans are mapped to Elastic APM -{apm-overview-ref-v}/data-model-spans.html[`Span`]. +{apm-guide-ref}/data-model-spans.html[`Span`]. [float] [[otel-getting-started]] From a71e8ad5946f5d2964d303bace37626de1a0c87c Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 8 Feb 2022 14:06:08 +0100 Subject: [PATCH 72/94] aim for release in 1.30.0 --- CHANGELOG.asciidoc | 4 ++-- docs/api-opentelemetry.asciidoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 9332e7cecf..dd60e50f96 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -20,8 +20,8 @@ endif::[] === Unreleased -[[release-notes-1.29.1]] -==== 1.29.1 - YYYY/MM/DD +[[release-notes-1.30.0]] +==== 1.30.0 - YYYY/MM/DD [float] ===== Features diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 4e448b5643..82733d5875 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -6,7 +6,7 @@ endif::[] [[opentelementry-bridge]] === OpenTelemetry bridge -NOTE: Added as experimental in 1.29.0. +NOTE: Added as experimental in 1.30.0. To enable it, set <> to `true`. The Elastic APM OpenTelemetry bridge allows creating Elastic APM `Transactions` and `Spans`, From 097ab8a3065f967dd0f04421c8656ffb1843a60d Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 11 Feb 2022 15:03:49 +0100 Subject: [PATCH 73/94] add missing otel attributes & kind serialization --- .../report/serialize/DslJsonSerializer.java | 63 ++++++++++++++++++- .../serialize/DslJsonSerializerTest.java | 45 ++++++++++++- .../opentelemetry/sdk/OTelSpanBuilder.java | 6 +- .../sdk/ElasticOpenTelemetryTest.java | 8 ++- 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java index e6ef5f1c9c..dce06e820a 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java @@ -35,11 +35,11 @@ import co.elastic.apm.agent.impl.context.Url; import co.elastic.apm.agent.impl.context.User; import co.elastic.apm.agent.impl.error.ErrorCapture; -import co.elastic.apm.agent.impl.metadata.MetaData; import co.elastic.apm.agent.impl.metadata.Agent; import co.elastic.apm.agent.impl.metadata.CloudProviderInfo; import co.elastic.apm.agent.impl.metadata.Framework; import co.elastic.apm.agent.impl.metadata.Language; +import co.elastic.apm.agent.impl.metadata.MetaData; import co.elastic.apm.agent.impl.metadata.NameAndIdField; import co.elastic.apm.agent.impl.metadata.Node; import co.elastic.apm.agent.impl.metadata.ProcessInfo; @@ -50,6 +50,7 @@ import co.elastic.apm.agent.impl.transaction.Faas; import co.elastic.apm.agent.impl.transaction.FaasTrigger; import co.elastic.apm.agent.impl.transaction.Id; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.SpanCount; import co.elastic.apm.agent.impl.transaction.StackFrame; @@ -57,6 +58,8 @@ import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.metrics.Labels; import co.elastic.apm.agent.report.ApmServerClient; +import co.elastic.apm.agent.sdk.logging.Logger; +import co.elastic.apm.agent.sdk.logging.LoggerFactory; import co.elastic.apm.agent.util.HexUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; import com.dslplatform.json.BoolConverter; @@ -64,8 +67,6 @@ import com.dslplatform.json.JsonWriter; import com.dslplatform.json.NumberConverter; import com.dslplatform.json.StringConverter; -import co.elastic.apm.agent.sdk.logging.Logger; -import co.elastic.apm.agent.sdk.logging.LoggerFactory; import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; @@ -708,10 +709,66 @@ private void serializeSpan(final Span span) { if (!Double.isNaN(sampleRate)) { writeField("sample_rate", sampleRate); } + serializeOTel(span); serializeSpanType(span); jw.writeByte(OBJECT_END); } + private void serializeOTel(Span span) { + OTelSpanKind kind = span.getOtelKind(); + Map attributes = span.getOtelAttributes(); + boolean hasAttributes = !attributes.isEmpty(); + boolean hasKind = kind != null; + if (hasKind || hasAttributes) { + writeFieldName("otel"); + jw.writeByte(OBJECT_START); + + if (hasKind) { + writeFieldName("span_kind"); + writeStringValue(kind.name()); + } + + if (hasAttributes) { + if (hasKind) { + jw.writeByte(COMMA); + } + writeFieldName("attributes"); + jw.writeByte(OBJECT_START); + int index = 0; + for (Map.Entry entry : attributes.entrySet()) { + if (index++ > 0) { + jw.writeByte(COMMA); + } + writeFieldName(entry.getKey()); + Object o = entry.getValue(); + if (o instanceof Number) { + serializeNumber((Number) o, jw); + } else if (o instanceof String) { + writeStringValue((String) o); + } else if (o instanceof Boolean) { + BoolConverter.serialize((Boolean) o, jw); + } + } + jw.writeByte(OBJECT_END); + } + + jw.writeByte(OBJECT_END); + jw.writeByte(COMMA); + } + } + + private void serializeNumber(Number n, JsonWriter jw){ + if (n instanceof Integer) { + NumberConverter.serialize(n.intValue(), jw); + } else if (n instanceof Long) { + NumberConverter.serialize(n.longValue(), jw); + } else if (n instanceof Double) { + NumberConverter.serialize(n.doubleValue(), jw); + } else if (n instanceof Float) { + NumberConverter.serialize(n.floatValue(), jw); + } + } + private void serializeServiceNameWithFramework(@Nullable final Transaction transaction, final TraceContext traceContext, final ServiceOrigin serviceOrigin) { String serviceName = traceContext.getServiceName(); String serviceVersion = traceContext.getServiceVersion(); diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java index d140d0471b..e0685cb817 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java @@ -25,9 +25,6 @@ import co.elastic.apm.agent.configuration.ServerlessConfiguration; import co.elastic.apm.agent.configuration.SpyConfiguration; import co.elastic.apm.agent.impl.ElasticApmTracer; -import co.elastic.apm.agent.impl.metadata.FaaSMetaDataExtension; -import co.elastic.apm.agent.impl.metadata.MetaData; -import co.elastic.apm.agent.impl.metadata.MetaDataMock; import co.elastic.apm.agent.impl.Tracer; import co.elastic.apm.agent.impl.context.AbstractContext; import co.elastic.apm.agent.impl.context.Headers; @@ -36,8 +33,11 @@ import co.elastic.apm.agent.impl.error.ErrorCapture; import co.elastic.apm.agent.impl.metadata.Agent; import co.elastic.apm.agent.impl.metadata.CloudProviderInfo; +import co.elastic.apm.agent.impl.metadata.FaaSMetaDataExtension; import co.elastic.apm.agent.impl.metadata.Framework; import co.elastic.apm.agent.impl.metadata.Language; +import co.elastic.apm.agent.impl.metadata.MetaData; +import co.elastic.apm.agent.impl.metadata.MetaDataMock; import co.elastic.apm.agent.impl.metadata.NameAndIdField; import co.elastic.apm.agent.impl.metadata.ProcessInfo; import co.elastic.apm.agent.impl.metadata.Service; @@ -46,6 +46,7 @@ import co.elastic.apm.agent.impl.sampling.Sampler; import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration; import co.elastic.apm.agent.impl.transaction.Id; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.StackFrame; import co.elastic.apm.agent.impl.transaction.TraceContext; @@ -1345,6 +1346,44 @@ void multiValueHeaders(boolean supportsMulti) { assertThat(headersJson).isNotNull(); } + @Test + void testOTelSpanSerialization() { + Span span = new Span(MockTracer.create()).withName("span name"); + assertThat(span.getOtelKind()) + .describedAs("otel span kind should not be set by default") + .isNull(); + + JsonNode spanJson = readJsonString(serializer.toJsonString(span)); + assertThat(spanJson.get("name").asText()).isEqualTo("span name"); + assertThat(spanJson.get("otel")).isNull(); + + for (OTelSpanKind kind : OTelSpanKind.values()) { + span.withOtelKind(kind); + spanJson = readJsonString(serializer.toJsonString(span)); + + JsonNode otelJson = spanJson.get("otel"); + assertThat(otelJson).isNotNull(); + assertThat(otelJson.get("span_kind").asText()).isEqualTo(kind.name()); + } + + // with custom otel attributes + span.getOtelAttributes().put("attribute.string", "hello"); + span.getOtelAttributes().put("attribute.long", 123L); + span.getOtelAttributes().put("attribute.boolean", false); + span.getOtelAttributes().put("attribute.float", 0.42f); + spanJson = readJsonString(serializer.toJsonString(span)); + JsonNode otelJson = spanJson.get("otel"); + assertThat(otelJson).isNotNull(); + JsonNode otelAttributes = otelJson.get("attributes"); + assertThat(otelAttributes).isNotNull(); + assertThat(otelAttributes.size()).isEqualTo(4); + assertThat(otelAttributes.get("attribute.string").asText()).isEqualTo("hello"); + assertThat(otelAttributes.get("attribute.long").asLong()).isEqualTo(123L); + assertThat(otelAttributes.get("attribute.boolean").asBoolean()).isFalse(); + assertThat(otelAttributes.get("attribute.float").asDouble()).isEqualTo(0.42d); + + } + private static void checkSingleValueHeader(JsonNode json, String fieldName, String value){ JsonNode fieldValue = json.get(fieldName); assertThat(fieldValue.isTextual()).isTrue(); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 9b0ecb83ea..0eb28793f0 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -152,10 +152,14 @@ public Span startSpan() { return Span.getInvalid(); } span.withName(spanName); - if (kind != null) { + + if (kind == null) { + span.withOtelKind(OTelSpanKind.INTERNAL); + } else { span.withOtelKind(OTelSpanKind.valueOf(kind.name())); } + // 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); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java index 2c4c489080..a90ff9b94b 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java @@ -21,6 +21,7 @@ import co.elastic.apm.agent.AbstractInstrumentationTest; import co.elastic.apm.agent.impl.transaction.AbstractSpan; import co.elastic.apm.agent.impl.transaction.ElasticContext; +import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; import co.elastic.apm.agent.impl.transaction.Transaction; import io.opentelemetry.api.GlobalOpenTelemetry; @@ -81,7 +82,12 @@ public void testTransaction() { .startSpan() .end(); assertThat(reporter.getTransactions()).hasSize(1); - assertThat(reporter.getFirstTransaction().getNameAsString()).isEqualTo("transaction"); + Transaction transaction = reporter.getFirstTransaction(); + assertThat(transaction.getNameAsString()).isEqualTo("transaction"); + + assertThat(transaction.getOtelKind()) + .describedAs("default span kind should be internal when not set explicitly") + .isEqualTo(OTelSpanKind.INTERNAL); } @Test From 8099d37cbfbea2a76680749f63f656860b610c18 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 22 Feb 2022 10:56:17 +0100 Subject: [PATCH 74/94] prevent NPE when Context.root() is not called first --- .../apm/agent/opentelemetry/context/OTelContextStorage.java | 5 +++++ .../apm/agent/opentelemetry/sdk/OTelBridgeContext.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index 6fb6d64998..4028452b0d 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -83,6 +83,11 @@ public Context current() { logger.debug("upgrading active context {} to a bridged context", current); tracer.deactivate(current); + + // Ensure that root context is being accessed at least once to capture the original root + // OTel 1.0 directly calls ArrayBasedContext.root(), whereas later versions delegate to ContextStorage.root(). + Context.root(); + OTelBridgeContext upgradedContext = OTelBridgeContext.wrapElasticActiveSpan(tracer, (AbstractSpan) current); tracer.activate(upgradedContext); diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index cad80f0f9a..161c091bdd 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -28,6 +28,7 @@ import io.opentelemetry.context.Scope; import javax.annotation.Nullable; +import java.util.Objects; public class OTelBridgeContext implements ElasticContext, Context, Scope { @@ -46,7 +47,7 @@ public class OTelBridgeContext implements ElasticContext, Con /** * OTel context used for key/value storage */ - private Context otelContext; + private final Context otelContext; private final ElasticApmTracer tracer; @@ -83,6 +84,7 @@ public static OTelBridgeContext bridgeRootContext(ElasticApmTracer tracer, Conte */ public static OTelBridgeContext wrapElasticActiveSpan(ElasticApmTracer tracer, AbstractSpan span) { OTelSpan otelSpan = new OTelSpan(span); + Objects.requireNonNull(originalRootContext, "OTel original context must be set through bridgeRootContext first"); return new OTelBridgeContext(tracer, originalRootContext.with(otelSpan)); } From a4fd963db474eadd68662283366fedfbad9995e4 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 24 Feb 2022 16:53:46 +0100 Subject: [PATCH 75/94] move to a single module for opentelemetry --- .../apm-opentelemetry-plugin/pom.xml | 9 ++---- .../AbstractOpenTelemetryInstrumentation.java | 0 .../ArrayBasedContextInstrumentation.java | 0 .../ContextStorageInstrumentation.java | 0 .../GlobalOpenTelemetryInstrumentation.java | 0 .../context/OTelContextStorage.java | 0 .../opentelemetry/context/package-info.java | 0 .../apm/agent/opentelemetry/package-info.java | 0 .../sdk/ElasticOpenTelemetry.java | 0 .../opentelemetry/sdk/OTelBridgeContext.java | 0 .../apm/agent/opentelemetry/sdk/OTelSpan.java | 0 .../opentelemetry/sdk/OTelSpanBuilder.java | 0 .../opentelemetry/sdk/OTelSpanContext.java | 0 .../sdk/OTelTextMapPropagator.java | 0 .../agent/opentelemetry/sdk/OTelTracer.java | 0 .../opentelemetry/sdk/OTelTracerProvider.java | 0 .../agent/opentelemetry/sdk/package-info.java | 0 ...ic.apm.agent.sdk.ElasticApmInstrumentation | 0 .../sdk/ElasticOpenTelemetryTest.java | 0 .../opentelemetry/sdk/OTelSpanKindTest.java | 0 .../java/specs/OTelBridgeCucumberTest.java | 0 .../specs/OTelBridgeStepsDefinitions.java | 0 .../apm-opentelemetry-test/pom.xml | 6 ++-- .../opentelemetry/OpenTelemetryVersionIT.java | 0 apm-agent-plugins/apm-opentelemetry/pom.xml | 30 +++++++++++++++++++ 25 files changed, 36 insertions(+), 9 deletions(-) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/pom.xml (89%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java (100%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-test/pom.xml (92%) rename apm-agent-plugins/{ => apm-opentelemetry}/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java (100%) create mode 100644 apm-agent-plugins/apm-opentelemetry/pom.xml diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml similarity index 89% rename from apm-agent-plugins/apm-opentelemetry-plugin/pom.xml rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml index 42aee08338..e9dc9ed094 100644 --- a/apm-agent-plugins/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml @@ -2,21 +2,18 @@ + 4.0.0 - apm-agent-plugins co.elastic.apm + apm-opentelemetry 1.29.1-SNAPSHOT - 4.0.0 apm-opentelemetry-plugin ${project.groupId}:${project.artifactId} - ${project.basedir}/../.. - 8 - 8 - true + ${project.basedir}/../../.. 1.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/AbstractOpenTelemetryInstrumentation.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ArrayBasedContextInstrumentation.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/ContextStorageInstrumentation.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/GlobalOpenTelemetryInstrumentation.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/package-info.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/package-info.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetry.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpan.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanContext.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracer.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTracerProvider.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/package-info.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/ElasticOpenTelemetryTest.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanKindTest.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeCucumberTest.java diff --git a/apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/test/java/specs/OTelBridgeStepsDefinitions.java diff --git a/apm-agent-plugins/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml similarity index 92% rename from apm-agent-plugins/apm-opentelemetry-test/pom.xml rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml index 9222642b07..1941f54946 100644 --- a/apm-agent-plugins/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml @@ -2,18 +2,18 @@ + 4.0.0 - apm-agent-plugins co.elastic.apm + apm-opentelemetry 1.29.1-SNAPSHOT - 4.0.0 ${project.groupId}:${project.artifactId} apm-opentelemetry-test - ${project.basedir}/../.. + ${project.basedir}/../../.. diff --git a/apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java similarity index 100% rename from apm-agent-plugins/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java rename to apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/src/test/java/co/elastic/apm/opentelemetry/OpenTelemetryVersionIT.java diff --git a/apm-agent-plugins/apm-opentelemetry/pom.xml b/apm-agent-plugins/apm-opentelemetry/pom.xml new file mode 100644 index 0000000000..cf03f84f0a --- /dev/null +++ b/apm-agent-plugins/apm-opentelemetry/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + + co.elastic.apm + apm-agent-plugins + 1.29.1-SNAPSHOT + + + apm-opentelemetry + ${project.groupId}:${project.artifactId} + pom + + + + ${project.basedir}/../.. + + 8 + 8 + true + + + + + apm-opentelemetry-plugin + apm-opentelemetry-test + + + From 6bae41e8f4d37a8e7ee21b7158bc2881c3382713 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 24 Feb 2022 16:54:18 +0100 Subject: [PATCH 76/94] move to dedicated sub-module for opentelemetry --- apm-agent-plugins/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apm-agent-plugins/pom.xml b/apm-agent-plugins/pom.xml index a413bbab7f..4aa0fe1850 100644 --- a/apm-agent-plugins/pom.xml +++ b/apm-agent-plugins/pom.xml @@ -59,8 +59,7 @@ apm-jdk-httpserver-plugin apm-rabbitmq apm-okhttp-test - apm-opentelemetry-plugin - apm-opentelemetry-test + apm-opentelemetry apm-cassandra apm-struts-plugin apm-vertx From 54d961f9ae2199cf902600db6c53019e3bca9d43 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Mon, 28 Feb 2022 13:41:13 +0100 Subject: [PATCH 77/94] capture OTel API version when possible --- .../agent/opentelemetry/sdk/OTelSpanBuilder.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 0eb28793f0..0b964246fe 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -23,10 +23,13 @@ import co.elastic.apm.agent.impl.transaction.MultiValueMapAccessor; import co.elastic.apm.agent.impl.transaction.OTelSpanKind; import co.elastic.apm.agent.impl.transaction.Outcome; +import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.sdk.logging.Logger; import co.elastic.apm.agent.sdk.logging.LoggerFactory; import co.elastic.apm.agent.util.LoggerUtils; import co.elastic.apm.agent.util.PotentiallyMultiValuedMap; +import co.elastic.apm.agent.util.VersionUtils; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; @@ -153,6 +156,16 @@ public Span startSpan() { } span.withName(spanName); + if (span instanceof Transaction) { + Transaction t = ((Transaction) span); + t.setFrameworkName("OpenTelemetry API"); + + String otelVersion = VersionUtils.getVersion(OpenTelemetry.class, "io.opentelemetry", "opentelemetry-api"); + if(otelVersion != null){ + t.setFrameworkVersion(otelVersion); + } + } + if (kind == null) { span.withOtelKind(OTelSpanKind.INTERNAL); } else { From 6b55f8810c31d0be89c9256f700a3ca7079a96b6 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 15:00:50 +0100 Subject: [PATCH 78/94] minimize changelog diff --- CHANGELOG.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 10c4bd9ea5..c547f5104c 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -20,8 +20,8 @@ endif::[] === Unreleased -[[release-notes-1.30.0]] -==== 1.30.0 - YYYY/MM/DD +[[release-notes-1.29.1]] +==== 1.29.1 - YYYY/MM/DD [float] ===== Features From bf95b39a5ba9f2c032f4d952544b814dea82719e Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 15:05:19 +0100 Subject: [PATCH 79/94] clarify some comments/doc --- .../agent/opentelemetry/context/OTelContextStorage.java | 7 ++++++- .../apm/agent/opentelemetry/sdk/OTelBridgeContext.java | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java index 4028452b0d..4d35b2e558 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/context/OTelContextStorage.java @@ -73,6 +73,7 @@ public Context current() { } if (current instanceof OTelBridgeContext) { + // current context is already OTel compliant, no need to upgrade it return (Context) current; } @@ -80,12 +81,16 @@ public Context current() { throw new IllegalStateException("unexpected context type to upgrade: " + current.getClass().getName()); } + // At this stage, the currently active span is a "regular elastic span", we need to upgrade and replace it with + // a bridged implementation that allows to make "regular elastic span" visible in the OTel context. + logger.debug("upgrading active context {} to a bridged context", current); tracer.deactivate(current); // Ensure that root context is being accessed at least once to capture the original root - // OTel 1.0 directly calls ArrayBasedContext.root(), whereas later versions delegate to ContextStorage.root(). + // OTel 1.0 directly calls ArrayBasedContext.root() which is not publicly accessible, later versions delegate + // to ContextStorage.root() which we can't call from here either. Context.root(); OTelBridgeContext upgradedContext = OTelBridgeContext.wrapElasticActiveSpan(tracer, (AbstractSpan) current); diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index 161c091bdd..17396dc037 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -30,6 +30,9 @@ import javax.annotation.Nullable; import java.util.Objects; +/** + * Bridge implementation of OpenTelemetry {@link Context} that allows to provide compatibility with {@link ElasticContext}. + */ public class OTelBridgeContext implements ElasticContext, Context, Scope { /** @@ -57,7 +60,7 @@ private OTelBridgeContext(ElasticApmTracer tracer, Context otelContext) { } /** - * Captures the original root context and setup the bridged root if required + * Captures the original root context and sets-up the bridged root if required * * @param tracer tracer * @param originalRoot original OTel root context From 71b53fa03c7b72a9ce21f2337eac9601ec32dfd5 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 15:07:44 +0100 Subject: [PATCH 80/94] properly reformat --- .../apm/agent/report/serialize/DslJsonSerializer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java index dce06e820a..f0cda03ac0 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java @@ -716,7 +716,7 @@ private void serializeSpan(final Span span) { private void serializeOTel(Span span) { OTelSpanKind kind = span.getOtelKind(); - Map attributes = span.getOtelAttributes(); + Map attributes = span.getOtelAttributes(); boolean hasAttributes = !attributes.isEmpty(); boolean hasKind = kind != null; if (hasKind || hasAttributes) { @@ -757,7 +757,7 @@ private void serializeOTel(Span span) { } } - private void serializeNumber(Number n, JsonWriter jw){ + private void serializeNumber(Number n, JsonWriter jw) { if (n instanceof Integer) { NumberConverter.serialize(n.intValue(), jw); } else if (n instanceof Long) { @@ -1397,7 +1397,7 @@ private void writeField(final String fieldName, final PotentiallyMultiValuedMap writeFieldName(fieldName); jw.writeByte(OBJECT_START); int size = map.size(); - if(supportsMultipleValues){ + if (supportsMultipleValues) { serializePotentiallyMultiValuedEntry(map.getKey(0), map.getValue(0)); for (int i = 1; i < size; i++) { jw.writeByte(COMMA); From 42751d9a443c16afdab2804983d1237f29a3ee01 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 15:22:28 +0100 Subject: [PATCH 81/94] minor fix to otel mvn dependencies --- .../apm-opentelemetry/apm-opentelemetry-plugin/pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml index e9dc9ed094..58be5c2b7e 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml @@ -15,7 +15,9 @@ ${project.basedir}/../../.. + 1.0.0 + 1.0.0-alpha @@ -32,7 +34,7 @@ io.opentelemetry opentelemetry-semconv - ${version.opentelemetry}-alpha + ${version.opentelemetry.semconv} provided From 1f59e49620b63fa48c591c514c22118af14cd451 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 15:22:52 +0100 Subject: [PATCH 82/94] remove unused context propagator --- .../sdk/OTelTextMapPropagator.java | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java deleted file mode 100644 index fe175fccd0..0000000000 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelTextMapPropagator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package co.elastic.apm.agent.opentelemetry.sdk; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.propagation.TextMapGetter; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.context.propagation.TextMapSetter; - -import javax.annotation.Nullable; -import java.util.Collection; - -public class OTelTextMapPropagator implements TextMapPropagator { - - private static final TextMapPropagator W3C_PROPAGATOR = W3CTraceContextPropagator.getInstance(); - - @Override - public Collection fields() { - return W3C_PROPAGATOR.fields(); - } - - @Override - public void inject(Context context, @Nullable C carrier, TextMapSetter setter) { - Span span = Span.fromContext(context); - if (span instanceof OTelSpan) { - ((OTelSpan) span).getInternalSpan().setNonDiscardable(); - } - W3C_PROPAGATOR.inject(context, carrier, setter); - } - - @Override - public Context extract(Context context, @Nullable C carrier, TextMapGetter getter) { - return W3C_PROPAGATOR.extract(context, carrier, getter); - } -} From f91dcdfcb41e1234a1e350fc826b6c2b22ddeedc Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 3 Mar 2022 16:28:39 +0100 Subject: [PATCH 83/94] bump version to 1.30.0 --- apm-agent-api/pom.xml | 2 +- apm-agent-attach-cli/pom.xml | 2 +- apm-agent-attach/pom.xml | 2 +- apm-agent-benchmarks/pom.xml | 2 +- apm-agent-bootstrap/pom.xml | 2 +- apm-agent-cached-lookup-key/pom.xml | 2 +- apm-agent-common/pom.xml | 2 +- apm-agent-core/pom.xml | 2 +- apm-agent-plugin-sdk/pom.xml | 2 +- apm-agent-plugins/apm-apache-httpclient-plugin/pom.xml | 2 +- apm-agent-plugins/apm-api-plugin/pom.xml | 2 +- apm-agent-plugins/apm-asynchttpclient-plugin/pom.xml | 2 +- apm-agent-plugins/apm-awslambda-plugin/pom.xml | 2 +- .../apm-cassandra/apm-cassandra-core-plugin/pom.xml | 2 +- apm-agent-plugins/apm-cassandra/apm-cassandra3-plugin/pom.xml | 2 +- apm-agent-plugins/apm-cassandra/apm-cassandra4-plugin/pom.xml | 2 +- apm-agent-plugins/apm-cassandra/pom.xml | 2 +- apm-agent-plugins/apm-dubbo-plugin/pom.xml | 2 +- apm-agent-plugins/apm-ecs-logging-plugin/pom.xml | 2 +- apm-agent-plugins/apm-error-logging-plugin/pom.xml | 2 +- .../apm-es-restclient-plugin-5_6/pom.xml | 2 +- .../apm-es-restclient-plugin-6_4/pom.xml | 2 +- .../apm-es-restclient-plugin-7_x/pom.xml | 2 +- .../apm-es-restclient-plugin-common/pom.xml | 2 +- apm-agent-plugins/apm-es-restclient-plugin/pom.xml | 2 +- apm-agent-plugins/apm-grails-plugin/pom.xml | 2 +- apm-agent-plugins/apm-grpc/apm-grpc-plugin/pom.xml | 2 +- apm-agent-plugins/apm-grpc/apm-grpc-test-1.6.1/pom.xml | 2 +- apm-agent-plugins/apm-grpc/apm-grpc-test-latest/pom.xml | 2 +- apm-agent-plugins/apm-grpc/pom.xml | 2 +- .../apm-hibernate-search-plugin-5_x/pom.xml | 2 +- .../apm-hibernate-search-plugin-6_x/pom.xml | 2 +- .../apm-hibernate-search-plugin-common/pom.xml | 2 +- apm-agent-plugins/apm-hibernate-search-plugin/pom.xml | 2 +- apm-agent-plugins/apm-httpclient-core/pom.xml | 2 +- apm-agent-plugins/apm-jakarta-websocket-plugin/pom.xml | 2 +- apm-agent-plugins/apm-java-concurrent-plugin/pom.xml | 2 +- apm-agent-plugins/apm-javalin-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jaxrs-plugin-jakartaee-test/pom.xml | 2 +- apm-agent-plugins/apm-jaxrs-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jaxws-plugin-jakartaee-test/pom.xml | 2 +- apm-agent-plugins/apm-jaxws-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jdbc-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jdk-httpclient-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jdk-httpserver-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jms-plugin/apm-jms-plugin-base/pom.xml | 2 +- apm-agent-plugins/apm-jms-plugin/apm-jms-spring-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jms-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jmx-plugin/pom.xml | 2 +- apm-agent-plugins/apm-jsf-plugin/pom.xml | 2 +- .../apm-kafka-plugin/apm-kafka-base-plugin/pom.xml | 2 +- .../apm-kafka-plugin/apm-kafka-headers-plugin/pom.xml | 2 +- apm-agent-plugins/apm-kafka-plugin/pom.xml | 2 +- apm-agent-plugins/apm-log-correlation-plugin/pom.xml | 2 +- .../apm-log-shader-plugin/apm-log-shader-plugin-common/pom.xml | 2 +- .../apm-log-shader-plugin/apm-log4j1-plugin/pom.xml | 2 +- .../apm-log-shader-plugin/apm-log4j2-plugin/pom.xml | 2 +- .../apm-logback-plugin/apm-logback-plugin-impl/pom.xml | 2 +- .../apm-logback-plugin/apm-logback-plugin-legacy-tests/pom.xml | 2 +- .../apm-log-shader-plugin/apm-logback-plugin/pom.xml | 2 +- apm-agent-plugins/apm-log-shader-plugin/pom.xml | 2 +- apm-agent-plugins/apm-log-shipper-plugin/pom.xml | 2 +- apm-agent-plugins/apm-micrometer-plugin/pom.xml | 2 +- apm-agent-plugins/apm-mongoclient-plugin/pom.xml | 2 +- apm-agent-plugins/apm-okhttp-plugin/pom.xml | 2 +- apm-agent-plugins/apm-okhttp-test/pom.xml | 2 +- .../apm-opentelemetry/apm-opentelemetry-plugin/pom.xml | 2 +- .../apm-opentelemetry/apm-opentelemetry-test/pom.xml | 2 +- apm-agent-plugins/apm-opentelemetry/pom.xml | 2 +- apm-agent-plugins/apm-opentracing-plugin/pom.xml | 2 +- apm-agent-plugins/apm-process-plugin/pom.xml | 2 +- apm-agent-plugins/apm-profiling-plugin/pom.xml | 2 +- .../apm-quartz-job-plugin/apm-quartz-1-plugin/pom.xml | 2 +- .../apm-quartz-job-plugin/apm-quartz-2-plugin/pom.xml | 2 +- apm-agent-plugins/apm-quartz-job-plugin/pom.xml | 2 +- apm-agent-plugins/apm-quartz-job-plugin/quartz-common/pom.xml | 2 +- apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-plugin/pom.xml | 2 +- apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-spring/pom.xml | 2 +- apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-3/pom.xml | 2 +- apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-4/pom.xml | 2 +- apm-agent-plugins/apm-rabbitmq/pom.xml | 2 +- apm-agent-plugins/apm-reactor-plugin/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-jedis-2-tests/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-jedis-3-tests/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-jedis-plugin/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-lettuce-3-tests/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-redis-common/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/apm-redisson-plugin/pom.xml | 2 +- apm-agent-plugins/apm-redis-plugin/pom.xml | 2 +- apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml | 2 +- .../apm-scheduled-annotation-plugin-jakartaee-test/pom.xml | 2 +- apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml | 2 +- apm-agent-plugins/apm-servlet-jakarta-test/pom.xml | 2 +- apm-agent-plugins/apm-servlet-plugin/pom.xml | 2 +- apm-agent-plugins/apm-sparkjava-plugin/pom.xml | 2 +- .../apm-spring-resttemplate-plugin/pom.xml | 2 +- .../apm-spring-resttemplate-test/pom.xml | 2 +- apm-agent-plugins/apm-spring-resttemplate/pom.xml | 2 +- .../apm-spring-webflux/apm-spring-webflux-plugin/pom.xml | 2 +- .../apm-spring-webflux/apm-spring-webflux-testapp/pom.xml | 2 +- apm-agent-plugins/apm-spring-webflux/pom.xml | 2 +- apm-agent-plugins/apm-spring-webmvc-plugin/pom.xml | 2 +- apm-agent-plugins/apm-struts-plugin/pom.xml | 2 +- apm-agent-plugins/apm-urlconnection-plugin/pom.xml | 2 +- apm-agent-plugins/apm-vertx/apm-vertx-common/pom.xml | 2 +- apm-agent-plugins/apm-vertx/apm-vertx3-plugin/pom.xml | 2 +- apm-agent-plugins/apm-vertx/apm-vertx3-test-latest/pom.xml | 2 +- apm-agent-plugins/apm-vertx/apm-vertx4-plugin/pom.xml | 2 +- apm-agent-plugins/apm-vertx/pom.xml | 2 +- apm-agent-plugins/pom.xml | 2 +- apm-agent/pom.xml | 2 +- apm-opentracing/pom.xml | 2 +- elastic-apm-agent/pom.xml | 2 +- integration-tests/application-server-integration-tests/pom.xml | 2 +- integration-tests/cdi-app/cdi-app-dependent/pom.xml | 2 +- integration-tests/cdi-app/cdi-app-standalone/pom.xml | 2 +- integration-tests/cdi-app/pom.xml | 2 +- .../cdi-jakartaee-app/cdi-jakartaee-app-dependent/pom.xml | 2 +- .../cdi-jakartaee-app/cdi-jakartaee-app-standalone/pom.xml | 2 +- integration-tests/cdi-jakartaee-app/pom.xml | 2 +- .../external-plugin-test/external-plugin-app/pom.xml | 2 +- .../external-plugin-test/external-plugin-jakarta-app/pom.xml | 2 +- integration-tests/external-plugin-test/external-plugin/pom.xml | 2 +- .../external-plugin-test/plugin-instrumentation-target/pom.xml | 2 +- integration-tests/external-plugin-test/pom.xml | 2 +- .../jakartaee-jsf-app/jakartaee-jsf-app-dependent/pom.xml | 2 +- .../jakartaee-jsf-app/jakartaee-jsf-app-standalone/pom.xml | 2 +- integration-tests/jakartaee-jsf-app/pom.xml | 2 +- integration-tests/jakartaee-simple-webapp/pom.xml | 2 +- integration-tests/jsf-app/jsf-app-dependent/pom.xml | 2 +- integration-tests/jsf-app/jsf-app-standalone/pom.xml | 2 +- integration-tests/jsf-app/pom.xml | 2 +- integration-tests/main-app-test/pom.xml | 2 +- integration-tests/pom.xml | 2 +- integration-tests/runtime-attach/pom.xml | 2 +- integration-tests/runtime-attach/runtime-attach-app/pom.xml | 2 +- integration-tests/runtime-attach/runtime-attach-test/pom.xml | 2 +- integration-tests/simple-webapp/pom.xml | 2 +- integration-tests/soap-test/pom.xml | 2 +- integration-tests/spring-boot-1-5/pom.xml | 2 +- integration-tests/spring-boot-2/pom.xml | 2 +- integration-tests/spring-boot-2/spring-boot-2-base/pom.xml | 2 +- integration-tests/spring-boot-2/spring-boot-2-jetty/pom.xml | 2 +- integration-tests/spring-boot-2/spring-boot-2-tomcat/pom.xml | 2 +- integration-tests/spring-boot-2/spring-boot-2-undertow/pom.xml | 2 +- pom.xml | 2 +- 147 files changed, 147 insertions(+), 147 deletions(-) diff --git a/apm-agent-api/pom.xml b/apm-agent-api/pom.xml index 58e0e60aeb..ef4a956faa 100644 --- a/apm-agent-api/pom.xml +++ b/apm-agent-api/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-api diff --git a/apm-agent-attach-cli/pom.xml b/apm-agent-attach-cli/pom.xml index de61597487..137dde5893 100644 --- a/apm-agent-attach-cli/pom.xml +++ b/apm-agent-attach-cli/pom.xml @@ -3,7 +3,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-attach/pom.xml b/apm-agent-attach/pom.xml index 882f786713..517a323f2e 100644 --- a/apm-agent-attach/pom.xml +++ b/apm-agent-attach/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-attach diff --git a/apm-agent-benchmarks/pom.xml b/apm-agent-benchmarks/pom.xml index 722c484829..7b0d9b5242 100644 --- a/apm-agent-benchmarks/pom.xml +++ b/apm-agent-benchmarks/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-benchmarks diff --git a/apm-agent-bootstrap/pom.xml b/apm-agent-bootstrap/pom.xml index 94a130b166..49e32e1af0 100644 --- a/apm-agent-bootstrap/pom.xml +++ b/apm-agent-bootstrap/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-bootstrap diff --git a/apm-agent-cached-lookup-key/pom.xml b/apm-agent-cached-lookup-key/pom.xml index 3d087265f3..2f4efbd6ae 100644 --- a/apm-agent-cached-lookup-key/pom.xml +++ b/apm-agent-cached-lookup-key/pom.xml @@ -3,7 +3,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-common/pom.xml b/apm-agent-common/pom.xml index 19c0ea89fc..692d536e77 100644 --- a/apm-agent-common/pom.xml +++ b/apm-agent-common/pom.xml @@ -3,7 +3,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-core/pom.xml b/apm-agent-core/pom.xml index 7cd5a1f435..9aed6aa5b2 100644 --- a/apm-agent-core/pom.xml +++ b/apm-agent-core/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-core diff --git a/apm-agent-plugin-sdk/pom.xml b/apm-agent-plugin-sdk/pom.xml index 59e2ed1a55..61bd32cb55 100644 --- a/apm-agent-plugin-sdk/pom.xml +++ b/apm-agent-plugin-sdk/pom.xml @@ -3,7 +3,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-apache-httpclient-plugin/pom.xml b/apm-agent-plugins/apm-apache-httpclient-plugin/pom.xml index 584c0cec7b..4ef61e1cfb 100644 --- a/apm-agent-plugins/apm-apache-httpclient-plugin/pom.xml +++ b/apm-agent-plugins/apm-apache-httpclient-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-apache-httpclient-plugin diff --git a/apm-agent-plugins/apm-api-plugin/pom.xml b/apm-agent-plugins/apm-api-plugin/pom.xml index 97dc8778e2..0da3ed3130 100644 --- a/apm-agent-plugins/apm-api-plugin/pom.xml +++ b/apm-agent-plugins/apm-api-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT diff --git a/apm-agent-plugins/apm-asynchttpclient-plugin/pom.xml b/apm-agent-plugins/apm-asynchttpclient-plugin/pom.xml index 20e38ac8b5..f40c00a911 100644 --- a/apm-agent-plugins/apm-asynchttpclient-plugin/pom.xml +++ b/apm-agent-plugins/apm-asynchttpclient-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-asynchttpclient-plugin diff --git a/apm-agent-plugins/apm-awslambda-plugin/pom.xml b/apm-agent-plugins/apm-awslambda-plugin/pom.xml index e0f984e866..4d1c0d34ac 100644 --- a/apm-agent-plugins/apm-awslambda-plugin/pom.xml +++ b/apm-agent-plugins/apm-awslambda-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-cassandra/apm-cassandra-core-plugin/pom.xml b/apm-agent-plugins/apm-cassandra/apm-cassandra-core-plugin/pom.xml index dcf994f8e3..acc2414795 100644 --- a/apm-agent-plugins/apm-cassandra/apm-cassandra-core-plugin/pom.xml +++ b/apm-agent-plugins/apm-cassandra/apm-cassandra-core-plugin/pom.xml @@ -3,7 +3,7 @@ apm-cassandra co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-cassandra/apm-cassandra3-plugin/pom.xml b/apm-agent-plugins/apm-cassandra/apm-cassandra3-plugin/pom.xml index 567f63260b..055698b81a 100644 --- a/apm-agent-plugins/apm-cassandra/apm-cassandra3-plugin/pom.xml +++ b/apm-agent-plugins/apm-cassandra/apm-cassandra3-plugin/pom.xml @@ -3,7 +3,7 @@ apm-cassandra co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-cassandra/apm-cassandra4-plugin/pom.xml b/apm-agent-plugins/apm-cassandra/apm-cassandra4-plugin/pom.xml index 526cbc9627..4887171c39 100644 --- a/apm-agent-plugins/apm-cassandra/apm-cassandra4-plugin/pom.xml +++ b/apm-agent-plugins/apm-cassandra/apm-cassandra4-plugin/pom.xml @@ -3,7 +3,7 @@ apm-cassandra co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-cassandra/pom.xml b/apm-agent-plugins/apm-cassandra/pom.xml index d64faebf6f..297dd610eb 100644 --- a/apm-agent-plugins/apm-cassandra/pom.xml +++ b/apm-agent-plugins/apm-cassandra/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-dubbo-plugin/pom.xml b/apm-agent-plugins/apm-dubbo-plugin/pom.xml index fa4b3b7285..20f2b8c561 100644 --- a/apm-agent-plugins/apm-dubbo-plugin/pom.xml +++ b/apm-agent-plugins/apm-dubbo-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-ecs-logging-plugin/pom.xml b/apm-agent-plugins/apm-ecs-logging-plugin/pom.xml index 0bd3c0f80e..a8424a0060 100644 --- a/apm-agent-plugins/apm-ecs-logging-plugin/pom.xml +++ b/apm-agent-plugins/apm-ecs-logging-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-ecs-logging-plugin diff --git a/apm-agent-plugins/apm-error-logging-plugin/pom.xml b/apm-agent-plugins/apm-error-logging-plugin/pom.xml index d1dbc2fbf0..d051565ad2 100644 --- a/apm-agent-plugins/apm-error-logging-plugin/pom.xml +++ b/apm-agent-plugins/apm-error-logging-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-error-logging-plugin diff --git a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-5_6/pom.xml b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-5_6/pom.xml index 0cebba5ab4..fc96731626 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-5_6/pom.xml +++ b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-5_6/pom.xml @@ -5,7 +5,7 @@ apm-es-restclient-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-es-restclient-plugin-5_6 diff --git a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-6_4/pom.xml b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-6_4/pom.xml index db7e3854b2..3cea906adf 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-6_4/pom.xml +++ b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-6_4/pom.xml @@ -5,7 +5,7 @@ apm-es-restclient-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-es-restclient-plugin-6_4 diff --git a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-7_x/pom.xml b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-7_x/pom.xml index b9cec05f19..36d54c5745 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-7_x/pom.xml +++ b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-7_x/pom.xml @@ -5,7 +5,7 @@ apm-es-restclient-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-es-restclient-plugin-7_x diff --git a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/pom.xml b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/pom.xml index 703dd61089..4e09236923 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/pom.xml +++ b/apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-common/pom.xml @@ -5,7 +5,7 @@ apm-es-restclient-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-es-restclient-plugin-common diff --git a/apm-agent-plugins/apm-es-restclient-plugin/pom.xml b/apm-agent-plugins/apm-es-restclient-plugin/pom.xml index bd54ada6fa..2e13607c1b 100644 --- a/apm-agent-plugins/apm-es-restclient-plugin/pom.xml +++ b/apm-agent-plugins/apm-es-restclient-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-es-restclient-plugin diff --git a/apm-agent-plugins/apm-grails-plugin/pom.xml b/apm-agent-plugins/apm-grails-plugin/pom.xml index 9f7941c797..797c9148d2 100644 --- a/apm-agent-plugins/apm-grails-plugin/pom.xml +++ b/apm-agent-plugins/apm-grails-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-grails-plugin diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/pom.xml b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/pom.xml index a274dab997..c77876dbed 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/pom.xml +++ b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-grpc - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-grpc-plugin diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-test-1.6.1/pom.xml b/apm-agent-plugins/apm-grpc/apm-grpc-test-1.6.1/pom.xml index deb6826a5e..c138cfa990 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-test-1.6.1/pom.xml +++ b/apm-agent-plugins/apm-grpc/apm-grpc-test-1.6.1/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-grpc - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-grpc-test-1.6.1 diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/pom.xml b/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/pom.xml index 7ae82986a7..077093803f 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/pom.xml +++ b/apm-agent-plugins/apm-grpc/apm-grpc-test-latest/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-grpc - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-grpc-test-latest diff --git a/apm-agent-plugins/apm-grpc/pom.xml b/apm-agent-plugins/apm-grpc/pom.xml index 0939e0ca88..3b8255263b 100644 --- a/apm-agent-plugins/apm-grpc/pom.xml +++ b/apm-agent-plugins/apm-grpc/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-plugins - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-grpc diff --git a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-5_x/pom.xml b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-5_x/pom.xml index 9b3d82c62a..c86a2ad3d1 100644 --- a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-5_x/pom.xml +++ b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-5_x/pom.xml @@ -5,7 +5,7 @@ apm-hibernate-search-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-hibernate-search-plugin-5_x diff --git a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-6_x/pom.xml b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-6_x/pom.xml index 115329f8d2..4dec17fb24 100644 --- a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-6_x/pom.xml +++ b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-6_x/pom.xml @@ -5,7 +5,7 @@ apm-hibernate-search-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-hibernate-search-plugin-6_x diff --git a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-common/pom.xml b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-common/pom.xml index 96cf1f7aa8..734fbac343 100644 --- a/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-common/pom.xml +++ b/apm-agent-plugins/apm-hibernate-search-plugin/apm-hibernate-search-plugin-common/pom.xml @@ -5,7 +5,7 @@ apm-hibernate-search-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-hibernate-search-plugin-common diff --git a/apm-agent-plugins/apm-hibernate-search-plugin/pom.xml b/apm-agent-plugins/apm-hibernate-search-plugin/pom.xml index 446d8fe5b2..9ca877963c 100644 --- a/apm-agent-plugins/apm-hibernate-search-plugin/pom.xml +++ b/apm-agent-plugins/apm-hibernate-search-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-hibernate-search-plugin diff --git a/apm-agent-plugins/apm-httpclient-core/pom.xml b/apm-agent-plugins/apm-httpclient-core/pom.xml index a010da12ac..065a6bd8db 100644 --- a/apm-agent-plugins/apm-httpclient-core/pom.xml +++ b/apm-agent-plugins/apm-httpclient-core/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-httpclient-core diff --git a/apm-agent-plugins/apm-jakarta-websocket-plugin/pom.xml b/apm-agent-plugins/apm-jakarta-websocket-plugin/pom.xml index 302a6d3045..478a480ddd 100644 --- a/apm-agent-plugins/apm-jakarta-websocket-plugin/pom.xml +++ b/apm-agent-plugins/apm-jakarta-websocket-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jakarta-websocket-plugin diff --git a/apm-agent-plugins/apm-java-concurrent-plugin/pom.xml b/apm-agent-plugins/apm-java-concurrent-plugin/pom.xml index 85d1bba7b5..79d36b2a2c 100644 --- a/apm-agent-plugins/apm-java-concurrent-plugin/pom.xml +++ b/apm-agent-plugins/apm-java-concurrent-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-java-concurrent-plugin diff --git a/apm-agent-plugins/apm-javalin-plugin/pom.xml b/apm-agent-plugins/apm-javalin-plugin/pom.xml index 78b3238c4f..d15c2fb192 100644 --- a/apm-agent-plugins/apm-javalin-plugin/pom.xml +++ b/apm-agent-plugins/apm-javalin-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-javalin-plugin diff --git a/apm-agent-plugins/apm-jaxrs-plugin-jakartaee-test/pom.xml b/apm-agent-plugins/apm-jaxrs-plugin-jakartaee-test/pom.xml index 4ceba9c1c0..d6c6a10ae8 100644 --- a/apm-agent-plugins/apm-jaxrs-plugin-jakartaee-test/pom.xml +++ b/apm-agent-plugins/apm-jaxrs-plugin-jakartaee-test/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-jaxrs-plugin/pom.xml b/apm-agent-plugins/apm-jaxrs-plugin/pom.xml index f7f039eae0..a31e4cafd1 100644 --- a/apm-agent-plugins/apm-jaxrs-plugin/pom.xml +++ b/apm-agent-plugins/apm-jaxrs-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jaxrs-plugin diff --git a/apm-agent-plugins/apm-jaxws-plugin-jakartaee-test/pom.xml b/apm-agent-plugins/apm-jaxws-plugin-jakartaee-test/pom.xml index 675555795d..193846170e 100644 --- a/apm-agent-plugins/apm-jaxws-plugin-jakartaee-test/pom.xml +++ b/apm-agent-plugins/apm-jaxws-plugin-jakartaee-test/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-jaxws-plugin/pom.xml b/apm-agent-plugins/apm-jaxws-plugin/pom.xml index 28308c9b57..c292444e47 100644 --- a/apm-agent-plugins/apm-jaxws-plugin/pom.xml +++ b/apm-agent-plugins/apm-jaxws-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jaxws-plugin diff --git a/apm-agent-plugins/apm-jdbc-plugin/pom.xml b/apm-agent-plugins/apm-jdbc-plugin/pom.xml index 110fa846aa..715f7835e8 100644 --- a/apm-agent-plugins/apm-jdbc-plugin/pom.xml +++ b/apm-agent-plugins/apm-jdbc-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jdbc-plugin diff --git a/apm-agent-plugins/apm-jdk-httpclient-plugin/pom.xml b/apm-agent-plugins/apm-jdk-httpclient-plugin/pom.xml index cbad9b9e86..922d06f6f3 100644 --- a/apm-agent-plugins/apm-jdk-httpclient-plugin/pom.xml +++ b/apm-agent-plugins/apm-jdk-httpclient-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jdk-httpclient-plugin diff --git a/apm-agent-plugins/apm-jdk-httpserver-plugin/pom.xml b/apm-agent-plugins/apm-jdk-httpserver-plugin/pom.xml index 3e88bf1742..083fad6dba 100644 --- a/apm-agent-plugins/apm-jdk-httpserver-plugin/pom.xml +++ b/apm-agent-plugins/apm-jdk-httpserver-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jdk-httpserver-plugin diff --git a/apm-agent-plugins/apm-jms-plugin/apm-jms-plugin-base/pom.xml b/apm-agent-plugins/apm-jms-plugin/apm-jms-plugin-base/pom.xml index 1fc3885ffc..51837eb21f 100644 --- a/apm-agent-plugins/apm-jms-plugin/apm-jms-plugin-base/pom.xml +++ b/apm-agent-plugins/apm-jms-plugin/apm-jms-plugin-base/pom.xml @@ -5,7 +5,7 @@ apm-jms-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jms-plugin-base diff --git a/apm-agent-plugins/apm-jms-plugin/apm-jms-spring-plugin/pom.xml b/apm-agent-plugins/apm-jms-plugin/apm-jms-spring-plugin/pom.xml index 5d00865d59..eca76acbd0 100644 --- a/apm-agent-plugins/apm-jms-plugin/apm-jms-spring-plugin/pom.xml +++ b/apm-agent-plugins/apm-jms-plugin/apm-jms-spring-plugin/pom.xml @@ -5,7 +5,7 @@ apm-jms-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jms-spring-plugin diff --git a/apm-agent-plugins/apm-jms-plugin/pom.xml b/apm-agent-plugins/apm-jms-plugin/pom.xml index 3f9c60b0f7..3ab71594c7 100644 --- a/apm-agent-plugins/apm-jms-plugin/pom.xml +++ b/apm-agent-plugins/apm-jms-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jms-plugin diff --git a/apm-agent-plugins/apm-jmx-plugin/pom.xml b/apm-agent-plugins/apm-jmx-plugin/pom.xml index d1810cc9f8..0bba656b3d 100644 --- a/apm-agent-plugins/apm-jmx-plugin/pom.xml +++ b/apm-agent-plugins/apm-jmx-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jmx-plugin diff --git a/apm-agent-plugins/apm-jsf-plugin/pom.xml b/apm-agent-plugins/apm-jsf-plugin/pom.xml index c3ac10d548..bed5aabd6b 100644 --- a/apm-agent-plugins/apm-jsf-plugin/pom.xml +++ b/apm-agent-plugins/apm-jsf-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jsf-plugin diff --git a/apm-agent-plugins/apm-kafka-plugin/apm-kafka-base-plugin/pom.xml b/apm-agent-plugins/apm-kafka-plugin/apm-kafka-base-plugin/pom.xml index 836774b645..019f80e0c3 100644 --- a/apm-agent-plugins/apm-kafka-plugin/apm-kafka-base-plugin/pom.xml +++ b/apm-agent-plugins/apm-kafka-plugin/apm-kafka-base-plugin/pom.xml @@ -3,7 +3,7 @@ apm-kafka-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-kafka-plugin/apm-kafka-headers-plugin/pom.xml b/apm-agent-plugins/apm-kafka-plugin/apm-kafka-headers-plugin/pom.xml index eb63b9f22d..5f6c869b72 100644 --- a/apm-agent-plugins/apm-kafka-plugin/apm-kafka-headers-plugin/pom.xml +++ b/apm-agent-plugins/apm-kafka-plugin/apm-kafka-headers-plugin/pom.xml @@ -4,7 +4,7 @@ apm-kafka-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-kafka-plugin/pom.xml b/apm-agent-plugins/apm-kafka-plugin/pom.xml index 155f636066..98e8e2900f 100644 --- a/apm-agent-plugins/apm-kafka-plugin/pom.xml +++ b/apm-agent-plugins/apm-kafka-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-log-correlation-plugin/pom.xml b/apm-agent-plugins/apm-log-correlation-plugin/pom.xml index 50af18fa39..2ee34e9689 100644 --- a/apm-agent-plugins/apm-log-correlation-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-correlation-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log-correlation-plugin diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-log-shader-plugin-common/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-log-shader-plugin-common/pom.xml index 9dfddf3610..05117f3a90 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-log-shader-plugin-common/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-log-shader-plugin-common/pom.xml @@ -5,7 +5,7 @@ apm-log-shader-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log-shader-plugin-common diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-log4j1-plugin/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-log4j1-plugin/pom.xml index afb3c251bc..dc832c4693 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-log4j1-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-log4j1-plugin/pom.xml @@ -5,7 +5,7 @@ apm-log-shader-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log4j1-plugin diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-log4j2-plugin/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-log4j2-plugin/pom.xml index 38fe67cc13..27cb3f5e2d 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-log4j2-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-log4j2-plugin/pom.xml @@ -5,7 +5,7 @@ apm-log-shader-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log4j2-plugin diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-impl/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-impl/pom.xml index 9f558575dd..9fd908f291 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-impl/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-impl/pom.xml @@ -5,7 +5,7 @@ apm-logback-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-logback-plugin-impl diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-legacy-tests/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-legacy-tests/pom.xml index 0b72418e35..32414cae74 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-legacy-tests/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/apm-logback-plugin-legacy-tests/pom.xml @@ -5,7 +5,7 @@ apm-logback-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-logback-plugin-legacy-tests diff --git a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/pom.xml index d52439f019..f5b3a860d2 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/apm-logback-plugin/pom.xml @@ -5,7 +5,7 @@ apm-log-shader-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-logback-plugin diff --git a/apm-agent-plugins/apm-log-shader-plugin/pom.xml b/apm-agent-plugins/apm-log-shader-plugin/pom.xml index 10db060eb6..a984cce54e 100644 --- a/apm-agent-plugins/apm-log-shader-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-shader-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log-shader-plugin diff --git a/apm-agent-plugins/apm-log-shipper-plugin/pom.xml b/apm-agent-plugins/apm-log-shipper-plugin/pom.xml index b13385a153..1c993fb706 100644 --- a/apm-agent-plugins/apm-log-shipper-plugin/pom.xml +++ b/apm-agent-plugins/apm-log-shipper-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-log-shipper-plugin diff --git a/apm-agent-plugins/apm-micrometer-plugin/pom.xml b/apm-agent-plugins/apm-micrometer-plugin/pom.xml index 63548090ff..8a987b9429 100644 --- a/apm-agent-plugins/apm-micrometer-plugin/pom.xml +++ b/apm-agent-plugins/apm-micrometer-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-mongoclient-plugin/pom.xml b/apm-agent-plugins/apm-mongoclient-plugin/pom.xml index 0997a5d3ef..ebbc7a50ee 100644 --- a/apm-agent-plugins/apm-mongoclient-plugin/pom.xml +++ b/apm-agent-plugins/apm-mongoclient-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-okhttp-plugin/pom.xml b/apm-agent-plugins/apm-okhttp-plugin/pom.xml index 18ec29b0c7..82d937e406 100644 --- a/apm-agent-plugins/apm-okhttp-plugin/pom.xml +++ b/apm-agent-plugins/apm-okhttp-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-okhttp-plugin diff --git a/apm-agent-plugins/apm-okhttp-test/pom.xml b/apm-agent-plugins/apm-okhttp-test/pom.xml index f36e10c091..f6d3ff5eab 100644 --- a/apm-agent-plugins/apm-okhttp-test/pom.xml +++ b/apm-agent-plugins/apm-okhttp-test/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml index 58be5c2b7e..5a0f0f355a 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/pom.xml @@ -6,7 +6,7 @@ co.elastic.apm apm-opentelemetry - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-opentelemetry-plugin diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml index 1941f54946..69a948bcea 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-test/pom.xml @@ -6,7 +6,7 @@ co.elastic.apm apm-opentelemetry - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/apm-agent-plugins/apm-opentelemetry/pom.xml b/apm-agent-plugins/apm-opentelemetry/pom.xml index cf03f84f0a..8fd80d473a 100644 --- a/apm-agent-plugins/apm-opentelemetry/pom.xml +++ b/apm-agent-plugins/apm-opentelemetry/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-plugins - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-opentelemetry diff --git a/apm-agent-plugins/apm-opentracing-plugin/pom.xml b/apm-agent-plugins/apm-opentracing-plugin/pom.xml index b1523903b1..a99b718065 100644 --- a/apm-agent-plugins/apm-opentracing-plugin/pom.xml +++ b/apm-agent-plugins/apm-opentracing-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-opentracing-plugin diff --git a/apm-agent-plugins/apm-process-plugin/pom.xml b/apm-agent-plugins/apm-process-plugin/pom.xml index 181384059b..b195fd47d3 100644 --- a/apm-agent-plugins/apm-process-plugin/pom.xml +++ b/apm-agent-plugins/apm-process-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-profiling-plugin/pom.xml b/apm-agent-plugins/apm-profiling-plugin/pom.xml index e6b5b85971..1697bae89e 100644 --- a/apm-agent-plugins/apm-profiling-plugin/pom.xml +++ b/apm-agent-plugins/apm-profiling-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-profiling-plugin diff --git a/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-1-plugin/pom.xml b/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-1-plugin/pom.xml index bc8e380a37..809fcb8ba9 100644 --- a/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-1-plugin/pom.xml +++ b/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-1-plugin/pom.xml @@ -3,7 +3,7 @@ apm-quartz-job-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-2-plugin/pom.xml b/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-2-plugin/pom.xml index 5e0b958ff6..a021d265f6 100644 --- a/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-2-plugin/pom.xml +++ b/apm-agent-plugins/apm-quartz-job-plugin/apm-quartz-2-plugin/pom.xml @@ -3,7 +3,7 @@ apm-quartz-job-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-quartz-job-plugin/pom.xml b/apm-agent-plugins/apm-quartz-job-plugin/pom.xml index e0c213bb38..87a985b00f 100644 --- a/apm-agent-plugins/apm-quartz-job-plugin/pom.xml +++ b/apm-agent-plugins/apm-quartz-job-plugin/pom.xml @@ -11,7 +11,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-quartz-job-plugin diff --git a/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/pom.xml b/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/pom.xml index 46ea522d5f..d45e5becc8 100644 --- a/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/pom.xml +++ b/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/pom.xml @@ -3,7 +3,7 @@ apm-quartz-job-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-plugin/pom.xml b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-plugin/pom.xml index 78709c8884..73c3c07974 100644 --- a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-plugin/pom.xml +++ b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-plugin/pom.xml @@ -5,7 +5,7 @@ apm-rabbitmq co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-rabbitmq-plugin diff --git a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-spring/pom.xml b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-spring/pom.xml index 71aaece9cb..23b50ec89e 100644 --- a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-spring/pom.xml +++ b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-spring/pom.xml @@ -5,7 +5,7 @@ apm-rabbitmq co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-rabbitmq-spring diff --git a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-3/pom.xml b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-3/pom.xml index 096dd7d188..81c9e32b2a 100644 --- a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-3/pom.xml +++ b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-3/pom.xml @@ -5,7 +5,7 @@ apm-rabbitmq co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-rabbitmq-test-3 diff --git a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-4/pom.xml b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-4/pom.xml index f55cb46c4d..01c70ed93f 100644 --- a/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-4/pom.xml +++ b/apm-agent-plugins/apm-rabbitmq/apm-rabbitmq-test-4/pom.xml @@ -5,7 +5,7 @@ apm-rabbitmq co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-rabbitmq-test-4 diff --git a/apm-agent-plugins/apm-rabbitmq/pom.xml b/apm-agent-plugins/apm-rabbitmq/pom.xml index 61f3638e49..03d4441bef 100644 --- a/apm-agent-plugins/apm-rabbitmq/pom.xml +++ b/apm-agent-plugins/apm-rabbitmq/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-rabbitmq diff --git a/apm-agent-plugins/apm-reactor-plugin/pom.xml b/apm-agent-plugins/apm-reactor-plugin/pom.xml index 87625cb913..730c3127a4 100644 --- a/apm-agent-plugins/apm-reactor-plugin/pom.xml +++ b/apm-agent-plugins/apm-reactor-plugin/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-plugins - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-reactor-plugin diff --git a/apm-agent-plugins/apm-redis-plugin/apm-jedis-2-tests/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-jedis-2-tests/pom.xml index a3c7aa0a56..16d18a6565 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-jedis-2-tests/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-jedis-2-tests/pom.xml @@ -5,7 +5,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jedis-2-tests diff --git a/apm-agent-plugins/apm-redis-plugin/apm-jedis-3-tests/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-jedis-3-tests/pom.xml index f3f75c9c2a..2bf392045c 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-jedis-3-tests/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-jedis-3-tests/pom.xml @@ -5,7 +5,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jedis-3-tests diff --git a/apm-agent-plugins/apm-redis-plugin/apm-jedis-plugin/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-jedis-plugin/pom.xml index 514478a2d7..0017a84c23 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-jedis-plugin/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-jedis-plugin/pom.xml @@ -5,7 +5,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-jedis-plugin diff --git a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-3-tests/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-3-tests/pom.xml index 35222ade43..0490982b65 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-3-tests/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-3-tests/pom.xml @@ -3,7 +3,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/pom.xml index e3daf5dd85..fa7860a849 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/pom.xml @@ -3,7 +3,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-redis-plugin/apm-redis-common/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-redis-common/pom.xml index 2bf3ce50e2..8d6c84ac4d 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-redis-common/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-redis-common/pom.xml @@ -5,7 +5,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-redis-common diff --git a/apm-agent-plugins/apm-redis-plugin/apm-redisson-plugin/pom.xml b/apm-agent-plugins/apm-redis-plugin/apm-redisson-plugin/pom.xml index 064cb8a48f..4fb2e04d95 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-redisson-plugin/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/apm-redisson-plugin/pom.xml @@ -5,7 +5,7 @@ apm-redis-plugin co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-redisson-plugin diff --git a/apm-agent-plugins/apm-redis-plugin/pom.xml b/apm-agent-plugins/apm-redis-plugin/pom.xml index f86ad01f1f..3008ab169d 100644 --- a/apm-agent-plugins/apm-redis-plugin/pom.xml +++ b/apm-agent-plugins/apm-redis-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-redis-plugin diff --git a/apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml b/apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml index 7be4890c5f..c251cbfe3b 100644 --- a/apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml +++ b/apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-scala-concurrent-plugin diff --git a/apm-agent-plugins/apm-scheduled-annotation-plugin-jakartaee-test/pom.xml b/apm-agent-plugins/apm-scheduled-annotation-plugin-jakartaee-test/pom.xml index 362f2727f7..5cceb3b720 100644 --- a/apm-agent-plugins/apm-scheduled-annotation-plugin-jakartaee-test/pom.xml +++ b/apm-agent-plugins/apm-scheduled-annotation-plugin-jakartaee-test/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml b/apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml index 63f9cedfb5..7e866d2678 100644 --- a/apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml +++ b/apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-scheduled-annotation-plugin diff --git a/apm-agent-plugins/apm-servlet-jakarta-test/pom.xml b/apm-agent-plugins/apm-servlet-jakarta-test/pom.xml index 47688ad5fa..9e1376129b 100644 --- a/apm-agent-plugins/apm-servlet-jakarta-test/pom.xml +++ b/apm-agent-plugins/apm-servlet-jakarta-test/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-servlet-jakarta-test diff --git a/apm-agent-plugins/apm-servlet-plugin/pom.xml b/apm-agent-plugins/apm-servlet-plugin/pom.xml index f3b3d9fb7d..0a8ffad6eb 100644 --- a/apm-agent-plugins/apm-servlet-plugin/pom.xml +++ b/apm-agent-plugins/apm-servlet-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-servlet-plugin diff --git a/apm-agent-plugins/apm-sparkjava-plugin/pom.xml b/apm-agent-plugins/apm-sparkjava-plugin/pom.xml index c5a38e175a..d3e0f46843 100644 --- a/apm-agent-plugins/apm-sparkjava-plugin/pom.xml +++ b/apm-agent-plugins/apm-sparkjava-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/pom.xml b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/pom.xml index a649b83cad..509dfa6f99 100644 --- a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/pom.xml +++ b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-plugin/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-spring-resttemplate - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-resttemplate-plugin diff --git a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-test/pom.xml b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-test/pom.xml index bfe841f571..f08325f563 100644 --- a/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-test/pom.xml +++ b/apm-agent-plugins/apm-spring-resttemplate/apm-spring-resttemplate-test/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-spring-resttemplate - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-resttemplate-test diff --git a/apm-agent-plugins/apm-spring-resttemplate/pom.xml b/apm-agent-plugins/apm-spring-resttemplate/pom.xml index c5c29faa49..a1c1551134 100644 --- a/apm-agent-plugins/apm-spring-resttemplate/pom.xml +++ b/apm-agent-plugins/apm-spring-resttemplate/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-plugins - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-resttemplate diff --git a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-plugin/pom.xml b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-plugin/pom.xml index 1ec8bf562e..d705a4ce60 100644 --- a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-plugin/pom.xml +++ b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-plugin/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-spring-webflux - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-webflux-plugin diff --git a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-testapp/pom.xml b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-testapp/pom.xml index bc43caf827..06389f49ab 100644 --- a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-testapp/pom.xml +++ b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-testapp/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-spring-webflux - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-webflux-testapp diff --git a/apm-agent-plugins/apm-spring-webflux/pom.xml b/apm-agent-plugins/apm-spring-webflux/pom.xml index aa987e32ad..66a54ea05e 100644 --- a/apm-agent-plugins/apm-spring-webflux/pom.xml +++ b/apm-agent-plugins/apm-spring-webflux/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-plugins - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-webflux diff --git a/apm-agent-plugins/apm-spring-webmvc-plugin/pom.xml b/apm-agent-plugins/apm-spring-webmvc-plugin/pom.xml index 3b28a93479..889d713269 100644 --- a/apm-agent-plugins/apm-spring-webmvc-plugin/pom.xml +++ b/apm-agent-plugins/apm-spring-webmvc-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-spring-webmvc-plugin diff --git a/apm-agent-plugins/apm-struts-plugin/pom.xml b/apm-agent-plugins/apm-struts-plugin/pom.xml index bbb7aa79ed..b3526c57dc 100644 --- a/apm-agent-plugins/apm-struts-plugin/pom.xml +++ b/apm-agent-plugins/apm-struts-plugin/pom.xml @@ -3,7 +3,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/apm-agent-plugins/apm-urlconnection-plugin/pom.xml b/apm-agent-plugins/apm-urlconnection-plugin/pom.xml index f556acddbe..1d9ba17efa 100644 --- a/apm-agent-plugins/apm-urlconnection-plugin/pom.xml +++ b/apm-agent-plugins/apm-urlconnection-plugin/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-urlconnection-plugin diff --git a/apm-agent-plugins/apm-vertx/apm-vertx-common/pom.xml b/apm-agent-plugins/apm-vertx/apm-vertx-common/pom.xml index d09e737d55..83ca9f13b1 100644 --- a/apm-agent-plugins/apm-vertx/apm-vertx-common/pom.xml +++ b/apm-agent-plugins/apm-vertx/apm-vertx-common/pom.xml @@ -5,7 +5,7 @@ apm-vertx co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-vertx-common diff --git a/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/pom.xml b/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/pom.xml index c4ea5c2f03..9d3136dbaf 100644 --- a/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/pom.xml +++ b/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/pom.xml @@ -5,7 +5,7 @@ apm-vertx co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-vertx3-plugin diff --git a/apm-agent-plugins/apm-vertx/apm-vertx3-test-latest/pom.xml b/apm-agent-plugins/apm-vertx/apm-vertx3-test-latest/pom.xml index 536f914878..ecb5af3524 100644 --- a/apm-agent-plugins/apm-vertx/apm-vertx3-test-latest/pom.xml +++ b/apm-agent-plugins/apm-vertx/apm-vertx3-test-latest/pom.xml @@ -5,7 +5,7 @@ apm-vertx co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-vertx3-test-latest diff --git a/apm-agent-plugins/apm-vertx/apm-vertx4-plugin/pom.xml b/apm-agent-plugins/apm-vertx/apm-vertx4-plugin/pom.xml index b7569f7647..b4e17733d6 100644 --- a/apm-agent-plugins/apm-vertx/apm-vertx4-plugin/pom.xml +++ b/apm-agent-plugins/apm-vertx/apm-vertx4-plugin/pom.xml @@ -5,7 +5,7 @@ apm-vertx co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-vertx4-plugin diff --git a/apm-agent-plugins/apm-vertx/pom.xml b/apm-agent-plugins/apm-vertx/pom.xml index 4b21068235..85ffe7f37f 100644 --- a/apm-agent-plugins/apm-vertx/pom.xml +++ b/apm-agent-plugins/apm-vertx/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-vertx diff --git a/apm-agent-plugins/pom.xml b/apm-agent-plugins/pom.xml index 4aa0fe1850..66a60163df 100644 --- a/apm-agent-plugins/pom.xml +++ b/apm-agent-plugins/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent-plugins diff --git a/apm-agent/pom.xml b/apm-agent/pom.xml index 2932b90cc3..71cd09250a 100644 --- a/apm-agent/pom.xml +++ b/apm-agent/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-parent - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-agent diff --git a/apm-opentracing/pom.xml b/apm-opentracing/pom.xml index 82e3eaf3ac..693dd35462 100644 --- a/apm-opentracing/pom.xml +++ b/apm-opentracing/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-opentracing diff --git a/elastic-apm-agent/pom.xml b/elastic-apm-agent/pom.xml index 3586949dc9..6cb5511bef 100644 --- a/elastic-apm-agent/pom.xml +++ b/elastic-apm-agent/pom.xml @@ -5,7 +5,7 @@ co.elastic.apm apm-agent-parent - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT elastic-apm-agent diff --git a/integration-tests/application-server-integration-tests/pom.xml b/integration-tests/application-server-integration-tests/pom.xml index 7c5a4a182c..06916c2b20 100644 --- a/integration-tests/application-server-integration-tests/pom.xml +++ b/integration-tests/application-server-integration-tests/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT application-server-integration-tests diff --git a/integration-tests/cdi-app/cdi-app-dependent/pom.xml b/integration-tests/cdi-app/cdi-app-dependent/pom.xml index 09e5034a89..46ec11d619 100644 --- a/integration-tests/cdi-app/cdi-app-dependent/pom.xml +++ b/integration-tests/cdi-app/cdi-app-dependent/pom.xml @@ -4,7 +4,7 @@ cdi-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/cdi-app/cdi-app-standalone/pom.xml b/integration-tests/cdi-app/cdi-app-standalone/pom.xml index a28ada37ca..8fb27b564f 100644 --- a/integration-tests/cdi-app/cdi-app-standalone/pom.xml +++ b/integration-tests/cdi-app/cdi-app-standalone/pom.xml @@ -4,7 +4,7 @@ cdi-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/cdi-app/pom.xml b/integration-tests/cdi-app/pom.xml index 18eda57159..d1914eb51f 100644 --- a/integration-tests/cdi-app/pom.xml +++ b/integration-tests/cdi-app/pom.xml @@ -4,7 +4,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-dependent/pom.xml b/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-dependent/pom.xml index 3061a761ef..80c7429c3d 100644 --- a/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-dependent/pom.xml +++ b/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-dependent/pom.xml @@ -4,7 +4,7 @@ cdi-jakartaee-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-standalone/pom.xml b/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-standalone/pom.xml index cc064d6419..7219727dbc 100644 --- a/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-standalone/pom.xml +++ b/integration-tests/cdi-jakartaee-app/cdi-jakartaee-app-standalone/pom.xml @@ -4,7 +4,7 @@ cdi-jakartaee-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/cdi-jakartaee-app/pom.xml b/integration-tests/cdi-jakartaee-app/pom.xml index da721096a7..5653719b89 100644 --- a/integration-tests/cdi-jakartaee-app/pom.xml +++ b/integration-tests/cdi-jakartaee-app/pom.xml @@ -4,7 +4,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/external-plugin-test/external-plugin-app/pom.xml b/integration-tests/external-plugin-test/external-plugin-app/pom.xml index 81d617adf0..52cf3b7d50 100644 --- a/integration-tests/external-plugin-test/external-plugin-app/pom.xml +++ b/integration-tests/external-plugin-test/external-plugin-app/pom.xml @@ -6,7 +6,7 @@ external-plugin-test co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT external-plugin-app diff --git a/integration-tests/external-plugin-test/external-plugin-jakarta-app/pom.xml b/integration-tests/external-plugin-test/external-plugin-jakarta-app/pom.xml index a00b6e3986..308aa390ad 100644 --- a/integration-tests/external-plugin-test/external-plugin-jakarta-app/pom.xml +++ b/integration-tests/external-plugin-test/external-plugin-jakarta-app/pom.xml @@ -6,7 +6,7 @@ external-plugin-test co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT external-plugin-jakarta-app diff --git a/integration-tests/external-plugin-test/external-plugin/pom.xml b/integration-tests/external-plugin-test/external-plugin/pom.xml index 3d20fb8ee1..480b376af0 100644 --- a/integration-tests/external-plugin-test/external-plugin/pom.xml +++ b/integration-tests/external-plugin-test/external-plugin/pom.xml @@ -6,7 +6,7 @@ external-plugin-test co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT external-plugin diff --git a/integration-tests/external-plugin-test/plugin-instrumentation-target/pom.xml b/integration-tests/external-plugin-test/plugin-instrumentation-target/pom.xml index 20061d40e4..d0ed4866a1 100644 --- a/integration-tests/external-plugin-test/plugin-instrumentation-target/pom.xml +++ b/integration-tests/external-plugin-test/plugin-instrumentation-target/pom.xml @@ -6,7 +6,7 @@ external-plugin-test co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT plugin-instrumentation-target diff --git a/integration-tests/external-plugin-test/pom.xml b/integration-tests/external-plugin-test/pom.xml index 2dc0f86b74..cc7ee3c593 100644 --- a/integration-tests/external-plugin-test/pom.xml +++ b/integration-tests/external-plugin-test/pom.xml @@ -3,7 +3,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-dependent/pom.xml b/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-dependent/pom.xml index 33a1fe6027..8fd28a5c1a 100644 --- a/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-dependent/pom.xml +++ b/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-dependent/pom.xml @@ -3,7 +3,7 @@ jakartaee-jsf-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-standalone/pom.xml b/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-standalone/pom.xml index 9fc9d70373..f24baacbf6 100644 --- a/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-standalone/pom.xml +++ b/integration-tests/jakartaee-jsf-app/jakartaee-jsf-app-standalone/pom.xml @@ -3,7 +3,7 @@ jakartaee-jsf-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/jakartaee-jsf-app/pom.xml b/integration-tests/jakartaee-jsf-app/pom.xml index 049026ee93..66619281fa 100644 --- a/integration-tests/jakartaee-jsf-app/pom.xml +++ b/integration-tests/jakartaee-jsf-app/pom.xml @@ -3,7 +3,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 pom diff --git a/integration-tests/jakartaee-simple-webapp/pom.xml b/integration-tests/jakartaee-simple-webapp/pom.xml index e9c3371bd3..af805136e3 100644 --- a/integration-tests/jakartaee-simple-webapp/pom.xml +++ b/integration-tests/jakartaee-simple-webapp/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT jakartaee-simple-webapp diff --git a/integration-tests/jsf-app/jsf-app-dependent/pom.xml b/integration-tests/jsf-app/jsf-app-dependent/pom.xml index 2759940745..c2d5720fcd 100644 --- a/integration-tests/jsf-app/jsf-app-dependent/pom.xml +++ b/integration-tests/jsf-app/jsf-app-dependent/pom.xml @@ -4,7 +4,7 @@ jsf-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/jsf-app/jsf-app-standalone/pom.xml b/integration-tests/jsf-app/jsf-app-standalone/pom.xml index 81ff88a0e0..361107c118 100644 --- a/integration-tests/jsf-app/jsf-app-standalone/pom.xml +++ b/integration-tests/jsf-app/jsf-app-standalone/pom.xml @@ -6,7 +6,7 @@ jsf-app co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT jsf-app-standalone diff --git a/integration-tests/jsf-app/pom.xml b/integration-tests/jsf-app/pom.xml index 06d3c680ef..e092d4f213 100644 --- a/integration-tests/jsf-app/pom.xml +++ b/integration-tests/jsf-app/pom.xml @@ -6,7 +6,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT jsf-app diff --git a/integration-tests/main-app-test/pom.xml b/integration-tests/main-app-test/pom.xml index b9511d8f68..3d2ddd8b98 100644 --- a/integration-tests/main-app-test/pom.xml +++ b/integration-tests/main-app-test/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT main-app-test diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 6c0aa99f35..28d841ccaa 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -5,7 +5,7 @@ apm-agent-parent co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT integration-tests diff --git a/integration-tests/runtime-attach/pom.xml b/integration-tests/runtime-attach/pom.xml index 8459ec2470..a974a7c4ce 100644 --- a/integration-tests/runtime-attach/pom.xml +++ b/integration-tests/runtime-attach/pom.xml @@ -6,7 +6,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT runtime-attach diff --git a/integration-tests/runtime-attach/runtime-attach-app/pom.xml b/integration-tests/runtime-attach/runtime-attach-app/pom.xml index 5768c57067..3ed3fef074 100644 --- a/integration-tests/runtime-attach/runtime-attach-app/pom.xml +++ b/integration-tests/runtime-attach/runtime-attach-app/pom.xml @@ -3,7 +3,7 @@ runtime-attach co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/runtime-attach/runtime-attach-test/pom.xml b/integration-tests/runtime-attach/runtime-attach-test/pom.xml index de0e3c1004..925f60afe8 100644 --- a/integration-tests/runtime-attach/runtime-attach-test/pom.xml +++ b/integration-tests/runtime-attach/runtime-attach-test/pom.xml @@ -3,7 +3,7 @@ runtime-attach co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT 4.0.0 diff --git a/integration-tests/simple-webapp/pom.xml b/integration-tests/simple-webapp/pom.xml index e8e1ed3c6d..7a6f4fe64b 100644 --- a/integration-tests/simple-webapp/pom.xml +++ b/integration-tests/simple-webapp/pom.xml @@ -6,7 +6,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT simple-webapp diff --git a/integration-tests/soap-test/pom.xml b/integration-tests/soap-test/pom.xml index 303aa62290..151c7c95e9 100644 --- a/integration-tests/soap-test/pom.xml +++ b/integration-tests/soap-test/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT soap-test diff --git a/integration-tests/spring-boot-1-5/pom.xml b/integration-tests/spring-boot-1-5/pom.xml index 37509b8a7b..6021c2975f 100644 --- a/integration-tests/spring-boot-1-5/pom.xml +++ b/integration-tests/spring-boot-1-5/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-1-5 diff --git a/integration-tests/spring-boot-2/pom.xml b/integration-tests/spring-boot-2/pom.xml index b415a60d86..f0f9b280a1 100644 --- a/integration-tests/spring-boot-2/pom.xml +++ b/integration-tests/spring-boot-2/pom.xml @@ -5,7 +5,7 @@ integration-tests co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-2 diff --git a/integration-tests/spring-boot-2/spring-boot-2-base/pom.xml b/integration-tests/spring-boot-2/spring-boot-2-base/pom.xml index f179d58bf1..43ede3bb56 100644 --- a/integration-tests/spring-boot-2/spring-boot-2-base/pom.xml +++ b/integration-tests/spring-boot-2/spring-boot-2-base/pom.xml @@ -5,7 +5,7 @@ spring-boot-2 co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-2-base diff --git a/integration-tests/spring-boot-2/spring-boot-2-jetty/pom.xml b/integration-tests/spring-boot-2/spring-boot-2-jetty/pom.xml index 5f3a291099..6df38a8e6a 100644 --- a/integration-tests/spring-boot-2/spring-boot-2-jetty/pom.xml +++ b/integration-tests/spring-boot-2/spring-boot-2-jetty/pom.xml @@ -5,7 +5,7 @@ spring-boot-2 co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-2-jetty diff --git a/integration-tests/spring-boot-2/spring-boot-2-tomcat/pom.xml b/integration-tests/spring-boot-2/spring-boot-2-tomcat/pom.xml index 433ea3f104..7686cdc5e8 100644 --- a/integration-tests/spring-boot-2/spring-boot-2-tomcat/pom.xml +++ b/integration-tests/spring-boot-2/spring-boot-2-tomcat/pom.xml @@ -5,7 +5,7 @@ spring-boot-2 co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-2-tomcat diff --git a/integration-tests/spring-boot-2/spring-boot-2-undertow/pom.xml b/integration-tests/spring-boot-2/spring-boot-2-undertow/pom.xml index 47daf9e22b..9a6a7e6a56 100644 --- a/integration-tests/spring-boot-2/spring-boot-2-undertow/pom.xml +++ b/integration-tests/spring-boot-2/spring-boot-2-undertow/pom.xml @@ -5,7 +5,7 @@ spring-boot-2 co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT spring-boot-2-undertow diff --git a/pom.xml b/pom.xml index 0e896fecae..343dc98e56 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ co.elastic.apm apm-agent-parent - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT pom ${project.groupId}:${project.artifactId} From 26a7d60ddda29c347f495110c7742b2cbf3b45d0 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 15 Mar 2022 16:03:58 +0100 Subject: [PATCH 84/94] prevent multiple root contexts --- .../apm/agent/opentelemetry/sdk/OTelBridgeContext.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index 17396dc037..68bda455b7 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -72,8 +72,10 @@ public static OTelBridgeContext bridgeRootContext(ElasticApmTracer tracer, Conte } synchronized (OTelBridgeContext.class) { - originalRootContext = originalRoot; - root = new OTelBridgeContext(tracer, originalRoot); + if (root != null) { + originalRootContext = originalRoot; + root = new OTelBridgeContext(tracer, originalRoot); + } } return root; } From f5cdebc0c68331da0006ec17481dbe57f2378a86 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 15 Mar 2022 16:21:20 +0100 Subject: [PATCH 85/94] fix pebkc --- .../elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java index 68bda455b7..6eeec76608 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelBridgeContext.java @@ -72,7 +72,7 @@ public static OTelBridgeContext bridgeRootContext(ElasticApmTracer tracer, Conte } synchronized (OTelBridgeContext.class) { - if (root != null) { + if (root == null) { originalRootContext = originalRoot; root = new OTelBridgeContext(tracer, originalRoot); } From 984d3751b176ea90e664e8ee2afc5b815c3e5108 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 15 Mar 2022 16:31:36 +0100 Subject: [PATCH 86/94] set implicit active parent only at startSpan --- .../apm/agent/opentelemetry/sdk/OTelSpanBuilder.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java index 0b964246fe..dc0066949b 100644 --- a/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java +++ b/apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/sdk/OTelSpanBuilder.java @@ -64,7 +64,6 @@ class OTelSpanBuilder implements SpanBuilder { public OTelSpanBuilder(String spanName, ElasticApmTracer elasticApmTracer) { this.spanName = spanName; this.elasticApmTracer = elasticApmTracer; - this.parent = elasticApmTracer.getActive(); } @Override @@ -142,6 +141,12 @@ public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { @Override public Span startSpan() { AbstractSpan span; + + if (parent == null) { + // when parent is not explicitly set, the currently active parent is used as fallback + parent = elasticApmTracer.getActive(); + } + if (remoteContext != null) { PotentiallyMultiValuedMap headers = new PotentiallyMultiValuedMap(2); W3CTraceContextPropagator.getInstance().inject(remoteContext, headers, PotentiallyMultiValuedMap::add); From 4070339094b30e6636cf69f12bab6b5ff70ee314 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 15 Mar 2022 17:05:53 +0100 Subject: [PATCH 87/94] fix docs (attempt for menu) --- docs/api-opentelemetry.asciidoc | 2 +- docs/apis.asciidoc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index d0597c2f4a..2572a9fc24 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -46,7 +46,7 @@ The first step in getting started with the OpenTelemetry API bridge is to declar compile "io.opentelemetry:opentelemetry-api:$openTelemetryVersion" ---- -The minimum required OpenTelemetry version is 0.17.0. +The minimum required OpenTelemetry version is 1.0.1. [float] [[otel-init-tracer]] diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc index 28c77f3301..f47febf6f0 100644 --- a/docs/apis.asciidoc +++ b/docs/apis.asciidoc @@ -45,6 +45,6 @@ but instead only rely on manual instrumentation, disable the auto instrumentation setting the configuration option <> to `false`. -- -include::./api-elastic.asciidoc[] -include::./api-opentelemetry.asciidoc[] -include::./api-opentracing.asciidoc[] +include::./api-elastic.asciidoc[Public API] +include::./api-opentelemetry.asciidoc[OpenTelemetry API Bridge] +include::./api-opentracing.asciidoc[OpenTracing API Bridge] From e1a00e57337cb33a83214ffa591def63e17af3a9 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 16 Mar 2022 09:21:32 +0100 Subject: [PATCH 88/94] fix API docs menu integration --- docs/api-elastic.asciidoc | 1 + docs/api-opentelemetry.asciidoc | 1 + docs/api-opentracing.asciidoc | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/api-elastic.asciidoc b/docs/api-elastic.asciidoc index 54a70cf15d..3d1d029cd7 100644 --- a/docs/api-elastic.asciidoc +++ b/docs/api-elastic.asciidoc @@ -4,6 +4,7 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] +[float] [[public-api]] == Public API The public API of the Elastic APM Java agent lets you diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 2572a9fc24..868fe7b021 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -3,6 +3,7 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] +[float] [[opentelementry-bridge]] === OpenTelemetry bridge diff --git a/docs/api-opentracing.asciidoc b/docs/api-opentracing.asciidoc index 1a30828e76..86b8cc3348 100644 --- a/docs/api-opentracing.asciidoc +++ b/docs/api-opentracing.asciidoc @@ -3,6 +3,7 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] +[float] [[opentracing-bridge]] === OpenTracing bridge From 72bce1f310bede01ce40ba7920642f41e9415b63 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 16 Mar 2022 09:21:47 +0100 Subject: [PATCH 89/94] trim whitespace --- docs/api-elastic.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-elastic.asciidoc b/docs/api-elastic.asciidoc index 3d1d029cd7..c5d7edd3f7 100644 --- a/docs/api-elastic.asciidoc +++ b/docs/api-elastic.asciidoc @@ -785,7 +785,7 @@ Using `null` or empty resource string will result in the omission of this field [float] [[api-span-set-destination-address]] ==== `Span setDestinationAddress(String address, int port)` added[1.25.0] -Provides a way to manually set the span's `destination.address` and `destination.port` fields. +Provides a way to manually set the span's `destination.address` and `destination.port` fields. Values set through this method will take precedence over the automatically discovered ones. Using `null` or empty address or non-positive port will result in the omission of the corresponding field from the span context. From 3493ee15900bc39afe9d3434a11c26ea3f1115da Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 16 Mar 2022 11:01:13 +0100 Subject: [PATCH 90/94] fix links to public-api --- CHANGELOG.asciidoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index dca01841fa..579eddfbf5 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -917,7 +917,7 @@ config option] * Added `ElasticApmAttacher.attach(String propertiesLocation)` to specify a custom properties location * Logs message when `transaction_max_spans` has been exceeded {pull}849[#849] * Report the number of affected rows by a SQL statement (UPDATE,DELETE,INSERT) in 'affected_rows' span attribute {pull}707[#707] -* Add https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-traced[`@Traced`] annotation which either creates a span or a transaction, depending on the context +* Add <> annotation which either creates a span or a transaction, depending on the context * Report JMS destination as a span/transaction context field {pull}906[#906] * Added https://www.elastic.co/guide/en/apm/agent/java/master/config-jmx.html#config-capture-jmx-metrics[`capture_jmx_metrics`] configuration option @@ -1240,14 +1240,14 @@ controls which `Content-Type`s should be captured. ===== Features * Adds `@CaptureTransaction` and `@CaptureSpan` annotations which let you declaratively add custom transactions and spans. Note that it is required to configure the `application_packages` for this to work. - See the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-annotation[documentation] for more information. + See the <> for more information. * The public API now supports to activate a span on the current thread. This makes the span available via `ElasticApm#currentSpan()` - Refer to the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-span-activate[documentation] for more details. + Refer to <> for more details. * Capturing of Elasticsearch RestClient 5.0.2+ calls. Currently, the `*Async` methods are not supported, only their synchronous counterparts. * Added API methods to enable correlating the spans created from the JavaScrip Real User Monitoring agent with the Java agent transaction. - More information can be found in the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-ensure-parent-id[documentation]. + More information can be found in the <>. * Added `Transaction.isSampled()` and `Span.isSampled()` methods to the public API * Added `Transaction#setResult` to the public API {pull}293[#293] @@ -1272,14 +1272,14 @@ controls which `Content-Type`s should be captured. * Support for Distributed Tracing * Adds `@CaptureTransaction` and `@CaptureSpan` annotations which let you declaratively add custom transactions and spans. Note that it is required to configure the `application_packages` for this to work. - See the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-annotation[documentation] for more information. + See the <> for more information. * The public API now supports to activate a span on the current thread. This makes the span available via `ElasticApm#currentSpan()` - Refer to the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-span-activate[documentation] for more details. + Refer to the <> for more details. * Capturing of Elasticsearch RestClient 5.0.2+ calls. Currently, the `*Async` methods are not supported, only their synchronous counterparts. * Added API methods to enable correlating the spans created from the JavaScrip Real User Monitoring agent with the Java agent transaction. - More information can be found in the https://www.elastic.co/guide/en/apm/agent/java/master/public-api.html#api-ensure-parent-id[documentation]. + More information can be found in the <>. * Microsecond accurate timestamps {pull}261[#261] * Support for JAX-RS annotations. Transactions are named based on your resources (`ResourceClass#resourceMethod`). From e4b85c12af902bc4da26e34ada8c60e648c9150a Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 17 Mar 2022 13:33:37 +0100 Subject: [PATCH 91/94] fix generated doc --- docs/configuration.asciidoc | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 84a7fad6b2..b1d6c382ea 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -761,11 +761,7 @@ you should add an additional entry to this list (make sure to also include the d ==== `enable_instrumentations` (added[1.28.0]) A list of instrumentations which should be selectively enabled. -<<<<<<< HEAD -Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. -======= -Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> c8e7936b1a6a897aef609b820d20e254cd1440cc +Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. When set to non-empty value, only listed instrumentations will be enabled if they are not disabled through <> or <>. When not set or empty (default), all instrumentations enabled by default will be enabled unless they are disabled through <> or <>. @@ -793,11 +789,7 @@ NOTE: Changing this value at runtime can slow down the application temporarily. ==== `disable_instrumentations` (added[1.0.0,Changing this value at runtime is possible since version 1.15.0]) A list of instrumentations which should be disabled. -<<<<<<< HEAD -Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. -======= -Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> c8e7936b1a6a897aef609b820d20e254cd1440cc +Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. For version `1.25.0` and later, use <> to enable experimental instrumentations. NOTE: Changing this value at runtime can slow down the application temporarily. @@ -3155,11 +3147,7 @@ Example: `5ms`. # sanitize_field_names=password,passwd,pwd,secret,*key,*token*,*session*,*credit*,*card*,*auth*,set-cookie # A list of instrumentations which should be selectively enabled. -<<<<<<< HEAD -# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. -======= -# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> c8e7936b1a6a897aef609b820d20e254cd1440cc +# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. # When set to non-empty value, only listed instrumentations will be enabled if they are not disabled through <> or <>. # When not set or empty (default), all instrumentations enabled by default will be enabled unless they are disabled through <> or <>. # @@ -3172,11 +3160,7 @@ Example: `5ms`. # enable_instrumentations= # A list of instrumentations which should be disabled. -<<<<<<< HEAD -# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-ecs`, `log4j2-ecs`, `log4j2-error`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. -======= -# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. ->>>>>>> c8e7936b1a6a897aef609b820d20e254cd1440cc +# Valid options are `annotations`, `annotations-capture-span`, `annotations-capture-transaction`, `annotations-traced`, `apache-commons-exec`, `apache-httpclient`, `asynchttpclient`, `aws-lambda`, `cassandra`, `concurrent`, `dubbo`, `elasticsearch-restclient`, `exception-handler`, `executor`, `executor-collection`, `experimental`, `fork-join`, `grails`, `grpc`, `hibernate-search`, `http-client`, `jakarta-websocket`, `javalin`, `javax-websocket`, `jax-rs`, `jax-ws`, `jboss-logging-correlation`, `jdbc`, `jdk-httpclient`, `jdk-httpserver`, `jedis`, `jms`, `jsf`, `kafka`, `lettuce`, `log4j1-correlation`, `log4j1-ecs`, `log4j1-error`, `log4j2-correlation`, `log4j2-ecs`, `log4j2-error`, `logback-correlation`, `logback-ecs`, `logging`, `micrometer`, `mongodb-client`, `okhttp`, `opentelemetry`, `opentracing`, `process`, `public-api`, `quartz`, `rabbitmq`, `reactor`, `redis`, `redisson`, `render`, `scala-future`, `scheduled`, `servlet-api`, `servlet-api-async`, `servlet-api-dispatch`, `servlet-input-stream`, `slf4j-error`, `sparkjava`, `spring-amqp`, `spring-mvc`, `spring-resttemplate`, `spring-service-name`, `spring-view-render`, `spring-webflux`, `ssl-context`, `struts`, `timer-task`, `urlconnection`, `vertx`, `vertx-web`, `vertx-webclient`, `websocket`. # For version `1.25.0` and later, use <> to enable experimental instrumentations. # # NOTE: Changing this value at runtime can slow down the application temporarily. From 72e5d246fbe5afb9733bc54f9795b534966d3fa7 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 17 Mar 2022 14:33:40 +0100 Subject: [PATCH 92/94] doc: try removing float blocks --- docs/api-elastic.asciidoc | 1 - docs/api-opentelemetry.asciidoc | 1 - docs/api-opentracing.asciidoc | 1 - 3 files changed, 3 deletions(-) diff --git a/docs/api-elastic.asciidoc b/docs/api-elastic.asciidoc index c5d7edd3f7..d53686c280 100644 --- a/docs/api-elastic.asciidoc +++ b/docs/api-elastic.asciidoc @@ -4,7 +4,6 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] -[float] [[public-api]] == Public API The public API of the Elastic APM Java agent lets you diff --git a/docs/api-opentelemetry.asciidoc b/docs/api-opentelemetry.asciidoc index 868fe7b021..2572a9fc24 100644 --- a/docs/api-opentelemetry.asciidoc +++ b/docs/api-opentelemetry.asciidoc @@ -3,7 +3,6 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] -[float] [[opentelementry-bridge]] === OpenTelemetry bridge diff --git a/docs/api-opentracing.asciidoc b/docs/api-opentracing.asciidoc index 86b8cc3348..1a30828e76 100644 --- a/docs/api-opentracing.asciidoc +++ b/docs/api-opentracing.asciidoc @@ -3,7 +3,6 @@ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/java[elastic.co] endif::[] -[float] [[opentracing-bridge]] === OpenTracing bridge From eaaa29280ee0fabc616824060c67f15610f66914 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Thu, 17 Mar 2022 15:01:32 +0100 Subject: [PATCH 93/94] fix API menu --- docs/api-elastic.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-elastic.asciidoc b/docs/api-elastic.asciidoc index d53686c280..93822cac64 100644 --- a/docs/api-elastic.asciidoc +++ b/docs/api-elastic.asciidoc @@ -5,7 +5,7 @@ please view this documentation at https://www.elastic.co/guide/en/apm/agent/java endif::[] [[public-api]] -== Public API +=== Public API The public API of the Elastic APM Java agent lets you customize and manually create spans and transactions, as well as track errors. From 020ed20cc99d80a9a3b99163683aad22ea57b99a Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Fri, 18 Mar 2022 15:09:35 +0100 Subject: [PATCH 94/94] fix new module version --- apm-agent-plugins/apm-httpserver-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent-plugins/apm-httpserver-core/pom.xml b/apm-agent-plugins/apm-httpserver-core/pom.xml index 2deb1d3e45..25ea503b65 100644 --- a/apm-agent-plugins/apm-httpserver-core/pom.xml +++ b/apm-agent-plugins/apm-httpserver-core/pom.xml @@ -5,7 +5,7 @@ apm-agent-plugins co.elastic.apm - 1.29.1-SNAPSHOT + 1.30.0-SNAPSHOT apm-httpserver-core