A zero-code-change Java agent that intercepts file I/O and directory listing operations in any Java application and logs them to a file. Uses Byte Buddy bytecode instrumentation to inline advice directly into JDK classes at runtime.
| Class | Operations | Log Label |
|---|---|---|
java.io.FileInputStream |
Constructor (file reads) | READ |
java.io.FileOutputStream |
Constructor (file writes) | WRITE |
java.io.RandomAccessFile |
Constructor (read or read-write) | READ / READ_WRITE |
java.nio.file.Files |
list, walk, newDirectoryStream |
LIST_DIR |
java.nio.file.Files |
readAllBytes, readAllLines, readString, newInputStream, newBufferedReader |
NIO_READ |
java.nio.file.Files |
write, writeString, newOutputStream, newBufferedWriter |
NIO_WRITE |
java.nio.file.Files |
copy |
NIO_COPY |
java.nio.file.Files |
move |
NIO_MOVE |
java.nio.file.Files |
delete, deleteIfExists |
NIO_DELETE |
- Java 21+
- Maven 3.x
mvn clean packageThis produces the shaded uber-JAR at:
target/file-logger-javaagent-1.0.0.jar
Byte Buddy is relocated to com.filelogger.shaded.bytebuddy to avoid classloader conflicts with the target application.
Attach the agent to any Java application with the -javaagent JVM flag:
# With a JAR
java -javaagent:/path/to/file-logger-javaagent-1.0.0.jar -jar your-app.jar
# With a classpath
java -javaagent:/path/to/file-logger-javaagent-1.0.0.jar -cp your-classpath com.example.MainTo specify a custom log file path, pass it as the agent argument (separated by =):
java -javaagent:/path/to/file-logger-javaagent-1.0.0.jar=/var/log/my-app-files.txt -jar your-app.jarThe filename is automatically prefixed with the JVM process ID. For example:
- Default (no argument): log file becomes
/tmp/<PID>-files.txt - Custom path
/var/log/my-app-files.txt: becomes/var/log/<PID>-my-app-files.txt
This ensures multiple JVM instances do not overwrite each other's logs.
| Variable | Default | Description |
|---|---|---|
FILE_LOGGER_JAVAAGENT_ENABLED |
true |
Set to false to disable all logging. Any other value (or unset) keeps logging enabled. |
FILE_LOGGER_JAVAAGENT_COOLDOWN_MS |
5000 |
Deduplication window in milliseconds. Repeated identical operation + status + path entries within this window are suppressed. Set to 0 to log every access. |
FILE_LOGGER_JAVAAGENT_FILENAME |
(unset) | Override the log file path. Takes precedence over the agent argument. The PID prefix is still applied automatically. |
Priority for log file path resolution: FILE_LOGGER_JAVAAGENT_FILENAME env var > agent argument > default (/tmp/files.txt).
Example:
FILE_LOGGER_JAVAAGENT_ENABLED=true \
FILE_LOGGER_JAVAAGENT_COOLDOWN_MS=2000 \
FILE_LOGGER_JAVAAGENT_FILENAME=/var/log/app-files.txt \
java -javaagent:target/file-logger-javaagent-1.0.0.jar -jar your-app.jarEach line written to the log file:
[yyyy-MM-dd HH:mm:ss.SSS] [thread-name] OPERATION STATUS -- /absolute/path
On failure, the exception is appended:
[yyyy-MM-dd HH:mm:ss.SSS] [thread-name] OPERATION FAILED -- /absolute/path -- ExceptionClass: message
Example output:
[2026-03-16 10:30:45.123] [main] READ OK -- /tmp/demo/classic.txt
[2026-03-16 10:30:45.234] [main] WRITE OK -- /tmp/demo/classic.txt
[2026-03-16 10:30:45.345] [main] LIST_DIR OK -- /tmp/demo
[2026-03-16 10:30:45.456] [worker-1] NIO_WRITE OK -- /tmp/demo/thread-1.txt
[2026-03-16 10:30:45.567] [main] NIO_READ FAILED -- /tmp/no-such-file.txt -- java.nio.file.NoSuchFileException: /tmp/no-such-file.txt
The included setup.sh script builds the agent, compiles the demo app, and runs it:
# Default log location (/tmp/files.txt)
./setup.sh
# Custom log location
./setup.sh /tmp/my-custom-log.txtThe demo (demo/SampleApp.java) exercises all intercepted operations including multi-threaded writes and intentional failures.