Fail test if advice threw an exception (#9654)

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Lauri Tulmin 2023-10-11 22:17:20 +03:00 committed by GitHub
parent b7df46dda5
commit 0de1dcff45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 52 additions and 8 deletions

View File

@ -19,7 +19,6 @@ dependencies {
library("com.amazonaws:aws-lambda-java-core:1.0.0")
testImplementation(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:testing"))
testInstrumentation(project(":instrumentation:aws-lambda:aws-lambda-events-2.2:javaagent"))
}
tasks.withType<Test>().configureEach {

View File

@ -5,12 +5,15 @@
package io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static java.util.Collections.singletonList;
import static net.bytebuddy.matcher.ElementMatchers.not;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class)
public class AwsLambdaInstrumentationModule extends InstrumentationModule {
@ -18,6 +21,12 @@ public class AwsLambdaInstrumentationModule extends InstrumentationModule {
super("aws-lambda-core", "aws-lambda-core-1.0", "aws-lambda");
}
@Override
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
// aws-lambda-events-2.2 is used when SQSEvent is present
return not(hasClassesNamed("com.amazonaws.services.lambda.runtime.events.SQSEvent"));
}
@Override
public boolean isHelperClass(String className) {
return className.startsWith("io.opentelemetry.contrib.awsxray.");

View File

@ -24,6 +24,7 @@ import io.opentelemetry.javaagent.bootstrap.kafka.KafkaClientsConsumerProcessTra
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import net.bytebuddy.asm.Advice;
@ -61,7 +62,12 @@ public class KafkaConsumerInstrumentation implements TypeInstrumentation {
public static class ConstructorMapAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(@Advice.Argument(0) Map<String, Object> config) {
public static void onEnter(
@Advice.Argument(value = 0, readOnly = false) Map<String, Object> config) {
// ensure config is a mutable map
if (config.getClass() != HashMap.class) {
config = new HashMap<>(config);
}
enhanceConfig(config);
}
}

View File

@ -20,6 +20,7 @@ import io.opentelemetry.instrumentation.kafka.internal.KafkaPropagation;
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import net.bytebuddy.asm.Advice;
@ -57,7 +58,12 @@ public class KafkaProducerInstrumentation implements TypeInstrumentation {
public static class ConstructorMapAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(@Advice.Argument(0) Map<String, Object> config) {
public static void onEnter(
@Advice.Argument(value = 0, readOnly = false) Map<String, Object> config) {
// ensure config is a mutable map
if (config.getClass() != HashMap.class) {
config = new HashMap<>(config);
}
enhanceConfig(config);
}
}

View File

@ -71,7 +71,9 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
ChannelHandler ourHandler = virtualField.get(handler);
if (ourHandler != null) {
pipeline.remove(ourHandler);
if (pipeline.context(ourHandler) != null) {
pipeline.remove(ourHandler);
}
virtualField.set(handler, null);
}
}
@ -92,7 +94,9 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
ChannelHandler ourHandler = virtualField.get(handler);
if (ourHandler != null) {
pipeline.remove(ourHandler);
if (pipeline.context(ourHandler) != null) {
pipeline.remove(ourHandler);
}
virtualField.set(handler, null);
}
}
@ -114,7 +118,9 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
ChannelHandler ourHandler = virtualField.get(handler);
if (ourHandler != null) {
pipeline.remove(ourHandler);
if (pipeline.context(ourHandler) != null) {
pipeline.remove(ourHandler);
}
virtualField.set(handler, null);
}
}
@ -130,7 +136,9 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
ChannelHandler ourHandler = virtualField.get(handler);
if (ourHandler != null) {
pipeline.remove(ourHandler);
if (pipeline.context(ourHandler) != null) {
pipeline.remove(ourHandler);
}
virtualField.set(handler, null);
}
}

View File

@ -32,7 +32,7 @@ public class Servlet2SpanNameExtractor<REQUEST, RESPONSE>
if (!knownMethods.contains(method)) {
method = "HTTP";
}
if (servletPath.isEmpty()) {
if (servletPath == null || servletPath.isEmpty()) {
return method;
}
String contextPath = accessor.getRequestContextPath(request);

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.bootstrap;
import static java.util.logging.Level.FINE;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
/**
@ -17,11 +18,18 @@ import java.util.logging.Logger;
public final class ExceptionLogger {
private static final Logger logger = Logger.getLogger(ExceptionLogger.class.getName());
private static final AtomicInteger counter = new AtomicInteger();
/** See {@code io.opentelemetry.javaagent.tooling.ExceptionHandlers} for usages. */
@SuppressWarnings("unused")
public static void logSuppressedError(String message, Throwable error) {
logger.log(FINE, message, error);
counter.incrementAndGet();
}
// only used by tests
public static int getAndReset() {
return counter.getAndSet(0);
}
private ExceptionLogger() {}

View File

@ -46,6 +46,7 @@ dependencies {
api("org.slf4j:slf4j-api")
compileOnly(project(":testing:armeria-shaded-for-testing", configuration = "shadow"))
compileOnly(project(":javaagent-bootstrap"))
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")

View File

@ -55,6 +55,8 @@ public final class AgentTestRunner extends InstrumentationTestRunner {
assert TestAgentListenerAccess.getInstrumentationErrorCount() == 0
: TestAgentListenerAccess.getInstrumentationErrorCount()
+ " Instrumentation errors during test";
int adviceFailureCount = TestAgentListenerAccess.getAndResetAdviceFailureCount();
assert adviceFailureCount == 0 : adviceFailureCount + " Advice failures during test";
int muzzleFailureCount = TestAgentListenerAccess.getAndResetMuzzleFailureCount();
assert muzzleFailureCount == 0 : muzzleFailureCount + " Muzzle failures during test";
// additional library ignores are ignored during tests, because they can make it really

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.testing.common;
import static java.lang.invoke.MethodType.methodType;
import io.opentelemetry.javaagent.bootstrap.ExceptionLogger;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.List;
@ -105,5 +106,9 @@ public final class TestAgentListenerAccess {
}
}
public static int getAndResetAdviceFailureCount() {
return ExceptionLogger.getAndReset();
}
private TestAgentListenerAccess() {}
}