Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import co.elastic.apm.agent.configuration.CoreConfiguration;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.ElasticApmTracerBuilder;
import co.elastic.apm.agent.impl.GlobalTracer;
import co.elastic.apm.agent.util.DependencyInjectingServiceLoader;
import co.elastic.apm.agent.util.ExecutorUtils;
import co.elastic.apm.agent.util.ThreadUtils;
Expand Down Expand Up @@ -84,7 +85,6 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static co.elastic.apm.agent.bci.ElasticApmInstrumentation.tracer;
import static co.elastic.apm.agent.bci.bytebuddy.ClassLoaderNameMatcher.classLoaderWithName;
import static co.elastic.apm.agent.bci.bytebuddy.ClassLoaderNameMatcher.isReflectionClassLoader;
import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.anyMatch;
Expand Down Expand Up @@ -174,7 +174,7 @@ public void run() {
logger.warn("Instrumentation has already been initialized");
return;
}
ElasticApmInstrumentation.staticInit(tracer);
GlobalTracer.set(tracer);
// POOL_ONLY because we don't want to cause eager linking on startup as the class path may not be complete yet
AgentBuilder agentBuilder = initAgentBuilder(tracer, instrumentation, instrumentations, logger, AgentBuilder.DescriptionStrategy.Default.POOL_ONLY, premain);
resettableClassFileTransformer = agentBuilder.installOn(ElasticApmAgent.instrumentation);
Expand All @@ -190,24 +190,24 @@ public void onChange(ConfigurationOption configurationOption, Object oldValue, O
}

public static synchronized Future<?> reInitInstrumentation() {
final ElasticApmTracer tracer = ElasticApmInstrumentation.tracer;
if (tracer == null || instrumentation == null) {
final ElasticApmTracer tracer = GlobalTracer.requireTracerImpl();
if (instrumentation == null) {
throw new IllegalStateException("Can't re-init agent before it has been initialized");
}
ThreadPoolExecutor executor = ExecutorUtils.createSingleThreadDeamonPool("apm-reinit", 1);
try {
return executor.submit(new Runnable() {
@Override
public void run() {
doReInitInstrumentation(loadInstrumentations(tracer));
doReInitInstrumentation(loadInstrumentations(tracer), tracer);
}
});
} finally {
executor.shutdown();
}
}

static synchronized void doReInitInstrumentation(Iterable<ElasticApmInstrumentation> instrumentations) {
static synchronized void doReInitInstrumentation(Iterable<ElasticApmInstrumentation> instrumentations, ElasticApmTracer tracer) {
final Logger logger = LoggerFactory.getLogger(ElasticApmAgent.class);
logger.info("Re initializing instrumentation");
AgentBuilder agentBuilder = initAgentBuilder(tracer, instrumentation, instrumentations, logger, AgentBuilder.DescriptionStrategy.Default.POOL_ONLY, false);
Expand Down Expand Up @@ -305,7 +305,7 @@ public boolean matches(TypeDescription typeDescription, ClassLoader classLoader,
}
})
.transform(new PatchBytecodeVersionTo51Transformer())
.transform(getTransformer(tracer, instrumentation, logger, methodMatcher))
.transform(getTransformer(instrumentation, logger, methodMatcher))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
Expand All @@ -315,7 +315,7 @@ public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDesc
});
}

