autolog 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +82 -3
- data/lib/autolog.rb +94 -115
- data/lib/autolog/methods.rb +4 -15
- data/lib/autolog/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Autolog
|
2
2
|
=====
|
3
3
|
|
4
|
-
Automatically log tracing events in Ruby more easily.
|
4
|
+
Automatically log and do things with tracing events in Ruby more easily.
|
5
5
|
|
6
6
|
To trace Ruby, you can just define `set_trace_func`. But, why not use fewer keystrokes to output debug information? And what about just logging certain sets of events? How about just:
|
7
7
|
|
@@ -19,8 +19,16 @@ Or a block outputting method calls and c-calls:
|
|
19
19
|
# ...
|
20
20
|
end
|
21
21
|
|
22
|
+
Or a block specifying a different format/proc you can register:
|
23
|
+
|
24
|
+
autolog format: :taw do
|
25
|
+
# ...
|
26
|
+
end
|
27
|
+
|
22
28
|
### Example Output
|
23
29
|
|
30
|
+
Default format just outputs literally what set_trace_func makes available, which isn't pretty:
|
31
|
+
|
24
32
|
call /path/to/.rvm/gems/ruby-1.9.3-p194@my_rails_app/gems/activerecord-3.2.8/lib/active_record/inheritance.rb.61 #<Binding:0x007fc50cf4c080> ActiveRecord::Inheritance::ClassMethods instantiate
|
25
33
|
call /path/to/.rvm/gems/ruby-1.9.3-p194@my_rails_app/gems/activerecord-3.2.8/lib/active_record/model_schema.rb.160 #<Binding:0x007fc50dec48c8> ActiveRecord::ModelSchema::ClassMethods inheritance_column
|
26
34
|
call /path/to/.rvm/gems/ruby-1.9.3-p194@my_rails_app/gems/activerecord-3.2.8/lib/active_record/model_schema.rb.160 #<Binding:0x007fc50dec40d0> ActiveRecord::ModelSchema::ClassMethods inheritance_column
|
@@ -29,7 +37,22 @@ Or a block outputting method calls and c-calls:
|
|
29
37
|
call /path/to/.rvm/gems/ruby-1.9.3-p194@my_rails_app/gems/activerecord-3.2.8/lib/active_record/inheritance.rb.132 #<Binding:0x007fc50dec3720> ActiveRecord::Inheritance::ClassMethods find_sti_class
|
30
38
|
call /path/to/.rvm/gems/ruby-1.9.3-p194@my_rails_app/gems/mail-2.4.4/lib/mail/core_extensions/nil.rb.6 #<Binding:0x007fc50dec3388> NilClass blank?
|
31
39
|
|
32
|
-
|
40
|
+
taw's [format][taw_format] is more tree-like and easier to read:
|
41
|
+
|
42
|
+
c-call Complex.new
|
43
|
+
call <Complex#-605829048>.initialize
|
44
|
+
c-call 11.0.kind_of?
|
45
|
+
c-call 11.0.kind_of?
|
46
|
+
c-call -5.0.kind_of?
|
47
|
+
c-call -5.0.kind_of?
|
48
|
+
c-call Complex.new
|
49
|
+
call <Complex#-605832038>.initialize
|
50
|
+
c-call 2.0.kind_of?
|
51
|
+
c-call 2.0.kind_of?
|
52
|
+
c-call 13.5.kind_of?
|
53
|
+
c-call 13.5.kind_of?
|
54
|
+
|
55
|
+
Or, you can use your own format.
|
33
56
|
|
34
57
|
### See also
|
35
58
|
|
@@ -163,10 +186,65 @@ More examples:
|
|
163
186
|
|
164
187
|
### Changing the format, Using another logger, collecting stats, etc.
|
165
188
|
|
166
|
-
|
189
|
+
#### Use the taw format
|
190
|
+
|
191
|
+
Use [Tomasz Wegrzanowski's (taw's) format][taw_format]:
|
192
|
+
|
193
|
+
autolog format: :taw do
|
194
|
+
# ...
|
195
|
+
end
|
196
|
+
|
197
|
+
Do a pull request if you have another format or hack you'd like to share!
|
198
|
+
|
199
|
+
#### Overriding the default
|
200
|
+
|
201
|
+
You can either just override the default, while still letting Autolog filter by event type before it calls your proc:
|
167
202
|
|
168
203
|
Autolog.procedure = lambda {|event, file, line, id, binding, classname| puts "#{event} #{file}.#{line} #{binding} #{classname} #{id}"}
|
169
204
|
|
205
|
+
#### Register proc and then use :using or :format to use a registered proc
|
206
|
+
|
207
|
+
`:using` and `:format` are equivalent.
|
208
|
+
|
209
|
+
Register a proc that autolog will filter automatically by event type, per documentation:
|
210
|
+
|
211
|
+
Autolog.filtered_proc :simple, lambda {|event, file, line, id, binding, classname|
|
212
|
+
puts "#{classname}.#{id}"
|
213
|
+
}
|
214
|
+
|
215
|
+
or register a proc that autolog will just send into set_trace_func (which means effectively you'd just be using autolog for its ability to have a block and unset set_trace_func at the end of the block, but you also have access to last args from autolog so you can use user-provided args):
|
216
|
+
|
217
|
+
Autolog.unfiltered_proc :all_calls_counter, lambda {|event, file, line, id, binding, classname|
|
218
|
+
$counts ||= {}
|
219
|
+
if Autolog.last_args[0] == event
|
220
|
+
$counts[event.to_sym] = $counts[event.to_sym] ? $counts[event.to_sym] + 1 : 1
|
221
|
+
end
|
222
|
+
}
|
223
|
+
|
224
|
+
And then the :format and :using options are synonymous. For ease of reading code, using `format` to specify something that is just formatting the output differently or `using` for more involved procs:
|
225
|
+
|
226
|
+
autolog :calls, using: :simple do
|
227
|
+
# ...
|
228
|
+
end
|
229
|
+
|
230
|
+
or
|
231
|
+
|
232
|
+
autolog 'call', using: :all_calls_counter do
|
233
|
+
# ...
|
234
|
+
end
|
235
|
+
|
236
|
+
#### Single-context-safe variables available for usage in custom procs
|
237
|
+
|
238
|
+
These variables are "safe" as long as more than one autolog context is not being used at the same time. Multiple thread, etc. could be used within the context of the autolog block, etc. but if you have two different autolog calls executing at once sharing the same module class attributes, that would be a problem.
|
239
|
+
|
240
|
+
`Autolog.level` is just a variable that you can use to increment to find place in the call stack:
|
241
|
+
|
242
|
+
Autolog.level += 1
|
243
|
+
|
244
|
+
It is initialized to 0 on gem load and at the end of each autolog block or when Autolog.off is called.
|
245
|
+
|
246
|
+
`Autolog.last_args` contains the last set of args and options sent into autolog.
|
247
|
+
|
170
248
|
### Warning
|
171
249
|
|
172
250
|
Enabling some of these like lines or trace will significantly slow down execution and may generate a lot of output.
|
@@ -179,6 +257,7 @@ It's as easy as [forking][fork], making your changes, and [submitting a pull req
|
|
179
257
|
|
180
258
|
Copyright (c) 2012 Gary S. Weaver, released under the [MIT license][lic].
|
181
259
|
|
260
|
+
[taw_format]: http://t-a-w.blogspot.com/2007/04/settracefunc-smoke-and-mirrors.html
|
182
261
|
[fork]: https://help.github.com/articles/fork-a-repo
|
183
262
|
[pull]: https://help.github.com/articles/using-pull-requests
|
184
263
|
[tracer]: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tracer/rdoc/index.html
|
data/lib/autolog.rb
CHANGED
@@ -4,150 +4,129 @@ require 'autolog/methods'
|
|
4
4
|
module Autolog
|
5
5
|
class << self
|
6
6
|
# called procedure instead of proc because set_trace_func proc was calling the proc attribute. Fun!
|
7
|
+
attr_accessor :last_args
|
8
|
+
attr_accessor :level
|
7
9
|
attr_accessor :procedure
|
8
|
-
attr_accessor :
|
10
|
+
attr_accessor :filtered_procs
|
11
|
+
attr_accessor :unfiltered_procs
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
args.flatten!
|
13
|
-
args.collect!{|e|e.to_s.gsub('_','-')}
|
14
|
-
|
15
|
-
# What's up with the Exception hiding?
|
16
|
-
# Ruby bug 7180: can use up 100% cpu in 1.9.3p194 if let anything be raised. We'll silently rescue and ignore issues. Otherwise, it produces a deluge of output.
|
17
|
-
if args.size == 1
|
18
|
-
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; Autolog.procedure.call(event, file, line, id, binding, classname) if event == #{args[0].inspect}; rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
19
|
-
elsif args.size > 1
|
20
|
-
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; Autolog.procedure.call(event, file, line, id, binding, classname) if #{args.inspect}.include?(event); rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
21
|
-
else
|
22
|
-
set_trace_func proc {|event, file, line, id, binding, classname| begin; Autolog.procedure.call(event, file, line, id, binding, classname); rescue SystemExit, Interrupt; raise; rescue Exception; end}
|
23
|
-
end
|
24
|
-
|
25
|
-
if block_given?
|
26
|
-
begin
|
27
|
-
yield
|
28
|
-
ensure
|
29
|
-
off
|
30
|
-
end
|
31
|
-
end
|
13
|
+
def filtered_proc(name, procedure)
|
14
|
+
filtered_procs[name.to_sym] = procedure
|
32
15
|
end
|
33
|
-
alias_method :event, :events
|
34
16
|
|
35
|
-
def
|
36
|
-
|
37
|
-
events args, &Proc.new
|
38
|
-
else
|
39
|
-
events args
|
40
|
-
end
|
17
|
+
def unfiltered_proc(name, procedure)
|
18
|
+
unfiltered_procs[name.to_sym] = procedure
|
41
19
|
end
|
42
20
|
|
43
|
-
# log
|
44
|
-
def
|
45
|
-
|
46
|
-
events ['c-call', args].flatten, &Proc.new
|
47
|
-
else
|
48
|
-
events ['c-call', args].flatten
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# log c-return events only
|
53
|
-
def c_returns(*args)
|
54
|
-
if block_given?
|
55
|
-
events ['c-return', args].flatten, &Proc.new
|
56
|
-
else
|
57
|
-
events ['c-return', args].flatten
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# log c-call and c-return events only
|
62
|
-
def c_calls_and_returns(*args)
|
63
|
-
if block_given?
|
64
|
-
events ['c-call', 'c-return', args].flatten, &Proc.new
|
65
|
-
else
|
66
|
-
events ['c-call', 'c-return', args].flatten
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# log class events only
|
71
|
-
def class_starts(*args)
|
72
|
-
if block_given?
|
73
|
-
events ['class', args].flatten, &Proc.new
|
74
|
-
else
|
75
|
-
events ['class', args].flatten
|
76
|
-
end
|
77
|
-
end
|
21
|
+
# log all specified events
|
22
|
+
def events(*args)
|
23
|
+
args = convert_args(*args)
|
78
24
|
|
79
|
-
|
80
|
-
def class_ends(*args)
|
81
|
-
if block_given?
|
82
|
-
events ['end', args].flatten, &Proc.new
|
83
|
-
else
|
84
|
-
events ['end', args].flatten
|
85
|
-
end
|
86
|
-
end
|
25
|
+
Autolog.last_args = args.dup # to allow access by custom procs later in set_trace_func. only "single-context-safe"
|
87
26
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
else
|
93
|
-
events ['class', 'end', args].flatten
|
27
|
+
using = nil
|
28
|
+
if args.size > 0 && args.last.is_a?(Hash)
|
29
|
+
options = args.pop
|
30
|
+
using = options[:using] ? options[:using].to_s.to_sym : options[:format] ? options[:format].to_s.to_sym : nil
|
94
31
|
end
|
95
|
-
end
|
96
32
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
33
|
+
if unfiltered_procs[using]
|
34
|
+
# What's up with the Exception hiding in the body of the procs?
|
35
|
+
# Ruby bug 7180: can use up 100% cpu in 1.9.3p194 if let anything be raised. We'll silently rescue and ignore issues. Otherwise, it produces a deluge of output.
|
36
|
+
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; Autolog.unfiltered_procs[#{using.inspect}].call(event, file, line, id, binding, classname); rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
101
37
|
else
|
102
|
-
|
103
|
-
|
104
|
-
|
38
|
+
if using && !filtered_procs.has_key?(using)
|
39
|
+
raise "Unregistered format/using: #{using.inspect}"
|
40
|
+
end
|
105
41
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
42
|
+
proc_string = using ? "Autolog.filtered_procs[#{using.inspect}]" : 'Autolog.procedure'
|
43
|
+
|
44
|
+
if args.size > 0
|
45
|
+
# What's up with the Exception hiding in the body of the procs?
|
46
|
+
# Ruby bug 7180: can use up 100% cpu in 1.9.3p194 if let anything be raised. We'll silently rescue and ignore issues. Otherwise, it produces a deluge of output.
|
47
|
+
if args.size == 1
|
48
|
+
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; #{proc_string}.call(event, file, line, id, binding, classname) if event == #{args[0].inspect}; rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
49
|
+
elsif args.size > 1
|
50
|
+
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; #{proc_string}.call(event, file, line, id, binding, classname) if #{args.inspect}.include?(event); rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
eval "set_trace_func proc {|event, file, line, id, binding, classname| begin; #{proc_string}.call(event, file, line, id, binding, classname); rescue SystemExit, Interrupt; raise; rescue Exception; end}"
|
54
|
+
end
|
112
55
|
end
|
113
|
-
end
|
114
56
|
|
115
|
-
# log call and return events only
|
116
|
-
def methods(*args)
|
117
57
|
if block_given?
|
118
|
-
|
119
|
-
|
120
|
-
|
58
|
+
begin
|
59
|
+
yield
|
60
|
+
ensure
|
61
|
+
off
|
62
|
+
end
|
121
63
|
end
|
122
64
|
end
|
65
|
+
alias_method :event, :events
|
123
66
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
67
|
+
def convert_args(*args)
|
68
|
+
result = []
|
69
|
+
args.each do |a|
|
70
|
+
case a
|
71
|
+
when :trace
|
72
|
+
when :c_calls; result << 'c-call'
|
73
|
+
when :c_return; result << 'c-return'
|
74
|
+
when :c_calls_and_returns; result << 'c-call' << 'c-return'
|
75
|
+
when :class_starts; result << 'class'
|
76
|
+
when :class_ends; result << 'end'
|
77
|
+
when :classes; result << 'class' << 'end'
|
78
|
+
when :method_calls; result << 'call'
|
79
|
+
when :method_returns; result << 'return'
|
80
|
+
when :methods; result << 'call' << 'return'
|
81
|
+
when :raises; result << 'raise'
|
82
|
+
when :lines; result << 'line'
|
83
|
+
else
|
84
|
+
a = a.to_s.gsub('_','-') if a.is_a?(Symbol)
|
85
|
+
result << a
|
86
|
+
end
|
130
87
|
end
|
88
|
+
result
|
131
89
|
end
|
132
90
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
events ['line', args].flatten, &Proc.new
|
137
|
-
else
|
138
|
-
events ['line', args].flatten
|
139
|
-
end
|
140
|
-
end
|
91
|
+
[:trace, :c_calls, :c_returns, :c_calls_and_returns, :class_starts, :class_ends, :classes, :method_calls, :method_returns, :methods, :raises, :lines].each {|m|
|
92
|
+
eval "def #{m}(*args); if block_given?; events #{m.inspect}, *args, &Proc.new; else; events #{m.inspect}, *args; end; end"
|
93
|
+
}
|
141
94
|
|
142
95
|
# turn logging off
|
143
96
|
def off(*args)
|
144
|
-
# accepts *args to make implementation of autolog in methods easier, but ignores them
|
145
97
|
set_trace_func nil
|
98
|
+
Autolog.level = 0
|
146
99
|
end
|
147
100
|
end
|
148
101
|
end
|
149
102
|
|
150
|
-
Autolog.
|
103
|
+
Autolog.filtered_procs = {}
|
104
|
+
Autolog.unfiltered_procs = {}
|
105
|
+
|
106
|
+
Autolog.filtered_proc :default, lambda {|event, file, line, id, binding, classname|
|
107
|
+
puts "#{event} #{file}.#{line} #{binding} #{classname} #{id}"
|
108
|
+
}
|
109
|
+
|
110
|
+
# Tomasz Wegrzanowski (taw)'s format, modified a little: http://t-a-w.blogspot.com/2007/04/settracefunc-smoke-and-mirrors.html
|
111
|
+
Autolog.unfiltered_proc :taw, lambda { |event, file, line, id, binding, classname|
|
112
|
+
if event == "line"
|
113
|
+
# Ignore
|
114
|
+
elsif %w[return c-return end].include?(event)
|
115
|
+
Autolog.level -= 2
|
116
|
+
else
|
117
|
+
obj = eval("self", binding)
|
118
|
+
if event == "class"
|
119
|
+
STDERR.printf "%*s%s %s\n", Autolog.level, "", event, obj
|
120
|
+
else
|
121
|
+
obj = "<#{obj.class}##{obj.object_id}>" if id == :initialize
|
122
|
+
STDERR.printf "%*s%s %s.%s\n", Autolog.level, "", event, obj, id
|
123
|
+
end
|
124
|
+
Autolog.level += 2 if %w[call c-call class].include?(event)
|
125
|
+
end
|
126
|
+
}
|
127
|
+
|
128
|
+
Autolog.procedure = Autolog.filtered_procs[:default]
|
129
|
+
Autolog.level = 0
|
151
130
|
|
152
131
|
class Object
|
153
132
|
# make autolog a method on every object except main (?)
|
data/lib/autolog/methods.rb
CHANGED
@@ -1,23 +1,12 @@
|
|
1
1
|
module Autolog
|
2
2
|
module Methods
|
3
3
|
def autolog(*args)
|
4
|
-
args.
|
5
|
-
|
6
|
-
if Autolog.respond_to?(args[0])
|
7
|
-
if block_given?
|
8
|
-
Autolog.send(args.delete_at(0), args, &Proc.new)
|
9
|
-
else
|
10
|
-
Autolog.send(args.delete_at(0), args)
|
11
|
-
end
|
12
|
-
elsif block_given?
|
13
|
-
Autolog.events args, &Proc.new
|
14
|
-
else
|
15
|
-
Autolog.events args
|
16
|
-
end
|
4
|
+
if args.size > 1 && !args[0].is_a?(Hash) && args[0].to_sym == :off
|
5
|
+
Autolog.off
|
17
6
|
elsif block_given?
|
18
|
-
Autolog.events &Proc.new
|
7
|
+
Autolog.events *args, &Proc.new
|
19
8
|
else
|
20
|
-
Autolog.events
|
9
|
+
Autolog.events *args
|
21
10
|
end
|
22
11
|
end
|
23
12
|
end
|
data/lib/autolog/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autolog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Automatically log events like executed lines, methods, class and module
|
15
15
|
definitions, C-language routines, and/or raises in Ruby.
|