Network Latency Monitor (java, written by Codex)
envgap__codex__java-t1-29
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
None
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
codex/java-t1 #29 · read the task the agent was given
Codex wrote this java project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Network Latency Monitor Write a program that continuously monitors network latency to multiple hosts using ICMP-like probes or TCP connection timing, tracking statistics over time and alerting on anomalies. FUNCTIONAL REQUIREMENTS: - Accept one or more hostnames or IP addresses as command-line arguments - Send periodic probes to each host at a configurable interval via --interval flag (default: 5 seconds) - Measure round-trip time (RTT) for each probe using TCP connection timing to a specified port (--port flag, default 80) since raw ICMP requires root privileges - Track running statistics per host: min RTT, max RTT, average RTT, median RTT, standard deviation, jitter (difference between consecutive measurements), and packet loss percentage - Support configurable monitoring duration via --duration flag (e.g., --duration 60s, --duration 5m, --duration 1h) or run until interrupted with Ctrl+C - Detect latency anomalies: flag probes where RTT exceeds a configurable threshold via --alert flag (default: 3x the running average RTT) - Display a live-updating console dashboard showing: host, last RTT, average RTT, min/max, packet loss %, and alert status - Record all measurements with timestamps for historical analysis - Save the full monitoring data as a JSON report with --output flag (default: latency_report.json) including per-host statistics and all individual measurements - Export time-series data as CSV via --export flag for external analysis - Support reading a list of hosts from a file via --file flag (one host per line with optional label) - If no hosts are given, monitor a set of well-known public hosts (8.8.8.8, 1.1.1.1, example.com, google.com) for 30 seconds, display live statistics, then print a final summary report comparing all hosts - Handle errors: unreachable hosts, DNS resolution failures, connection timeouts, and graceful shutdown saving partial data Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tmlr.codegen</groupId>
<artifactId>network-latency-monitor</artifactId>
<version>1.0.0</version>
<name>Network Latency Monitor</name>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<mainClass>NetworkLatencyMonitor</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# Network Latency Monitor (Java) Continuously probes host latency via TCP connect timing and tracks RTT statistics, jitter, loss, and alerts. ## Requirements - Ubuntu 22.04 - JDK 17+ - Maven 3.8+ ## Dependencies - `com.google.code.gson:gson:2.11.0` (JSON report generation) ## Build ```bash mvn -q -DskipTests compile ``` ## Run ```bash mvn -q exec:java -Dexec.args="google.com 1.1.1.1 --interval 5 --port 80 --duration 60s" ``` Using host file and CSV export: ```bash mvn -q exec:java -Dexec.args="--file hosts.txt --interval 2 --duration 5m --output latency_report.json --export latency_series.csv" ``` Alert threshold: ```bash mvn -q exec:java -Dexec.args="google.com --alert 3x" mvn -q exec:java -Dexec.args="google.com --alert 200" ``` ## Host file format ```text 8.8.8.8 Google-DNS 1.1.1.1,Cloudflare example.com ``` ## Output - Live dashboard in terminal - JSON report (`--output`, default `latency_report.json`) - Optional CSV time-series export (`--export`)
src/main/java/NetworkLatencyMonitor.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public final class NetworkLatencyMonitor {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static volatile boolean STOP = false;
private NetworkLatencyMonitor() {}
private record HostTarget(String host, String label) {}
private record ProbeResult(boolean success, Double rttMs, String error) {}
private record AlertConfig(String mode, double value) {}
private static final class Measurement {
String timestamp;
boolean success;
Double rttMs;
String error;
boolean alert;
}
private static final class HostState {
final String host;
final String label;
int sent = 0;
int lost = 0;
Double lastRtt = null;
boolean lastAlert = false;
final List<Double> rtts = new ArrayList<>();
final List<Double> jitters = new ArrayList<>();
final List<Measurement> measurements = new ArrayList<>();
HostState(String host, String label) {
this.host = host;
this.label = label;
}
Map<String, Object> stats() {
Map<String, Object> out = new LinkedHashMap<>();
int n = rtts.size();
Double avg = n == 0 ? null : rtts.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
Double med = n == 0 ? null : median(rtts);
Double std = n == 0 ? null : stddev(rtts, avg == null ? 0.0 : avg);
Double jitter = jitters.isEmpty() ? null : jitters.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
out.put("sent", sent);
out.put("lost", lost);
out.put("success_count", n);
out.put("min_rtt_ms", n == 0 ? null : rtts.stream().min(Double::compare).orElse(null));
out.put("max_rtt_ms", n == 0 ? null : rtts.stream().max(Double::compare).orElse(null));
out.put("avg_rtt_ms", avg);
out.put("median_rtt_ms", med);
out.put("stddev_rtt_ms", std);
out.put("jitter_ms", jitter);
out.put("packet_loss_pct", sent == 0 ? 0.0 : (lost * 100.0) / sent);
out.put("last_rtt_ms", lastRtt);
return out;
}
}
private static final class Config {
double intervalSec = 5.0;
int port = 80;
Long durationMs = null;
AlertConfig alert = new AlertConfig("multiplier", 3.0);
String output = "latency_report.json";
String exportCsv = null;
String filePath = null;
int timeoutMs = 5000;
final List<HostTarget> hosts = new ArrayList<>();
}
public static void main(String[] args) {
try {
Runtime.getRuntime().addShutdownHook(new Thread(() -> STOP = true));
Config cfg = parseArgs(args);
if (cfg.filePath != null) cfg.hosts.addAll(parseHostFile(Path.of(cfg.filePath)));
if (cfg.hosts.isEmpty()) {
cfg.hosts.add(new HostTarget("8.8.8.8", "Google DNS"));
cfg.hosts.add(new HostTarget("1.1.1.1", "Cloudflare DNS"));
cfg.hosts.add(new HostTarget("example.com", "Example"));
cfg.hosts.add(new HostTarget("google.com", "Google"));
cfg.durationMs = 30_000L;
}
List<HostState> states = cfg.hosts.stream().map(h -> new HostState(h.host(), h.label())).toList();
long startedAt = System.currentTimeMillis();
long endAt = cfg.durationMs == null ? Long.MAX_VALUE : startedAt + cfg.durationMs;
ExecutorService pool = Executors.newFixedThreadPool(Math.max(1, Math.min(32, states.size())));
boolean interrupted = false;
while (!STOP && System.currentTimeMillis() < endAt) {
long tickStart = System.currentTimeMillis();
List<Future<ProbeResult>> futures = new ArrayList<>();
for (HostState st : states) {
futures.add(pool.submit(probeTask(st.host, cfg.port, cfg.timeoutMs)));
}
for (int i = 0; i < states.size(); i++) {
HostState st = states.get(i);
ProbeResult result;
try {
result = futures.get(i).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
interrupted = true;
STOP = true;
break;
} catch (ExecutionException e) {
result = new ProbeResult(false, null, "probe_exception:" + e.getCause().getMessage());
}
st.sent++;
Measurement m = new Measurement();
m.timestamp = Instant.now().toString();
m.success = result.success;
m.rttMs = result.rttMs;
m.error = result.error;
m.alert = false;
if (!result.success) {
st.lost++;
st.lastAlert = false;
st.measurements.add(m);
continue;
}
double rtt = result.rttMs;
boolean alert = shouldAlert(st, cfg.alert, rtt);
if (st.lastRtt != null) st.jitters.add(Math.abs(rtt - st.lastRtt));
st.lastRtt = rtt;
st.lastAlert = alert;
st.rtts.add(rtt);
m.alert = alert;
st.measurements.add(m);
}
renderDashboard(states, startedAt, endAt == Long.MAX_VALUE ? null : endAt);
long elapsed = System.currentTimeMillis() - tickStart;
long sleepMs = Math.max(0L, (long) (cfg.intervalSec * 1000.0) - elapsed);
Thread.sleep(sleepMs);
}
if (STOP) interrupted = true;
pool.shutdownNow();
long endedAt = System.currentTimeMillis();
renderDashboard(states, startedAt, endAt == Long.MAX_VALUE ? null : endAt);
printFinalSummary(states);
writeJsonReport(states, cfg, startedAt, endedAt, interrupted);
if (cfg.exportCsv != null) writeCsv(states, Path.of(cfg.exportCsv));
System.out.println("\nSaved JSON report: " + cfg.output);
if (cfg.exportCsv != null) System.out.println("Saved CSV export: " + cfg.exportCsv);
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
System.exit(1);
}
}
private static Config parseArgs(String[] args) throws IOException {
Config cfg = new Config();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (!arg.startsWith("--")) {
cfg.hosts.add(new HostTarget(arg, arg));
continue;
}
if (i + 1 >= args.length) throw new IllegalArgumentException("Missing value for " + arg);
String value = args[++i];
switch (arg) {
case "--interval" -> cfg.intervalSec = Double.parseDouble(value);
case "--port" -> cfg.port = Integer.parseInt(value);
case "--duration" -> cfg.durationMs = parseDurationMs(value);
case "--alert" -> cfg.alert = parseAlert(value);
case "--output" -> cfg.output = value;
case "--export" -> cfg.exportCsv = value;
case "--file" -> cfg.filePath = value;
case "--timeout" -> cfg.timeoutMs = Integer.parseInt(value);
default -> throw new IllegalArgumentException("Unknown option: " + arg);
}
}
if (cfg.intervalSec <= 0) throw new IllegalArgumentException("--interval must be > 0");
if (cfg.port < 1 || cfg.port > 65535) throw new IllegalArgumentException("--port must be 1..65535");
if (cfg.timeoutMs <= 0) throw new IllegalArgumentException("--timeout must be > 0");
return cfg;
}
private static long parseDurationMs(String s) {
String v = s.trim().toLowerCase(Locale.ROOT);
if (v.endsWith("ms")) return Long.parseLong(v.substring(0, v.length() - 2));
if (v.endsWith("s")) return Long.parseLong(v.substring(0, v.length() - 1)) * 1_000L;
if (v.endsWith("m")) return Long.parseLong(v.substring(0, v.length() - 1)) * 60_000L;
if (v.endsWith("h")) return Long.parseLong(v.substring(0, v.length() - 1)) * 3_600_000L;
throw new IllegalArgumentException("Invalid --duration value: " + s);
}
private static AlertConfig parseAlert(String s) {
String v = s.trim().toLowerCase(Locale.ROOT);
if (v.endsWith("x")) return new AlertConfig("multiplier", Double.parseDouble(v.substring(0, v.length() - 1)));
return new AlertConfig("absolute", Double.parseDouble(v));
}
private static List<HostTarget> parseHostFile(Path p) throws IOException {
List<HostTarget> out = new ArrayList<>();
for (String raw : Files.readAllLines(p, StandardCharsets.UTF_8)) {
String line = raw.trim();
if (line.isEmpty() || line.startsWith("#")) continue;
if (line.contains(",")) {
String[] parts = line.split(",", 2);
String host = parts[0].trim();
String label = parts[1].trim().isEmpty() ? host : parts[1].trim();
out.add(new HostTarget(host, label));
} else {
String[] parts = line.split("\\s+");
String host = parts[0];
String label = parts.length > 1 ? line.substring(host.length()).trim() : host;
out.add(new HostTarget(host, label));
}
}
return out;
}
private static Callable<ProbeResult> probeTask(String host, int port, int timeoutMs) {
return () -> {
long start = System.nanoTime();
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeoutMs);
double rttMs = (System.nanoTime() - start) / 1_000_000.0;
return new ProbeResult(true, rttMs, null);
} catch (IOException ex) {
return new ProbeResult(false, null, ex.getClass().getSimpleName() + ":" + ex.getMessage());
}
};
}
private static boolean shouldAlert(HostState st, AlertConfig alert, double rtt) {
if ("absolute".equals(alert.mode)) return rtt > alert.value;
if (st.rtts.isEmpty()) return false;
double avg = st.rtts.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
return rtt > avg * alert.value;
}
private static void renderDashboard(List<HostState> states, long startedAt, Long endAt) {
System.out.print("\033[2J\033[H");
System.out.println("Network Latency Monitor " + Instant.now());
if (endAt == null) {
long elapsed = (System.currentTimeMillis() - startedAt) / 1000;
System.out.println("Elapsed: " + elapsed + "s");
} else {
long rem = Math.max(0L, (endAt - System.currentTimeMillis()) / 1000);
System.out.println("Remaining: " + rem + "s");
}
System.out.println("--------------------------------------------------------------------------------------");
System.out.println("Host Last RTT Avg RTT Min/Max Loss % Alert");
System.out.println("--------------------------------------------------------------------------------------");
for (HostState st : states) {
Map<String, Object> s = st.stats();
String hostCol = (st.label + " (" + st.host + ")");
if (hostCol.length() > 25) hostCol = hostCol.substring(0, 22) + "...";
hostCol = String.format("%-25s", hostCol);
String minMax = String.format("%s/%s", fmtMs((Double) s.get("min_rtt_ms")), fmtMs((Double) s.get("max_rtt_ms")));
System.out.printf(
Locale.US,
"%s %-10s %-10s %-18s %6.2f%% %s%n",
hostCol,
fmtMs((Double) s.get("last_rtt_ms")),
fmtMs((Double) s.get("avg_rtt_ms")),
minMax,
(Double) s.get("packet_loss_pct"),
st.lastAlert ? "ALERT" : "OK"
);
}
System.out.println("--------------------------------------------------------------------------------------");
}
private static String fmtMs(Double v) {
return v == null ? "-" : String.format(Locale.US, "%.2fms", v);
}
private static void printFinalSummary(List<HostState> states) {
List<HostState> ranked = new ArrayList<>(states);
ranked.sort(Comparator.comparingDouble(st -> {
Double avg = (Double) st.stats().get("avg_rtt_ms");
return avg == null ? Double.POSITIVE_INFINITY : avg;
}));
System.out.println("\nFinal Summary (best average RTT first)");
System.out.println("--------------------------------------------------------------------------");
for (HostState st : ranked) {
Map<String, Object> s = st.stats();
System.out.printf(
Locale.US,
"%s (%s) avg=%s min=%s max=%s loss=%.2f%% jitter=%s%n",
st.label,
st.host,
fmtMs((Double) s.get("avg_rtt_ms")),
fmtMs((Double) s.get("min_rtt_ms")),
fmtMs((Double) s.get("max_rtt_ms")),
(Double) s.get("packet_loss_pct"),
fmtMs((Double) s.get("jitter_ms"))
);
}
}
private static void writeJsonReport(List<HostState> states, Config cfg, long startedAt, long endedAt, boolean interrupted)
throws IOException {
Map<String, Object> root = new LinkedHashMap<>();
root.put("generated_at", Instant.now().toString());
Map<String, Object> monitoring = new LinkedHashMap<>();
monitoring.put("started_at", Instant.ofEpochMilli(startedAt).toString());
monitoring.put("ended_at", Instant.ofEpochMilli(endedAt).toString());
monitoring.put("interrupted", interrupted);
monitoring.put("interval_sec", cfg.intervalSec);
monitoring.put("port", cfg.port);
monitoring.put("timeout_ms", cfg.timeoutMs);
monitoring.put("duration_ms", cfg.durationMs);
monitoring.put("alert", Map.of("mode", cfg.alert.mode, "value", cfg.alert.value));
root.put("monitoring", monitoring);
List<Map<String, Object>> hosts = new ArrayList<>();
for (HostState st : states) {
Map<String, Object> h = new LinkedHashMap<>();
h.put("host", st.host);
h.put("label", st.label);
h.put("stats", st.stats());
List<Map<String, Object>> ms = new ArrayList<>();
for (Measurement m : st.measurements) {
Map<String, Object> row = new LinkedHashMap<>();
row.put("timestamp", m.timestamp);
row.put("success", m.success);
row.put("rtt_ms", m.rttMs);
row.put("error", m.error);
row.put("alert", m.alert);
ms.add(row);
}
h.put("measurements", ms);
hosts.add(h);
}
root.put("hosts", hosts);
Files.writeString(Path.of(cfg.output), GSON.toJson(root), StandardCharsets.UTF_8);
}
private static void writeCsv(List<HostState> states, Path out) throws IOException {
try (BufferedWriter w = Files.newBufferedWriter(out, StandardCharsets.UTF_8)) {
w.write("timestamp,host,label,success,rtt_ms,error,alert\n");
for (HostState st : states) {
for (Measurement m : st.measurements) {
w.write(csv(m.timestamp) + "," + csv(st.host) + "," + csv(st.label) + "," + m.success + ","
+ (m.rttMs == null ? "" : String.format(Locale.US, "%.3f", m.rttMs)) + ","
+ csv(m.error == null ? "" : m.error) + "," + m.alert + "\n");
}
}
}
}
private static String csv(String s) {
String v = s.replace("\"", "\"\"");
return "\"" + v + "\"";
}
private static double median(List<Double> values) {
List<Double> sorted = new ArrayList<>(values);
Collections.sort(sorted);
int n = sorted.size();
if (n % 2 == 0) return (sorted.get(n / 2 - 1) + sorted.get(n / 2)) / 2.0;
return sorted.get(n / 2);
}
private static double stddev(List<Double> values, double mean) {
if (values.size() < 2) return 0.0;
double sumSq = 0.0;
for (double v : values) sumSq += (v - mean) * (v - mean);
return Math.sqrt(sumSq / values.size());
}
}