private static AgentBuilder.Transformer.ForAdvice getTransformer(final ElasticApmTracer tracer, final ElasticApmInstrumentation instrumentation, final Logger logger, final ElementMatcher<? super MethodDescription> methodMatcher) {
private static AgentBuilder.Transformer.ForAdvice getTransformer(final ElasticApmInstrumentation instrumentation, final Logger logger, final ElementMatcher<? super MethodDescription> methodMatcher) {
Advice.WithCustomMapping withCustomMapping = Advice
.withCustomMapping()
.with(new AssignToPostProcessorFactory())
Expand Down Expand Up @@ -574,8 +574,8 @@ public static void ensureInstrumented(Class<?> classToInstrument, Collection<Cla

if (!appliedInstrumentations.contains(instrumentationClasses)) {
synchronized (ElasticApmAgent.class) {
ElasticApmTracer tracer = ElasticApmInstrumentation.tracer;
if (tracer == null || instrumentation == null) {
ElasticApmTracer tracer = GlobalTracer.requireTracerImpl();
if (instrumentation == null) {
throw new IllegalStateException("Agent is not initialized");
}

Expand Down Expand Up @@ -666,7 +666,7 @@ private static ElasticApmInstrumentation tryInstantiate(Class<? extends ElasticA
if (constructor != null) {
try {
if (withTracer) {
instance = constructor.newInstance(ElasticApmInstrumentation.tracer);
instance = constructor.newInstance(GlobalTracer.requireTracerImpl());
} else {
instance = constructor.newInstance();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
*/
package co.elastic.apm.agent.bci;

import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
import co.elastic.apm.agent.impl.transaction.Span;
import co.elastic.apm.agent.threadlocal.GlobalThreadLocal;
import net.bytebuddy.asm.Advice;
Expand All @@ -48,73 +46,8 @@
* The actual instrumentation of the matched methods is performed by static methods within this class,
* which are annotated by {@link net.bytebuddy.asm.Advice.OnMethodEnter} or {@link net.bytebuddy.asm.Advice.OnMethodExit}.
* </p>
* <p>
* The constructor can optionally have a {@link ElasticApmTracer} parameter.
* </p>
*/
public abstract class ElasticApmInstrumentation {

@Nullable
@VisibleForAdvice
public static ElasticApmTracer tracer;

/**
* Initializes the advice with the {@link ElasticApmTracer}
* <p>
* This enables tests to register a custom instance with a {@link co.elastic.apm.agent.impl.ElasticApmTracerBuilder#configurationRegistry}
* and {@link co.elastic.apm.agent.impl.ElasticApmTracerBuilder#reporter} which is specific to a particular test or test class.
* </p>
*
* @param tracer the tracer to use for this advice.
*/
static void staticInit(ElasticApmTracer tracer) {
// allow re-init with a different tracer
ElasticApmInstrumentation.tracer = tracer;
}

@Nullable
@VisibleForAdvice
public static AbstractSpan<?> getActive() {
if (tracer != null) {
return tracer.getActive();
}
return null;
}

@Nullable
@VisibleForAdvice
public static Span getActiveSpan() {
if (tracer != null) {
final AbstractSpan<?> active = tracer.getActive();
if (active instanceof Span) {
return (Span) active;
}
}
return null;
}


@Nullable
@VisibleForAdvice
public static Span getActiveExitSpan() {
final Span span = getActiveSpan();
if (span != null && span.isExit()) {
return span;
}
return null;
}

@Nullable
@VisibleForAdvice
public static Span createExitSpan() {
final AbstractSpan<?> activeSpan = getActive();
if (activeSpan == null || activeSpan.isExit()) {
return null;
}

return activeSpan.createExitSpan();
}

/**
* Pre-select candidates solely based on the class name for the slower {@link #getTypeMatcher()},
* at the expense of potential false negative matches.
Expand Down Expand Up @@ -167,7 +100,6 @@ public Class<?> getAdviceClass() {
return getClass();
}


/**
* Return {@code true},
* if this instrumentation should even be applied when
Expand Down Expand Up @@ -218,8 +150,7 @@ public void onTypeMatch(TypeDescription typeDescription, ClassLoader classLoader
* <li>
* Both the return type and the arguments of advice methods must not contain types from the agent.
* If you'd like to return a {@link Span} from an advice, for example, return an {@link Object} instead.
* When using an {@link net.bytebuddy.asm.Advice.Enter} argument on the
* {@linkplain net.bytebuddy.asm.Advice.OnMethodExit exit advice},
* When using an {@link Advice.Enter} argument on the {@linkplain Advice.OnMethodExit exit advice},
* that argument also has to be of type {@link Object} and you have to cast it within the method body.
* The reason is that the return value will become a local variable in the instrumented method.
* Due to OSGi, those methods may not have access to agent types.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package co.elastic.apm.agent.bci;

import co.elastic.apm.agent.impl.Tracer;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
import net.bytebuddy.description.type.TypeDescription;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import co.elastic.apm.agent.bci.bytebuddy.MatcherTimer;
import co.elastic.apm.agent.context.AbstractLifecycleListener;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 - 2020 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.bci;

import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.GlobalTracer;
import co.elastic.apm.agent.impl.Tracer;

/**
* The constructor can optionally have a {@link ElasticApmTracer} parameter.
*/
public abstract class TracerAwareInstrumentation extends ElasticApmInstrumentation {

@VisibleForAdvice
public static final Tracer tracer = GlobalTracer.get();

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
package co.elastic.apm.agent.bci.methodmatching;

import co.elastic.apm.agent.bci.ElasticApmInstrumentation;
import co.elastic.apm.agent.bci.TracerAwareInstrumentation;
import co.elastic.apm.agent.bci.bytebuddy.SimpleMethodSignatureOffsetMappingFactory;
import co.elastic.apm.agent.configuration.CoreConfiguration;
import co.elastic.apm.agent.impl.ElasticApmTracer;
Expand All @@ -51,38 +51,37 @@
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer;
import static net.bytebuddy.matcher.ElementMatchers.nameContains;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

public class TraceMethodInstrumentation extends ElasticApmInstrumentation {
public class TraceMethodInstrumentation extends TracerAwareInstrumentation {

public static long traceMethodThresholdMicros;

protected final MethodMatcher methodMatcher;
private final CoreConfiguration config;

public TraceMethodInstrumentation(ElasticApmTracer tracer, MethodMatcher methodMatcher) {
this.methodMatcher = methodMatcher;
traceMethodThresholdMicros = tracer.getConfig(CoreConfiguration.class).getTraceMethodsDurationThreshold().getMillis() * 1000;
config = tracer.getConfig(CoreConfiguration.class);
traceMethodThresholdMicros = config.getTraceMethodsDurationThreshold().getMillis() * 1000;
}

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onMethodEnter(@Advice.Origin Class<?> clazz,
@SimpleMethodSignatureOffsetMappingFactory.SimpleMethodSignature String signature,
@Advice.Local("span") AbstractSpan<?> span) {
if (tracer != null) {
final AbstractSpan<?> parent = tracer.getActive();
if (parent == null) {
span = tracer.startRootTransaction(clazz.getClassLoader());
if (span != null) {
span.withName(signature).activate();
}
} else if (parent.isSampled()) {
span = parent.createSpan()
.withName(signature)
.activate();
final AbstractSpan<?> parent = tracer.getActive();
if (parent == null) {
span = tracer.startRootTransaction(clazz.getClassLoader());
if (span != null) {
span.withName(signature).activate();
}
} else if (parent.isSampled()) {
span = parent.createSpan()
.withName(signature)
.activate();
}
}

Expand Down Expand Up @@ -118,9 +117,8 @@ public ElementMatcher<? super TypeDescription> getTypeMatcher() {
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
ElementMatcher.Junction<? super MethodDescription> matcher = matches(methodMatcher.getMethodMatcher());

final List<WildcardMatcher> methodsExcludedFromInstrumentation =
(tracer != null)? tracer.getConfig(CoreConfiguration.class).getMethodsExcludedFromInstrumentation(): null;
if (methodsExcludedFromInstrumentation != null && !methodsExcludedFromInstrumentation.isEmpty()) {
final List<WildcardMatcher> methodsExcludedFromInstrumentation = config.getMethodsExcludedFromInstrumentation();
if (!methodsExcludedFromInstrumentation.isEmpty()) {
matcher = matcher.and(not(new ElementMatcher<MethodDescription>() {
@Override
public boolean matches(MethodDescription target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import co.elastic.apm.agent.impl.ElasticApmTracer;

import java.io.Closeable;

/**
* A {@link LifecycleListener} notifies about the start and stop event of the {@link ElasticApmTracer}.
* <p>
Expand Down
Loading