Skip to content

Commit

Permalink
NH-37575: download agent from GitHub
Browse files Browse the repository at this point in the history
  • Loading branch information
cleverchuk committed Jul 2, 2024
1 parent 9ff38e6 commit 8a50dc0
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 90 deletions.
1 change: 0 additions & 1 deletion benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ plugins {
spotless {
java {
googleJavaFormat()
licenseHeaderFile(rootProject.file("../buildscripts/spotless.license.java"), "(package|import|public)")
target("src/**/*.java")
}
}
Expand Down
50 changes: 35 additions & 15 deletions benchmark/src/test/java/io/opentelemetry/OverheadTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ public class OverheadTests {
private static GenericContainer<?> aoCollector;
private final NamingConventions namingConventions = new NamingConventions();
private final Map<String, Long> runDurations = new HashMap<>();
private static Set<String> verboseConfig = new HashSet<>(Arrays.asList(Strings.split(System.getenv("CONTAINER_LOGS") != null ? System.getenv("CONTAINER_LOGS") : "", '|')));
private static Set<String> verboseConfig =
new HashSet<>(
Arrays.asList(
Strings.split(
System.getenv("CONTAINER_LOGS") != null ? System.getenv("CONTAINER_LOGS") : "",
'|')));

@BeforeAll
static void setUp() {
Expand Down Expand Up @@ -104,14 +109,18 @@ void runAppOnce(TestConfig config, Agent agent) throws Exception {

if (verboseConfig.contains("all") || verboseConfig.contains("app")) {
String logs = petclinic.getLogs();
System.err.println(String.format("\n\n===============%s====================\n\n%s\n\n==============================="
, agent.getName(), logs));
System.err.println(
String.format(
"\n\n===============%s====================\n\n%s\n\n===============================",
agent.getName(), logs));
}

if (verboseConfig.contains("all") || verboseConfig.contains("collector")) {
String aoCollectorLogs = aoCollector.getLogs();
System.err.println(String.format("\n\n===============%s====================\n\n%s\n\n==============================="
, aoCollector.getDockerImageName(), aoCollectorLogs));
System.err.println(
String.format(
"\n\n===============%s====================\n\n%s\n\n===============================",
aoCollector.getDockerImageName(), aoCollectorLogs));
}
// This is required to get a graceful exit of the VM before testcontainers kills it forcibly.
// Without it, our jfr file will be empty.
Expand All @@ -136,22 +145,33 @@ private void startRecording(Agent agent, GenericContainer<?> petclinic) throws E
petclinic.execInContainer(command);
}

private void doWarmupPhase(TestConfig testConfig, GenericContainer<?> petclinic) throws IOException, InterruptedException {
System.out.println("Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds...");
private void doWarmupPhase(TestConfig testConfig, GenericContainer<?> petclinic)
throws IOException, InterruptedException {
System.out.println(
"Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds...");

// excluding the JFR recording from the warmup causes strange inconsistencies in the results
System.out.println("Starting disposable JFR warmup recording...");
String[] startCommand = {"jcmd", "1", "JFR.start", "settings=/app/overhead.jfc", "dumponexit=true", "name=warmup", "filename=warmup.jfr"};
String[] startCommand = {
"jcmd",
"1",
"JFR.start",
"settings=/app/overhead.jfc",
"dumponexit=true",
"name=warmup",
"filename=warmup.jfr"
};
petclinic.execInContainer(startCommand);

long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds());
while(System.currentTimeMillis() < deadline) {
long deadline =
System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds());
while (System.currentTimeMillis() < deadline) {
GenericContainer<?> k6 =
new GenericContainer<>(DockerImageName.parse("loadimpact/k6"))
.withNetwork(NETWORK)
.withCopyFileToContainer(MountableFile.forHostPath("./k6"), "/app")
.withCommand("run", "-u", "5", "-i", "200", "/app/basic.js")
.withStartupCheckStrategy(new OneShotStartupCheckStrategy());
new GenericContainer<>(DockerImageName.parse("loadimpact/k6"))
.withNetwork(NETWORK)
.withCopyFileToContainer(MountableFile.forHostPath("./k6"), "/app")
.withCommand("run", "-u", "5", "-i", "200", "/app/basic.js")
.withStartupCheckStrategy(new OneShotStartupCheckStrategy());
k6.start();
}

Expand Down
3 changes: 2 additions & 1 deletion benchmark/src/test/java/io/opentelemetry/agents/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public class Agent {
new Agent("latest", "latest mainstream release", OTEL_LATEST);
public static final Agent LATEST_SNAPSHOT =
new Agent("snapshot", "latest available snapshot version from main");
public static final Agent NH_LATEST_RELEASE = new Agent(LatestSolarwindsAgentResolver.useAOAgent ? "AO" : "NH", "latest Solarwinds agent");
public static final Agent NH_LATEST_RELEASE =
new Agent(LatestSolarwindsAgentResolver.useAOAgent ? "AO" : "NH", "latest Solarwinds agent");

private final String name;
private final String description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
public class AgentResolver {

private final LatestAgentSnapshotResolver snapshotResolver = new LatestAgentSnapshotResolver();
private final LatestSolarwindsAgentResolver nighthawkAgentResolver = new LatestSolarwindsAgentResolver();
private final LatestSolarwindsAgentResolver nighthawkAgentResolver =
new LatestSolarwindsAgentResolver();

public Optional<Path> resolve(Agent agent) throws Exception {
if (Agent.NONE.equals(agent)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,120 @@
package io.opentelemetry.agents;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Optional;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.testcontainers.shaded.com.fasterxml.jackson.core.type.TypeReference;
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;

public class LatestSolarwindsAgentResolver {
private static final String NH_URL = "https://agent-binaries.global.st-ssp.solarwinds.com/apm/java/latest/solarwinds-apm-agent.jar";
private static final String AO_URL = "https://files.appoptics.com/java/latest/appoptics-agent.jar";
private static final String NH_AGENT_JAR_NAME = "solarwinds-apm-agent.jar";
private static final String AO_AGENT_JAR_NAME = "appoptics-agent.jar";
public static boolean useAOAgent = "AO".equals(System.getenv("AGENT_TYPE"));

Optional<Path> resolve() throws Exception {
return Optional.of(downloadAgent());
}

private Path downloadAgent() throws Exception {
String assetURL;
if (useAOAgent) {
assetURL = AO_URL;
} else {
assetURL = NH_URL;
}
private static final String NH_URL = " https://api.github.com/repos/solarwinds/apm-java/releases";
private static final String AO_URL =
"https://files.appoptics.com/java/latest/appoptics-agent.jar";
private static final String NH_AGENT_JAR_NAME = "solarwinds-apm-agent.jar";
private static final String AO_AGENT_JAR_NAME = "appoptics-agent.jar";
public static boolean useAOAgent = "AO".equals(System.getenv("AGENT_TYPE"));

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(assetURL)
.header("Authorization", "token " + System.getenv("GITHUB_TOKEN"))
.header("Accept", "application/octet-stream").build();

Path path = Paths.get(".", useAOAgent ? AO_AGENT_JAR_NAME : NH_AGENT_JAR_NAME);
try (Response response = client.newCall(request).execute()) {
assert response.body() != null;
byte[] fileRaw = response.body().bytes();
Files.write(
path,
fileRaw,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING);
Optional<Path> resolve() throws Exception {
return Optional.of(downloadAgent());
}

private Path downloadAgent() throws Exception {
String assetURL;
OkHttpClient client = new OkHttpClient();
if (useAOAgent) {
assetURL = AO_URL;
} else {
assetURL = NH_URL;
Request request =
new Request.Builder()
.url(NH_URL)
.header("Authorization", "token " + System.getenv("GITHUB_TOKEN"))
.header("Accept", "application/vnd.github.v3+json")
.build();

try (Response response = client.newCall(request).execute()) {
assert response.body() != null;
byte[] raw = response.body().bytes();

ObjectMapper mapper = new ObjectMapper();
List<GithubRelease> releases =
mapper.readValue(raw, new TypeReference<List<GithubRelease>>() {});

outerLoop:
for (GithubRelease release : releases) {
for (Asset asset : release.assets) {
if (asset.name.equals(NH_AGENT_JAR_NAME)) {
assetURL = asset.url;
break outerLoop;
}
}
}
return path;
if (assetURL == null) {
throw new RuntimeException("Asset url not found for the NH agent.");
}
}
}

Request request =
new Request.Builder()
.url(assetURL)
.header("Authorization", "token " + System.getenv("GITHUB_TOKEN"))
.header("Accept", "application/octet-stream")
.build();

Path path = Paths.get(".", useAOAgent ? AO_AGENT_JAR_NAME : NH_AGENT_JAR_NAME);
try (Response response = client.newCall(request).execute()) {
assert response.body() != null;
byte[] fileRaw = response.body().bytes();
Files.write(
path,
fileRaw,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING);
}
return path;
}

@JsonIgnoreProperties(ignoreUnknown = true)
public static class GithubRelease {
private List<Asset> assets;

public List<Asset> getAssets() {
return assets;
}

public void setAssets(List<Asset> assets) {
this.assets = assets;
}
}

@JsonIgnoreProperties(ignoreUnknown = true)
public static class Asset {
private String url;
private String name;

public String getUrl() {
return url;
}

public String getName() {
return name;
}

public void setUrl(String url) {
this.url = url;
}

public void setName(String name) {
this.name = name;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,22 @@
import org.testcontainers.utility.MountableFile;

public class AOTestCollectorContainer {
static final int COLLECTOR_PORT = 12223;
static final int COLLECTOR_HEALTH_CHECK_PORT = 8181;
static final int COLLECTOR_PORT = 12223;
static final int COLLECTOR_HEALTH_CHECK_PORT = 8181;

private static final Logger logger = LoggerFactory.getLogger(CollectorContainer.class);
private static final Logger logger = LoggerFactory.getLogger(CollectorContainer.class);


public static GenericContainer<?> build(Network network) {
return new GenericContainer<>(
DockerImageName.parse("ghcr.io/solarwinds/apm-agent-test-collector:v2.0.4"))
.withNetwork(network)
.withNetworkAliases("AOCollector")
.withLogConsumer(new Slf4jLogConsumer(logger))
.withExposedPorts(COLLECTOR_PORT, COLLECTOR_HEALTH_CHECK_PORT)
.waitingFor(Wait.forHttp("/collectors").forPort(COLLECTOR_HEALTH_CHECK_PORT))
.withCopyFileToContainer(
MountableFile.forClasspathResource("test-server-grpc.crt"), "/server-grpc.crt")
.withCopyFileToContainer(
MountableFile.forClasspathResource("test-server-grpc.pem"), "/server-grpc.pem");
}
public static GenericContainer<?> build(Network network) {
return new GenericContainer<>(
DockerImageName.parse("ghcr.io/solarwinds/apm-agent-test-collector:v2.0.4"))
.withNetwork(network)
.withNetworkAliases("AOCollector")
.withLogConsumer(new Slf4jLogConsumer(logger))
.withExposedPorts(COLLECTOR_PORT, COLLECTOR_HEALTH_CHECK_PORT)
.waitingFor(Wait.forHttp("/collectors").forPort(COLLECTOR_HEALTH_CHECK_PORT))
.withCopyFileToContainer(
MountableFile.forClasspathResource("test-server-grpc.crt"), "/server-grpc.crt")
.withCopyFileToContainer(
MountableFile.forClasspathResource("test-server-grpc.pem"), "/server-grpc.pem");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ public GenericContainer<?> build() throws Exception {
.withEnv("SW_APM_DEBUG_LEVEL", "info")
.withEnv("SW_APM_COLLECTOR", "AOCollector:12223")
.withEnv("SW_APM_TRUSTEDPATH", "/test-server-grpc.crt")
.withEnv("APPOPTICS_DEBUG_LEVEL", "info")
.withEnv("APPOPTICS_COLLECTOR", "AOCollector:12223")
.withEnv("APPOPTICS_TRUSTEDPATH", "/test-server-grpc.crt")
.withEnv("APPOPTICS_DEBUG_LEVEL", "info")
.withEnv("APPOPTICS_COLLECTOR", "AOCollector:12223")
.withEnv("APPOPTICS_TRUSTEDPATH", "/test-server-grpc.crt")
.withCopyFileToContainer(
MountableFile.forClasspathResource("test-server-grpc.crt"), "/test-server-grpc.crt")
MountableFile.forClasspathResource("test-server-grpc.crt"), "/test-server-grpc.crt")
.dependsOn(collector)
.withCommand(buildCommandline(agentJar));
agentJar.ifPresent(
Expand All @@ -91,20 +91,33 @@ private String[] buildCommandline(Optional<Path> agentJar) {
List<String> result = new ArrayList<>();
if (!agent.equals(Agent.NH_LATEST_RELEASE)) {
result.addAll(
Arrays.asList(
"java",
"-Dotel.traces.exporter=otlp",
"-Dotel.imr.export.interval=5000",
"-Dotel.exporter.otlp.insecure=true",
"-Dotel.exporter.otlp.protocol=grpc",
"-Dotel.exporter.otlp.endpoint=http://collector:4317",
"-Dotel.resource.attributes=service.name=petclinic-otel-overhead"));
Arrays.asList(
"java",
"-Dotel.traces.exporter=otlp",
"-Dotel.imr.export.interval=5000",
"-Dotel.exporter.otlp.insecure=true",
"-Dotel.exporter.otlp.protocol=grpc",
"-Dotel.exporter.otlp.endpoint=http://collector:4317",
"-Dotel.resource.attributes=service.name=petclinic-otel-overhead"));
} else {
result.addAll(Arrays.asList("java",
"-Dotel.solarwinds.service.key=" + System.getenv("SW_APM_SERVICE_KEY") + ":sw-java-benchmark"));
result.addAll(
Arrays.asList(
"java",
"-Dotel.solarwinds.service.key="
+ System.getenv("SW_APM_SERVICE_KEY")
+ ":sw-java-benchmark"));
}
result.addAll(this.agent.getAdditionalJvmArgs());
agentJar.ifPresent(path -> result.add("-javaagent:/app/" + path.getFileName() + (LatestSolarwindsAgentResolver.useAOAgent ? "=service_key="+System.getenv("SW_APM_SERVICE_KEY")+":sw-java-benchmark":"")));
agentJar.ifPresent(
path ->
result.add(
"-javaagent:/app/"
+ path.getFileName()
+ (LatestSolarwindsAgentResolver.useAOAgent
? "=service_key="
+ System.getenv("SW_APM_SERVICE_KEY")
+ ":sw-java-benchmark"
: "")));
result.add("-jar");
result.add("/app/spring-petclinic-rest.jar");
System.err.println("Running app with command:\n" + String.join(" ", result));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public void write(List<AppPerfResults> results) {
display(results, "| Min heap used (MB)", res -> format(res.getMinHeapUsedMB()));
display(results, "| Max heap used (MB)", res -> format(res.getMaxHeapUsedMB()));
display(results, "| Thread switch rate", res -> String.valueOf(res.maxThreadContextSwitchRate));
display(results, "| GC time (ms)", res -> String.valueOf(NANOSECONDS.toMillis(res.totalGCTime)));
display(
results, "| GC time (ms)", res -> String.valueOf(NANOSECONDS.toMillis(res.totalGCTime)));
display(
results,
"| GC pause time (ms)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ public class NamingConventions {
public final NamingConvention container = new NamingConvention("/results");
public final NamingConvention local = new NamingConvention(".");

/** @return Root path for the local naming convention (where results are output) */
/**
* @return Root path for the local naming convention (where results are output)
*/
public String localResults() {
return local.root();
}

/** @return Root path for the container naming convention (where results are output) */
/**
* @return Root path for the container naming convention (where results are output)
*/
public String containerResults() {
return container.root();
}
Expand Down

0 comments on commit 8a50dc0

Please sign in to comment.