strace_log 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 591335f397f9c5892b35533fef68ae0ee892ee44
4
+ data.tar.gz: 4a7aee2c5f1277020cac75899c13dc33e5ed087c
5
+ SHA512:
6
+ metadata.gz: 70cb159cdc830926381dad06fa186c03fa50640e18dd492b1d60447715d493561029e872f2b1dbed62fb3469f20f6ffdc72c7726a61af2a9daa31f029993bd44
7
+ data.tar.gz: 2296435aa1b62347d13fbad77d71d0071aebd28f23d026025194f6cbea2519fbccd7d3eae6da29c0f6262491e88cc902bf025ae8a3c78a173d57b10ab4316f97
data/.gitignore ADDED
@@ -0,0 +1,28 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .config
19
+ *~
20
+ */*~
21
+ */*/*~
22
+ *.bak
23
+ */*.bak
24
+ */*/*.bak
25
+ .#*
26
+ */.#*
27
+ */*/.#*
28
+ rhosts
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in strace_log.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # StraceLog
2
+
3
+ Parse logs generated by Strace (system call tracer) and obtain statistics.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'strace_log'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install strace_log
20
+
21
+ ## Usage
22
+
23
+ Run command with strace:
24
+
25
+ $ strace -ttt -T -o strace.log command
26
+
27
+ Print statistics of strace log:
28
+
29
+ $ strace-stat strace.log
30
+
31
+ ## Classes
32
+
33
+ * StraceLog::ParsedCall
34
+ * StraceLog::IOCounter
35
+ * StraceLog::Stat
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it ( https://github.com/[my-github-username]/strace_log/fork )
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/strace-stat ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "strace_log"
4
+
5
+ stat = StraceLog::Stat.new
6
+ stat.parse(ARGF)
7
+ stat.print
data/lib/strace_log.rb ADDED
@@ -0,0 +1,266 @@
1
+ require 'strscan'
2
+
3
+ module StraceLog
4
+
5
+ VERSION = "0.1.0"
6
+
7
+ class ParsedCall
8
+ ESCAPES = [ /x[\da-f][\da-f]/i, /n/, /t/, /r/, /\\/, /"/, /\d+/]
9
+
10
+ def initialize(line)
11
+ if /^---.*---$/ =~ line
12
+ @mesg = line
13
+ else
14
+ s = StringScanner.new(line)
15
+ s.scan(/^(?:(\d\d:\d\d:\d\d|\d+)(?:\.(\d+))? )?([\w\d]+)\(/)
16
+ @time = s[1]
17
+ @usec = s[2]
18
+ @func = s[3]
19
+ @args = scan_items(s,/\s*\)\s*/)
20
+ s.scan(/\s*= ([^=<>\s]+)(?:\s+([^<>]+))?(?: <([\d.]+)>)?$/)
21
+ @ret = s[1]
22
+ @mesg = s[2]
23
+ @elap = s[3]
24
+ end
25
+ end
26
+ attr_reader :time, :usec, :func, :args, :ret , :mesg, :elap
27
+
28
+ def scan_items(s,close)
29
+ args = []
30
+ i = 0
31
+ while !s.scan(close)
32
+ x = scan_string(s) || scan_bracket(s) ||
33
+ scan_brace(s) || scan_method(s) || scan_other(s)
34
+ if x.nil?
35
+ raise "match error: args=#{args.inspect} post_match=#{s.post_match}"
36
+ end
37
+ (args[i] ||= "") << x
38
+ if s.scan(/\s*,\s*/)
39
+ i += 1
40
+ end
41
+ end
42
+ args
43
+ end
44
+
45
+ def scan_string(s)
46
+ return nil if s.scan(/\s*"/).nil?
47
+ arg = ""
48
+ while !s.scan(/"/)
49
+ if s.scan(/\\/)
50
+ ESCAPES.each do |re|
51
+ if x = s.scan(re)
52
+ arg << eval('"\\'+x+'"')
53
+ break
54
+ end
55
+ end
56
+ elsif x = s.scan(/[^\\"]+/)
57
+ arg << x
58
+ end
59
+ end
60
+ if x = s.scan(/\.+/)
61
+ arg << x
62
+ end
63
+ arg
64
+ end
65
+
66
+ def scan_bracket(s)
67
+ s.scan(/\s*\[\s*/) && '['+scan_items(s,/\s*\]\s*/).join(',')+']'
68
+ end
69
+
70
+ def scan_brace(s)
71
+ s.scan(/\s*{\s*/) && '{'+scan_items(s,/\s*}\s*/).join(',')+'}'
72
+ end
73
+
74
+ def scan_method(s)
75
+ if s.scan(/([^"\\,{}()\[\]]+)\(/)
76
+ meth = s[1]
77
+ meth+'('+scan_items(s,/\s*\)\s*/).join(',')+')'
78
+ end
79
+ end
80
+
81
+ def scan_other(s)
82
+ s.scan(/[^"\\,{}()\[\]]+/)
83
+ end
84
+ end
85
+
86
+
87
+ class IOCounter
88
+ def initialize(path)
89
+ @path = path
90
+ @ok = {}
91
+ @fail = {}
92
+ @size = {}
93
+ @time = {}
94
+ @rename = []
95
+ end
96
+ attr_reader :path, :ok, :fail, :size, :time, :rename
97
+
98
+ def add(h,func,c)
99
+ h[func] = (h[func] || 0) + c
100
+ end
101
+
102
+ def count(fc)
103
+ if fc.ret == "-1"
104
+ add(@fail, fc.func, 1)
105
+ else
106
+ add(@ok, fc.func, 1)
107
+ end
108
+ add(@time, fc.func, fc.elap.to_f) if fc.elap
109
+ end
110
+
111
+ def count_size(fc)
112
+ sz = fc.ret.to_i
113
+ if sz >= 0
114
+ add(@size, fc.func, sz)
115
+ end
116
+ count(fc)
117
+ end
118
+
119
+ def rename_as(newpath)
120
+ @rename << @path
121
+ @path = newpath
122
+ end
123
+
124
+ def print
125
+ Kernel.print @path+":\n"
126
+ if !@ok.empty?
127
+ keys = @ok.keys.sort
128
+ Kernel.print " ok={"+keys.map{|k| "#{k}:#{@ok[k]}"}.join(", ")+"}\n"
129
+ end
130
+ if !@fail.empty?
131
+ keys = @fail.keys.sort
132
+ Kernel.print " fail={"+keys.map{|k| "#{k}:#{@fail[k]}"}.join(", ")+"}\n"
133
+ end
134
+ if !@size.empty?
135
+ keys = @size.keys.sort
136
+ Kernel.print " size={"+keys.map{|k| "#{k}:#{@size[k]}"}.join(", ")+"}\n"
137
+ end
138
+ if !@time.empty?
139
+ keys = @time.keys.sort
140
+ Kernel.print " time={"+keys.map{|k| "#{k}:#{@time[k]}"}.join(", ")+"}\n"
141
+ end
142
+ if !@rename.empty?
143
+ Kernel.print " rename={#{@rename.join(', ')}}\n"
144
+ end
145
+ puts
146
+ end
147
+ end
148
+
149
+
150
+ class Stat
151
+
152
+ def initialize
153
+ @stat = {}
154
+ @count = {}
155
+ @spent = {}
156
+ end
157
+
158
+ attr_reader :stat, :count, :spent
159
+
160
+ def parse(a)
161
+ @fd2path = ["stdin", "stdout", "stderr"]
162
+ a.each do |line|
163
+ stat_call( ParsedCall.new(line) )
164
+ end
165
+ end
166
+
167
+ def stat_call(pc)
168
+ m = pc.func
169
+ return if m.nil?
170
+ @count[m] = (@count[m] || 0) + 1
171
+ @spent[m] = (@spent[m] || 0) + pc.elap.to_f if pc.elap
172
+
173
+ case m
174
+
175
+ when /^(open|execve|l?stat|(read|un)?link|getc?wd|access|mkdir|mknod|chmod|chown)$/
176
+ path = pc.args[0]
177
+ count_path(path,pc)
178
+ if m=="open" && pc.ret != "-1"
179
+ fd = pc.ret.to_i
180
+ @fd2path[fd] = path
181
+ end
182
+
183
+ when /^(readv?|writev?)$/
184
+ path = @fd2path[pc.args[0].to_i]
185
+ count_size(path,pc)
186
+
187
+ when /^(fstat|fchmod|[fl]chown|lseek|ioctl|fcntl|getdents|sendto|recvmsg|close)$/
188
+ fd = pc.args[0].to_i
189
+ count_fd(fd,pc)
190
+ if m=="close" && pc.ret != "-1"
191
+ @fd2path[fd] = nil
192
+ end
193
+
194
+ when /^rename$/
195
+ path = pc.args[0]
196
+ count_path(path,pc)
197
+ rename(pc)
198
+
199
+ when /^dup[23]?$/
200
+ fd = pc.args[0].to_i
201
+ count_fd(fd,pc)
202
+ if pc.ret != "-1"
203
+ fd = pc.ret.to_i
204
+ @fd2path[fd] = path
205
+ end
206
+
207
+ when /^mmap$/
208
+ fd = pc.args[4].to_i
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)
217
+
218
+ end
219
+ end
220
+
221
+ def count_fd(fd,pc)
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
229
+
230
+ def count_size(path,pc)
231
+ io_counter(path).count_size(pc)
232
+ end
233
+
234
+ def io_counter(path)
235
+ @stat[path] ||= IOCounter.new(path)
236
+ end
237
+
238
+ def rename(pc)
239
+ if pc.ret != "-1"
240
+ oldpath = pc.args[0]
241
+ newpath = pc.args[1]
242
+ ioc = @stat[newpath] = @stat[oldpath]
243
+ ioc.rename_as(newpath)
244
+ @stat.delete(oldpath)
245
+ end
246
+ end
247
+
248
+ def print
249
+ Kernel.print "count={\n"
250
+ @count.each do |m,c|
251
+ Kernel.print " #{m}: #{c},\n"
252
+ end
253
+ Kernel.print "}\n\n"
254
+ Kernel.print "time={\n"
255
+ @spent.each do |m,t|
256
+ Kernel.print " #{m}: #{t},\n"
257
+ end
258
+ Kernel.print "}\n\n"
259
+ files = @stat.keys.select{|x| x.class==String}.sort
260
+ files.each do |fn|
261
+ @stat[fn].print
262
+ end
263
+ end
264
+
265
+ end
266
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'strace_log'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "strace_log"
8
+ spec.version = StraceLog::VERSION
9
+ spec.authors = ["Masahiro TANAKA"]
10
+ spec.email = ["masa16.tanaka@gmail.com"]
11
+
12
+ spec.summary = %q{Parse strace's log}
13
+ spec.description = %q{Parse strace's log, summary of system call}
14
+ spec.homepage = ""
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "bin"
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.9"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: strace_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Masahiro TANAKA
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Parse strace's log, summary of system call
42
+ email:
43
+ - masa16.tanaka@gmail.com
44
+ executables:
45
+ - strace-stat
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".travis.yml"
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/strace-stat
55
+ - lib/strace_log.rb
56
+ - strace_log.gemspec
57
+ homepage: ''
58
+ licenses: []
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.4.5
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Parse strace's log
80
+ test_files: []
81
+ has_rdoc: