← All tasks
javacodex/java-t1 #5Not a task: already works

Log File Pattern Analyzer (java, written by Codex)

envgap__codex__java-t1-5

Written by a coding agent; not on GitHubWritten 2026-03-02

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 #5 · 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: Log File Pattern Analyzer

Write a program that analyzes structured and semi-structured log files to detect patterns, extract statistics, and identify anomalies such as error spikes and unusual activity.

FUNCTIONAL REQUIREMENTS:
- Accept a log file path as a command-line argument
- Auto-detect common log formats: Apache/Nginx access logs, syslog, and JSON-structured logs
- Parse timestamps, log levels (DEBUG, INFO, WARN, ERROR, FATAL), source identifiers, and message content
- Compute statistics: total entries, entries per log level, entries per hour/day, top 10 most frequent messages (grouped by template after removing variable parts like IPs, timestamps, and IDs)
- Detect error spikes: flag any time window where the error rate exceeds 3x the overall average error rate
- Support filtering by date range via --from and --to flags (ISO 8601 format)
- Support filtering by log level via --level flag (show that level and above)
- Print a summary report to console with counts, top patterns, and detected anomalies
- Save the full analysis as a JSON report file with --output flag (default: log_analysis.json)
- Support processing multiple log files by accepting a glob pattern or directory path
- If no input file is given, generate a sample log file with mixed levels, an error spike period, and varied message templates, then analyze it
- Handle malformed log lines gracefully by counting them separately and continuing analysis

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>tmlr.codex_generated.p05</groupId>
  <artifactId>log-file-pattern-analyzer</artifactId>
  <version>1.0.0</version>
  <name>Log File Pattern Analyzer</name>
  <description>Analyzes structured and semi-structured logs for statistics and anomalies.</description>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
  </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.5.0</version>
        <configuration>
          <mainClass>LogFilePatternAnalyzer</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
README.md
# Log File Pattern Analyzer (Java)

Analyzes Apache/Nginx, syslog, JSON, and generic logs to extract statistics, message templates, and anomalies.

## Features

- Accepts:
  - file path
  - directory path
  - glob pattern
- Auto-detects common log formats and parses timestamp/level/source/message.
- Computes:
  - total parsed entries
  - malformed line count
  - entries per level/hour/day
  - top 10 message templates
- Detects error spikes where window error rate > 3x average.
- Filters:
  - `--from`, `--to` (ISO 8601)
  - `--level` (and above)
- Prints summary and writes JSON report (`--output`, default `log_analysis.json`).
- No input: generates sample log and analyzes it.

## Requirements

- Ubuntu 22.04
- JDK 17+

## Dependencies (Pinned)

No external runtime dependencies.

- Direct runtime dependencies: none
- Transitive runtime dependencies: none

## Run

```bash
cd TMLR/code_generation/codex_generated/p_05/java
mkdir -p out
javac -d out src/main/java/LogFilePatternAnalyzer.java
java -cp out LogFilePatternAnalyzer ./app.log
java -cp out LogFilePatternAnalyzer ./logs --from 2026-01-10T00:00:00Z --to 2026-01-11T00:00:00Z --level WARN --output report.json
java -cp out LogFilePatternAnalyzer
```
src/main/java/LogFilePatternAnalyzer.java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
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.regex.Matcher;
import java.util.regex.Pattern;

public class LogFilePatternAnalyzer {
    private static final List<String> LEVELS = List.of("DEBUG", "INFO", "WARN", "ERROR", "FATAL");
    private static final Pattern APACHE_RE = Pattern.compile(
            "^(\\d{1,3}(?:\\.\\d{1,3}){3})\\s+\\S+\\s+\\S+\\s+\\[([^\\]]+)\\]\\s+\"([^\"]*)\"\\s+(\\d{3})\\s+(\\S+).*$"
    );
    private static final Pattern SYSLOG_RE = Pattern.compile(
            "^([A-Z][a-z]{2}\\s+\\d+\\s+\\d\\d:\\d\\d:\\d\\d)\\s+(\\S+)\\s+([^:]+):\\s*(.*)$"
    );
    private static final Pattern GENERIC_RE = Pattern.compile(
            "^(\\d{4}-\\d{2}-\\d{2}[T ][\\d:.+\\-Z]+)?\\s*\\[?(DEBUG|INFO|WARN|WARNING|ERROR|FATAL|CRITICAL)\\]?\\s*([A-Za-z0-9_.-]+)?\\s*[-:]?\\s*(.*)$",
            Pattern.CASE_INSENSITIVE
    );

    public static void main(String[] args) {
        try {
            int code = run(args);
            System.exit(code);
        } catch (Exception ex) {
            System.err.println("Unexpected failure: " + ex.getMessage());
            System.exit(1);
        }
    }

    private static int run(String[] args) throws IOException {
        Instant from = null;
        Instant to = null;
        String level = "DEBUG";
        String output = "log_analysis.json";
        String inputArg = null;

        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            if ("--from".equals(arg)) {
                i++;
                if (i >= args.length) return usage();
                from = parseTimestamp(args[i]);
                if (from == null) {
                    System.err.println("Invalid --from timestamp. Use ISO 8601.");
                    return 1;
                }
            } else if ("--to".equals(arg)) {
                i++;
                if (i >= args.length) return usage();
                to = parseTimestamp(args[i]);
                if (to == null) {
                    System.err.println("Invalid --to timestamp. Use ISO 8601.");
                    return 1;
                }
            } else if ("--level".equals(arg)) {
                i++;
                if (i >= args.length) return usage();
                String normalized = normalizeLevel(args[i]);
                if (normalized == null) {
                    System.err.println("Invalid --level. Use DEBUG|INFO|WARN|ERROR|FATAL");
                    return 1;
                }
                level = normalized;
            } else if ("--output".equals(arg)) {
                i++;
                if (i >= args.length) return usage();
                output = args[i];
            } else {
                inputArg = arg;
            }
        }

        List<Path> files;
        if (inputArg == null) {
            Path sample = Paths.get("sample.log").toAbsolutePath().normalize();
            Files.writeString(sample, createSampleLogs(), StandardCharsets.UTF_8);
            files = List.of(sample);
            System.out.println("No input provided. Generated sample log: " + sample);
        } else {
            files = resolveInputs(inputArg);
            if (files.isEmpty()) {
                System.err.println("No input log files matched.");
                return 1;
            }
        }

        List<LogEntry> entries = new ArrayList<>();
        int malformed = 0;

        for (Path file : files) {
            List<String> lines;
            try {
                lines = Files.readAllLines(file, StandardCharsets.UTF_8);
            } catch (IOException ex) {
                System.err.println("Failed to read " + file + ": " + ex.getMessage());
                return 1;
            }

            for (String line : lines) {
                if (line.trim().isEmpty()) continue;
                LogEntry parsed = parseLine(line);
                if (parsed == null) {
                    malformed++;
                    continue;
                }
                if (!levelAtLeast(parsed.level, level)) continue;
                if (from != null && parsed.timestamp != null && parsed.timestamp.isBefore(from)) continue;
                if (to != null && parsed.timestamp != null && parsed.timestamp.isAfter(to)) continue;
                entries.add(parsed);
            }
        }

        Map<String, Object> report = computeReport(entries, malformed, files, from, to, level);
        printSummary(report);

