daikon 0.4.0 → 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.
- data/Gemfile +3 -2
- data/Gemfile.lock +2 -0
- data/daikon.gemspec +14 -9
- data/lib/daikon.rb +2 -1
- data/lib/daikon/client.rb +10 -15
- data/lib/daikon/monitor.rb +37 -0
- data/spec/client_spec.rb +13 -9
- data/spec/monitor_spec.rb +96 -0
- data/spec/spec_helper.rb +1 -0
- metadata +24 -8
- data/VERSION +0 -1
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -39,6 +39,7 @@ GEM
|
|
39
39
|
diff-lcs (~> 1.1.2)
|
40
40
|
rspec-mocks (2.1.0)
|
41
41
|
term-ansicolor (1.0.5)
|
42
|
+
timecop (0.3.5)
|
42
43
|
webmock (1.6.1)
|
43
44
|
addressable (>= 2.2.2)
|
44
45
|
crack (>= 0.1.7)
|
@@ -56,4 +57,5 @@ DEPENDENCIES
|
|
56
57
|
net-http-persistent (~> 1.4.1)
|
57
58
|
redis (~> 2.1.1)
|
58
59
|
rspec
|
60
|
+
timecop
|
59
61
|
webmock
|
data/daikon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{daikon}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nick Quaranto"]
|
12
|
-
s.date = %q{2010-12-
|
12
|
+
s.date = %q{2010-12-12}
|
13
13
|
s.default_executable = %q{daikon}
|
14
14
|
s.description = %q{daikon, a radishapp.com client}
|
15
15
|
s.email = %q{nick@quaran.to}
|
@@ -25,7 +25,6 @@ Gem::Specification.new do |s|
|
|
25
25
|
"MIT-LICENSE",
|
26
26
|
"README.rdoc",
|
27
27
|
"Rakefile",
|
28
|
-
"VERSION",
|
29
28
|
"bin/daikon",
|
30
29
|
"daikon.gemspec",
|
31
30
|
"features/daikon.feature",
|
@@ -35,12 +34,14 @@ Gem::Specification.new do |s|
|
|
35
34
|
"lib/daikon/client.rb",
|
36
35
|
"lib/daikon/configuration.rb",
|
37
36
|
"lib/daikon/daemon.rb",
|
37
|
+
"lib/daikon/monitor.rb",
|
38
38
|
"lib/daikon/namespace_tools.rb",
|
39
39
|
"lib/daikon/redis_hacks.rb",
|
40
40
|
"spec/client_spec.rb",
|
41
41
|
"spec/configuration_spec.rb",
|
42
42
|
"spec/daemon_spec.rb",
|
43
43
|
"spec/daikon_spec.rb",
|
44
|
+
"spec/monitor_spec.rb",
|
44
45
|
"spec/spec_helper.rb"
|
45
46
|
]
|
46
47
|
s.homepage = %q{http://github.com/qrush/daikon}
|
@@ -53,6 +54,7 @@ Gem::Specification.new do |s|
|
|
53
54
|
"spec/configuration_spec.rb",
|
54
55
|
"spec/daemon_spec.rb",
|
55
56
|
"spec/daikon_spec.rb",
|
57
|
+
"spec/monitor_spec.rb",
|
56
58
|
"spec/spec_helper.rb"
|
57
59
|
]
|
58
60
|
|
@@ -66,10 +68,11 @@ Gem::Specification.new do |s|
|
|
66
68
|
s.add_runtime_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
67
69
|
s.add_runtime_dependency(%q<redis>, ["~> 2.1.1"])
|
68
70
|
s.add_runtime_dependency(%q<SystemTimer>, ["~> 1.2.1"])
|
69
|
-
s.add_development_dependency(%q<
|
71
|
+
s.add_development_dependency(%q<bourne>, [">= 0"])
|
70
72
|
s.add_development_dependency(%q<cucumber>, [">= 0"])
|
71
73
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
72
|
-
s.add_development_dependency(%q<
|
74
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
75
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
73
76
|
s.add_development_dependency(%q<webmock>, [">= 0"])
|
74
77
|
else
|
75
78
|
s.add_dependency(%q<daemons>, ["~> 1.1.0"])
|
@@ -77,10 +80,11 @@ Gem::Specification.new do |s|
|
|
77
80
|
s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
78
81
|
s.add_dependency(%q<redis>, ["~> 2.1.1"])
|
79
82
|
s.add_dependency(%q<SystemTimer>, ["~> 1.2.1"])
|
80
|
-
s.add_dependency(%q<
|
83
|
+
s.add_dependency(%q<bourne>, [">= 0"])
|
81
84
|
s.add_dependency(%q<cucumber>, [">= 0"])
|
82
85
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
83
|
-
s.add_dependency(%q<
|
86
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
87
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
84
88
|
s.add_dependency(%q<webmock>, [">= 0"])
|
85
89
|
end
|
86
90
|
else
|
@@ -89,10 +93,11 @@ Gem::Specification.new do |s|
|
|
89
93
|
s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
90
94
|
s.add_dependency(%q<redis>, ["~> 2.1.1"])
|
91
95
|
s.add_dependency(%q<SystemTimer>, ["~> 1.2.1"])
|
92
|
-
s.add_dependency(%q<
|
96
|
+
s.add_dependency(%q<bourne>, [">= 0"])
|
93
97
|
s.add_dependency(%q<cucumber>, [">= 0"])
|
94
98
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
95
|
-
s.add_dependency(%q<
|
99
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
100
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
96
101
|
s.add_dependency(%q<webmock>, [">= 0"])
|
97
102
|
end
|
98
103
|
end
|
data/lib/daikon.rb
CHANGED
data/lib/daikon/client.rb
CHANGED
@@ -15,10 +15,11 @@ module Daikon
|
|
15
15
|
attr_accessor :redis, :logger, :config, :http, :monitor
|
16
16
|
|
17
17
|
def setup(config, logger = nil)
|
18
|
-
self.config
|
19
|
-
self.logger
|
20
|
-
self.redis
|
21
|
-
self.http
|
18
|
+
self.config = config
|
19
|
+
self.logger = logger
|
20
|
+
self.redis = connect
|
21
|
+
self.http = Net::HTTP::Persistent.new
|
22
|
+
self.monitor = Monitor.new(connect, logger)
|
22
23
|
http.headers['Authorization'] = config.api_key
|
23
24
|
|
24
25
|
log "Started Daikon v#{VERSION}"
|
@@ -29,12 +30,7 @@ module Daikon
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def start_monitor
|
32
|
-
|
33
|
-
Thread.new do
|
34
|
-
connect.monitor do |line|
|
35
|
-
monitor.puts line
|
36
|
-
end
|
37
|
-
end
|
33
|
+
monitor.start
|
38
34
|
end
|
39
35
|
|
40
36
|
def log(message)
|
@@ -82,13 +78,12 @@ module Daikon
|
|
82
78
|
end
|
83
79
|
|
84
80
|
def rotate_monitor
|
85
|
-
|
86
|
-
monitor.reopen(StringIO.new)
|
81
|
+
lines = monitor.rotate
|
87
82
|
|
88
|
-
http_request(:post, "api/v1/monitor") do |request|
|
89
|
-
request.body =
|
83
|
+
http_request(:post, "api/v1/monitor.json") do |request|
|
84
|
+
request.body = {"lines" => lines}.to_json
|
90
85
|
request.add_field "Content-Length", request.body.size.to_s
|
91
|
-
request.add_field "Content-Type", "application/
|
86
|
+
request.add_field "Content-Type", "application/json"
|
92
87
|
end
|
93
88
|
rescue *EXCEPTIONS => ex
|
94
89
|
log ex.to_s
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Daikon
|
2
|
+
class Monitor
|
3
|
+
attr_accessor :queue
|
4
|
+
|
5
|
+
NEW_FORMAT = /^(\d+\.\d+)( "[A-Z]+".*)/i
|
6
|
+
OLD_SINGLE_FORMAT = /^(QUIT|RANDOMKEY|DBSIZE|EXPIRE|TTL|SAVE|BGSAVE|SHUTDOWN|BGREWRITEAOF|INFO|MONITOR|SLAVEOF)$/i
|
7
|
+
OLD_MORE_FORMAT = /^[A-Z]+ .*$/i
|
8
|
+
|
9
|
+
def initialize(redis = nil, logger = nil)
|
10
|
+
@queue = []
|
11
|
+
@redis = redis
|
12
|
+
@logger = logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
Thread.new do
|
17
|
+
@redis.monitor do |line|
|
18
|
+
parse(line)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def rotate
|
24
|
+
@queue.shift(@queue.size)
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse(line)
|
28
|
+
if line =~ NEW_FORMAT
|
29
|
+
timestamp = $1
|
30
|
+
line = $2.strip
|
31
|
+
@queue.push({:at => Time.at(*timestamp.split('.').map(&:to_i)), :command => line})
|
32
|
+
elsif line =~ OLD_SINGLE_FORMAT || line =~ OLD_MORE_FORMAT
|
33
|
+
@queue.push({:at => Time.now, :command => line.strip})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -18,7 +18,7 @@ describe Daikon::Client, "setup" do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it "sets redis to listen on the given port" do
|
21
|
-
Redis.should have_received(:new).with(:host => "8.8.8.8", :port => "1234")
|
21
|
+
Redis.should have_received(:new).with(:host => "8.8.8.8", :port => "1234").twice
|
22
22
|
subject.should have_received(:redis=).with(redis)
|
23
23
|
end
|
24
24
|
end
|
@@ -31,7 +31,7 @@ describe Daikon::Client, "setup" do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it "sets redis to listen on the given port" do
|
34
|
-
Redis.should have_received(:new).with(:host => "127.0.0.1", :port => "6379")
|
34
|
+
Redis.should have_received(:new).with(:host => "127.0.0.1", :port => "6379").twice
|
35
35
|
subject.should have_received(:redis=).with(redis)
|
36
36
|
end
|
37
37
|
end
|
@@ -168,16 +168,16 @@ end
|
|
168
168
|
|
169
169
|
shared_examples_for "a monitor api consumer" do
|
170
170
|
it "shoots the results back to radish" do
|
171
|
-
|
171
|
+
payload = {"lines" => lines}
|
172
172
|
|
173
173
|
headers = {
|
174
174
|
"Authorization" => api_key,
|
175
|
-
"Content-Length" =>
|
176
|
-
"Content-Type" => "application/
|
175
|
+
"Content-Length" => payload.to_json.size,
|
176
|
+
"Content-Type" => "application/json"
|
177
177
|
}
|
178
178
|
|
179
|
-
WebMock.should have_requested(:post, "#{server}/api/v1/monitor").
|
180
|
-
with(:body =>
|
179
|
+
WebMock.should have_requested(:post, "#{server}/api/v1/monitor.json").
|
180
|
+
with(:body => payload.to_json, :headers => headers)
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -185,11 +185,15 @@ describe Daikon::Client, "rotate monitor" do
|
|
185
185
|
subject { Daikon::Client.new }
|
186
186
|
let(:results) { %{1290289048.96581 "info"\n1290289053.568815 "info"} }
|
187
187
|
let(:redis) { stub("redis instance", :info => results) }
|
188
|
+
let(:lines) do
|
189
|
+
[{"at" => Time.at(1290289048, 96581), "command" => "info"},
|
190
|
+
{"at" => Time.at(1290289053, 568815), "command" => "info"}]
|
191
|
+
end
|
188
192
|
|
189
193
|
before do
|
190
|
-
stub_request(:post, "#{server}/api/v1/monitor")
|
191
|
-
subject.monitor = StringIO.new(results)
|
194
|
+
stub_request(:post, "#{server}/api/v1/monitor.json")
|
192
195
|
subject.setup(config)
|
196
|
+
subject.monitor = stub("monitor", :rotate => lines)
|
193
197
|
subject.rotate_monitor
|
194
198
|
end
|
195
199
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Daikon::Monitor, "#rotate" do
|
4
|
+
it "pops off what is on the queue" do
|
5
|
+
subject.parse("INCR foo")
|
6
|
+
subject.parse("DECR foo")
|
7
|
+
|
8
|
+
data = subject.rotate
|
9
|
+
data.first[:command].should == "INCR foo"
|
10
|
+
data.last[:command].should == "DECR foo"
|
11
|
+
data.size.should == 2
|
12
|
+
subject.queue.size.should be_zero
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe Daikon::Monitor, "#parse with new format" do
|
17
|
+
subject { Daikon::Monitor.new }
|
18
|
+
let(:line) { '1291699658.994073 "decrby" "fooz" "2000"' }
|
19
|
+
|
20
|
+
it "parses the log into json" do
|
21
|
+
subject.parse(line)
|
22
|
+
subject.queue.should include({:at => Time.at(1291699658, 994073), :command => '"decrby" "fooz" "2000"'})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Daikon::Monitor, "#parse with multiple inputs" do
|
27
|
+
subject { Daikon::Monitor.new }
|
28
|
+
before { Timecop.freeze }
|
29
|
+
after { Timecop.return }
|
30
|
+
|
31
|
+
it "queues up multiple lines" do
|
32
|
+
subject.parse("+OK")
|
33
|
+
subject.parse("INCR foo")
|
34
|
+
subject.parse("INCR fooz")
|
35
|
+
subject.parse("info")
|
36
|
+
|
37
|
+
subject.queue.size.should == 3
|
38
|
+
subject.queue.should include({:at => Time.now, :command => 'INCR foo'})
|
39
|
+
subject.queue.should include({:at => Time.now, :command => 'INCR fooz'})
|
40
|
+
subject.queue.should include({:at => Time.now, :command => 'info'})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe Daikon::Monitor, "#parse with old multi line input" do
|
45
|
+
subject { Daikon::Monitor.new }
|
46
|
+
before { Timecop.freeze }
|
47
|
+
after { Timecop.return }
|
48
|
+
|
49
|
+
it "parses gzipped logs into raws" do
|
50
|
+
subject.parse("incr foo")
|
51
|
+
subject.parse("sismember project-13897-global-error-classes 17")
|
52
|
+
subject.parse("incrApiParameterError")
|
53
|
+
subject.parse("decr foo")
|
54
|
+
|
55
|
+
subject.queue.size.should == 3
|
56
|
+
subject.queue.should include({:at => Time.now, :command => 'incr foo'})
|
57
|
+
subject.queue.should include({:at => Time.now, :command => 'sismember project-13897-global-error-classes 17'})
|
58
|
+
subject.queue.should include({:at => Time.now, :command => 'decr foo'})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe Daikon::Monitor, "#parse with multi line input with numbers" do
|
63
|
+
subject { Daikon::Monitor.new }
|
64
|
+
before { Timecop.freeze }
|
65
|
+
after { Timecop.return }
|
66
|
+
|
67
|
+
it "parses gzipped logs into raws" do
|
68
|
+
subject.parse("incr foo")
|
69
|
+
subject.parse("set g:2470920:mrn 9")
|
70
|
+
subject.parse("554079885")
|
71
|
+
subject.parse("decr foo")
|
72
|
+
|
73
|
+
subject.queue.size.should == 3
|
74
|
+
subject.queue.should include({:at => Time.now, :command => 'incr foo'})
|
75
|
+
subject.queue.should include({:at => Time.now, :command => 'set g:2470920:mrn 9'})
|
76
|
+
subject.queue.should include({:at => Time.now, :command => 'decr foo'})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe Daikon::Monitor, "#parse with strings that may to_i to a number" do
|
81
|
+
subject { Daikon::Monitor.new }
|
82
|
+
before { Timecop.freeze }
|
83
|
+
after { Timecop.return }
|
84
|
+
|
85
|
+
it "parses gzipped logs into raws" do
|
86
|
+
subject.parse("incr foo")
|
87
|
+
subject.parse("set g:2470920:mrn 9")
|
88
|
+
subject.parse("46fdcf77c1bb2108e6191602c2f5f9ae")
|
89
|
+
subject.parse("decr foo")
|
90
|
+
|
91
|
+
subject.queue.size.should == 3
|
92
|
+
subject.queue.should include({:at => Time.now, :command => 'incr foo'})
|
93
|
+
subject.queue.should include({:at => Time.now, :command => 'set g:2470920:mrn 9'})
|
94
|
+
subject.queue.should include({:at => Time.now, :command => 'decr foo'})
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daikon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Nick Quaranto
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-12 00:00:00 -05:00
|
19
19
|
default_executable: daikon
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -101,7 +101,7 @@ dependencies:
|
|
101
101
|
- !ruby/object:Gem::Dependency
|
102
102
|
prerelease: false
|
103
103
|
type: :development
|
104
|
-
name:
|
104
|
+
name: bourne
|
105
105
|
version_requirements: &id006 !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|
@@ -143,7 +143,7 @@ dependencies:
|
|
143
143
|
- !ruby/object:Gem::Dependency
|
144
144
|
prerelease: false
|
145
145
|
type: :development
|
146
|
-
name:
|
146
|
+
name: rspec
|
147
147
|
version_requirements: &id009 !ruby/object:Gem::Requirement
|
148
148
|
none: false
|
149
149
|
requirements:
|
@@ -157,7 +157,7 @@ dependencies:
|
|
157
157
|
- !ruby/object:Gem::Dependency
|
158
158
|
prerelease: false
|
159
159
|
type: :development
|
160
|
-
name:
|
160
|
+
name: timecop
|
161
161
|
version_requirements: &id010 !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|
@@ -168,6 +168,20 @@ dependencies:
|
|
168
168
|
- 0
|
169
169
|
version: "0"
|
170
170
|
requirement: *id010
|
171
|
+
- !ruby/object:Gem::Dependency
|
172
|
+
prerelease: false
|
173
|
+
type: :development
|
174
|
+
name: webmock
|
175
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
176
|
+
none: false
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
hash: 3
|
181
|
+
segments:
|
182
|
+
- 0
|
183
|
+
version: "0"
|
184
|
+
requirement: *id011
|
171
185
|
description: daikon, a radishapp.com client
|
172
186
|
email: nick@quaran.to
|
173
187
|
executables:
|
@@ -184,7 +198,6 @@ files:
|
|
184
198
|
- MIT-LICENSE
|
185
199
|
- README.rdoc
|
186
200
|
- Rakefile
|
187
|
-
- VERSION
|
188
201
|
- bin/daikon
|
189
202
|
- daikon.gemspec
|
190
203
|
- features/daikon.feature
|
@@ -194,12 +207,14 @@ files:
|
|
194
207
|
- lib/daikon/client.rb
|
195
208
|
- lib/daikon/configuration.rb
|
196
209
|
- lib/daikon/daemon.rb
|
210
|
+
- lib/daikon/monitor.rb
|
197
211
|
- lib/daikon/namespace_tools.rb
|
198
212
|
- lib/daikon/redis_hacks.rb
|
199
213
|
- spec/client_spec.rb
|
200
214
|
- spec/configuration_spec.rb
|
201
215
|
- spec/daemon_spec.rb
|
202
216
|
- spec/daikon_spec.rb
|
217
|
+
- spec/monitor_spec.rb
|
203
218
|
- spec/spec_helper.rb
|
204
219
|
has_rdoc: true
|
205
220
|
homepage: http://github.com/qrush/daikon
|
@@ -240,4 +255,5 @@ test_files:
|
|
240
255
|
- spec/configuration_spec.rb
|
241
256
|
- spec/daemon_spec.rb
|
242
257
|
- spec/daikon_spec.rb
|
258
|
+
- spec/monitor_spec.rb
|
243
259
|
- spec/spec_helper.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.0.0
|