dike 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/README +175 -0
  2. data/bin/dike +66 -0
  3. data/dike-0.0.1.gem +0 -0
  4. data/gemspec.rb +28 -0
  5. data/install.rb +210 -0
  6. data/lib/dike.rb +264 -0
  7. metadata +53 -0
data/README ADDED
@@ -0,0 +1,175 @@
1
+ NAME
2
+
3
+ dike
4
+
5
+ SYNOPSIS
6
+
7
+ a simple memory leak detector for ruby with preconfigured rails' hooks.
8
+
9
+ INSTALL
10
+
11
+ gem install dike
12
+
13
+ URIS
14
+
15
+ http://www.codeforpeople.com/lib/ruby/
16
+ http://rubyforge.org/projects/codeforpeople/
17
+
18
+ DESCRIPTION
19
+
20
+ the concept behind is simple: Object is extended in order that the location
21
+ of each objects' creation is tracked. a summarizer command is given to walk
22
+ ObjectSpace using each objects class and the location if it's creation to
23
+ detect memory leaks. not all leaks can be detected and some that are may
24
+ not really be leaks, but dike provided a simple way to see the hotspots in
25
+ your code that may potentially be leaking.
26
+
27
+ EXAMPLES
28
+
29
+ PURE RUBY
30
+
31
+ require 'dike'
32
+
33
+ Dike.log STDERR # the default
34
+
35
+ Thread.new do
36
+ sleep 4.2 and Dike.finger
37
+ end
38
+
39
+ Main.start
40
+
41
+
42
+ RAILS
43
+
44
+ file:RAILS_ROOT/config/environment.rb
45
+ ...
46
+ require 'dike'
47
+
48
+ shell: ./script/server
49
+
50
+ shell: curl --silent http://localhost:3000
51
+
52
+ shell: cat ./log/dike/0
53
+ ---
54
+ - class: String
55
+ count: 90769
56
+ trace: []
57
+ - class: Array
58
+ count: 18931
59
+ trace: []
60
+ - class: Class
61
+ count: 2
62
+ trace:
63
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:222:in `class_factory'
64
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:220:in `each'
65
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:220:in `class_factory'
66
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:248:in `Widget'
67
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets/page/base.rb:1
68
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:31:in `require'
69
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:31:in `load'
70
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:16:in `for_controller'
71
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:243:in `widget'
72
+ - /Users/ahoward/site/votelink.com/public/../config/../app/controllers/application.rb:150
73
+ ...
74
+
75
+ shell: curl --silent http://localhost:3000
76
+
77
+ shell: cat ./log/dike/1
78
+ ---
79
+ - class: String
80
+ count: 100769
81
+ trace: []
82
+ - class: Array
83
+ count: 19931
84
+ trace: []
85
+ - class: Class
86
+ count: 5
87
+ trace:
88
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:222:in `class_factory'
89
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:220:in `each'
90
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:220:in `class_factory'
91
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:248:in `Widget'
92
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets/page/base.rb:1
93
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:31:in `require'
94
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:31:in `load'
95
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:16:in `for_controller'
96
+ - /Users/ahoward/site/votelink.com/public/../config/../lib/widgets.rb:243:in `widget'
97
+ - /Users/ahoward/site/votelink.com/public/../config/../app/controllers/application.rb:150
98
+ ...
99
+
100
+ shell: dike ./log/dike
101
+ ---
102
+ - class: Proc
103
+ count: 65
104
+ trace:
105
+ - /opt/local/lib/ruby/1.8/cgi/session.rb:165:in `new'
106
+ - /opt/local/lib/ruby/1.8/cgi/session.rb:165:in `callback'
107
+ - /opt/local/lib/ruby/1.8/cgi/session.rb:299:in `initialize'
108
+ - /Users/ahoward/src/ruby/dike/dike-0.0.1/lib/dike.rb:233:in `new'
109
+ - /Users/ahoward/src/ruby/dike/dike-0.0.1/lib/dike.rb:233:in `call'
110
+ - /Users/ahoward/src/ruby/dike/dike-0.0.1/lib/dike.rb:233:in `new'
111
+ - /Users/ahoward/site/votelink.com/public/../config/../vendor/rails/actionpack/lib/action_contr oller/cgi_process.rb:123:in `session'
112
+ ...
113
+
114
+ SUMMARY
115
+
116
+ * the 'Dike.finger' method dumps it's log in a format showing
117
+
118
+ class : the class of object being leaked/allocated
119
+ count : the number instances leaked from the trace location
120
+ trace : the trace location of object birth
121
+
122
+ * loading into a rails environment causes snapshots of the above format to
123
+ be dumped into RAILS_ROOT/log/dike/ after each request. each snapshot is
124
+ incrementally numbered 0, 1, ...
125
+
126
+ * the 'dike' command line tool can be used in two ways
127
+
128
+ dike directory/with/logs/dike/
129
+
130
+ dike old_dump new_dump
131
+
132
+ if given a directory 'old_dump' and 'new_dump' are auto-calculated by
133
+ scanning the directory. in either case the tool dups a delta running old
134
+ -->> new. the delta shows only changes from old to new, so a line like
135
+
136
+ - class: Proc
137
+ count: 3
138
+ ...
139
+
140
+ means that 3 Proc objects were created between the two dumps. note that,
141
+ when given a directory, the default old and new dumps are the oldest and
142
+ newest dumps respectively, to get fine grained information sumarizing the
143
+ changes between two requests give the files manually, for example
144
+
145
+ dike ./log/dike/41 ./log/dike/42
146
+
147
+ * options that affect logging
148
+
149
+ - Dike.filter pattern
150
+
151
+ pattern must respond to '===' and each object in ObjectSpace will be
152
+ compared against it. for example
153
+
154
+ Dile.filter Array
155
+
156
+ would cause logging to restrict itself to Array, or sublcasses of
157
+ Array, only
158
+
159
+ - Dike.log io
160
+
161
+ set the dike logging object. the object should respond to 'puts'.
162
+
163
+ - Dike.logfactory directory
164
+
165
+ cause logging to occur into a new log for each call the 'Dike.finger'.
166
+ the logs will be auto numbered 0, 1, ...
167
+
168
+ LIMITATIONS
169
+
170
+ not all object creation can be tracked and not all leaks are reported.
171
+
172
+ AUTHOR
173
+
174
+ ara [dot] t [dot] howard [at] gmail [dot] com
175
+
data/bin/dike ADDED
@@ -0,0 +1,66 @@
1
+ #! /usr/bin/env ruby
2
+ require "yaml"
3
+ require "orderedhash"
4
+
5
+ ### TODO objectify - this is crap
6
+
7
+ ### parse argv
8
+ help = ARGV.delete("-h") || ARGV.delete("--help") || ARGV.delete("help")
9
+
10
+ a, b, *ignored = ARGV
11
+
12
+ if help or a.nil?
13
+ puts "dike (directory || old_dump new_dump)"
14
+ exit 42
15
+ end
16
+
17
+ ### load/determine files
18
+ if b
19
+ old_dump = a
20
+ new_dump = b
21
+ else
22
+ directory = a
23
+ Dir.chdir directory do
24
+ list = Dir.glob "*"
25
+ list = list.grep(%r/^[0-9]+$/).map{|entry| entry.to_i}
26
+ a, b = list.min, list.max
27
+ abort "not enough dumps" unless((a and b) and (a != b))
28
+ old_dump = File.join directory, a.to_s
29
+ new_dump = File.join directory, b.to_s
30
+ end
31
+ end
32
+
33
+ ### compute stats
34
+ a = open(old_dump){|fd| YAML.load fd}
35
+ a_index = {}
36
+ a.each{|record| a_index[record["trace"]] = record}
37
+
38
+ b = open(new_dump){|fd| YAML.load fd}
39
+ b_index = {}
40
+ b.each{|record| b_index[record["trace"]] = record}
41
+
42
+ ### generate report
43
+ report = []
44
+
45
+ (a_index.keys + b_index.keys).uniq.each do |trace|
46
+ record = OrderedHash.new
47
+
48
+ a_record = a_index[trace] || {}
49
+ b_record = b_index[trace] || {}
50
+
51
+ klass = a_record["class"] || b_record["class"]
52
+ count = b_record["count"].to_i - a_record["count"].to_i
53
+
54
+ next unless count > 0
55
+
56
+ record["class"] = klass
57
+ record["count"] = count
58
+ record["trace"] = trace.clone
59
+
60
+ report << record
61
+ end
62
+
63
+ report =
64
+ report.sort_by{|record| [-record["count"], record["class"]]}
65
+
66
+ y report
data/dike-0.0.1.gem ADDED
File without changes
data/gemspec.rb ADDED
@@ -0,0 +1,28 @@
1
+
2
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
3
+
4
+ require 'rubygems'
5
+
6
+ Gem::Specification::new do |spec|
7
+ $VERBOSE = nil
8
+ spec.name = lib
9
+ spec.version = version
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.summary = lib
12
+
13
+ spec.files = Dir::glob "**/**"
14
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
15
+
16
+ spec.require_path = "lib"
17
+ spec.autorequire = lib
18
+
19
+ spec.has_rdoc = File::exist? "doc"
20
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
21
+ #spec.add_dependency 'lib', '>= version'
22
+
23
+ spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
24
+
25
+ spec.author = "Ara T. Howard"
26
+ spec.email = "ara.t.howard@gmail.com"
27
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
28
+ end
data/install.rb ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -s, --sudo
160
+ -h, --help
161
+ usage
162
+
163
+ begin
164
+ while switch = ARGV.switch
165
+ case switch
166
+ when '-d', '--destdir'
167
+ libdir = ARGV.req_arg
168
+ when '-l', '--libdir'
169
+ libdir = ARGV.req_arg
170
+ when '-b', '--bindir'
171
+ bindir = ARGV.req_arg
172
+ when '-r', '--ruby'
173
+ $ruby = ARGV.req_arg
174
+ when '-n', '--no_linkify'
175
+ no_linkify = true
176
+ when '-s', '--sudo'
177
+ sudo = 'sudo'
178
+ when '-h', '--help'
179
+ help = true
180
+ else
181
+ raise "unknown switch #{switch.dump}"
182
+ end
183
+ end
184
+ rescue
185
+ STDERR.puts $!.to_s
186
+ STDERR.puts usage
187
+ exit 1
188
+ end
189
+
190
+ if help
191
+ STDOUT.puts usage
192
+ exit
193
+ end
194
+
195
+ system "#{ sudo } #{ $ruby } pre-install.rb" if test(?s, 'pre-install.rb')
196
+
197
+ unless no_linkify
198
+ linked = linkify('lib') + linkify('bin')
199
+ end
200
+
201
+ system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
202
+
203
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
204
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
205
+
206
+ if linked
207
+ linked.each{|path| File::rm_f path}
208
+ end
209
+
210
+ system "#{ sudo } #{ $ruby } post-install.rb" if test(?s, 'post-install.rb')
data/lib/dike.rb ADDED
@@ -0,0 +1,264 @@
1
+ require "yaml"
2
+ require "attributes"
3
+ require "orderedhash"
4
+
5
+ module Dike
6
+ class LogFactory
7
+ attribute "directory"
8
+ attribute "current"
9
+
10
+ def initialize directory = "dike"
11
+ require "fileutils"
12
+ FileUtils.mkdir_p directory
13
+ @directory = directory
14
+ list = Dir.glob(File.join(@directory, "*"))
15
+ list = list.grep(%r/^[0-9]+$/).map{|entry| entry.to_i}
16
+ @current = list.max || -1
17
+ end
18
+
19
+ def next &block
20
+ if block
21
+ open File.join(@directory, self.next.to_s), "w", &block
22
+ else
23
+ @current += 1
24
+ end
25
+ end
26
+ end
27
+
28
+ class << self
29
+ Objects = Hash.new
30
+
31
+ def mark_birth object, stacktrace
32
+ return if Objects[object_id]
33
+ object_id = Object::Methods["object_id"].bind(object).call
34
+ Objects[object_id] = stacktrace
35
+ ObjectSpace.define_finalizer object, &mark_birth_finalizer(object_id)
36
+ end
37
+
38
+ def mark_birth_finalizer object_id
39
+ lambda{ Objects.delete object_id }
40
+ end
41
+
42
+ Ignore = Hash.new
43
+
44
+ Ignore[Ignore.object_id] = true
45
+
46
+ class << Ignore
47
+ def transaction
48
+ state = clone
49
+ Ignore[state.object_id] = true
50
+ yield
51
+ ensure
52
+ clear
53
+ update state
54
+ Ignore.delete state.object_id
55
+ state = nil
56
+ end
57
+ end
58
+
59
+ def ignore *list
60
+ list.flatten.each do |object|
61
+ object_id = ::Object::Methods["object_id"].bind(object).call
62
+ Ignore[object_id] = true
63
+ #ObjectSpace.define_finalizer object, &ignore_finalizer(object_id)
64
+ end
65
+ end
66
+
67
+ def ignored &block
68
+ object = block.call
69
+ ignore object
70
+ object
71
+ end
72
+
73
+ def ignore_finalizer object_id
74
+ lambda{ Ignore.delete object_id }
75
+ end
76
+
77
+ attribute("filter"){ Object }
78
+ attribute("threshold"){ Struct.new(:class, :code, :object)[42, 42, 1] }
79
+ attribute("log"){ STDERR }
80
+ attribute("logfactory"){ nil }
81
+
82
+ def finger options = {}
83
+ Thread.critical = true
84
+
85
+ begin
86
+ GC.start
87
+
88
+ count, code = :remembered
89
+
90
+ Ignore.transaction do
91
+ count = Hash.new 0
92
+ ignore count
93
+
94
+ code = Hash.new do |h,k|
95
+ sh = Hash.new 0
96
+ ignore sh
97
+ h[k] = sh
98
+ end
99
+ ignore code
100
+
101
+ ObjectSpace.each_object(filter) do |object|
102
+ m = Object::Methods["object_id"].bind object
103
+ ignore m
104
+ object_id = m.call
105
+
106
+ next if Ignore[object_id]
107
+
108
+ m = Object::Methods["class"].bind object
109
+ ignore m
110
+ klass = m.call
111
+
112
+ defined_at = Objects[object_id]
113
+ count[klass] += 1
114
+ code[klass][defined_at] += 1
115
+ end
116
+ end
117
+
118
+ GC.start
119
+
120
+ worst_klasses =
121
+ count.to_a.sort_by{|pair| pair.last}.last(threshold.class).reverse
122
+
123
+ count.clear
124
+ count = nil
125
+
126
+ =begin
127
+ report = []
128
+ =end
129
+ total = 0
130
+
131
+ logging do |log|
132
+ log.puts "---"
133
+
134
+ worst_klasses.each do |klass, count|
135
+ worst_code = code[klass].to_a.sort_by{|pair| pair.last}.last(threshold.code).reverse
136
+
137
+ name = Class::Methods["name"].bind(klass).call.to_s
138
+ name = Class::Methods["inspect"].bind(klass).call.to_s if name.empty?
139
+ name = 'UNKNOWN' if name.empty?
140
+
141
+ worst_code.each do |stacktrace, count|
142
+ next unless count > threshold.object
143
+ =begin
144
+
145
+ TODO - figure out why the hell yaml leaks so bad!
146
+
147
+ report << OrderedHash[
148
+ 'class', name,
149
+ 'count', count,
150
+ 'stacktrace', (stacktrace ? stacktrace.clone : []),
151
+ ]
152
+ =end
153
+ trace = stacktrace ? stacktrace.clone : []
154
+
155
+ ### roll our own because yaml leaks!
156
+ log.puts "- class: #{ name }"
157
+ log.puts " count: #{ count }"
158
+ if trace.empty?
159
+ log.puts " trace: []"
160
+ else
161
+ log.puts " trace:"
162
+ trace.each do |line|
163
+ log.puts " - #{ line }"
164
+ end
165
+ end
166
+ end
167
+
168
+ worst_code.clear
169
+ worst_code = nil
170
+
171
+ total += count
172
+ end
173
+ end
174
+
175
+ =begin
176
+ logging do |log|
177
+ log.puts report.to_yaml
178
+ log.flush
179
+ end
180
+
181
+ report.clear
182
+ report = nil
183
+ GC.start
184
+ =end
185
+
186
+ worst_klasses.clear
187
+ worst_klasses = nil
188
+
189
+ code.clear
190
+ code = nil
191
+
192
+ GC.start
193
+
194
+ total
195
+ ensure
196
+ Thread.critical = false
197
+ end
198
+ end
199
+
200
+ def logging &block
201
+ logfactory ? logfactory.next(&block) : block.call(log)
202
+ end
203
+ end
204
+
205
+ class ::Object
206
+ Methods = instance_methods.inject(Hash.new){|h, m| h.update m => instance_method(m)}
207
+ Methods["initialize"] = instance_method "initialize"
208
+ Dike.ignore Methods
209
+ Methods.each{|k,v| Dike.ignore k, v}
210
+
211
+ verbose = $VERBOSE
212
+ begin
213
+ $VERBOSE = nil
214
+ def initialize *a, &b
215
+ Methods["initialize"].bind(self).call *a, &b
216
+ ensure
217
+ Dike.mark_birth self, caller rescue nil
218
+ end
219
+ ensure
220
+ $VERBOSE = verbose
221
+ end
222
+ end
223
+
224
+ class ::Class
225
+ Methods = instance_methods.inject(Hash.new){|h, m| h.update m => instance_method(m)}
226
+ Dike.ignore Methods
227
+ Methods.each{|k,v| Dike.ignore k, v}
228
+
229
+ verbose = $VERBOSE
230
+ begin
231
+ $VERBOSE = nil
232
+ def new *a, &b
233
+ object = Methods["new"].bind(self).call *a, &b
234
+ ensure
235
+ Dike.mark_birth object, caller rescue nil
236
+ end
237
+ def allocate *a, &b
238
+ object = Methods["allocate"].bind(self).call *a, &b
239
+ ensure
240
+ Dike.mark_birth object, caller rescue nil
241
+ end
242
+ ensure
243
+ $VERBOSE = verbose
244
+ end
245
+ end
246
+
247
+ class ::Module
248
+ Methods = instance_methods.inject(Hash.new){|h, m| h.update m => instance_method(m)}
249
+ Dike.ignore Methods
250
+ Methods.each{|k,v| Dike.ignore k, v}
251
+ end
252
+ end
253
+
254
+
255
+ if defined? Rails
256
+ Dike.logfactory Dike::LogFactory.new(File.join(RAILS_ROOT, "log", "dike"))
257
+
258
+ ActionController::Base.module_eval do
259
+ after_filter do |controller|
260
+ Dike.finger
261
+ true
262
+ end
263
+ end
264
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: dike
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-09-27 00:00:00 -06:00
8
+ summary: dike
9
+ require_paths:
10
+ - lib
11
+ email: ara.t.howard@gmail.com
12
+ homepage: http://codeforpeople.com/lib/ruby/dike/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: dike
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ara T. Howard
31
+ files:
32
+ - bin
33
+ - bin/dike
34
+ - dike-0.0.1.gem
35
+ - gemspec.rb
36
+ - install.rb
37
+ - lib
38
+ - lib/dike.rb
39
+ - README
40
+ test_files: []
41
+
42
+ rdoc_options: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ executables:
47
+ - dike
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies: []
53
+