Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support auto-trace #73

Merged
merged 8 commits into from
Jun 26, 2024
Merged
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
2 changes: 2 additions & 0 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ tag = True

[bumpversion:file:src/main/java/io/lumigo/core/configuration/Configuration.java]

[bumpversion:file:layer/generate.sh]

[bumpversion:file:src/main/resources/lumigo-version.txt]
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ Find the latest version here (the format of the version will be n.n.n):
}
}
```

## Lambda Auto tracing with lambda layer

* Add to your lambda a new layer with the arn from here
* Add environment variable `JAVA_TOOL_OPTIONS` and set it to `-javaagent:/opt/lumigo-java/lumigo-agent.jar` (This is instead of the flag for more than java11 support)
* Add the `LUMIGO_TRACER_TOKEN` env var.
nadav3396 marked this conversation as resolved.
Show resolved Hide resolved


### Configuration

Expand Down Expand Up @@ -120,7 +127,7 @@ class MyFunction implements RequestHandler<String, String> {
### Support Java 11 and Above

Add the environment variable `JAVA_TOOL_OPTIONS` to your Lambda functions and set it to
`-Djdk.attach.allowAttachSelf=true` in addition to the manual code mentioned above.
`-Djdk.attach.allowAttachSelf=true` in addition to the manual code mentioned above (This is not needed for the auto trace with lambda layer).

### Supported Instrumentation Libraries

Expand Down
11 changes: 4 additions & 7 deletions agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@
<organization>Lumigo</organization>
<organizationUrl>https://lumigo.io/</organizationUrl>
</developer>
<developer>
<name>Uri Parush</name>
<email>[email protected]</email>
<organization>Lumigo</organization>
<organizationUrl>https://lumigo.io</organizationUrl>
</developer>
</developers>

<organization>
Expand Down Expand Up @@ -104,9 +98,12 @@
<archive>
<manifestEntries>
<Agent-Class>io.lumigo.agent.Agent</Agent-Class>
<Can-Redefine-Classes>false</Can-Redefine-Classes>
<Main-Class>io.lumigo.agent.Agent</Main-Class>
<Premain-Class>io.lumigo.agent.Agent</Premain-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
<Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix>
<Implementation-Vendor>Lumigo</Implementation-Vendor>
</manifestEntries>
</archive>
</configuration>
Expand Down
35 changes: 34 additions & 1 deletion agent/src/main/java/io/lumigo/agent/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,39 @@
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Agent {

private static boolean initialized = false;

public static String LUMIGO_JAVA_TRACER_PATH = "/opt/lumigo-java/lumigo-tracer.jar";

public static void premain(String agentArgs, Instrumentation inst) {
if (!isKillSwitchOn()) {
nadav3396 marked this conversation as resolved.
Show resolved Hide resolved
agentmain(agentArgs, inst);
}
}

public static void agentmain(String agentArgs, Instrumentation inst) {
if (initialized) {
return;
}
initialized = true;
try {
URL[] urls;
if ("lib".equalsIgnoreCase(agentArgs)) {
urls = getUrls();
} else {
urls = new URL[] {new File("/var/task/").toURI().toURL()};
urls =
new URL[] {
new File("/var/task/").toURI().toURL(),
new File(LUMIGO_JAVA_TRACER_PATH).toURI().toURL()
};
}
installTracerJar(inst);
URLClassLoader newClassLoader = new URLClassLoader(urls, null);
Thread.currentThread().setContextClassLoader(newClassLoader);
final Class<?> loader =
Expand All @@ -35,6 +55,14 @@ public static void agentmain(String agentArgs, Instrumentation inst) {
}
}

private static void installTracerJar(Instrumentation inst) {
try (JarFile jar = new JarFile(new File(new File(LUMIGO_JAVA_TRACER_PATH).toURI()))) {
inst.appendToSystemClassLoaderSearch(jar);
} catch (Exception e) {
e.printStackTrace();
}
}

public static URL[] getUrls() {
List<URL> jars = new LinkedList<>();
try (Stream<Path> paths = Files.walk(Paths.get("/var/task/lib"))) {
Expand All @@ -56,4 +84,9 @@ public static URL[] getUrls() {
}
return jars.toArray(new URL[jars.size()]);
}

public static boolean isKillSwitchOn() {
String value = System.getenv("LUMIGO_SWITCH_OFF");
return "true".equalsIgnoreCase(value);
}
}
4 changes: 4 additions & 0 deletions layers/LAYERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Java Layers
----
| Region | ARN |
| --- | --- |
34 changes: 34 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,28 +116,33 @@
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
<version>2.25.45</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sqs</artifactId>
<version>2.25.45</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sns</artifactId>
<version>2.25.45</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kinesis</artifactId>
<version>2.25.45</version>
<scope>provided</scope>
</dependency>

<!-- Kafka dependencies -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<!-- Tracer dependencies -->
Expand Down Expand Up @@ -182,6 +187,7 @@
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>

<!-- Testing dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down Expand Up @@ -372,4 +378,32 @@
</plugin>
</plugins>
</build>
<profiles>
nadav3396 marked this conversation as resolved.
Show resolved Hide resolved
<profile>
<id>shade</id>
<activation>
<property>
<name>includeShade</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
20 changes: 20 additions & 0 deletions scripts/bd_to_prod.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ mvn -f agent/pom.xml nexus-staging:release
mvn -Dmaven.test.skip=true -Dfindbugs.skip=true clean deploy
mvn nexus-staging:release

echo "Creating lumigo-java-tracer layer"
./scripts/prepare_layer_files.sh

echo "Creating layer latest version arn table md file (LAYERS.md)"
commit_version="$(git describe --abbrev=0 --tags)"
../utils/common_bash/create_layer.sh \
--layer-name lumigo-java-tracer \
--region ALL \
--package-folder lumigo-java \
--version "$commit_version" \
--runtimes "java11 java17 java21"

cd ../larn && npm i -g
larn -r java11 -n layers/LAYERS.md --filter lumigo-java-tracer -p ~/java-tracer
cd ../java-tracer

git add layers/LAYERS.md
git commit -m "docs: update layers md [skip ci]"
git push origin master

echo "Create release tag"
push_tags

Expand Down
11 changes: 11 additions & 0 deletions scripts/prepare_layer_files.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

mkdir -p lumigo-java

MVN_DEFAULT_FLAGS="-Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10"

mvn "$MVN_DEFAULT_FLAGS" -Dmaven.test.skip=true -Dfindbugs.skip=true -DincludeShade=true clean package --quiet
mvn "$MVN_DEFAULT_FLAGS" -f agent/pom.xml clean package --quiet

cp target/java-tracer-1.0.47.jar lumigo-java/lumigo-tracer.jar
cp agent/target/lumigo-agent-1.0.47.jar lumigo-java/lumigo-agent.jar
28 changes: 6 additions & 22 deletions src/main/java/io/lumigo/core/instrumentation/agent/Loader.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package io.lumigo.core.instrumentation.agent;

import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.not;

import io.lumigo.core.instrumentation.impl.*;
import net.bytebuddy.agent.builder.AgentBuilder;
import org.pmw.tinylog.Logger;

@SuppressWarnings("unused")
public class Loader {
public static void instrument(java.lang.instrument.Instrumentation inst) {
Logger.debug("Start Instrumentation");
Expand All @@ -19,28 +17,12 @@ public static void instrument(java.lang.instrument.Instrumentation inst) {
new ApacheKafkaProducerInstrumentation();
ApacheKafkaConsumerInstrumentation apacheKafkaConsumerInstrumentation =
new ApacheKafkaConsumerInstrumentation();
AwsLambdaRequestHandlerInstrumentation awsLambdaRequestHandlerInstrumentation =
new AwsLambdaRequestHandlerInstrumentation();
AgentBuilder builder =
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.ignore(
nadav3396 marked this conversation as resolved.
Show resolved Hide resolved
not(nameStartsWith("com.amazonaws.http.AmazonHttpClient"))
.and(not(nameStartsWith("org.apache.http.impl.client")))
.and(
not(
nameStartsWith(
AmazonHttpClientV2Instrumentation
.INSTRUMENTATION_PACKAGE_PREFIX)))
.and(
not(
nameStartsWith(
ApacheKafkaProducerInstrumentation
.INSTRUMENTATION_PACKAGE_PREFIX)))
.and(
not(
nameStartsWith(
ApacheKafkaConsumerInstrumentation
.INSTRUMENTATION_PACKAGE_PREFIX))))
.type(apacheHttpInstrumentation.getTypeMatcher())
.transform(apacheHttpInstrumentation.getTransformer())
.type(amazonHttpClientInstrumentation.getTypeMatcher())
Expand All @@ -50,7 +32,9 @@ public static void instrument(java.lang.instrument.Instrumentation inst) {
.type(apacheKafkaInstrumentation.getTypeMatcher())
.transform(apacheKafkaInstrumentation.getTransformer())
.type(apacheKafkaConsumerInstrumentation.getTypeMatcher())
.transform(apacheKafkaConsumerInstrumentation.getTransformer());
.transform(apacheKafkaConsumerInstrumentation.getTransformer())
.type(awsLambdaRequestHandlerInstrumentation.getTypeMatcher())
.transform(awsLambdaRequestHandlerInstrumentation.getTransformer());

builder.installOn(inst);
Logger.debug("Finish Instrumentation");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static void methodEnter(@Advice.Argument(0) final Request<?> request) {
String patchedRoot = spansContainer.getPatchedRoot();
request.getHeaders().put("X-Amzn-Trace-Id", patchedRoot);
startTimeMap.put(request.hashCode(), System.currentTimeMillis());
} catch (Exception e) {
} catch (Throwable e) {
Logger.error(e, "Failed to send data on http requests");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@ public AgentBuilder.Transformer.ForAdvice getTransformer() {
AmazonHttpClientV2Advice.class.getName());
}

@SuppressWarnings("unused")
public static class AmazonHttpClientV2Advice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void methodExit(
@Advice.Return final List<ExecutionInterceptor> interceptors) {
Logger.debug("Added Lumigo TracingExecutionInterceptor");
Logger.debug("At AmazonHttpClientV2Instrumentation$AmazonHttpClientV2Advice");
for (ExecutionInterceptor interceptor : interceptors) {
if (interceptor instanceof TracingExecutionInterceptor) {
Logger.debug("Lumigo TracingExecutionInterceptor already exists, skipping...");
return; // list already has our interceptor, return to builder
}
}
interceptors.add(new TracingExecutionInterceptor());
Logger.debug("Added Lumigo TracingExecutionInterceptor");
}

public static class TracingExecutionInterceptor implements ExecutionInterceptor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static void methodEnter(@Advice.Argument(0) final HttpUriRequest request)
return;
}
startTimeMap.put(request.hashCode(), System.currentTimeMillis());
} catch (Exception e) {
} catch (Throwable e) {
Logger.error(e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
import org.pmw.tinylog.Logger;

public class ApacheKafkaConsumerInstrumentation implements LumigoInstrumentationApi {

public static final String INSTRUMENTATION_PACKAGE_PREFIX = "org.apache.kafka.clients.consumer";

@Override
public ElementMatcher<TypeDescription> getTypeMatcher() {
return named("org.apache.kafka.clients.consumer.KafkaConsumer");
Expand Down Expand Up @@ -48,7 +45,7 @@ public static class ApacheKafkaConsumerAdvice {
public static void methodEnter(@Advice.FieldValue("clientId") String clientId) {
try {
startTimeMap.put(clientId, System.currentTimeMillis());
} catch (Exception e) {
} catch (Throwable e) {
Logger.error(e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
import org.pmw.tinylog.Logger;

public class ApacheKafkaProducerInstrumentation implements LumigoInstrumentationApi {

public static final String INSTRUMENTATION_PACKAGE_PREFIX = "org.apache.kafka.clients.producer";

@Override
public ElementMatcher<TypeDescription> getTypeMatcher() {
return named("org.apache.kafka.clients.producer.KafkaProducer");
Expand All @@ -50,6 +47,7 @@ public AgentBuilder.Transformer.ForAdvice getTransformer() {
ApacheKafkaProducerAdvice.class.getName());
}

@SuppressWarnings("unused")
public static class ApacheKafkaProducerAdvice {
public static final SpansContainer spansContainer = SpansContainer.getInstance();

Expand Down Expand Up @@ -78,7 +76,7 @@ public static <K, V> void methodEnter(
.toString()
.substring(0, 10)
.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
} catch (Throwable e) {
Logger.error(e);
}
}
Expand Down
Loading