Class: Hiiro::PsProcess

Inherits:
Object
  • Object
show all
Defined in:
lib/hiiro/ps_process.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user:, pid:, cpu:, mem:, vsz:, rss:, tty:, stat:, start:, time:, cmd:) ⇒ PsProcess

Returns a new instance of PsProcess.



7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/hiiro/ps_process.rb', line 7

def initialize(user:, pid:, cpu:, mem:, vsz:, rss:, tty:, stat:, start:, time:, cmd:)
  @user = user
  @pid = pid
  @cpu = cpu
  @mem = mem
  @vsz = vsz
  @rss = rss
  @tty = tty
  @stat = stat
  @start = start
  @time = time
  @cmd = cmd
end

Instance Attribute Details

#cmdObject (readonly)

Returns the value of attribute cmd.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def cmd
  @cmd
end

#cpuObject (readonly)

Returns the value of attribute cpu.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def cpu
  @cpu
end

#memObject (readonly)

Returns the value of attribute mem.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def mem
  @mem
end

#pidObject (readonly)

Returns the value of attribute pid.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def pid
  @pid
end

#rssObject (readonly)

Returns the value of attribute rss.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def rss
  @rss
end

#startObject (readonly)

Returns the value of attribute start.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def start
  @start
end

#statObject (readonly)

Returns the value of attribute stat.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def stat
  @stat
end

#timeObject (readonly)

Returns the value of attribute time.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def time
  @time
end

#ttyObject (readonly)

Returns the value of attribute tty.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def tty
  @tty
end

#userObject (readonly)

Returns the value of attribute user.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def user
  @user
end

#vszObject (readonly)

Returns the value of attribute vsz.



5
6
7
# File 'lib/hiiro/ps_process.rb', line 5

def vsz
  @vsz
end

Class Method Details

.allObject

Get all processes



43
44
45
# File 'lib/hiiro/ps_process.rb', line 43

def self.all
  `ps awwux`.lines[1..].filter_map { |line| from_line(line) }
end

.by_port(*ports) ⇒ Object

Find processes listening on given port numbers



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/hiiro/ps_process.rb', line 58

def self.by_port(*ports)
  pids = Set.new
  ports.each do |port|
    lsof_output = `lsof -i :#{port.to_i} 2>/dev/null`.lines[1..]
    next unless lsof_output

    lsof_output.each do |line|
      fields = line.split
      pids << fields[1] if fields[1]
    end
  end

  all.select { |p| pids.include?(p.pid) }
end

.find(pid) ⇒ Object

Find process by PID



53
54
55
# File 'lib/hiiro/ps_process.rb', line 53

def self.find(pid)
  all.find { |p| p.pid == pid.to_s }
end

.from_line(line) ⇒ Object

Parse a line from ‘ps awwux` output Format: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND…



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/hiiro/ps_process.rb', line 23

def self.from_line(line)
  parts = line.split
  return nil if parts.size < 11

  new(
    user: parts[0],
    pid: parts[1],
    cpu: parts[2],
    mem: parts[3],
    vsz: parts[4],
    rss: parts[5],
    tty: parts[6],
    stat: parts[7],
    start: parts[8],
    time: parts[9],
    cmd: parts[10..].join(' ')
  )
end

.in_dirs(*paths) ⇒ Object

Find processes with files open in given directories



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/hiiro/ps_process.rb', line 74

def self.in_dirs(*paths)
  pids = Set.new
  paths.each do |path|
    expanded = File.expand_path(path)
    lsof_output = `lsof +D #{expanded.shellescape} 2>/dev/null`.lines[1..]
    next unless lsof_output

    lsof_output.each do |line|
      fields = line.split
      pids << fields[1] if fields[1]
    end
  end

  all.select { |p| pids.include?(p.pid) }
end

.search(pattern) ⇒ Object

Search processes by pattern (matches against full line)



48
49
50
# File 'lib/hiiro/ps_process.rb', line 48

def self.search(pattern)
  all.select { |p| p.cmd.include?(pattern) || p.user.include?(pattern) }
end

Instance Method Details

#childrenObject

Child processes



123
124
125
126
# File 'lib/hiiro/ps_process.rb', line 123

def children
  child_pids = `pgrep -P #{pid}`.lines.map(&:strip)
  child_pids.filter_map { |cpid| self.class.find(cpid) }
end

#dirObject

Current working directory



109
110
111
112
113
# File 'lib/hiiro/ps_process.rb', line 109

def dir
  cwd_line = `lsof -p #{pid} 2>/dev/null | grep ' cwd '`.strip
  return nil if cwd_line.empty?
  cwd_line.split.last
end

#filesObject

Open files for this process



91
92
93
94
95
96
97
# File 'lib/hiiro/ps_process.rb', line 91

def files
  lines = `lsof -p #{pid} 2>/dev/null`.lines[1..] || []
  lines.filter_map do |line|
    parts = line.split
    { fd: parts[3], type: parts[4], name: parts[8] } if parts.size >= 9
  end
end

#inspectObject

Detailed display



134
135
136
# File 'lib/hiiro/ps_process.rb', line 134

def inspect
  "#<PsProcess pid=#{pid} user=#{user} stat=#{stat} cmd=#{cmd.slice(0, 40)}...>"
end

#parentObject

Parent process



116
117
118
119
120
# File 'lib/hiiro/ps_process.rb', line 116

def parent
  ppid = `ps -o ppid= -p #{pid}`.strip
  return nil if ppid.empty?
  self.class.find(ppid)
end

#portsObject

Open network ports for this process



100
101
102
103
104
105
106
# File 'lib/hiiro/ps_process.rb', line 100

def ports
  lines = `lsof -a -p #{pid} -i 2>/dev/null`.lines[1..] || []
  lines.filter_map do |line|
    parts = line.split
    { protocol: parts[7], name: parts[8] } if parts.size >= 9
  end
end

#to_sObject

Simple display: PID and CMD



129
130
131
# File 'lib/hiiro/ps_process.rb', line 129

def to_s
  "#{pid}\t#{cmd}"
end