raindrops 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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'