diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f79321a..0bd5b560 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -290,6 +290,9 @@ jobs: - run: name: Build agent command: ./gradlew clean build -x test + - run: + name: Muzzle check + command: ./gradlew muzzle - run: name: Execute tests command: ./gradlew test diff --git a/build.gradle b/build.gradle index 05642783..f98d7d0e 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { } dependencies { classpath "com.diffplug.spotless:spotless-plugin-gradle:6.14.0" - classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.2" + classpath "com.github.johnrengelman:shadow:8.1.1" classpath "io.opentelemetry.instrumentation:gradle-plugins:2.3.0-alpha" } } diff --git a/instrumentation/jdbc/build.gradle b/instrumentation/jdbc/build.gradle index 16afbf74..d7a74c4d 100644 --- a/instrumentation/jdbc/build.gradle +++ b/instrumentation/jdbc/build.gradle @@ -1,19 +1,13 @@ apply plugin: 'groovy' apply from: "$rootDir/gradle/instrumentation.gradle" -//apply plugin: "otel.javaagent-instrumentation" - -//muzzle { -// pass { -// coreJdk() -// } -//} - dependencies { compileOnly project(":bootstrap") - compileOnly "com.solarwinds.joboe:core:${versions.joboe}" + compileOnly "com.solarwinds.joboe:config:${versions.joboe}" compileOnly "io.opentelemetry:opentelemetry-sdk-trace:${versions.opentelemetry}" + compileOnly "io.opentelemetry.semconv:opentelemetry-semconv:${versions.opentelemetrySemconv}" + compileOnly "com.github.ben-manes.caffeine:caffeine:${versions.caffeine}" testImplementation project(path: ":instrumentation:jdbc") testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common:${versions.opentelemetryJavaagentAlpha}") { diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceCache.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceCache.java new file mode 100644 index 00000000..1a0ab6d0 --- /dev/null +++ b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceCache.java @@ -0,0 +1,22 @@ +package com.solarwinds.opentelemetry.instrumentation; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import java.time.Duration; +import java.util.List; + +public class BackTraceCache { + private static final Cache, String> backTraceCache = + Caffeine.newBuilder() + .maximumSize(20) + .expireAfterAccess(Duration.ofHours(1L)) + .build(); // 1 hour cache; + + static String getBackTraceString(List stackTrace) { + return backTraceCache.getIfPresent(stackTrace); + } + + static void putBackTraceString(List stackTrace, String stackTraceString) { + backTraceCache.put(stackTrace, stackTraceString); + } +} diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceUtil.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceUtil.java new file mode 100644 index 00000000..a20306a3 --- /dev/null +++ b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/BackTraceUtil.java @@ -0,0 +1,87 @@ +package com.solarwinds.opentelemetry.instrumentation; + +import com.solarwinds.joboe.logging.Logger; +import com.solarwinds.joboe.logging.LoggerFactory; +import java.util.Arrays; +import java.util.List; + +public class BackTraceUtil { + private static final int MAX_BACK_TRACE_TOP_LINE_COUNT = 100; + + private static final int MAX_BACK_TRACE_BOTTOM_LINE_COUNT = 20; + + private static final int MAX_BACK_TRACE_LINE_COUNT = + MAX_BACK_TRACE_TOP_LINE_COUNT + MAX_BACK_TRACE_BOTTOM_LINE_COUNT; + + private static final Logger logger = LoggerFactory.getLogger(); + + public static StackTraceElement[] getBackTrace(int skipElements) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + + int startPosition = + 2 + skipElements; // Starts with 2: To exclude the getStackTrace() and addBackTrace calls + // themselves. Also adds the number of skipElements provided in the + // argument to skip elements + + if (startPosition >= stackTrace.length) { + logger.debug( + "Attempt to skip [" + + skipElements + + "] elements in addBackTrace is invalid, no stack trace element is left!"); + return new StackTraceElement[0]; + } + + int targetStackTraceLength = stackTrace.length - startPosition; + StackTraceElement[] targetStackTrace = new StackTraceElement[targetStackTraceLength]; + System.arraycopy(stackTrace, startPosition, targetStackTrace, 0, targetStackTraceLength); + + return targetStackTrace; + } + + public static String backTraceToString(StackTraceElement[] stackTrace) { + List wrappedStackTrace = + Arrays.asList(stackTrace); // wrap it so hashCode and equals work + + String cachedValue = BackTraceCache.getBackTraceString(wrappedStackTrace); + if (cachedValue != null) { + return cachedValue; + } + + StringBuffer stringBuffer = new StringBuffer(); + if (stackTrace.length > MAX_BACK_TRACE_LINE_COUNT) { // then we will have to skip some lines + appendStackTrace( + stackTrace, 0, MAX_BACK_TRACE_TOP_LINE_COUNT, stringBuffer); // add the top lines + + stringBuffer + .append("...Skipped ") + .append(stackTrace.length - MAX_BACK_TRACE_LINE_COUNT) + .append(" line(s)\n"); + + appendStackTrace( + stackTrace, + stackTrace.length - MAX_BACK_TRACE_BOTTOM_LINE_COUNT, + MAX_BACK_TRACE_BOTTOM_LINE_COUNT, + stringBuffer); // add the bottom lines + + } else { + appendStackTrace(stackTrace, 0, stackTrace.length, stringBuffer); // add everything + } + + String value = stringBuffer.toString(); + BackTraceCache.putBackTraceString(wrappedStackTrace, value); + return value; + } + + /** + * Build the stackTrace output and append the result to the buffer provided + * + * @param stackTrace The source of the stack trace array + * @param buffer The buffer that stores the result + */ + private static void appendStackTrace( + StackTraceElement[] stackTrace, int startPosition, int lineCount, StringBuffer buffer) { + for (int i = startPosition; i < startPosition + lineCount && i < stackTrace.length; i++) { + buffer.append(stackTrace[i].toString()).append("\n"); + } + } +} diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/JdbcEventValueConverter.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/JdbcEventValueConverter.java deleted file mode 100644 index 9c469f72..00000000 --- a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/JdbcEventValueConverter.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.solarwinds.opentelemetry.instrumentation; - -import com.solarwinds.joboe.core.EventValueConverter; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Ref; -import java.sql.SQLData; - -public class JdbcEventValueConverter extends EventValueConverter { - public static final int STRING_VALUE_MAX_LENGTH = 256; - private static final JdbcEventValueConverter SINGLETON = - new JdbcEventValueConverter(STRING_VALUE_MAX_LENGTH); - - public static Object convert(Object rawValue) { - return SINGLETON.convertToEventValue(rawValue); - } - - private JdbcEventValueConverter(int maxValueLength) { - super(maxValueLength); - - // do not reference the sql classes directly. Since JDK 9+, those classes are no longer - // accessible from bootstrap classloader, which is the class loader that loads all our - // agent classes. Making reference to classes not from `java.base` module will throw - // `NoClassDefFoundError` - try { - registerSpecialTypes("java.sql.Blob", new BlobParameterHandler()); - registerSpecialTypes("java.sql.Clob", new ClobParameterHandler()); - registerSpecialTypes("java.io.InputStream", new ClassNameParameterHandler()); - registerSpecialTypes("java.io.Reader", new ClassNameParameterHandler()); - registerSpecialTypes("java.sql.Array", new ArrayParameterHandler()); - registerSpecialTypes("java.sql.Ref", new RefParameterHandler()); - } catch (ClassNotFoundException e) { - logger.info( - "Cannot load value class for JDBC event value converter, JDBC instrumentation might not report proper values for some cases : " - + e.getMessage()); - } - - // add support of 1.6+ classes, special handling since we have to be 1.5 compatible - try { - registerSpecialTypes("java.sql.RowId", new ToStringParameterHandler()); - registerSpecialTypes( - "java.sql.SQLXML", new SqlXmlParameterHandler()); // TODO getString too costly? - registerSpecialTypes("java.sql.NClob", new ClobParameterHandler()); - registerSpecialTypes("java.sql.SQLData", new SqlDataParameterHandler()); - } catch (ClassNotFoundException e) { - logger.info( - "Running java 1.5 or earlier version, would not track RowId nor SQLXML (1.6 classes) in PreparedStatement instrumentation"); - } - } - - private void registerSpecialTypes(String className, Converter converter) - throws ClassNotFoundException { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - Class targetClass; - if (systemClassLoader != null) { - targetClass = systemClassLoader.loadClass(className); - } else { - targetClass = Class.forName(className); - } - - EXPECTED_SPECIAL_TYPES.put(targetClass, converter); - } - - /** - * Clob parameter handler, displays the type and the length (bytes designated) of the Clob object - * - * @author Patson Luk - */ - private static class ClobParameterHandler extends Converter { - @Override - protected String getValue(Clob parameter) { - try { - return "(Clob " + parameter.length() + " Bytes)"; - } catch (Exception e) { - logger.warn("Failed to retrieve length of the Clob object: " + e.getMessage()); - return "(Clob)"; - } - } - } - - /** - * Blob parameter handler, displays the type and the length (bytes designated) of the Blob object - * - * @author Patson Luk - */ - private static class BlobParameterHandler extends Converter { - @Override - protected String getValue(Blob parameter) { - try { - return "(Blob " + parameter.length() + " Bytes)"; - } catch (Exception e) { - logger.warn("Failed to retrieve length of the Blob object: " + e.getMessage()); - return "(Blob)"; - } - } - } - - /** - * Ref parameter handler. Display the baseTypeName of the Ref parameter - * - * @author Patson Luk - */ - private static class RefParameterHandler extends Converter { - @Override - protected String getValue(Ref parameter) { - try { - return "(Ref " + parameter.getBaseTypeName() + ")"; - } catch (Exception e) { - logger.warn("Failed to retrieve base type name of the Ref object: " + e.getMessage()); - return "(Ref)"; - } - } - } - - /** - * Array parameter handler. Do not do special handling as accessing the array might involve data - * loading - * - * @author Patson Luk - */ - private static class ArrayParameterHandler extends Converter { - @Override - protected String getValue(Object parameter) { - return "(Array)"; - } - } - - /** - * SQLData(since java 1.6) handler, take note that it is OK to reference SQLData here as this - * handler would not be loaded for 1.5 - * - * @author Patson Luk - */ - private static class SqlDataParameterHandler extends Converter { - @Override - protected String getValue(SQLData parameter) { - try { - return "(SQLData " + parameter.getSQLTypeName() + ")"; - } catch (Exception e) { - logger.warn(e.getMessage()); - return "(SQLData unknown type)"; - } - } - } - - /** - * SQLXML(since java 1.6) handler, take note that it is OK to reference SQLData here as this - * handler would not be loaded for 1.5 - * - * @author Patson Luk - */ - private static class SqlXmlParameterHandler extends Converter { - @Override - protected String getValue(Object parameter) { - return "(SQLXML)"; - } - } -} diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/QueryArgsCollector.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/QueryArgsCollector.java deleted file mode 100644 index d60f4484..00000000 --- a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/QueryArgsCollector.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.solarwinds.opentelemetry.instrumentation; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.context.Context; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; - -public class QueryArgsCollector { - private static final Map> instrumentationStore = - new ConcurrentHashMap<>(); - - public static void collect(Statement statement, Context context, int index, Object value) { - Span span = Span.fromContext(context); - SpanContext spanContext = span.getSpanContext(); - if (!(spanContext.isValid() && spanContext.isSampled())) { - return; - } - - SortedMap queryArgs = - instrumentationStore.computeIfAbsent( - statement, stmt -> Collections.synchronizedSortedMap(new TreeMap<>())); - queryArgs.put(String.valueOf(index), JdbcEventValueConverter.convert(value).toString()); - } - - public static void maybeAttach(Statement statement, Context context) { - Span span = Span.fromContext(context); - SpanContext spanContext = span.getSpanContext(); - if (!(spanContext.isValid() && spanContext.isSampled())) { - return; - } - - SortedMap argsMap = instrumentationStore.get(statement); - if (argsMap != null && !argsMap.isEmpty()) { - List queryArgs = new ArrayList<>(argsMap.values()); - span.setAttribute(SwoPreparedStatementInstrumentation.QueryArgsAttributeKey.KEY, queryArgs); - argsMap.clear(); - } - instrumentationStore.computeIfPresent(statement, (stmt, sortedMap) -> null); - } -} diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoPreparedStatementInstrumentation.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoPreparedStatementInstrumentation.java index 88828dc4..107efa86 100644 --- a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoPreparedStatementInstrumentation.java +++ b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoPreparedStatementInstrumentation.java @@ -11,10 +11,8 @@ import com.solarwinds.joboe.config.ConfigManager; import com.solarwinds.joboe.config.ConfigProperty; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import java.util.List; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -43,10 +41,6 @@ public void transform(TypeTransformer transformer) { SwoPreparedStatementInstrumentation.class.getName() + "$PreparedStatementExecuteAdvice"); } - public static class QueryArgsAttributeKey { - public static final AttributeKey> KEY = AttributeKey.stringArrayKey("QueryArgs"); - } - @SuppressWarnings("unused") public static class PreparedStatementExecuteAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) diff --git a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoStatementTracer.java b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoStatementTracer.java index 18162395..cf30e58f 100644 --- a/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoStatementTracer.java +++ b/instrumentation/jdbc/src/main/java/com/solarwinds/opentelemetry/instrumentation/SwoStatementTracer.java @@ -5,29 +5,15 @@ package com.solarwinds.opentelemetry.instrumentation; -import com.solarwinds.joboe.core.util.BackTraceUtil; import com.solarwinds.opentelemetry.core.Constants; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; -import java.util.LinkedHashMap; -import java.util.Map; public class SwoStatementTracer { - private static final Map LRUCache = - new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > 128; - } - }; - public static void writeStackTraceSpec(Context context) { Span span = Span.fromContext(context); if (span.getSpanContext().isSampled()) { - String backTraceString = - LRUCache.computeIfAbsent( - span.getSpanContext().getSpanId(), - (ignored) -> BackTraceUtil.backTraceToString(BackTraceUtil.getBackTrace(1))); + String backTraceString = BackTraceUtil.backTraceToString(BackTraceUtil.getBackTrace(1)); span.setAttribute(Constants.SW_KEY_PREFIX + "Backtrace", backTraceString); span.setAttribute(Constants.SW_KEY_PREFIX + "Spec", "query"); } diff --git a/instrumentation/servlet-3.0/build.gradle b/instrumentation/servlet-3.0/build.gradle index 91c446b8..4f093281 100644 --- a/instrumentation/servlet-3.0/build.gradle +++ b/instrumentation/servlet-3.0/build.gradle @@ -4,8 +4,6 @@ archivesBaseName = "servlet3" dependencies { compileOnly("javax.servlet:javax.servlet-api:3.0.1") - compileOnly "com.solarwinds.joboe:core:${versions.joboe}" - compileOnly project(":custom") compileOnly project(":bootstrap") } diff --git a/instrumentation/servlet-5.0/build.gradle b/instrumentation/servlet-5.0/build.gradle index 3facbdef..ca903c4a 100644 --- a/instrumentation/servlet-5.0/build.gradle +++ b/instrumentation/servlet-5.0/build.gradle @@ -4,7 +4,6 @@ archivesBaseName = "servlet5" dependencies { compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0") - compileOnly "com.solarwinds.joboe:core:${versions.joboe}" compileOnly project(":custom") compileOnly project(":bootstrap") } diff --git a/instrumentation/spring-webmvc-3.1/build.gradle b/instrumentation/spring-webmvc-3.1/build.gradle index c836faa3..796c8fef 100644 --- a/instrumentation/spring-webmvc-3.1/build.gradle +++ b/instrumentation/spring-webmvc-3.1/build.gradle @@ -30,7 +30,6 @@ dependencies { compileOnly "org.springframework:spring-webmvc:3.1.0.RELEASE" compileOnly "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:${versions.opentelemetryJavaagent}" compileOnly "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator:${versions.opentelemetryJavaagentAlpha}" - compileOnly "com.solarwinds.joboe:core:${versions.joboe}" compileOnly "javax.servlet:javax.servlet-api:3.1.0" } diff --git a/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java b/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java index 762f1f2e..456d0b37 100644 --- a/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java @@ -33,7 +33,10 @@ public class LambdaTest { private static final NamingConventions namingConventions = new NamingConventions(); private static final LogStreamAnalyzer logStreamAnalyzer = new LogStreamAnalyzer<>( - List.of("Got settings from file:") + List.of( + "Got settings from file:", + "Applying instrumentation: sw-jdbc" + ) , new Slf4jLogConsumer(LoggerFactory.getLogger("k6"))); @@ -59,12 +62,11 @@ static void runAppOnce(TestConfig config, Agent agent) throws Exception { GenericContainer petClinic = new PetClinicRestContainer(new SwoLambdaAgentResolver(), NETWORK, agent, namingConventions).build(); petClinic.start(); - petClinic.followOutput(logStreamAnalyzer, OutputFrame.OutputType.STDOUT); + petClinic.followOutput(logStreamAnalyzer); GenericContainer k6 = new K6Container(NETWORK, agent, config, namingConventions).build(); k6.start(); - k6.followOutput(new Slf4jLogConsumer(LoggerFactory.getLogger("k6")), - OutputFrame.OutputType.STDOUT); + k6.followOutput(new Slf4jLogConsumer(LoggerFactory.getLogger("k6"))); petClinic.execInContainer("kill", "1"); postgres.stop(); @@ -120,4 +122,10 @@ void assertThatSettingsAreReadFromFile() { Boolean actual = logStreamAnalyzer.getAnswer().get("Got settings from file:"); assertTrue(actual, "file based settings is not being used"); } + + @Test + void assertThatJDBCInstrumentationIsApplied() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); + assertTrue(actual, "sw-jdbc instrumentation is not applied"); + } } diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index 46cadd24..505fce3c 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -1,5 +1,10 @@ package com.solarwinds; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import com.solarwinds.agents.Agent; import com.solarwinds.agents.SwoAgentResolver; import com.solarwinds.config.Configs; @@ -12,6 +17,9 @@ import com.solarwinds.results.ResultsCollector; import com.solarwinds.util.LogStreamAnalyzer; import com.solarwinds.util.NamingConventions; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -23,15 +31,6 @@ import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - @EnabledIfEnvironmentVariable(named = "LAMBDA", matches = "false") public class SmokeTest { private static final Network NETWORK = Network.newNetwork(); @@ -44,6 +43,7 @@ public class SmokeTest { "hostId:.*[0-9a-z-]+", "Extension attached!","Created collector client : collector.appoptics.com:443", "trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=(01|00)", "This log line is used for validation only: service.name: java-apm-smoke-test", + "Applying instrumentation: sw-jdbc", "Clearing transaction name buffer. Unique transaction count: \\d+") , new Slf4jLogConsumer(LoggerFactory.getLogger("k6"))); @@ -66,18 +66,18 @@ static void runTestConfig() { static void runAppOnce(TestConfig config, Agent agent) throws Exception { GenericContainer webMvc = new SpringBootWebMvcContainer(new SwoAgentResolver(), NETWORK, agent).build(); webMvc.start(); - webMvc.followOutput(logStreamAnalyzer, OutputFrame.OutputType.STDOUT); + webMvc.followOutput(logStreamAnalyzer); GenericContainer webMvcAo = new AoContainer(new SwoAgentResolver(), NETWORK, agent).build(); webMvcAo.start(); - webMvcAo.followOutput(logStreamAnalyzer, OutputFrame.OutputType.STDOUT); + webMvcAo.followOutput(logStreamAnalyzer); GenericContainer postgres = new PostgresContainer(NETWORK).build(); postgres.start(); GenericContainer petClinic = new PetClinicRestContainer(new SwoAgentResolver(), NETWORK, agent, namingConventions).build(); petClinic.start(); - petClinic.followOutput(logStreamAnalyzer, OutputFrame.OutputType.STDOUT); + petClinic.followOutput(logStreamAnalyzer); GenericContainer k6 = new K6Container(NETWORK, agent, config, namingConventions).build(); k6.start(); @@ -219,4 +219,10 @@ void assertThatTransactionNameBufferIsCleared() { assertTrue(actual, "Transaction name buffer is not getting cleared on metric flush"); } + @Test + void assertThatJDBCInstrumentationIsApplied() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); + assertTrue(actual, "sw-jdbc instrumentation is not applied"); + } + } diff --git a/smoke-tests/src/test/java/com/solarwinds/containers/PetClinicRestContainer.java b/smoke-tests/src/test/java/com/solarwinds/containers/PetClinicRestContainer.java index c111a0ff..330d4c05 100644 --- a/smoke-tests/src/test/java/com/solarwinds/containers/PetClinicRestContainer.java +++ b/smoke-tests/src/test/java/com/solarwinds/containers/PetClinicRestContainer.java @@ -54,6 +54,9 @@ public GenericContainer build() { .withFileSystemBind(namingConventions.localResults(), namingConventions.containerResults()) .withFileSystemBind("./solarwinds-apm-settings.json", "/tmp/solarwinds-apm-settings.json") + .withEnv("OTEL_JAVAAGENT_DEBUG", "true") + .withEnv("SW_APM_SQL_TAG", "true") + .withEnv("SW_APM_SQL_TAG_PREPARED", "true") .waitingFor( Wait.forHttp("/petclinic/actuator/health").withReadTimeout(Duration.ofMinutes(5)) .forPort(PETCLINIC_PORT)) @@ -97,6 +100,8 @@ public GenericContainer build() { .withEnv("spring_datasource_password", PostgresContainer.PASSWORD) .withEnv("spring_jpa_hibernate_ddl-auto", "none") .withEnv("SW_APM_DEBUG_LEVEL", "trace") + .withEnv("SW_APM_SQL_TAG", "true") + .withEnv("SW_APM_SQL_TAG_PREPARED", "true") .withEnv("SW_APM_COLLECTOR", System.getenv("SW_APM_COLLECTOR")) .withEnv("SW_APM_SERVICE_KEY", String.format("%s:java-apm-smoke-test", System.getenv("SW_APM_SERVICE_KEY"))) .withStartupTimeout(Duration.ofMinutes(5))