-
Notifications
You must be signed in to change notification settings - Fork 4k
tools/filetop: Add directory filter #5300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,13 +18,16 @@ | |
from bcc import BPF | ||
from time import sleep, strftime | ||
import argparse | ||
import os | ||
import stat | ||
from subprocess import call | ||
|
||
# arguments | ||
examples = """examples: | ||
./filetop # file I/O top, 1 second refresh | ||
./filetop -C # don't clear the screen | ||
./filetop -p 181 # PID 181 only | ||
./filetop -d /home/user # trace files in /home/user directory only | ||
./filetop 5 # 5 second summaries | ||
./filetop 5 10 # 5 second summaries, 10 times only | ||
./filetop 5 --read-only # 5 second summaries, only read operations traced | ||
|
@@ -55,6 +58,9 @@ | |
help="number of outputs") | ||
parser.add_argument("--ebpf", action="store_true", | ||
help=argparse.SUPPRESS) | ||
parser.add_argument("-d", "--directory", type=str, | ||
help="trace this directory only") | ||
|
||
args = parser.parse_args() | ||
interval = int(args.interval) | ||
countdown = int(args.count) | ||
|
@@ -109,6 +115,10 @@ | |
if (d_name.len == 0 || TYPE_FILTER) | ||
return 0; | ||
|
||
// skip if not in the specified directory | ||
if (DIRECTORY_FILTER) | ||
return 0; | ||
|
||
// store counts and sizes by pid & file | ||
struct info_t info = { | ||
.pid = pid, | ||
|
@@ -163,6 +173,16 @@ | |
bpf_text = bpf_text.replace('TYPE_FILTER', '0') | ||
else: | ||
bpf_text = bpf_text.replace('TYPE_FILTER', '!S_ISREG(mode)') | ||
if args.directory: | ||
try: | ||
directory_inode = os.lstat(args.directory)[stat.ST_INO] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the target directory is a symbolic link, the directory_inode might differ from the target's inode. Does this behave as intended? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi, I used os.lstat, which doesn't follow symlinks, so currently if a symlink is provided as an argument, it doesn't report any activity. Switching to os.stat should fix this by properly following the symlink to its target. I'll update the PR accordingly. |
||
print(f'Tracing directory: {args.directory} (Inode: {directory_inode})') | ||
bpf_text = bpf_text.replace('DIRECTORY_FILTER', 'file->f_path.dentry->d_parent->d_inode->i_ino != %d' % directory_inode) | ||
except (FileNotFoundError, PermissionError) as e: | ||
print(f'Error accessing directory {args.directory}: {e}') | ||
exit(1) | ||
else: | ||
bpf_text = bpf_text.replace('DIRECTORY_FILTER', '0') | ||
|
||
if debug or args.ebpf: | ||
print(bpf_text) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current functionality is good, but adding support for including subdirectories would make it even more powerful.
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that makes sense. I'll work on adding support for subdirectories.
Thanks for the input.