Structured Log Processor (java, written by Claude Code)
envgap__claude-code__java-t2-50
Written by a coding agent; not on GitHubWritten 2026-02-28
01 / FAILURE SIGNATURE
As the study recorded it
No src directory - Java file in project root
Not scored yet.
- The failure reproduces in a clean container and the known fix makes the project run; it has not been scored yet.
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
claude-code/java-t2 #50 · read the task the agent was given
Claude Code wrote this java project from the task below. It does not run on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Structured Log Processor Write a program that parses, queries, transforms, and aggregates structured log data in JSON Lines format, supporting filtering, field extraction, statistical aggregation, and output formatting. FUNCTIONAL REQUIREMENTS: - Accept a log file path as a command-line argument (JSON Lines format: one JSON object per line) - Support filtering log entries via --where flag with field comparisons (e.g., --where "level==ERROR" or --where "response_time>500" or --where "status!=200") - Support multiple filters combined with AND logic; support OR logic via --or flag - Support field selection via --fields flag (comma-separated list of field names to include in output) - Support aggregation operations via --group-by and --aggregate flags: count, sum, avg, min, max, and percentile(N) grouped by a specified field (e.g., --group-by status --aggregate "count,avg:response_time") - Support time-based aggregation: group by time windows (--time-window flag: 1m, 5m, 1h, 1d) on a specified timestamp field (--time-field flag) - Support sorting via --sort flag (field name with optional :asc or :desc suffix) - Support limiting output via --limit flag and skipping via --offset flag - Support output in multiple formats via --format flag: json (default), csv, table (formatted console table), and jsonl (JSON Lines) - Compute and display summary statistics for numeric fields: count, min, max, mean, median, p95, p99 - Support extracting unique values of a field via --distinct flag - Print results to console by default - Save results to a file via --output flag - If no input file is given, generate a sample web server access log with 1000 entries containing fields (timestamp, method, path, status, response_time, user_agent, ip), then demonstrate: filtering ERROR entries, computing average response time grouped by HTTP method, finding the top 10 slowest requests, and computing hourly request counts - Handle errors: malformed JSON lines (skip with warning and count), missing fields in filter expressions, type mismatches in comparisons, and very large files 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.
LogProcessor.java
import com.google.gson.*;
import com.beust.jcommander.*;
import java.io.*;
import java.nio.file.*;
import java.time.*;
import java.time.format.*;
import java.util.*;
import java.util.stream.*;
/**
* Structured Log Processor (Trial 2)
* Parses/queries/aggregates JSON Lines logs with filtering, field selection,
* and time-based aggregation using Gson and JCommander.
*/
public class LogProcessor {
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private static final Gson compactGson = new Gson();
public static void main(String[] args) {
MainArgs mainArgs = new MainArgs();
QueryArgs queryArgs = new QueryArgs();
CountByArgs countByArgs = new CountByArgs();
StatsArgs statsArgs = new StatsArgs();
TimeSeriesArgs tsArgs = new TimeSeriesArgs();
TopArgs topArgs = new TopArgs();
JCommander commander = JCommander.newBuilder()
.addObject(mainArgs)
.addCommand("query", queryArgs)
.addCommand("count-by", countByArgs)
.addCommand("stats", statsArgs)
.addCommand("timeseries", tsArgs)
.addCommand("top", topArgs)
.build();
commander.setProgramName("logproc");
try {
commander.parse(args);
} catch (ParameterException e) {
System.err.println(e.getMessage());
commander.usage();
System.exit(1);
}
String cmd = commander.getParsedCommand();
if (cmd == null) {
commander.usage();
return;
}
try {
switch (cmd) {
case "query": executeQuery(queryArgs); break;
case "count-by": executeCountBy(countByArgs); break;
case "stats": executeStats(statsArgs); break;
case "timeseries": executeTimeSeries(tsArgs); break;
case "top": executeTop(topArgs); break;
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
}
static JsonElement getNestedField(JsonObject obj, String path) {
String[] parts = path.split("\\.");
JsonElement current = obj;
for (String part : parts) {
if (current == null || !current.isJsonObject()) return null;
JsonObject o = current.getAsJsonObject();
if (!o.has(part)) return null;
current = o.get(part);
}
return current;
}
static String elementToString(JsonElement el) {
if (el == null || el.isJsonNull()) return "<null>";
if (el.isJsonPrimitive()) return el.getAsString();
return el.toString();
}
static boolean matchesFilter(JsonObject record, String filterExpr) {
String[][] opDefs = {
{"!=", "ne"}, {">=", "gte"}, {"<=", "lte"},
{"==", "eq"}, {">", "gt"}, {"<", "lt"},
{"contains", "contains"}, {"startswith", "startswith"}, {"endswith", "endswith"}
};
for (String[] opDef : opDefs) {
String sym = opDef[0];
int idx = filterExpr.indexOf(sym);
if (idx > 0) {
String field = filterExpr.substring(0, idx).trim();
String value = filterExpr.substring(idx + sym.length()).trim();
JsonElement fieldEl = getNestedField(record, field);
if (fieldEl == null || fieldEl.isJsonNull()) return false;
String fieldStr = elementToString(fieldEl);
switch (opDef[1]) {
case "eq": return fieldStr.equals(value);
case "ne": return !fieldStr.equals(value);
case "contains": return fieldStr.toLowerCase().contains(value.toLowerCase());
case "startswith": return fieldStr.startsWith(value);
case "endswith": return fieldStr.endsWith(value);
case "gt": case "gte": case "lt": case "lte":
try {
double a = Double.parseDouble(fieldStr);
double b = Double.parseDouble(value);
switch (opDef[1]) {
case "gt": return a > b;
case "gte": return a >= b;
case "lt": return a < b;
case "lte": return a <= b;
}
} catch (NumberFormatException e) {
int cmp = fieldStr.compareTo(value);
switch (opDef[1]) {
case "gt": return cmp > 0;
case "gte": return cmp >= 0;
case "lt": return cmp < 0;
case "lte": return cmp <= 0;
}
}
}
break;
}
}
return true;
}
static List<JsonObject> readAndFilter(String logfile, List<String> filters) throws IOException {
List<JsonObject> results = new ArrayList<>();
JsonParser parser = new JsonParser();
try (BufferedReader reader = Files.newBufferedReader(Path.of(logfile))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.isEmpty()) continue;
try {
JsonObject obj = parser.parse(line).getAsJsonObject();
boolean passes = filters.stream().allMatch(f -> matchesFilter(obj, f));
if (passes) results.add(obj);
} catch (JsonSyntaxException ignored) {}
}
}
return results;
}
static JsonObject projectFields(JsonObject record, List<String> fields) {
JsonObject result = new JsonObject();
for (String field : fields) {
JsonElement val = getNestedField(record, field);
if (val != null) result.add(field, val);
}
return result;
}
static void executeQuery(QueryArgs args) throws IOException {
List<JsonObject> records = readAndFilter(args.logfile, args.filters);
List<String> fieldList = args.fields != null ?
Arrays.stream(args.fields.split(",")).map(String::trim).collect(Collectors.toList()) : null;
int count = 0;
for (JsonObject rec : records) {
if (args.limit > 0 && count >= args.limit) break;
JsonObject output = (fieldList != null) ? projectFields(rec, fieldList) : rec;
System.out.println(args.pretty ? gson.toJson(output) : compactGson.toJson(output));
count++;
}
System.err.printf("%n--- %d/%d records matched ---%n", count, records.size());
}
static void executeCountBy(CountByArgs args) throws IOException {
List<JsonObject> records = readAndFilter(args.logfile, args.filters);
Map<String, Long> counts = new LinkedHashMap<>();
for (JsonObject rec : records) {
JsonElement val = getNestedField(rec, args.field);
String key = elementToString(val);
counts.merge(key, 1L, Long::sum);
}
counts.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(e -> System.out.printf("%s: %d%n", e.getKey(), e.getValue()));
}
static void executeStats(StatsArgs args) throws IOException {
List<JsonObject> records = readAndFilter(args.logfile, args.filters);
DoubleSummaryStatistics stats = records.stream()
.map(r -> getNestedField(r, args.field))
.filter(Objects::nonNull)
.filter(e -> e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber())
.mapToDouble(JsonElement::getAsDouble)
.summaryStatistics();
System.out.printf("count: %d%nmin: %.4f%nmax: %.4f%navg: %.4f%nsum: %.4f%n",
stats.getCount(), stats.getMin(), stats.getMax(), stats.getAverage(), stats.getSum());
}
static void executeTimeSeries(TimeSeriesArgs args) throws IOException {
List<JsonObject> records = readAndFilter(args.logfile, args.filters);
Map<String, Long> buckets = new TreeMap<>();
for (JsonObject rec : records) {
JsonElement val = getNestedField(rec, args.timeField);
if (val == null) continue;
String timeStr = elementToString(val);
LocalDateTime dt = parseDateTime(timeStr);
if (dt == null) continue;
String bucket = formatBucket(dt, args.interval);
buckets.merge(bucket, 1L, Long::sum);
}
buckets.forEach((k, v) -> System.out.printf("%s: %d%n", k, v));
}
static void executeTop(TopArgs args) throws IOException {
List<JsonObject> records = readAndFilter(args.logfile, new ArrayList<>());
Map<String, Long> counts = new LinkedHashMap<>();
for (JsonObject rec : records) {
JsonElement val = getNestedField(rec, args.field);
if (val != null && !val.isJsonNull()) {
counts.merge(elementToString(val), 1L, Long::sum);
}
}
counts.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(args.top)
.forEach(e -> System.out.printf("%s: %d%n", e.getKey(), e.getValue()));
}
static LocalDateTime parseDateTime(String s) {
DateTimeFormatter[] fmts = {
DateTimeFormatter.ISO_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
};
for (DateTimeFormatter fmt : fmts) {
try { return LocalDateTime.parse(s, fmt); } catch (Exception ignored) {}
}
try {
return Instant.parse(s).atZone(ZoneId.systemDefault()).toLocalDateTime();
} catch (Exception ignored) {}
return null;
}
static String formatBucket(LocalDateTime dt, String interval) {
switch (interval) {
case "minute": return dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
case "day": return dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
case "month": return dt.format(DateTimeFormatter.ofPattern("yyyy-MM"));
default: return dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00"));
}
}
@Parameters static class MainArgs {}
@Parameters(commandDescription = "Query log records with filtering and field selection")
static class QueryArgs {
@Parameter(description = "logfile") List<String> main = new ArrayList<>();
@Parameter(names = {"-f", "--filter"}, description = "Filter expressions") List<String> filters = new ArrayList<>();
@Parameter(names = {"-s", "--fields"}, description = "Comma-separated field list") String fields;
@Parameter(names = {"-l", "--limit"}, description = "Max records") int limit = 0;
@Parameter(names = {"--pretty"}, description = "Pretty-print") boolean pretty = false;
String getLogfile() { return main.isEmpty() ? null : main.get(0); }
String logfile;
@Parameter(names = "--logfile", hidden = true) void setLogfile(String lf) { this.logfile = lf; }
}
@Parameters(commandDescription = "Count records grouped by a field")
static class CountByArgs {
@Parameter(description = "logfile field") List<String> main = new ArrayList<>();
@Parameter(names = {"-f", "--filter"}) List<String> filters = new ArrayList<>();
String getLogfile() { return main.size() > 0 ? main.get(0) : null; }
String logfile; String field;
}
@Parameters(commandDescription = "Compute numeric statistics for a field")
static class StatsArgs {
@Parameter(description = "logfile field") List<String> main = new ArrayList<>();
@Parameter(names = {"-f", "--filter"}) List<String> filters = new ArrayList<>();
String logfile; String field;
}
@Parameters(commandDescription = "Aggregate records by time intervals")
static class TimeSeriesArgs {
@Parameter(description = "logfile time_field") List<String> main = new ArrayList<>();
@Parameter(names = {"-f", "--filter"}) List<String> filters = new ArrayList<>();
@Parameter(names = {"-i", "--interval"}) String interval = "hour";
String logfile; String timeField;
}
@Parameters(commandDescription = "Show top N most frequent values")
static class TopArgs {
@Parameter(description = "logfile field") List<String> main = new ArrayList<>();
@Parameter(names = {"-n", "--top"}) int top = 10;
String logfile; String field;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.logprocessor</groupId>
<artifactId>structured-log-processor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Structured Log Processor</name>
<description>Parses/queries/aggregates JSON Lines logs using Gson and JCommander</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.82</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>LogProcessor</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# Structured Log Processor (Java - Trial 2)
## Description
Parses, queries, and aggregates JSON Lines log files with support for filtering,
field selection, and time-based aggregation. Built with Gson for JSON parsing
and JCommander for CLI argument handling.
## Dependencies
- **gson**: Google's JSON library for Java serialization/deserialization
- **jcommander**: Annotation-based CLI parameter parsing framework
## Usage
### Build
```bash
mvn clean package
```
### Query logs with filters
```bash
java -jar target/structured-log-processor-1.0-SNAPSHOT.jar query access.jsonl -f "level==ERROR" -s "timestamp,message" --pretty
```
### Count by field
```bash
java -jar target/structured-log-processor-1.0-SNAPSHOT.jar count-by access.jsonl level
```
### Numeric statistics
```bash
java -jar target/structured-log-processor-1.0-SNAPSHOT.jar stats access.jsonl response_time
```
### Time series aggregation
```bash
java -jar target/structured-log-processor-1.0-SNAPSHOT.jar timeseries access.jsonl timestamp -i hour
```
## Input Format
Expects JSON Lines format (one JSON object per line):
```json
{"timestamp": "2024-01-15T10:30:00Z", "level": "INFO", "message": "Request processed", "response_time": 42}
```