diff --git a/CHANGELOG.md b/CHANGELOG.md index 46649484dd..eee517a3bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Added `capture_headers` configuration option. Set to `false` to disable capturing request and response headers. This will reduce the allocation rate of the agent and can save you network bandwidth and disk space. + * Makes the API methods `addTag`, `setName`, `setType`, `setUser` and `setResult` fluent, so that calls can be chained. ## Bug Fixes diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/AbstractSpanImpl.java b/apm-agent-api/src/main/java/co/elastic/apm/api/AbstractSpanImpl.java new file mode 100644 index 0000000000..5635439e64 --- /dev/null +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/AbstractSpanImpl.java @@ -0,0 +1,73 @@ +package co.elastic.apm.api; + +import javax.annotation.Nonnull; + +public abstract class AbstractSpanImpl implements Span { + @Nonnull + // co.elastic.apm.impl.transaction.AbstractSpan + protected final Object span; + + AbstractSpanImpl(@Nonnull Object span) { + this.span = span; + } + + @Nonnull + @Override + public Span createSpan() { + Object span = doCreateSpan(); + return span != null ? new SpanImpl(span) : NoopSpan.INSTANCE; + } + + private Object doCreateSpan() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$DoCreateSpanInstrumentation.doCreateSpan + return null; + } + + void doSetName(String name) { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$SetNameInstrumentation.doSetName + } + + void doSetType(String type) { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$SetTypeInstrumentation.doSetType + } + + void doAddTag(String key, String value) { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$AddTagInstrumentation.doAddTag + } + + @Override + public void end() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$EndInstrumentation.end + } + + @Override + public void captureException(Throwable throwable) { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation.CaptureExceptionInstrumentation + } + + @Nonnull + @Override + public String getId() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation.GetIdInstrumentation + return ""; + } + + @Nonnull + @Override + public String getTraceId() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation.GetTraceIdInstrumentation + return ""; + } + + @Override + public Scope activate() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation.ActivateInstrumentation + return new ScopeImpl(span); + } + + @Override + public boolean isSampled() { + // co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation.IsSampledInstrumentation + return false; + } +} diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/NoopSpan.java b/apm-agent-api/src/main/java/co/elastic/apm/api/NoopSpan.java index 848fe7b8fd..2a6de07381 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/NoopSpan.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/NoopSpan.java @@ -24,19 +24,25 @@ enum NoopSpan implements Span { INSTANCE; + @Nonnull @Override - public void setName(String name) { + public Span setName(String name) { // noop + return this; } + @Nonnull @Override - public void setType(String type) { + public Span setType(String type) { // noop + return this; } + @Nonnull @Override - public void addTag(String key, String value) { + public Span addTag(String key, String value) { // noop + return this; } @Override @@ -66,6 +72,7 @@ public Scope activate() { return NoopScope.INSTANCE; } + @Nonnull @Override public boolean isSampled() { return false; diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/NoopTransaction.java b/apm-agent-api/src/main/java/co/elastic/apm/api/NoopTransaction.java index 6f20422a69..6bdb28085d 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/NoopTransaction.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/NoopTransaction.java @@ -25,29 +25,37 @@ enum NoopTransaction implements Transaction { INSTANCE; + @Nonnull @Override - public void setName(String name) { + public Transaction setName(String name) { // noop + return this; } + @Nonnull @Override - public void setType(String type) { + public Transaction setType(String type) { // noop + return this; } + @Nonnull @Override - public void addTag(String key, String value) { + public Transaction addTag(String key, String value) { // noop + return this; } @Override - public void setUser(String id, String email, String username) { + public Transaction setUser(String id, String email, String username) { // noop + return this; } @Override - public void setResult(String result) { + public Transaction setResult(String result) { // noop + return this; } @Override @@ -83,6 +91,7 @@ public Scope activate() { return NoopScope.INSTANCE; } + @Nonnull @Override public boolean isSampled() { return false; diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/Span.java b/apm-agent-api/src/main/java/co/elastic/apm/api/Span.java index b4ca1e1c80..d23ec0aaac 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/Span.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/Span.java @@ -46,7 +46,8 @@ public interface Span { * * @param name the name of the span */ - void setName(String name); + @Nonnull + Span setName(String name); /** * Sets the type of span. @@ -61,7 +62,8 @@ public interface Span { * * @param type the type of the span */ - void setType(String type); + @Nonnull + Span setType(String type); /** * A flat mapping of user-defined tags with string values. @@ -76,7 +78,8 @@ public interface Span { * @param key The tag key. * @param value The tag value. */ - void addTag(String key, String value); + @Nonnull + Span addTag(String key, String value); /** * Start and return a new custom span as a child of this span. @@ -105,6 +108,7 @@ public interface Span { * * @return the started span, never {@code null} */ + @Nonnull Span createSpan(); /** diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/SpanImpl.java b/apm-agent-api/src/main/java/co/elastic/apm/api/SpanImpl.java index 28c92c62e5..0f68f54ed3 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/SpanImpl.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/SpanImpl.java @@ -22,83 +22,36 @@ import javax.annotation.Nonnull; /** - * If the agent is active, it injects the implementation from - * co.elastic.apm.agent.plugin.api.SpanInstrumentation - * into this class. + * If the agent is active, it injects the implementation into this class. *
* Otherwise, this class is a noop. *
*/ -class SpanImpl implements Span { - - @Nonnull - // co.elastic.apm.agent.impl.transaction.AbstractSpan - protected final Object span; +class SpanImpl extends AbstractSpanImpl { SpanImpl(@Nonnull Object span) { - this.span = span; - } - - @Override - public void setName(String name) { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation$SetNameInstrumentation.setName - } - - @Override - public void setType(String type) { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation$SetTypeInstrumentation.setType - } - - @Override - public void addTag(String key, String value) { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation$AddTagInstrumentation.addTag - } - - @Override - public Span createSpan() { - Object span = doCreateSpan(); - return span != null ? new SpanImpl(span) : NoopSpan.INSTANCE; - } - - private Object doCreateSpan() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation$DoCreateSpanInstrumentation.doCreateSpan - return null; - } - - @Override - public void end() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation$EndInstrumentation.end - } - - @Override - public void captureException(Throwable throwable) { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation.CaptureExceptionInstrumentation + super(span); } @Nonnull @Override - public String getId() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation.GetIdInstrumentation - return ""; + public Span setName(String name) { + doSetName(name); + return this; } @Nonnull @Override - public String getTraceId() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation.GetTraceIdInstrumentation - return ""; - } - - @Override - public Scope activate() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation.ActivateInstrumentation - return new ScopeImpl(span); + public Span setType(String type) { + doSetType(type); + return this; } + @Nonnull @Override - public boolean isSampled() { - // co.elastic.apm.agent.plugin.api.SpanInstrumentation.IsSampledInstrumentation - return false; + public Span addTag(String key, String value) { + doAddTag(key, value); + return this; } } diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/Transaction.java b/apm-agent-api/src/main/java/co/elastic/apm/api/Transaction.java index 87f3e55c2f..fc2d311c58 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/Transaction.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/Transaction.java @@ -42,7 +42,8 @@ public interface Transaction extends Span { * * @param name A string describing name of the transaction. */ - void setName(String name); + @Nonnull + Transaction setName(String name); /** * The type of the transaction. @@ -54,7 +55,11 @@ public interface Transaction extends Span { * * @param type The type of the transaction. */ - void setType(String type); + @Nonnull + Transaction setType(String type); + + @Nonnull + Transaction addTag(String key, String value); /** * Call this to enrich collected performance data and errors with information about the user/client. @@ -70,7 +75,7 @@ public interface Transaction extends Span { * @param email The user's email address or {@code null}, if not applicable. * @param username The user's name or {@code null}, if not applicable. */ - void setUser(String id, String email, String username); + Transaction setUser(String id, String email, String username); /** * A string describing the result of the transaction. @@ -78,7 +83,7 @@ public interface Transaction extends Span { * * @param result a string describing the result of the transaction */ - void setResult(String result); + Transaction setResult(String result); /** * End tracking the transaction. @@ -111,6 +116,7 @@ public interface Transaction extends Span { * * @return the started span, never {@code null} */ + @Nonnull Span createSpan(); /** diff --git a/apm-agent-api/src/main/java/co/elastic/apm/api/TransactionImpl.java b/apm-agent-api/src/main/java/co/elastic/apm/api/TransactionImpl.java index 3f25667536..a9fe1449c7 100644 --- a/apm-agent-api/src/main/java/co/elastic/apm/api/TransactionImpl.java +++ b/apm-agent-api/src/main/java/co/elastic/apm/api/TransactionImpl.java @@ -29,20 +29,43 @@ * Otherwise, this class is a noop. * */ -class TransactionImpl extends SpanImpl implements Transaction { +class TransactionImpl extends AbstractSpanImpl implements Transaction { TransactionImpl(@Nonnull Object transaction) { super(transaction); } + @Nonnull @Override - public void setUser(String id, String email, String username) { - // co.elastic.apm.agent.plugin.api.TransactionInstrumentation$SetUserInstrumentation.setUser + public Transaction setName(String name) { + doSetName(name); + return this; } + @Nonnull @Override - public void setResult(String result) { + public Transaction setType(String type) { + doSetType(type); + return this; + } + @Nonnull + @Override + public Transaction addTag(String key, String value) { + doAddTag(key, value); + return this; + } + + @Override + public Transaction setUser(String id, String email, String username) { + // co.elastic.apm.agent.plugin.api.TransactionInstrumentation$SetUserInstrumentation.setUser + return this; + } + + @Override + public Transaction setResult(String result) { + // co.elastic.apm.agent.plugin.api.TransactionInstrumentation.SetResultInstrumentation + return this; } @Nonnull diff --git a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/SpanInstrumentation.java b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/AbstractSpanInstrumentation.java similarity index 82% rename from apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/SpanInstrumentation.java rename to apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/AbstractSpanInstrumentation.java index 5aca5fc395..6e252e0100 100644 --- a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/SpanInstrumentation.java +++ b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/AbstractSpanInstrumentation.java @@ -33,17 +33,17 @@ /** * Injects the actual implementation of the public API class co.elastic.apm.api.SpanImpl. */ -public class SpanInstrumentation extends ApiInstrumentation { +public class AbstractSpanInstrumentation extends ApiInstrumentation { private final ElementMatcher super MethodDescription> methodMatcher; - public SpanInstrumentation(ElementMatcher super MethodDescription> methodMatcher) { + public AbstractSpanInstrumentation(ElementMatcher super MethodDescription> methodMatcher) { this.methodMatcher = methodMatcher; } @Override public ElementMatcher super TypeDescription> getTypeMatcher() { - return named("co.elastic.apm.api.SpanImpl"); + return named("co.elastic.apm.api.AbstractSpanImpl"); } @Override @@ -51,9 +51,9 @@ public ElementMatcher super MethodDescription> getMethodMatcher() { return methodMatcher; } - public static class SetNameInstrumentation extends SpanInstrumentation { + public static class SetNameInstrumentation extends AbstractSpanInstrumentation { public SetNameInstrumentation() { - super(named("setName")); + super(named("doSetName")); } @VisibleForAdvice @@ -64,9 +64,9 @@ public static void setName(@Advice.FieldValue(value = "span", typing = Assigner. } } - public static class SetTypeInstrumentation extends SpanInstrumentation { + public static class SetTypeInstrumentation extends AbstractSpanInstrumentation { public SetTypeInstrumentation() { - super(named("setType")); + super(named("doSetType")); } @VisibleForAdvice @@ -77,7 +77,7 @@ public static void setType(@Advice.FieldValue(value = "span", typing = Assigner. } } - public static class DoCreateSpanInstrumentation extends SpanInstrumentation { + public static class DoCreateSpanInstrumentation extends AbstractSpanInstrumentation { public DoCreateSpanInstrumentation() { super(named("doCreateSpan")); } @@ -90,7 +90,7 @@ public static void doCreateSpan(@Advice.FieldValue(value = "span", typing = Assi } } - public static class EndInstrumentation extends SpanInstrumentation { + public static class EndInstrumentation extends AbstractSpanInstrumentation { public EndInstrumentation() { super(named("end")); } @@ -103,7 +103,7 @@ public static void end(@Advice.FieldValue(value = "span", typing = Assigner.Typi } - public static class CaptureExceptionInstrumentation extends SpanInstrumentation { + public static class CaptureExceptionInstrumentation extends AbstractSpanInstrumentation { public CaptureExceptionInstrumentation() { super(named("captureException").and(takesArguments(Throwable.class))); } @@ -116,7 +116,7 @@ public static void doCreateSpan(@Advice.FieldValue(value = "span", typing = Assi } } - public static class GetIdInstrumentation extends SpanInstrumentation { + public static class GetIdInstrumentation extends AbstractSpanInstrumentation { public GetIdInstrumentation() { super(named("getId").and(takesArguments(0))); } @@ -124,14 +124,14 @@ public GetIdInstrumentation() { @VisibleForAdvice @Advice.OnMethodExit(suppress = Throwable.class) public static void getId(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span, - @Advice.Return(readOnly = false) String id) { + @Advice.Return(readOnly = false) String id) { if (tracer != null) { id = span.getTraceContext().getId().toString(); } } } - public static class GetTraceIdInstrumentation extends SpanInstrumentation { + public static class GetTraceIdInstrumentation extends AbstractSpanInstrumentation { public GetTraceIdInstrumentation() { super(named("getTraceId").and(takesArguments(0))); } @@ -139,16 +139,16 @@ public GetTraceIdInstrumentation() { @VisibleForAdvice @Advice.OnMethodExit(suppress = Throwable.class) public static void getTraceId(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span, - @Advice.Return(readOnly = false) String traceId) { + @Advice.Return(readOnly = false) String traceId) { if (tracer != null) { traceId = span.getTraceContext().getTraceId().toString(); } } } - public static class AddTagInstrumentation extends SpanInstrumentation { + public static class AddTagInstrumentation extends AbstractSpanInstrumentation { public AddTagInstrumentation() { - super(named("addTag")); + super(named("doAddTag")); } @VisibleForAdvice @@ -159,7 +159,7 @@ public static void addTag(@Advice.FieldValue(value = "span", typing = Assigner.T } } - public static class ActivateInstrumentation extends SpanInstrumentation { + public static class ActivateInstrumentation extends AbstractSpanInstrumentation { public ActivateInstrumentation() { super(named("activate")); } @@ -171,7 +171,7 @@ public static void addTag(@Advice.FieldValue(value = "span", typing = Assigner.T } } - public static class IsSampledInstrumentation extends SpanInstrumentation { + public static class IsSampledInstrumentation extends AbstractSpanInstrumentation { public IsSampledInstrumentation() { super(named("isSampled")); } diff --git a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/LegacySpanInstrumentation.java b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/LegacySpanInstrumentation.java new file mode 100644 index 0000000000..69088d8891 --- /dev/null +++ b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/LegacySpanInstrumentation.java @@ -0,0 +1,194 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 Elastic and contributors + * %% + * Licensed 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.plugin.api; + +import co.elastic.apm.agent.bci.VisibleForAdvice; +import co.elastic.apm.agent.impl.transaction.AbstractSpan; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +/** + * Injects the actual implementation of the public API class co.elastic.apm.api.SpanImpl. + *
+ * Used for older versions of the API, for example 1.1.0 where there was no AbstractSpanImpl
+ *
+ * @deprecated can be removed in version 3.0.
+ * Users should be able to update the agent to 2.0, without having to simultaneously update the API.
+ */
+@Deprecated
+public class LegacySpanInstrumentation extends ApiInstrumentation {
+
+ private final ElementMatcher super MethodDescription> methodMatcher;
+
+ public LegacySpanInstrumentation(ElementMatcher super MethodDescription> methodMatcher) {
+ this.methodMatcher = methodMatcher;
+ }
+
+ @Override
+ public ElementMatcher super TypeDescription> getTypeMatcher() {
+ return named("co.elastic.apm.api.SpanImpl").and(not(hasSuperType(named("co.elastic.apm.api.AbstractSpanImpl"))));
+ }
+
+ @Override
+ public ElementMatcher super MethodDescription> getMethodMatcher() {
+ return methodMatcher;
+ }
+
+ public static class SetNameInstrumentation extends LegacySpanInstrumentation {
+ public SetNameInstrumentation() {
+ super(named("setName"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodEnter
+ public static void setName(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Argument(0) String name) {
+ span.setName(name);
+ }
+ }
+
+ public static class SetTypeInstrumentation extends LegacySpanInstrumentation {
+ public SetTypeInstrumentation() {
+ super(named("setType"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodEnter
+ public static void setType(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Argument(0) String type) {
+ span.withType(type);
+ }
+ }
+
+ public static class DoCreateSpanInstrumentation extends LegacySpanInstrumentation {
+ public DoCreateSpanInstrumentation() {
+ super(named("doCreateSpan"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodExit
+ public static void doCreateSpan(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Return(readOnly = false) Object result) {
+ result = span.createSpan();
+ }
+ }
+
+ public static class EndInstrumentation extends LegacySpanInstrumentation {
+ public EndInstrumentation() {
+ super(named("end"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodEnter
+ public static void end(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span) {
+ span.end();
+ }
+ }
+
+
+ public static class CaptureExceptionInstrumentation extends LegacySpanInstrumentation {
+ public CaptureExceptionInstrumentation() {
+ super(named("captureException").and(takesArguments(Throwable.class)));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodExit
+ public static void doCreateSpan(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Argument(0) Throwable t) {
+ span.captureException(t);
+ }
+ }
+
+ public static class GetIdInstrumentation extends LegacySpanInstrumentation {
+ public GetIdInstrumentation() {
+ super(named("getId").and(takesArguments(0)));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodExit
+ public static void getId(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Return(readOnly = false) String id) {
+ if (tracer != null) {
+ id = span.getTraceContext().getId().toString();
+ }
+ }
+ }
+
+ public static class GetTraceIdInstrumentation extends LegacySpanInstrumentation {
+ public GetTraceIdInstrumentation() {
+ super(named("getTraceId").and(takesArguments(0)));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodExit
+ public static void getTraceId(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Return(readOnly = false) String traceId) {
+ if (tracer != null) {
+ traceId = span.getTraceContext().getTraceId().toString();
+ }
+ }
+ }
+
+ public static class AddTagInstrumentation extends LegacySpanInstrumentation {
+ public AddTagInstrumentation() {
+ super(named("addTag"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodEnter
+ public static void addTag(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Argument(0) String key, @Advice.Argument(1) String value) {
+ span.addTag(key, value);
+ }
+ }
+
+ public static class ActivateInstrumentation extends LegacySpanInstrumentation {
+ public ActivateInstrumentation() {
+ super(named("activate"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodEnter
+ public static void addTag(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span) {
+ span.activate();
+ }
+ }
+
+ public static class IsSampledInstrumentation extends LegacySpanInstrumentation {
+ public IsSampledInstrumentation() {
+ super(named("isSampled"));
+ }
+
+ @VisibleForAdvice
+ @Advice.OnMethodExit
+ public static void addTag(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) AbstractSpan> span,
+ @Advice.Return(readOnly = false) boolean sampled) {
+ sampled = span.isSampled();
+ }
+ }
+}
diff --git a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentation.java b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentation.java
index f99836a255..6d529b7972 100644
--- a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentation.java
+++ b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentation.java
@@ -28,7 +28,9 @@
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.matcher.ElementMatcher;
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Injects the actual implementation of the public API class co.elastic.apm.api.TransactionImpl.
diff --git a/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation b/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation
index 01941e79d9..07849012af 100644
--- a/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation
+++ b/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation
@@ -5,17 +5,28 @@ co.elastic.apm.agent.plugin.api.ElasticApmApiInstrumentation$CaptureExceptionIns
co.elastic.apm.agent.plugin.api.TransactionInstrumentation$SetUserInstrumentation
co.elastic.apm.agent.plugin.api.TransactionInstrumentation$EnsureParentIdInstrumentation
co.elastic.apm.agent.plugin.api.TransactionInstrumentation$SetResultInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$SetNameInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$SetTypeInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$DoCreateSpanInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$EndInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$CaptureExceptionInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$GetIdInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$GetTraceIdInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$AddTagInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$ActivateInstrumentation
-co.elastic.apm.agent.plugin.api.SpanInstrumentation$IsSampledInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$SetNameInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$SetTypeInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$DoCreateSpanInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$EndInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$CaptureExceptionInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$GetIdInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$GetTraceIdInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$AddTagInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$ActivateInstrumentation
+co.elastic.apm.agent.plugin.api.AbstractSpanInstrumentation$IsSampledInstrumentation
co.elastic.apm.agent.plugin.api.CaptureExceptionInstrumentation
co.elastic.apm.agent.plugin.api.ApiScopeInstrumentation
co.elastic.apm.agent.plugin.api.CaptureTransactionInstrumentation
co.elastic.apm.agent.plugin.api.CaptureSpanInstrumentation
+# legacy
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$SetNameInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$SetTypeInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$DoCreateSpanInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$EndInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$CaptureExceptionInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$GetIdInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$GetTraceIdInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$AddTagInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$ActivateInstrumentation
+co.elastic.apm.agent.plugin.api.LegacySpanInstrumentation$IsSampledInstrumentation
diff --git a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/SpanInstrumentationTest.java b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/SpanInstrumentationTest.java
index 51a753de7a..cc7d3b36fd 100644
--- a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/SpanInstrumentationTest.java
+++ b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/SpanInstrumentationTest.java
@@ -54,6 +54,15 @@ void testSetType() {
assertThat(reporter.getFirstSpan().getType()).isEqualTo("foo");
}
+ @Test
+ void testChaining() {
+ span.setType("foo").setName("foo").addTag("foo", "bar");
+ endSpan();
+ assertThat(reporter.getFirstSpan().getName().toString()).isEqualTo("foo");
+ assertThat(reporter.getFirstSpan().getType()).isEqualTo("foo");
+ assertThat(reporter.getFirstSpan().getContext().getTags()).containsEntry("foo", "bar");
+ }
+
private void endSpan() {
span.end();
transaction.end();
diff --git a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentationTest.java b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentationTest.java
index ecc6502841..7b4fb19861 100644
--- a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentationTest.java
+++ b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/plugin/api/TransactionInstrumentationTest.java
@@ -76,7 +76,20 @@ void testResult() {
endTransaction();
assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("foo");
}
-
+
+ @Test
+ void testChaining() {
+ transaction.setType("foo").setName("foo").addTag("foo", "bar").setUser("foo", "bar", "baz").setResult("foo");
+ endTransaction();
+ assertThat(reporter.getFirstTransaction().getName().toString()).isEqualTo("foo");
+ assertThat(reporter.getFirstTransaction().getType()).isEqualTo("foo");
+ assertThat(reporter.getFirstTransaction().getContext().getTags()).containsEntry("foo", "bar");
+ assertThat(reporter.getFirstTransaction().getContext().getUser().getId()).isEqualTo("foo");
+ assertThat(reporter.getFirstTransaction().getContext().getUser().getEmail()).isEqualTo("bar");
+ assertThat(reporter.getFirstTransaction().getContext().getUser().getUsername()).isEqualTo("baz");
+ assertThat(reporter.getFirstTransaction().getResult()).isEqualTo("foo");
+ }
+
@Test
public void createSpan() throws Exception {
Span span = transaction.createSpan();
diff --git a/docs/public-api.asciidoc b/docs/public-api.asciidoc
index daf0db5a96..7420a44279 100644
--- a/docs/public-api.asciidoc
+++ b/docs/public-api.asciidoc
@@ -184,7 +184,7 @@ and the <