strace_log 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +59 -88
- data/bin/strace-stat +14 -2
- data/lib/strace_log.rb +132 -126
- metadata +3 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bf0ec0832d7b894a0b0bef334b4e7614313db881e9f2b1fc0e867943f2974d5a
|
4
|
+
data.tar.gz: 3f95e1df8f7d617df9783fbd9bd23de39ef4bbcd972c51de082bf81aae3390b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b01896fcb02a1ff979a5a4486450c81a935fd24759bfae2c47fc1d4e0509be344d7882805c88b7950c224c3ddf438aed7cb7fc6fb02c4ca29716f4a3098729b
|
7
|
+
data.tar.gz: 03272c4affd1a38c0a58ed141c6b0d88e4dc67139e0c4b6be162f800e2298b25c41b71553b02301bcb54dbc763f769c804ddaa0bbc372abdb13217248de818a5
|
data/README.md
CHANGED
@@ -25,104 +25,75 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
Run command with strace:
|
27
27
|
|
28
|
-
$ strace -
|
28
|
+
$ strace -T -o strace.log command
|
29
29
|
|
30
|
-
|
30
|
+
Output statistics of strace log by mount point to CSV file:
|
31
31
|
|
32
|
-
$ strace-stat strace.log
|
32
|
+
$ strace-stat -s -o strace.csv strace.log
|
33
|
+
|
34
|
+
Option for `strace-stat`:
|
35
|
+
|
36
|
+
Usage: strace-stat [options] [FILE]
|
37
|
+
FILE filename of strace log (default: stdin)
|
38
|
+
-o, --output OUTFILE output CSV filename
|
39
|
+
-s, --stat output statistics by mount point (default: statistics by each path)
|
40
|
+
-t, --table TABLEFILE filename of mounted file system table (default:/etc/mtab)
|
41
|
+
-c, --column TABLECOLUMN column number of mount point in mtab (default:2)
|
33
42
|
|
34
43
|
## Classes
|
35
44
|
|
36
45
|
* StraceLog::ParsedCall
|
37
|
-
* StraceLog::IOCounter
|
38
46
|
* StraceLog::Stat
|
39
47
|
|
40
48
|
## Example
|
41
49
|
|
42
|
-
$ strace -
|
43
|
-
|
44
|
-
$
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
dup2: 0.000213,
|
90
|
-
lseek: 0.000112,
|
91
|
-
clock_gettime: 0.000343,
|
92
|
-
write: 1.229899,
|
93
|
-
munmap: 0.000110,
|
94
|
-
}
|
95
|
-
|
96
|
-
/bin/dd:
|
97
|
-
ok={execve:1}
|
98
|
-
time={execve:0.000479}
|
99
|
-
|
100
|
-
/dev/zero:
|
101
|
-
ok={close:2, dup2:1, lseek:1, open:1, read:10000}
|
102
|
-
size={read:5120000}
|
103
|
-
time={close:0.000224, dup2:0.000112, lseek:0.000112, open:0.000119, read:1.176062}
|
104
|
-
|
105
|
-
/etc/ld.so.preload:
|
106
|
-
fail={access:1}
|
107
|
-
time={access:0.000157}
|
108
|
-
|
109
|
-
...
|
110
|
-
|
111
|
-
/usr/share/locale/locale.alias:
|
112
|
-
ok={close:1, fstat:1, open:1, read:2}
|
113
|
-
size={read:2512}
|
114
|
-
time={close:0.000202, fstat:0.000216, open:0.000124, read:0.000221}
|
115
|
-
|
116
|
-
stderr:
|
117
|
-
ok={close:1, write:3}
|
118
|
-
size={write:90}
|
119
|
-
time={close:0.000022, write:0.000243}
|
120
|
-
|
121
|
-
tmpfile:
|
122
|
-
ok={close:2, dup2:1, open:1, write:10000}
|
123
|
-
size={write:5120000}
|
124
|
-
time={close:0.005866, dup2:0.000101, open:0.000154, write:1.229656}
|
125
|
-
|
50
|
+
$ strace -T -o strace.log dd if=/dev/zero of=tmpfile count=10000
|
51
|
+
$ strace-stat -s -o strace.csv strace.log
|
52
|
+
$ cat strace.csv
|
53
|
+
path,syscall,calls,errors,time,size
|
54
|
+
*,execve,1,0,0.009673,
|
55
|
+
*,brk,4,0,0.000057,
|
56
|
+
*,mmap,10,0,0.000285,
|
57
|
+
*,access,1,1,0.000021,
|
58
|
+
*,open,39,32,0.001220,
|
59
|
+
*,stat,27,21,0.000470,
|
60
|
+
*,read,10003,0,0.123271,5123334
|
61
|
+
*,fstat,5,0,0.000147,
|
62
|
+
*,mprotect,4,0,0.000075,
|
63
|
+
*,close,10,0,0.000311,
|
64
|
+
*,arch_prctl,1,0,0.000012,
|
65
|
+
*,rt_sigaction,4,0,0.000050,
|
66
|
+
*,dup2,2,0,0.000037,
|
67
|
+
*,lseek,1,0,0.000006,
|
68
|
+
*,write,10003,0,0.246277,5120136
|
69
|
+
*,munmap,1,0,0.000049,
|
70
|
+
*,exit_group,1,0,0.000000,
|
71
|
+
/,execve,1,0,0.009673,
|
72
|
+
/,access,1,1,0.000021,
|
73
|
+
/,open,29,24,0.000885,
|
74
|
+
/,stat,19,14,0.000346,
|
75
|
+
/,read,3,0,0.000101,3334
|
76
|
+
/,fstat,5,0,0.000147,
|
77
|
+
/,mmap,5,0,0.000181,
|
78
|
+
/,close,5,0,0.000167,
|
79
|
+
/home,open,9,8,0.000251,
|
80
|
+
/home,stat,8,7,0.000124,
|
81
|
+
/home,dup2,1,0,0.000030,
|
82
|
+
/home,close,2,0,0.000054,
|
83
|
+
/home,write,10000,0,0.246116,5120000
|
84
|
+
/dev,open,1,0,0.000084,
|
85
|
+
/dev,dup2,1,0,0.000007,
|
86
|
+
/dev,close,2,0,0.000049,
|
87
|
+
/dev,lseek,1,0,0.000006,
|
88
|
+
/dev,read,10000,0,0.123170,5120000
|
89
|
+
stderr,write,3,0,0.000161,136
|
90
|
+
stderr,close,1,0,0.000041,
|
91
|
+
|
92
|
+
(path=* means total sum for each system call)
|
93
|
+
|
94
|
+
Same example using pipe:
|
95
|
+
|
96
|
+
$ strace -T -s 0 -o '|strace-stat -s -o strace.csv' dd if=/dev/zero of=tmpfile count=10000
|
126
97
|
|
127
98
|
## Contributing
|
128
99
|
|
data/bin/strace-stat
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "strace_log"
|
4
|
+
require 'optparse'
|
4
5
|
|
5
|
-
|
6
|
+
params = {}
|
7
|
+
outfile = nil
|
8
|
+
|
9
|
+
opt = OptionParser.new
|
10
|
+
opt.on('-o OUTFILE','--output','output CSV filename') {|v| outfile = v}
|
11
|
+
opt.on('-s','--stat','output statistics by mount point (default: statistics by each path)') {|v| params[:sum] = true}
|
12
|
+
opt.on('-t TABLEFILE','--table','filename of mounted file system table (default:/etc/mtab)') {|v| params[:table] = v}
|
13
|
+
opt.on('-c TABLECOLUMN','--column','column number of mount point in mtab (default:2)') {|v| params[:column] = v.to_i}
|
14
|
+
opt.banner += ' [STRACE_LOG_FILE]'
|
15
|
+
opt.parse!(ARGV)
|
16
|
+
|
17
|
+
stat = StraceLog::Stat.new(**params)
|
6
18
|
stat.parse(ARGF)
|
7
|
-
stat.
|
19
|
+
stat.write(outfile)
|
data/lib/strace_log.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require 'strscan'
|
2
|
+
require 'pathname'
|
3
|
+
require 'csv'
|
2
4
|
|
3
5
|
module StraceLog
|
4
6
|
|
5
|
-
VERSION = "0.1
|
7
|
+
VERSION = "0.2.1"
|
6
8
|
|
7
9
|
class ParsedCall
|
8
10
|
ESCAPES = [ /x[\da-f][\da-f]/i, /n/, /t/, /r/, /\\/, /"/, /\d+/]
|
9
11
|
|
10
12
|
def initialize(line)
|
13
|
+
@size = nil
|
11
14
|
if /^(?:(\d\d:\d\d:\d\d|\d+)(?:\.(\d+))? )?[+-]{3}.*[+-]{3}$/ =~ line
|
12
15
|
@mesg = line
|
13
16
|
else
|
@@ -17,13 +20,13 @@ module StraceLog
|
|
17
20
|
@usec = s[2]
|
18
21
|
@func = s[3]
|
19
22
|
@args = scan_items(s,/\s*\)\s*/)
|
20
|
-
s.scan(/\s*= ([^=<>\s]+)(?:\s+([^<>]+))?(?: <([\d.]+)>)?$/)
|
23
|
+
s.scan(/\s*= ([^=<>\s]+(?:<[^<>]*>)?)(?:\s+([^<>]+))?(?: <([\d.]+)>)?$/)
|
21
24
|
@ret = s[1]
|
22
25
|
@mesg = s[2]
|
23
26
|
@elap = s[3]
|
24
27
|
end
|
25
28
|
end
|
26
|
-
attr_reader :time, :usec, :func, :args, :ret , :mesg, :elap
|
29
|
+
attr_reader :time, :usec, :func, :args, :ret , :mesg, :elap, :size
|
27
30
|
|
28
31
|
def scan_items(s,close)
|
29
32
|
args = []
|
@@ -81,81 +84,77 @@ module StraceLog
|
|
81
84
|
def scan_other(s)
|
82
85
|
s.scan(/[^"\\,{}()\[\]]+/)
|
83
86
|
end
|
84
|
-
end
|
85
|
-
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@size = {}
|
93
|
-
@time = {}
|
94
|
-
@rename = []
|
88
|
+
def set_size
|
89
|
+
sz = @ret.to_i
|
90
|
+
if sz >= 0
|
91
|
+
@size = sz
|
92
|
+
end
|
95
93
|
end
|
96
|
-
|
94
|
+
end
|
97
95
|
|
98
|
-
def add(h,func,c)
|
99
|
-
h[func] = (h[func] || 0) + c
|
100
|
-
end
|
101
96
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
97
|
+
class Stat
|
98
|
+
|
99
|
+
class Counter
|
100
|
+
def initialize
|
101
|
+
@calls = 0
|
102
|
+
@errors = 0
|
103
|
+
@time = 0
|
104
|
+
@size = nil
|
107
105
|
end
|
108
|
-
|
109
|
-
end
|
106
|
+
attr_reader :calls, :errors, :size, :time
|
110
107
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
108
|
+
def count(call)
|
109
|
+
@calls += 1
|
110
|
+
@errors += 1 if call.ret == "-1"
|
111
|
+
@time += call.elap.to_f if call.elap
|
112
|
+
@size = (@size||0) + call.size if call.size
|
115
113
|
end
|
116
|
-
count(fc)
|
117
|
-
end
|
118
114
|
|
119
|
-
|
120
|
-
|
121
|
-
|
115
|
+
def to_a
|
116
|
+
[@calls,@errors,"%.6f"%@time,@size]
|
117
|
+
end
|
122
118
|
end
|
123
119
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
120
|
+
class CallCounter
|
121
|
+
def initialize(path)
|
122
|
+
@path = path
|
123
|
+
@rename = []
|
124
|
+
@counter = {}
|
129
125
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
keys = @size.keys.sort
|
136
|
-
Kernel.print " size={"+keys.map{|k| "#{k}:#{@size[k]}"}.join(", ")+"}\n"
|
126
|
+
attr_reader :path, :rename
|
127
|
+
|
128
|
+
def count(call)
|
129
|
+
c = (@counter[call.func] ||= Counter.new)
|
130
|
+
c.count(call)
|
137
131
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
132
|
+
|
133
|
+
def rename_as(newpath)
|
134
|
+
@rename << @path
|
135
|
+
@path = newpath
|
141
136
|
end
|
142
|
-
|
143
|
-
|
137
|
+
|
138
|
+
def each
|
139
|
+
@counter.keys.map do |func|
|
140
|
+
yield [@path,func,*@counter[func].to_a]
|
141
|
+
end
|
144
142
|
end
|
145
|
-
puts
|
146
143
|
end
|
147
|
-
end
|
148
144
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
def initialize
|
145
|
+
def initialize(sum:false,table:'/etc/mtab',column:2)
|
146
|
+
@sum = sum
|
153
147
|
@stat = {}
|
154
|
-
@
|
155
|
-
@
|
148
|
+
@total = CallCounter.new('*')
|
149
|
+
if @sum
|
150
|
+
a = open(table,'r').each_line.map do |line|
|
151
|
+
line.split(/\s+/)[column-1]
|
152
|
+
end.sort.reverse
|
153
|
+
@paths = Hash[ a.map{|x| [x, /^#{x.sub(/\/$/,'')}($|\/)/] } ]
|
154
|
+
end
|
156
155
|
end
|
157
156
|
|
158
|
-
attr_reader :stat, :
|
157
|
+
attr_reader :stat, :total
|
159
158
|
|
160
159
|
def parse(a)
|
161
160
|
@fd2path = ["stdin", "stdout", "stderr"]
|
@@ -164,101 +163,108 @@ module StraceLog
|
|
164
163
|
end
|
165
164
|
end
|
166
165
|
|
167
|
-
def
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
166
|
+
def get_fd(arg)
|
167
|
+
if /([-\d]+)(<.*>)?/ =~ arg
|
168
|
+
x = $1.to_i
|
169
|
+
return x
|
170
|
+
else
|
171
|
+
raise
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def stat_call(call)
|
176
|
+
path = nil
|
177
|
+
|
178
|
+
case call.func
|
172
179
|
|
173
|
-
|
180
|
+
when /^(execve|l?stat|(read|un)?link|getc?wd|access|mkdir|mknod|chmod|chown)$/
|
181
|
+
path = call.args[0]
|
174
182
|
|
175
|
-
when /^
|
176
|
-
path =
|
177
|
-
|
178
|
-
|
179
|
-
fd = pc.ret.to_i
|
183
|
+
when /^open$/
|
184
|
+
path = call.args[0]
|
185
|
+
if call.ret != "-1"
|
186
|
+
fd = call.ret.to_i
|
180
187
|
@fd2path[fd] = path
|
181
188
|
end
|
182
189
|
|
183
|
-
when /^
|
184
|
-
|
185
|
-
|
190
|
+
when /^connect$/
|
191
|
+
fd = get_fd(call.args[0])
|
192
|
+
@fd2path[fd] = path = "socket"
|
186
193
|
|
187
|
-
when /^
|
188
|
-
fd =
|
189
|
-
|
190
|
-
if
|
194
|
+
when /^close$/
|
195
|
+
fd = get_fd(call.args[0])
|
196
|
+
path = @fd2path[fd]
|
197
|
+
if call.ret != "-1"
|
191
198
|
@fd2path[fd] = nil
|
192
199
|
end
|
193
200
|
|
201
|
+
when /^(readv?|writev?)$/
|
202
|
+
call.set_size
|
203
|
+
fd = get_fd(call.args[0])
|
204
|
+
path = @fd2path[fd]
|
205
|
+
|
206
|
+
when /^(fstat|fchmod|[fl]chown|lseek|ioctl|fcntl|getdents|sendto|recvmsg)$/
|
207
|
+
fd = get_fd(call.args[0])
|
208
|
+
path = @fd2path[fd]
|
209
|
+
|
194
210
|
when /^rename$/
|
195
|
-
|
196
|
-
|
197
|
-
rename(pc)
|
211
|
+
rename(call)
|
212
|
+
path = call.args[1]
|
198
213
|
|
199
214
|
when /^dup[23]?$/
|
200
|
-
fd =
|
201
|
-
|
202
|
-
if
|
203
|
-
fd2 =
|
215
|
+
fd = get_fd(call.args[0])
|
216
|
+
path = @fd2path[fd]
|
217
|
+
if call.ret != "-1"
|
218
|
+
fd2 = call.ret.to_i
|
204
219
|
@fd2path[fd2] = @fd2path[fd]
|
205
220
|
end
|
206
221
|
|
207
222
|
when /^mmap$/
|
208
|
-
fd =
|
209
|
-
if fd >= 0
|
210
|
-
count_fd(fd,pc)
|
211
|
-
end
|
212
|
-
|
213
|
-
when /^connect$/
|
214
|
-
fd = pc.args[0].to_i
|
215
|
-
@fd2path[fd] = path = pc.args[1]
|
216
|
-
count_path(path,pc)
|
223
|
+
fd = get_fd(call.args[4])
|
224
|
+
path = @fd2path[fd] if fd >= 0
|
217
225
|
|
226
|
+
when NilClass
|
227
|
+
return
|
218
228
|
end
|
219
|
-
end
|
220
229
|
|
221
|
-
|
222
|
-
path = @fd2path[fd]
|
223
|
-
count_path(path,pc)
|
224
|
-
end
|
225
|
-
|
226
|
-
def count_path(path,pc)
|
227
|
-
io_counter(path).count(pc)
|
228
|
-
end
|
230
|
+
@total.count(call)
|
229
231
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
232
|
+
if path
|
233
|
+
if @sum
|
234
|
+
realpath = File.exist?(path) ? Pathname.new(path).realdirpath.to_s : path
|
235
|
+
@paths.each do |mp,re|
|
236
|
+
if re =~ realpath
|
237
|
+
(@stat[mp] ||= CallCounter.new(mp)).count(call)
|
238
|
+
return
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
(@stat[path] ||= CallCounter.new(path)).count(call)
|
243
|
+
end
|
236
244
|
end
|
237
245
|
|
238
|
-
def rename(
|
239
|
-
if
|
240
|
-
oldpath =
|
241
|
-
newpath =
|
242
|
-
ioc = @stat[newpath] = @stat[oldpath]
|
246
|
+
def rename(call)
|
247
|
+
if call.ret != "-1"
|
248
|
+
oldpath = call.args[0]
|
249
|
+
newpath = call.args[1]
|
250
|
+
ioc = @stat[newpath] = (@stat[oldpath] ||= CallCounter.new(oldpath))
|
243
251
|
ioc.rename_as(newpath)
|
244
252
|
@stat.delete(oldpath)
|
245
253
|
end
|
246
254
|
end
|
247
255
|
|
248
|
-
def
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
@spent.each do |m,t|
|
256
|
-
Kernel.printf " %s: %.6f,\n",m,t
|
256
|
+
def write(file=nil)
|
257
|
+
block = proc do |w|
|
258
|
+
w << ["path","syscall","calls","errors","time","size"]
|
259
|
+
@total.each{|item| w << item}
|
260
|
+
@stat.each do |path,cntr|
|
261
|
+
cntr.each{|item| w << item}
|
262
|
+
end
|
257
263
|
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
264
|
+
if file
|
265
|
+
CSV.open(file,'w',&block)
|
266
|
+
else
|
267
|
+
CSV.instance(&block)
|
262
268
|
end
|
263
269
|
end
|
264
270
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strace_log
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro TANAKA
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,10 +72,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '0'
|
74
74
|
requirements: []
|
75
|
-
|
76
|
-
rubygems_version: 2.4.5
|
75
|
+
rubygems_version: 3.0.1
|
77
76
|
signing_key:
|
78
77
|
specification_version: 4
|
79
78
|
summary: Parse strace log
|
80
79
|
test_files: []
|
81
|
-
has_rdoc:
|