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 methodMatcher; - public SpanInstrumentation(ElementMatcher methodMatcher) { + public AbstractSpanInstrumentation(ElementMatcher methodMatcher) { this.methodMatcher = methodMatcher; } @Override public ElementMatcher getTypeMatcher() { - return named("co.elastic.apm.api.SpanImpl"); + return named("co.elastic.apm.api.AbstractSpanImpl"); } @Override @@ -51,9 +51,9 @@ public ElementMatcher 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 methodMatcher; + + public LegacySpanInstrumentation(ElementMatcher methodMatcher) { + this.methodMatcher = methodMatcher; + } + + @Override + public ElementMatcher getTypeMatcher() { + return named("co.elastic.apm.api.SpanImpl").and(not(hasSuperType(named("co.elastic.apm.api.AbstractSpanImpl")))); + } + + @Override + public ElementMatcher 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 <> method. [float] [[api-set-name]] -==== `void setName(String name)` +==== `Transaction setName(String name)` Override the name of the current transaction. For supported frameworks, the transaction name is determined automatically, @@ -202,7 +202,7 @@ transaction.setName("My Transaction"); [float] [[api-transaction-set-type]] -==== `void 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. @@ -218,7 +218,7 @@ transaction.setType(Transaction.TYPE_REQUEST); [float] [[api-transaction-add-tag]] -==== `void addTag(String key, String value)` +==== `Transaction addTag(String key, String value)` A flat mapping of user-defined tags with string values. Note: the tags are indexed in Elasticsearch so that they are searchable and aggregatable. By all means, @@ -236,7 +236,7 @@ transaction.setTag("foo", "bar"); [float] [[api-transaction-set-user]] -==== `void 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. @@ -341,7 +341,7 @@ NOTE: Spans created via this method can not be retrieved by calling <> on how to get a reference of the current span. [float] [[api-span-set-name]] -==== `void setName(String name)` +==== `Span setName(String name)` Override the name of the current span. Example: @@ -425,7 +425,7 @@ span.setName("SELECT FROM customer"); [float] [[api-span-set-type]] -==== `void setType(String type)` +==== `Span setType(String type)` Sets the type of span. The type is a hierarchical string used to group similar spans together. For instance, all spans of MySQL queries are given the type `db.mysql.query`. @@ -438,7 +438,7 @@ the following are standardized across all Elastic APM agents: `app`, `db`, `cach [float] [[api-span-add-tag]] -==== `void addTag(String key, String value)` +==== `Span addTag(String key, String value)` A flat mapping of user-defined tags with string values. Note: the tags are indexed in Elasticsearch so that they are searchable and aggregatable. By all means,