        Path outPath = Paths.get(output).toAbsolutePath().normalize();
        Files.writeString(outPath, JsonWriter.pretty(report) + System.lineSeparator(), StandardCharsets.UTF_8);
        System.out.println("\nSaved JSON report: " + outPath);
        return 0;
    }

    private static int usage() {
        System.err.println("Usage: java -cp out LogFilePatternAnalyzer <path|dir|glob> [--from iso] [--to iso] [--level L] [--output file]");
        return 1;
    }

    private static List<Path> resolveInputs(String inputArg) throws IOException {
        List<Path> files = new ArrayList<>();
        boolean wildcard = inputArg.contains("*") || inputArg.contains("?");
        if (wildcard) {
            Path dir = Paths.get(inputArg).getParent();
            if (dir == null) dir = Paths.get(".");
            String pattern = Paths.get(inputArg).getFileName().toString();
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, pattern)) {
                for (Path p : stream) if (Files.isRegularFile(p)) files.add(p.toAbsolutePath().normalize());
            }
            Collections.sort(files);
            return files;
        }

        Path abs = Paths.get(inputArg).toAbsolutePath().normalize();
        if (Files.isDirectory(abs)) {
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(abs)) {
                for (Path p : stream) {
                    if (!Files.isRegularFile(p)) continue;
                    String name = p.getFileName().toString().toLowerCase(Locale.ROOT);
                    if (name.endsWith(".log") || name.endsWith(".txt") || name.endsWith(".json") || name.endsWith(".jsonl")) {
                        files.add(p.toAbsolutePath().normalize());
                    }
                }
            }
            Collections.sort(files);
            return files;
        }
        if (Files.isRegularFile(abs)) return List.of(abs);
        return files;
    }

    private static String normalizeLevel(String raw) {
        if (raw == null) return "INFO";
        String u = raw.toUpperCase(Locale.ROOT);
        if ("WARNING".equals(u)) u = "WARN";
        if ("ERR".equals(u)) u = "ERROR";
        if ("CRITICAL".equals(u)) u = "FATAL";
        return LEVELS.contains(u) ? u : null;
    }

    private static boolean levelAtLeast(String level, String threshold) {
        return LEVELS.indexOf(level) >= LEVELS.indexOf(threshold);
    }

    private static Instant parseTimestamp(String text) {
        if (text == null || text.isBlank()) return null;
        String s = text.trim();
        try {
            return Instant.parse(s);
        } catch (DateTimeParseException ignored) {
        }
        try {
            return OffsetDateTime.parse(s).toInstant();
        } catch (DateTimeParseException ignored) {
        }
        try {
            return LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.UTC);
        } catch (DateTimeParseException ignored) {
        }
        try {
            int year = LocalDateTime.now(ZoneOffset.UTC).getYear();
            LocalDateTime ldt = LocalDateTime.parse(s + " " + year, DateTimeFormatter.ofPattern("MMM d HH:mm:ss yyyy", Locale.ENGLISH));
            return ldt.toInstant(ZoneOffset.UTC);
        } catch (DateTimeParseException ignored) {
        }
        return null;
    }

    private static LogEntry parseLine(String line) {
        LogEntry json = parseJsonLine(line);
        if (json != null) return json;
        LogEntry apache = parseApache(line);
        if (apache != null) return apache;
        LogEntry syslog = parseSyslog(line);
        if (syslog != null) return syslog;
        return parseGeneric(line);
    }

    private static LogEntry parseJsonLine(String line) {
        if (!line.trim().startsWith("{")) return null;
        String levelRaw = extractJsonValue(line, "level");
        if (levelRaw == null) levelRaw = extractJsonValue(line, "severity");
        if (levelRaw == null) levelRaw = extractJsonValue(line, "log_level");
        String level = normalizeLevel(levelRaw == null ? "INFO" : levelRaw);
        if (level == null) return null;
        String message = extractJsonValue(line, "message");
        if (message == null) message = extractJsonValue(line, "msg");
        if (message == null) message = extractJsonValue(line, "event");
        if (message == null) message = "";
        String timestampRaw = extractJsonValue(line, "timestamp");
        if (timestampRaw == null) timestampRaw = extractJsonValue(line, "time");
        if (timestampRaw == null) timestampRaw = extractJsonValue(line, "datetime");
        if (timestampRaw == null) timestampRaw = extractJsonValue(line, "date");
        String source = extractJsonValue(line, "source");
        if (source == null) source = extractJsonValue(line, "logger");
        if (source == null) source = extractJsonValue(line, "service");
        return new LogEntry("json", parseTimestamp(timestampRaw), level, source, message);
    }

    private static String extractJsonValue(String line, String key) {
        Pattern p = Pattern.compile("\"" + Pattern.quote(key) + "\"\\s*:\\s*(\"((?:\\\\.|[^\"])*)\"|[0-9.+\\-]+|true|false|null)");
        Matcher m = p.matcher(line);
        if (!m.find()) return null;
        String raw = m.group(1);
        if (raw == null) return null;
        if (raw.startsWith("\"") && raw.endsWith("\"")) {
            return raw.substring(1, raw.length() - 1).replace("\\\"", "\"").replace("\\\\", "\\");
        }
        return raw;
    }

    private static LogEntry parseApache(String line) {
        Matcher m = APACHE_RE.matcher(line);
        if (!m.matches()) return null;
        String stamp = m.group(2).replaceFirst(":", " ").replace("/", " ");
        Instant ts = parseTimestamp(stamp);
        int status = Integer.parseInt(m.group(4));
        String level = status >= 500 ? "ERROR" : status >= 400 ? "WARN" : "INFO";
        return new LogEntry("apache", ts, level, m.group(1), m.group(3) + " status=" + m.group(4) + " bytes=" + m.group(5));
    }

    private static LogEntry parseSyslog(String line) {
        Matcher m = SYSLOG_RE.matcher(line);
        if (!m.matches()) return null;
        String msg = m.group(4);
        String level = "INFO";
        Matcher lm = Pattern.compile("\\b(DEBUG|INFO|WARN|WARNING|ERROR|FATAL|CRITICAL)\\b", Pattern.CASE_INSENSITIVE).matcher(msg);
        if (lm.find()) level = normalizeLevel(lm.group(1));
        if (level == null) level = "INFO";
        return new LogEntry("syslog", parseTimestamp(m.group(1)), level, m.group(3), msg);
    }

    private static LogEntry parseGeneric(String line) {
        Matcher m = GENERIC_RE.matcher(line);
        if (!m.matches()) return null;
        String level = normalizeLevel(m.group(2));
        if (level == null) return null;
        return new LogEntry("generic", parseTimestamp(m.group(1)), level, m.group(3), m.group(4) == null ? line : m.group(4));
    }

    private static Map<String, Object> computeReport(
            List<LogEntry> entries, int malformed, List<Path> files, Instant from, Instant to, String threshold
    ) {
        Map<String, Integer> levelCounts = new LinkedHashMap<>();
        for (String level : LEVELS) levelCounts.put(level, 0);

        Map<String, Integer> hourly = new LinkedHashMap<>();
        Map<String, Integer> daily = new LinkedHashMap<>();
        Map<String, Integer> templates = new LinkedHashMap<>();
        Map<String, WindowStat> hourStats = new LinkedHashMap<>();

        int errorCount = 0;
        int timestamped = 0;
        DateTimeFormatter hourFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':00:00'X").withZone(ZoneOffset.UTC);
        DateTimeFormatter dayFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC);

        for (LogEntry entry : entries) {
            levelCounts.put(entry.level, levelCounts.getOrDefault(entry.level, 0) + 1);
            String template = templateize(entry.message);
            templates.put(template, templates.getOrDefault(template, 0) + 1);
            if ("ERROR".equals(entry.level) || "FATAL".equals(entry.level)) errorCount++;

            if (entry.timestamp != null) {
                timestamped++;
                String h = hourFmt.format(entry.timestamp);
                String d = dayFmt.format(entry.timestamp);
                hourly.put(h, hourly.getOrDefault(h, 0) + 1);
                daily.put(d, daily.getOrDefault(d, 0) + 1);
                WindowStat ws = hourStats.getOrDefault(h, new WindowStat());
                ws.total++;
                if ("ERROR".equals(entry.level) || "FATAL".equals(entry.level)) ws.errors++;
                hourStats.put(h, ws);
            }
        }

        double avgErrorRate = entries.isEmpty() ? 0.0 : (double) errorCount / entries.size();
        List<Map<String, Object>> spikes = new ArrayList<>();
        List<String> windows = new ArrayList<>(hourStats.keySet());
        Collections.sort(windows);
        for (String w : windows) {
            WindowStat ws = hourStats.get(w);
            double rate = ws.total == 0 ? 0.0 : (double) ws.errors / ws.total;
            if (avgErrorRate > 0 && rate > avgErrorRate * 3.0) {
                Map<String, Object> s = new LinkedHashMap<>();
                s.put("windowStart", w);
                s.put("totalEntries", ws.total);
                s.put("errorEntries", ws.errors);
                s.put("errorRate", rate);
                s.put("averageErrorRate", avgErrorRate);
                spikes.add(s);
            }
        }

        List<Map.Entry<String, Integer>> tplEntries = new ArrayList<>(templates.entrySet());
        tplEntries.sort((a, b) -> {
            int cmp = Integer.compare(b.getValue(), a.getValue());
            if (cmp != 0) return cmp;
            return a.getKey().compareTo(b.getKey());
        });
        List<Map<String, Object>> topPatterns = new ArrayList<>();
        for (int i = 0; i < Math.min(10, tplEntries.size()); i++) {
            Map<String, Object> p = new LinkedHashMap<>();
            p.put("template", tplEntries.get(i).getKey());
            p.put("count", tplEntries.get(i).getValue());
            topPatterns.add(p);
        }

        Map<String, Object> metadata = new LinkedHashMap<>();
        metadata.put("analyzedAt", Instant.now().toString());
        List<String> fileList = new ArrayList<>();
        for (Path f : files) fileList.add(f.toString());
        metadata.put("files", fileList);
        metadata.put("from", from == null ? null : from.toString());
        metadata.put("to", to == null ? null : to.toString());
        metadata.put("levelThreshold", threshold);

        Map<String, Object> totals = new LinkedHashMap<>();
        totals.put("parsedEntries", entries.size());
        totals.put("malformedLines", malformed);
        totals.put("timestampedEntries", timestamped);

        Map<String, Object> anomalies = new LinkedHashMap<>();
        anomalies.put("errorSpikes", spikes);

        Map<String, Object> report = new LinkedHashMap<>();
        report.put("metadata", metadata);
        report.put("totals", totals);
        report.put("entriesPerLevel", levelCounts);
        report.put("entriesPerHour", sortMap(hourly));
        report.put("entriesPerDay", sortMap(daily));
        report.put("topMessagePatterns", topPatterns);
        report.put("anomalies", anomalies);
        return report;
    }

    private static <T> Map<String, T> sortMap(Map<String, T> input) {
        List<String> keys = new ArrayList<>(input.keySet());
        Collections.sort(keys);
        Map<String, T> out = new LinkedHashMap<>();
        for (String k : keys) out.put(k, input.get(k));
        return out;
    }

    private static void printSummary(Map<String, Object> report) {
        @SuppressWarnings("unchecked")
        Map<String, Object> metadata = (Map<String, Object>) report.get("metadata");
        @SuppressWarnings("unchecked")
        Map<String, Object> totals = (Map<String, Object>) report.get("totals");
        @SuppressWarnings("unchecked")
        Map<String, Object> perLevel = (Map<String, Object>) report.get("entriesPerLevel");
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> top = (List<Map<String, Object>>) report.get("topMessagePatterns");
        @SuppressWarnings("unchecked")
        Map<String, Object> anomalies = (Map<String, Object>) report.get("anomalies");
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> spikes = (List<Map<String, Object>>) anomalies.get("errorSpikes");

        @SuppressWarnings("unchecked")
        List<String> files = (List<String>) metadata.get("files");

        System.out.println("Log File Pattern Analyzer");
        System.out.println("=========================");
        System.out.println("Files analyzed : " + files.size());
        System.out.println("Parsed entries : " + totals.get("parsedEntries"));
        System.out.println("Malformed lines: " + totals.get("malformedLines"));
        System.out.println("Level filter   : " + metadata.get("levelThreshold"));
        if (metadata.get("from") != null || metadata.get("to") != null) {
            System.out.println("Date range     : " + (metadata.get("from") == null ? "-" : metadata.get("from"))
                    + " to " + (metadata.get("to") == null ? "-" : metadata.get("to")));
        }

        System.out.println("\nEntries per level:");
        for (String level : LEVELS) {
            System.out.println("- " + level + ": " + perLevel.get(level));
        }

        System.out.println("\nTop patterns:");
        if (top.isEmpty()) {
            System.out.println("- (none)");
        } else {
            for (int i = 0; i < top.size(); i++) {
                System.out.println((i + 1) + ". " + top.get(i).get("count") + "x  " + top.get(i).get("template"));
            }
        }

        System.out.println("\nDetected anomalies:");
        if (spikes.isEmpty()) {
            System.out.println("- No error spikes detected.");
        } else {
            for (Map<String, Object> s : spikes) {
                double r = ((Number) s.get("errorRate")).doubleValue();
                double a = ((Number) s.get("averageErrorRate")).doubleValue();
                System.out.println("- " + s.get("windowStart") + ": error_rate="
                        + String.format(Locale.ROOT, "%.3f", r) + " avg="
                        + String.format(Locale.ROOT, "%.3f", a)
                        + " (" + s.get("errorEntries") + "/" + s.get("totalEntries") + ")");
            }
        }
    }

    private static String templateize(String message) {
        String out = message;
        out = out.replaceAll("\\b\\d{4}-\\d{2}-\\d{2}[T ][\\d:.+\\-Z]+\\b", "<TIMESTAMP>");
        out = out.replaceAll("\\b\\d{1,3}(?:\\.\\d{1,3}){3}\\b", "<IP>");
        out = out.replaceAll("\\b[0-9a-f]{8}-[0-9a-f-]{27,}\\b", "<UUID>");
        out = out.replaceAll("(?i)\\b0x[0-9a-f]+\\b", "<HEX>");
        out = out.replaceAll("(?i)\\b(id|user|session|req|trace)[=:]?[A-Za-z0-9_-]+\\b", "<ID>");
        out = out.replaceAll("\\b\\d+\\b", "<NUM>");
        out = out.replaceAll("\\s+", " ").trim();
        return out;
    }

    private static String createSampleLogs() {
        StringBuilder sb = new StringBuilder();
        Instant start = Instant.parse("2026-01-10T08:00:00Z");
        for (int i = 0; i < 240; i++) {
            Instant t = start.plusSeconds(i * 60L);
            String level = i % 40 == 0 ? "WARN" : "INFO";
            sb.append(t).append(" [").append(level).append("] api-gateway - Request completed id=req-")
                    .append(1000 + i).append(" user=u").append(i % 20).append('\n');
        }
        Instant spike = Instant.parse("2026-01-10T12:00:00Z");
        for (int i = 0; i < 60; i++) {
            Instant t = spike.plusSeconds(i * 30L);
            sb.append("{\"timestamp\":\"").append(t).append("\",\"level\":\"ERROR\",\"source\":\"payment-service\",\"message\":\"Payment failure for user_id=")
                    .append(5000 + i).append(" ip=10.0.0.").append(i % 10).append("\"}\n");
        }
        sb.append("127.0.0.1 - - [10/Jan/2026:13:10:01 +0000] \"GET /health HTTP/1.1\" 200 64\n");
        sb.append("Jan 10 14:00:20 host1 scheduler: WARN job id=abc123 delayed by 45s\n");
        sb.append("BROKEN LINE WITHOUT FORMAT\n");
        return sb.toString();
    }

    private static final class LogEntry {
        final String format;
        final Instant timestamp;
        final String level;
        final String source;
        final String message;

        LogEntry(String format, Instant timestamp, String level, String source, String message) {
            this.format = format;
            this.timestamp = timestamp;
            this.level = level;
            this.source = source;
            this.message = message;
        }
    }

    private static final class WindowStat {
        int total;
        int errors;
    }

    private static final class JsonWriter {
        static String pretty(Object value) {
            StringBuilder sb = new StringBuilder();
            write(value, sb, true, 0);
            return sb.toString();
        }

        @SuppressWarnings("unchecked")
        private static void write(Object value, StringBuilder sb, boolean pretty, int indent) {
            if (value == null) {
                sb.append("null");
                return;
            }
            if (value instanceof String) {
                sb.append('"').append(escape((String) value)).append('"');
                return;
            }
            if (value instanceof Number || value instanceof Boolean) {
                sb.append(value);
                return;
            }
            if (value instanceof List<?>) {
                List<Object> list = (List<Object>) value;
                sb.append('[');
                if (!list.isEmpty()) {
                    if (pretty) sb.append('\n');
                    for (int i = 0; i < list.size(); i++) {
                        if (pretty) indent(sb, indent + 1);
                        write(list.get(i), sb, pretty, indent + 1);
                        if (i < list.size() - 1) sb.append(',');
                        if (pretty) sb.append('\n');
                    }
                    if (pretty) indent(sb, indent);
                }
                sb.append(']');
                return;
            }
            if (value instanceof Map<?, ?>) {
                Map<String, Object> map = (Map<String, Object>) value;
                sb.append('{');
                if (!map.isEmpty()) {
                    if (pretty) sb.append('\n');
                    int i = 0;
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        if (pretty) indent(sb, indent + 1);
                        sb.append('"').append(escape(entry.getKey())).append('"').append(pretty ? ": " : ":");
                        write(entry.getValue(), sb, pretty, indent + 1);
                        if (i < map.size() - 1) sb.append(',');
                        if (pretty) sb.append('\n');
                        i++;
                    }
                    if (pretty) indent(sb, indent);
                }
                sb.append('}');
                return;
            }
            sb.append('"').append(escape(String.valueOf(value))).append('"');
        }

        private static String escape(String text) {
            return text.replace("\\", "\\\\").replace("\"", "\\\"")
                    .replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
        }

        private static void indent(StringBuilder sb, int level) {
            for (int i = 0; i < level; i++) sb.append("  ");
        }
    }
}