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 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
- Note: You can change the format and behavior by setting `Autolog.procedure`.
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
- Keep the ease of Autolog and its minimal controls while doing nuts things with it:
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
@@ -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 :flush
10
+ attr_accessor :filtered_procs
11
+ attr_accessor :unfiltered_procs
9
12
 
10
- # log all specified events
11
- def events(*args)
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 trace(*args)
36
- if block_given?
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 c-call events only
44
- def c_calls(*args)
45
- if block_given?
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
- # log end events only
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
- # log class and end events only
89
- def classes(*args)
90
- if block_given?
91
- events ['class', 'end', args].flatten, &Proc.new
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
- # log call events only
98
- def method_calls(*args)
99
- if block_given?
100
- events ['call', args].flatten, &Proc.new
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
- events ['call', args].flatten
103
- end
104
- end
38
+ if using && !filtered_procs.has_key?(using)
39
+ raise "Unregistered format/using: #{using.inspect}"
40
+ end
105
41
 
106
- # log return events only
107
- def method_returns(*args)
108
- if block_given?
109
- events ['return', args].flatten, &Proc.new
110
- else
111
- events ['return', args].flatten
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
- events ['call', 'return'], &Proc.new
119
- else
120
- events ['call', 'return', args].flatten
58
+ begin
59
+ yield
60
+ ensure
61
+ off
62
+ end
121
63
  end
122
64
  end
65
+ alias_method :event, :events
123
66
 
124
- # log raise events only
125
- def raises(*args)
126
- if block_given?
127
- events ['raise', args].flatten, &Proc.new
128
- else
129
- events ['raise', args].flatten
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
- # log line events only
134
- def lines(*args)
135
- if block_given?
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.procedure = lambda {|event, file, line, id, binding, classname| begin; puts "#{event} #{file}.#{line} #{binding} #{classname} #{id}"; rescue SystemExit, Interrupt; raise; rescue Exception; end}
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 (?)
@@ -1,23 +1,12 @@
1
1
  module Autolog
2
2
  module Methods
3
3
  def autolog(*args)
4
- args.flatten!
5
- if args.size > 0
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
@@ -1,3 +1,3 @@
1
1
  module Autolog
2
- VERSION = '0.2.1'
2
+ VERSION = '0.3.0'
3
3
  end
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.2.1
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-10-19 00:00:00.000000000 Z
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.