Created
April 5, 2024 16:36
-
-
Save carlosroman/7ae3681bcc2ecab4f32e8149a8b61ea1 to your computer and use it in GitHub Desktop.
Java Runtime Metrics with dd-trace-java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
version: "3.9" | |
services: | |
java-app: | |
build: . | |
environment: | |
DD_SERVICE: "java-app" | |
DD_AGENT_HOST: "agent" | |
DD_JMXFETCH_STATSD_HOST: "agent" | |
depends_on: | |
- agent | |
agent: | |
image: datadog/agent:latest-jmx | |
pid: host | |
env_file: | |
- .env | |
environment: | |
DD_DOGSTATSD_NON_LOCAL_TRAFFIC: "true" | |
DD_DOGSTATSD_STATS_ENABLE: "true" | |
DD_DOGSTATSD_SOCKET: "/opt/datadog-agent/run/dsd.socket" | |
DD_APM_ENABLED: "true" | |
DD_APM_NON_LOCAL_TRAFFIC: "true" | |
volumes: | |
- /proc/:/host/proc/:ro | |
- /sys/fs/cgroup:/host/sys/fs/cgroup:ro | |
- /var/lib/docker/containers:/var/lib/docker/containers:ro | |
- /var/run/docker.sock:/var/run/docker.sock | |
- dd-run:/opt/datadog-agent/run:rw | |
volumes: | |
dd-run: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# syntax=docker/dockerfile:1 | |
# Allows to cheange the JDK image used | |
ARG JRE_DOCKER_IMAGE=eclipse-temurin:11 | |
# Use the official JDK image as the base image | |
FROM ${JRE_DOCKER_IMAGE} | |
WORKDIR /app | |
ADD 'https://dtdg.co/latest-java-tracer' dd-java-agent.jar | |
COPY run.sh SimpleApp.java /app/ | |
EXPOSE 9010 | |
EXPOSE 8080 | |
ENTRYPOINT [ "/app/run.sh" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
set -f | |
[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx128M -Xms128M" | |
[ -n "$RMI_PORT" ] || RMI_PORT="9010" | |
[ -n "$HOST_NAME" ] || HOST_NAME=`awk 'END{print $1}' /etc/hosts` | |
echo "Using `java --version`" | |
echo "With JAVA_OPTS '${JAVA_OPTS}'" | |
# shellcheck disable=SC2086 | |
javac -d app SimpleApp.java | |
echo "Starting app with hostname set to ${HOST_NAME}" | |
echo "RMI port is set to ${RMI_PORT}" | |
java -javaagent:dd-java-agent.jar \ | |
-cp ./app \ | |
${JAVA_OPTS} \ | |
SimpleApp | |
# java -jar jmxterm-1.0.2-uber.jar -l service:jmx:rmi:///jndi/rmi://${HOST_NAME}:${RMI_PORT}"/jmxrmi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.lang.management.ManagementFactory; | |
import java.net.InetSocketAddress; | |
import java.util.concurrent.atomic.AtomicInteger; | |
import java.util.concurrent.TimeUnit; | |
import java.util.Hashtable; | |
import java.util.Random; | |
import javax.management.InstanceAlreadyExistsException; | |
import javax.management.MalformedObjectNameException; | |
import javax.management.MBeanRegistrationException; | |
import javax.management.MBeanServer; | |
import javax.management.NotCompliantMBeanException; | |
import javax.management.ObjectName; | |
import com.sun.net.httpserver.HttpExchange; | |
import com.sun.net.httpserver.HttpHandler; | |
import com.sun.net.httpserver.HttpServer; | |
class SimpleApp { | |
public interface SampleMBean { | |
Integer getShouldBe100(); | |
Double getShouldBe1000(); | |
Long getShouldBe1337(); | |
Float getShouldBe1_1(); | |
int getShouldBeCounter(); | |
int incrementAndGet(); | |
int getSpecialCounter(); | |
int incrementSpecialCounter(); | |
} | |
public static class Sample implements SampleMBean { | |
private final AtomicInteger counter = new AtomicInteger(0); | |
private final AtomicInteger specialCounter = new AtomicInteger(0); | |
private final Random random = new Random(); | |
@Override | |
public Integer getShouldBe100() { | |
return 100; | |
} | |
@Override | |
public Double getShouldBe1000() { | |
return 200.0; | |
} | |
@Override | |
public Long getShouldBe1337() { | |
return 1337L; | |
} | |
@Override | |
public Float getShouldBe1_1() { | |
return 1.1F; | |
} | |
@Override | |
public int getShouldBeCounter() { | |
try { | |
final int seconds = this.random.nextInt(15) + 20; | |
Thread.sleep(seconds * 1000); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
return this.counter.get(); | |
} | |
@Override | |
public int incrementAndGet() { | |
return this.counter.incrementAndGet(); | |
} | |
@Override | |
public int getSpecialCounter(){ | |
return this.specialCounter.get(); | |
} | |
@Override | |
public int incrementSpecialCounter(){ | |
return this.specialCounter.incrementAndGet(); | |
} | |
} | |
public static void main(String[] args) throws Exception{ | |
System.out.println("Starting sample app..."); | |
try { | |
final Hashtable<String, String> pairs = new Hashtable<>(); | |
pairs.put("name", "default"); | |
pairs.put("type", "simple"); | |
final SampleMBean sample = new Sample(); | |
final Thread daemonThread = getThread(pairs, sample); | |
daemonThread.start(); | |
final HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); | |
server.createContext("/test", new TestHandler(sample)); | |
server.createContext("/increment", new IncHandler(sample)); | |
server.setExecutor(null); | |
server.start(); | |
} catch (MalformedObjectNameException | InstanceAlreadyExistsException | | |
MBeanRegistrationException | NotCompliantMBeanException | IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private static class IncHandler implements HttpHandler { | |
private final SampleMBean sample; | |
public IncHandler(final SampleMBean sample) { | |
this.sample = sample; | |
} | |
@Override | |
public void handle(HttpExchange t) throws IOException { | |
this.sample.incrementSpecialCounter(); | |
final String response = "This is the current count of " + this.sample.getShouldBeCounter() + "\n"; | |
t.sendResponseHeaders(200, response.length()); | |
final OutputStream os = t.getResponseBody(); | |
os.write(response.getBytes()); | |
os.close(); | |
} | |
} | |
private static class TestHandler implements HttpHandler { | |
private final SampleMBean sample; | |
public TestHandler(final SampleMBean sample) { | |
this.sample = sample; | |
} | |
@Override | |
public void handle(HttpExchange t) throws IOException { | |
final String response = "This is the current count of " + this.sample.getShouldBeCounter() + "\n"; | |
t.sendResponseHeaders(200, response.length()); | |
final OutputStream os = t.getResponseBody(); | |
os.write(response.getBytes()); | |
os.close(); | |
} | |
} | |
private static Thread getThread(final Hashtable<String, String> pairs, final SampleMBean sample) | |
throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { | |
final ObjectName objectName = new ObjectName("dd.test.sample", pairs); | |
final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); | |
server.registerMBean(sample, objectName); | |
final Thread daemonThread = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
while (sample.incrementAndGet() > 0) { | |
try { | |
Thread.sleep(TimeUnit.SECONDS.toSeconds(5)); | |
} catch (InterruptedException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} | |
}); | |
daemonThread.setDaemon(true); | |
System.out.println("Daemon thread started"); | |
return daemonThread; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment