raindrops 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.document +2 -1
  2. data/.gitignore +4 -0
  3. data/.wrongdoc.yml +4 -0
  4. data/GIT-VERSION-GEN +1 -1
  5. data/GNUmakefile +2 -196
  6. data/Gemfile +7 -0
  7. data/LICENSE +1 -1
  8. data/README +17 -47
  9. data/Rakefile +0 -104
  10. data/examples/linux-listener-stats.rb +123 -0
  11. data/examples/{config.ru → middleware.ru} +1 -1
  12. data/examples/watcher.ru +4 -0
  13. data/examples/watcher_demo.ru +13 -0
  14. data/examples/zbatery.conf.rb +13 -0
  15. data/ext/raindrops/extconf.rb +5 -0
  16. data/ext/raindrops/linux_inet_diag.c +449 -151
  17. data/ext/raindrops/linux_tcp_info.c +170 -0
  18. data/ext/raindrops/my_fileno.h +36 -0
  19. data/ext/raindrops/raindrops.c +232 -20
  20. data/lib/raindrops.rb +20 -7
  21. data/lib/raindrops/aggregate.rb +8 -0
  22. data/lib/raindrops/aggregate/last_data_recv.rb +86 -0
  23. data/lib/raindrops/aggregate/pmq.rb +239 -0
  24. data/lib/raindrops/last_data_recv.rb +100 -0
  25. data/lib/raindrops/linux.rb +26 -16
  26. data/lib/raindrops/middleware.rb +112 -41
  27. data/lib/raindrops/middleware/proxy.rb +34 -0
  28. data/lib/raindrops/struct.rb +15 -0
  29. data/lib/raindrops/watcher.rb +362 -0
  30. data/pkg.mk +171 -0
  31. data/raindrops.gemspec +10 -20
  32. data/test/ipv6_enabled.rb +10 -0
  33. data/test/rack_unicorn.rb +12 -0
  34. data/test/test_aggregate_pmq.rb +65 -0
  35. data/test/test_inet_diag_socket.rb +13 -0
  36. data/test/test_last_data_recv_unicorn.rb +69 -0
  37. data/test/test_linux.rb +55 -57
  38. data/test/test_linux_all_tcp_listen_stats.rb +66 -0
  39. data/test/test_linux_all_tcp_listen_stats_leak.rb +43 -0
  40. data/test/test_linux_ipv6.rb +158 -0
  41. data/test/test_linux_tcp_info.rb +61 -0
  42. data/test/test_middleware.rb +15 -2
  43. data/test/test_middleware_unicorn.rb +37 -0
  44. data/test/test_middleware_unicorn_ipv6.rb +37 -0
  45. data/test/test_raindrops.rb +65 -1
  46. data/test/test_raindrops_gc.rb +23 -1
  47. data/test/test_watcher.rb +85 -0
  48. metadata +69 -22
  49. data/examples/linux-tcp-listener-stats.rb +0 -44
data/.document CHANGED
@@ -3,5 +3,6 @@ LICENSE
3
3
  NEWS
4
4
  ChangeLog
5
5
  lib
6
- ext/raindrops/raindrops_ext.c
6
+ ext/raindrops/raindrops.c
7
7
  ext/raindrops/linux_inet_diag.c
8
+ ext/raindrops/linux_tcp_info.c
data/.gitignore CHANGED
@@ -11,3 +11,7 @@ Makefile
11
11
  /man
12
12
  /pkg
13
13
  /doc
14
+ /LATEST
15
+ /tmp
16
+ # http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
17
+ /Gemfile.lock
data/.wrongdoc.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ cgit_url: http://bogomips.org/raindrops.git
3
+ git_url: git://bogomips.org/raindrops.git
4
+ rdoc_url: http://raindrops.bogomips.org/
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.4.1.GIT
4
+ DEF_VER=v0.5.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,199 +1,5 @@
1
- # use GNU Make to run tests in parallel, and without depending on RubyGems
2
1
  all::
3
- RUBY = ruby
4
- RAKE = rake
5
- RSYNC = rsync
6
- GIT_URL = git://git.bogomips.org/raindrops.git
7
-
8
- GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
9
- @./GIT-VERSION-GEN
10
- -include GIT-VERSION-FILE
11
- -include local.mk
12
- ifeq ($(DLEXT),) # "so" for Linux
13
- DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
14
- endif
15
- ifeq ($(RUBY_VERSION),)
16
- RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
17
- endif
18
-
19
- install: $(bins)
20
- $(prep_setup_rb)
21
- $(RM) -r .install-tmp
22
- mkdir .install-tmp
23
- cp -p bin/* .install-tmp
24
- $(RUBY) setup.rb all
25
- $(RM) $^
26
- mv .install-tmp/* bin/
27
- $(RM) -r .install-tmp
28
- $(prep_setup_rb)
29
-
30
- setup_rb_files := .config InstalledFiles
31
- prep_setup_rb := @-$(RM) $(setup_rb_files);$(MAKE) -C $(ext) clean
32
-
33
- clean:
34
- -$(MAKE) -C ext/raindrops clean
35
- $(RM) $(setup_rb_files) ext/raindrops/Makefile
36
-
37
- pkg_extra := GIT-VERSION-FILE NEWS ChangeLog
38
- manifest: $(pkg_extra)
39
- $(RM) .manifest
40
- $(MAKE) .manifest
41
-
42
- .manifest:
43
- (git ls-files && \
44
- for i in $@ $(pkg_extra) $(man1_paths); \
45
- do echo $$i; done) | LC_ALL=C sort > $@+
46
- cmp $@+ $@ || mv $@+ $@
47
- $(RM) $@+
48
-
49
- NEWS: GIT-VERSION-FILE
50
- $(RAKE) -s news_rdoc > $@+
51
- mv $@+ $@
52
-
53
- latest: NEWS
54
- @awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' $<
55
-
56
- SINCE = 0.2.0
57
- ChangeLog: LOG_VERSION = \
58
- $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
59
- echo $(GIT_VERSION) || git describe)
60
- ifneq ($(SINCE),)
61
- ChangeLog: log_range = v$(SINCE)..$(LOG_VERSION)
62
- endif
63
- ChangeLog: GIT-VERSION-FILE
64
- @echo "ChangeLog from $(GIT_URL) ($(log_range))" > $@+
65
- @echo >> $@+
66
- git log $(log_range) | sed -e 's/^/ /' >> $@+
67
- mv $@+ $@
68
-
69
- news_atom := http://raindrops.bogomips.org/NEWS.atom.xml
70
- cgit_atom := http://git.bogomips.org/cgit/raindrops.git/atom/?h=master
71
- atom = <link rel="alternate" title="Atom feed" href="$(1)" \
72
- type="application/atom+xml"/>
73
-
74
- # using rdoc 2.5.x
75
- doc: .document NEWS ChangeLog
76
- for i in $(man1_bins); do > $$i; done
77
- rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
78
- install -m644 COPYING doc/COPYING
79
- install -m644 $(shell grep '^[A-Z]' .document) doc/
80
- cd doc && for i in $(base_bins); do \
81
- html=$$(echo $$i | sed 's/\.rb/_rb/')_1.html; \
82
- sed -e '/"documentation">/r man1/'$$i'.1.html' \
83
- < $$html > tmp && mv tmp $$html; done
84
- $(RUBY) -i -p -e \
85
- '$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
86
- doc/ChangeLog.html
87
- $(RUBY) -i -p -e \
88
- '$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
89
- doc/NEWS.html doc/README.html
90
- $(RAKE) -s news_atom > doc/NEWS.atom.xml
91
- cd doc && ln README.html tmp && mv tmp index.html
92
- $(RM) $(man1_bins)
93
-
94
- ifneq ($(VERSION),)
2
+ RSYNC_DEST := bogomips.org:/srv/raindrops
95
3
  rfproject := rainbows
96
4
  rfpackage := raindrops
97
- pkggem := pkg/$(rfpackage)-$(VERSION).gem
98
- pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
99
- release_notes := release_notes-$(VERSION)
100
- release_changes := release_changes-$(VERSION)
101
-
102
- release-notes: $(release_notes)
103
- release-changes: $(release_changes)
104
- $(release_changes):
105
- $(RAKE) -s release_changes > $@+
106
- $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
107
- $(release_notes):
108
- GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
109
- $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
110
-
111
- # ensures we're actually on the tagged $(VERSION), only used for release
112
- verify:
113
- test x"$(shell umask)" = x0022
114
- git rev-parse --verify refs/tags/v$(VERSION)^{}
115
- git diff-index --quiet HEAD^0
116
- test `git rev-parse --verify HEAD^0` = \
117
- `git rev-parse --verify refs/tags/v$(VERSION)^{}`
118
-
119
- fix-perms:
120
- -git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
121
- -git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
122
-
123
- gem: $(pkggem)
124
-
125
- install-gem: $(pkggem)
126
- gem install $(CURDIR)/$<
127
-
128
- $(pkggem): manifest fix-perms
129
- gem build $(rfpackage).gemspec
130
- mkdir -p pkg
131
- mv $(@F) $@
132
-
133
- $(pkgtgz): distdir = $(basename $@)
134
- $(pkgtgz): HEAD = v$(VERSION)
135
- $(pkgtgz): manifest fix-perms
136
- @test -n "$(distdir)"
137
- $(RM) -r $(distdir)
138
- mkdir -p $(distdir)
139
- tar c `cat .manifest` | (cd $(distdir) && tar x)
140
- cd pkg && tar c $(basename $(@F)) | gzip -9 > $(@F)+
141
- mv $@+ $@
142
-
143
- package: $(pkgtgz) $(pkggem)
144
-
145
- test-release: verify package $(release_notes) $(release_changes)
146
- release: verify package $(release_notes) $(release_changes)
147
- # make tgz release on RubyForge
148
- rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
149
- $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
150
- # push gem to Gemcutter
151
- gem push $(pkggem)
152
- # in case of gem downloads from RubyForge releases page
153
- -rubyforge add_file \
154
- $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
155
- $(RAKE) publish_news VERSION=$(VERSION)
156
- else
157
- gem install-gem: GIT-VERSION-FILE
158
- $(MAKE) $@ VERSION=$(GIT_VERSION)
159
- endif
160
-
161
- ext := ext/raindrops/raindrops_ext.$(DLEXT)
162
- ext/raindrops/Makefile: ext/raindrops/extconf.rb
163
- cd $(@D) && $(RUBY) extconf.rb
164
- $(ext): $(wildcard $(addprefix ext/raindrops/,*.c *.h)) ext/raindrops/Makefile
165
- $(MAKE) -C $(@D)
166
-
167
- all:: test
168
-
169
- export STRESS BENCHMARK
170
- build: $(ext)
171
- test_units := $(wildcard test/test_*.rb)
172
- test: test-unit
173
- test-unit: $(test_units)
174
- $(test_units): build
175
- $(RUBY) -I lib:ext/raindrops $@
176
-
177
- # this requires GNU coreutils variants
178
- publish_doc:
179
- -git set-file-times
180
- $(RM) -r doc ChangeLog NEWS
181
- $(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
182
- $(MAKE) -s latest > doc/LATEST
183
- find doc/images doc/js -type f | \
184
- TZ=UTC xargs touch -d '1970-01-01 00:00:00' doc/rdoc.css
185
- tar cf - $$(git ls-files examples/) | (cd doc && tar xf -)
186
- $(MAKE) doc_gz
187
- chmod 644 $$(find doc -type f)
188
- $(RSYNC) -av doc/ raindrops.bogomips.org:/srv/raindrops/
189
- git ls-files | xargs touch
190
-
191
- # Create gzip variants of the same timestamp as the original so nginx
192
- # "gzip_static on" can serve the gzipped versions directly.
193
- doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
194
- doc_gz:
195
- touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
196
- for i in $(docs); do \
197
- gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
198
-
199
- .PHONY: .FORCE-GIT-VERSION-FILE doc manifest man test $(test_units)
5
+ include pkg.mk
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source(ENV["GEM_SOURCE"] || :rubygems)
2
+ gem 'aggregate', '~> 0.2'
3
+ gem 'io-extra', '~> 1.2.3'
4
+ gem 'posix_mq', '~> 1.0'
5
+ gem 'wrongdoc', '~> 1.5'
6
+ gem 'rack', '~> 1.2'
7
+ gem 'unicorn', '>= 0.98'
data/LICENSE CHANGED
@@ -14,5 +14,5 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14
14
  License for more details.
15
15
 
16
16
  You should have received a copy of the GNU Lesser General Public License
17
- along with the GNU C Library; if not, write to the Free Software
17
+ along with the raindrops; if not, write to the Free Software
18
18
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
data/README CHANGED
@@ -1,13 +1,11 @@
1
1
  = raindrops - real-time stats for preforking Rack servers
2
2
 
3
- Raindrops is a real time stats package to show statistics for Rack HTTP
3
+ Raindrops is a real-time stats toolkit to show statistics for Rack HTTP
4
4
  servers. It is designed for preforking servers such as Rainbows! and
5
5
  Unicorn, but should support any Rack HTTP server under Ruby 1.9, 1.8 and
6
- possibly Rubinius (untested) on platforms supporting POSIX shared memory.
7
-
8
- Raindrops includes a Struct-like Raindrops::Struct class that may be used
9
- standalone to create atomic counters shared across any number of forked
10
- processes under SMP.
6
+ Rubinius on platforms supporting POSIX shared memory. It may also be
7
+ used as a generic scoreboard for sharing atomic counters across multiple
8
+ processes.
11
9
 
12
10
  == Features
13
11
 
@@ -32,6 +30,12 @@ processes under SMP.
32
30
  instead of parsing /proc/net/tcp to minimize overhead.
33
31
  This was fun to discover and write.
34
32
 
33
+ * TCP_Info reporting may be used to check stat for every accepted client
34
+ on TCP servers
35
+
36
+ Users of older Linux kernels need to ensure that the the "inet_diag"
37
+ and "tcp_diag" kernel modules are loaded as they do not autoload correctly
38
+
35
39
  == Install
36
40
 
37
41
  We recommend GCC 4+ (or compatible) to support the
@@ -54,58 +58,24 @@ http://raindrops.bogomips.org/files/
54
58
 
55
59
  Unpack it, and run "ruby setup.rb"
56
60
 
57
- == Usage (Rainbows!/Unicorn preload_app=false)
58
-
59
- If you're using preload_app=false (the default) in your Rainbows!/Unicorn
60
- config file, you'll need to create the global Stats object before
61
- forking.
62
-
63
- require 'raindrops'
64
- $stats ||= Raindrops::Middleware::Stats.new
65
-
66
- In your Rack config.ru:
67
-
68
- use Raindrops::Middleware, :stats => $stats
69
-
70
- == Usage (Rainbows!/Unicorn preload_app=true)
71
-
72
- If you're using preload_app=true in your Rainbows!/Unicorn
73
- config file, just add the middleware to your stack:
74
-
75
- In your Rack config.ru:
76
-
77
- use Raindrops::Middleware
78
-
79
- == Usage (Linux-extras)
80
-
81
- To get bound listener statistics under Linux, you need to specify the
82
- listener names for your server. You can even include listen sockets for
83
- *other* servers on the same machine. This can be handy for monitoring
84
- your nginx proxy as well.
85
-
86
- In your Rack config.ru, just pass the :listeners argument as an array of
87
- strings (along with any other arguments). You can specify any
88
- combination of TCP or Unix domain socket names:
89
-
90
- use Raindrops::Middleware, :listeners => %w(0.0.0.0:80 /tmp/.sock)
91
-
92
- See the tests/ and examples/ directory for more examples.
61
+ == Usage
93
62
 
94
- If you're running Unicorn 0.98.0 or later, you don't have to pass in
95
- the :listeners array, Raindrops will automatically detect the listeners
96
- used by Unicorn master process.
63
+ See Raindrops::Middleware and Raindrops::LastDataRecv documentation for
64
+ use Rack servers. The entire library is fully-documented and we are
65
+ responsive on the mailing list (mailto:raindrops@librelist.com) if you
66
+ have any questions or comments.
97
67
 
98
68
  == Development
99
69
 
100
70
  You can get the latest source via git from the following locations:
101
71
 
102
- git://git.bogomips.org/raindrops.git
72
+ git://bogomips.org/raindrops.git
103
73
  git://repo.or.cz/raindrops.git (mirror)
104
74
 
105
75
  You may browse the code from the web and download the latest snapshot
106
76
  tarballs here:
107
77
 
108
- * http://git.bogomips.org/cgit/raindrops.git (cgit)
78
+ * http://bogomips.org/raindrops.git (cgit)
109
79
  * http://repo.or.cz/w/raindrops.git (gitweb)
110
80
 
111
81
  Inline patches (from "git format-patch") to the mailing list are
data/Rakefile CHANGED
@@ -1,107 +1,3 @@
1
- # -*- encoding: binary -*-
2
-
3
- # most tasks are in the GNUmakefile which offers better parallelism
4
-
5
- def tags
6
- timefmt = '%Y-%m-%dT%H:%M:%SZ'
7
- @tags ||= `git tag -l`.split(/\n/).map do |tag|
8
- if %r{\Av[\d\.]+\z} =~ tag
9
- header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
10
- header = header.split(/\n/)
11
- tagger = header.grep(/\Atagger /).first
12
- body ||= "initial"
13
- {
14
- :time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
15
- :tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
16
- :tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
17
- :id => `git rev-parse refs/tags/#{tag}`.chomp!,
18
- :tag => tag,
19
- :subject => subject,
20
- :body => body,
21
- }
22
- end
23
- end.compact.sort { |a,b| b[:time] <=> a[:time] }
24
- end
25
-
26
- cgit_url = "http://git.bogomips.org/cgit/raindrops.git"
27
- git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/raindrops.git'
28
- web_url = "http://raindrops.bogomips.org/"
29
-
30
- desc 'prints news as an Atom feed'
31
- task :news_atom do
32
- require 'nokogiri'
33
- new_tags = tags[0,10]
34
- puts(Nokogiri::XML::Builder.new do
35
- feed :xmlns => "http://www.w3.org/2005/Atom" do
36
- id! "#{web_url}NEWS.atom.xml"
37
- title "Raindrops news"
38
- subtitle "real-time stats for Rack servers"
39
- link! :rel => "alternate", :type => "text/html",
40
- :href => "#{web_url}NEWS.html"
41
- updated(new_tags.empty? ? "1970-01-01T00:00:00Z" : new_tags.first[:time])
42
- new_tags.each do |tag|
43
- entry do
44
- title tag[:subject]
45
- updated tag[:time]
46
- published tag[:time]
47
- author {
48
- name tag[:tagger_name]
49
- email tag[:tagger_email]
50
- }
51
- url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
52
- link! :rel => "alternate", :type => "text/html", :href =>url
53
- id! url
54
- message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
55
- content({:type =>:text}, message_only)
56
- content(:type =>:xhtml) { pre tag[:body] }
57
- end
58
- end
59
- end
60
- end.to_xml)
61
- end
62
-
63
- desc 'prints RDoc-formatted news'
64
- task :news_rdoc do
65
- tags.each do |tag|
66
- time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
67
- puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
68
- puts ""
69
-
70
- body = tag[:body]
71
- puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
72
- puts ""
73
- end
74
- end
75
-
76
- desc "print release changelog for Rubyforge"
77
- task :release_changes do
78
- version = ENV['VERSION'] or abort "VERSION= needed"
79
- version = "v#{version}"
80
- vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
81
- prev = vtags[vtags.index(version) - 1]
82
- if prev
83
- system('git', 'diff', '--stat', prev, version) or abort $?
84
- puts ""
85
- system('git', 'log', "#{prev}..#{version}") or abort $?
86
- else
87
- system('git', 'log', version) or abort $?
88
- end
89
- end
90
-
91
- desc "print release notes for Rubyforge"
92
- task :release_notes do
93
- spec = Gem::Specification.load('raindrops.gemspec')
94
- puts spec.description.strip
95
- puts ""
96
- puts "* #{spec.homepage}"
97
- puts "* #{spec.email}"
98
- puts "* #{git_url}"
99
-
100
- _, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
101
- print "\nChanges:\n\n"
102
- puts body
103
- end
104
-
105
1
  desc "read news article from STDIN and post to rubyforge"
106
2
  task :publish_news do
107
3
  require 'rubyforge'