Skip to content

Instantly share code, notes, and snippets.

@carlosroman
Created April 5, 2024 16:36
Show Gist options
  • Save carlosroman/7ae3681bcc2ecab4f32e8149a8b61ea1 to your computer and use it in GitHub Desktop.
Save carlosroman/7ae3681bcc2ecab4f32e8149a8b61ea1 to your computer and use it in GitHub Desktop.
Java Runtime Metrics with dd-trace-java
---
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:
# 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" ]
#!/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
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