ustate-client 0.0.6 → 0.0.7
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/README.markdown +44 -5
- data/lib/ustate/query/and.rb +5 -1
- data/lib/ustate/query/approximately.rb +5 -1
- data/lib/ustate/query/ast.rb +8 -1
- data/lib/ustate/query/equals.rb +5 -1
- data/lib/ustate/query/false.rb +10 -0
- data/lib/ustate/query/greater.rb +16 -0
- data/lib/ustate/query/greater_equal.rb +16 -0
- data/lib/ustate/query/less.rb +16 -0
- data/lib/ustate/query/less_equal.rb +16 -0
- data/lib/ustate/query/node.rb +15 -0
- data/lib/ustate/query/not.rb +5 -1
- data/lib/ustate/query/not_equals.rb +5 -1
- data/lib/ustate/query/or.rb +5 -1
- data/lib/ustate/query/true.rb +10 -0
- data/lib/ustate/query_string.rb +588 -40
- data/lib/ustate/query_string.treetop +99 -7
- data/lib/ustate/reaper.rb +126 -0
- data/lib/ustate/server.rb +4 -0
- data/lib/ustate/server/index.rb +9 -36
- data/lib/ustate/version.rb +1 -1
- metadata +43 -33
@@ -2,7 +2,7 @@ module UState
|
|
2
2
|
grammar QueryString
|
3
3
|
# (state =~ "foo" or state == "bar") and service == "foo"
|
4
4
|
# Binding order proceeds from loosest to tightest.
|
5
|
-
|
5
|
+
|
6
6
|
rule or
|
7
7
|
first:and rest:(space 'or' space and)* {
|
8
8
|
def query
|
@@ -21,15 +21,15 @@ module UState
|
|
21
21
|
end
|
22
22
|
|
23
23
|
rule and
|
24
|
-
first:primary rest:(space 'and' space primary)* {
|
24
|
+
first:(not / primary) rest:(space 'and' space p:(not / primary))* {
|
25
25
|
def query
|
26
|
-
rest.elements.map { |x| x.
|
26
|
+
rest.elements.map { |x| x.p }.inject(first.query) do |a, sub|
|
27
27
|
Query::And.new a, sub.query
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def sql
|
32
|
-
rest.elements.map { |x| x.
|
32
|
+
rest.elements.map { |x| x.p }.
|
33
33
|
inject(first.sql) do |a, sub|
|
34
34
|
a & sub.sql
|
35
35
|
end
|
@@ -37,6 +37,18 @@ module UState
|
|
37
37
|
}
|
38
38
|
end
|
39
39
|
|
40
|
+
rule not
|
41
|
+
'not' space p:(not / primary) {
|
42
|
+
def query
|
43
|
+
Query::Not.new p.query
|
44
|
+
end
|
45
|
+
|
46
|
+
def sql
|
47
|
+
~ p.sql
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
40
52
|
rule primary
|
41
53
|
'(' space? x:or space? ')' {
|
42
54
|
def query
|
@@ -52,7 +64,7 @@ module UState
|
|
52
64
|
end
|
53
65
|
|
54
66
|
rule predicate
|
55
|
-
equals / not_equals / approximately
|
67
|
+
true / false / less_equal / less / greater_equal / greater / equals / not_equals / approximately
|
56
68
|
end
|
57
69
|
|
58
70
|
rule approximately
|
@@ -66,7 +78,55 @@ module UState
|
|
66
78
|
end
|
67
79
|
}
|
68
80
|
end
|
81
|
+
|
82
|
+
rule less_equal
|
83
|
+
field space? '<=' space? value {
|
84
|
+
def query
|
85
|
+
Query::LessEqual.new field.sql, value.sql
|
86
|
+
end
|
69
87
|
|
88
|
+
def sql
|
89
|
+
Sequel::SQL::BooleanExpression.new(:<=, field.sql, value.sql)
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
rule less
|
95
|
+
field space? '<' space? value {
|
96
|
+
def query
|
97
|
+
Query::Less.new field.sql, value.sql
|
98
|
+
end
|
99
|
+
|
100
|
+
def sql
|
101
|
+
Sequel::SQL::BooleanExpression.new(:<, field.sql, value.sql)
|
102
|
+
end
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
rule greater_equal
|
107
|
+
field space? '>=' space? value {
|
108
|
+
def query
|
109
|
+
Query::GreaterEqual.new field.sql, value.sql
|
110
|
+
end
|
111
|
+
|
112
|
+
def sql
|
113
|
+
Sequel::SQL::BooleanExpression.new(:>=, field.sql, value.sql)
|
114
|
+
end
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
rule greater
|
119
|
+
field space? '>' space? value {
|
120
|
+
def query
|
121
|
+
Query::Greater.new field.sql, value.sql
|
122
|
+
end
|
123
|
+
|
124
|
+
def sql
|
125
|
+
Sequel::SQL::BooleanExpression.new(:>, field.sql, value.sql)
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
70
130
|
rule not_equals
|
71
131
|
field space? '!=' space? value {
|
72
132
|
def query
|
@@ -92,9 +152,41 @@ module UState
|
|
92
152
|
end
|
93
153
|
|
94
154
|
rule value
|
95
|
-
double_quoted_string / float / integer / null
|
155
|
+
true / false / double_quoted_string / float / integer / null
|
96
156
|
end
|
97
157
|
|
158
|
+
rule true
|
159
|
+
'true' {
|
160
|
+
def query
|
161
|
+
Query::True.new
|
162
|
+
end
|
163
|
+
|
164
|
+
def ruby_value
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
def sql
|
169
|
+
Sequel::TRUE
|
170
|
+
end
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
rule false
|
175
|
+
'false' {
|
176
|
+
def query
|
177
|
+
Query::False.new
|
178
|
+
end
|
179
|
+
|
180
|
+
def ruby_value
|
181
|
+
false
|
182
|
+
end
|
183
|
+
|
184
|
+
def sql
|
185
|
+
Sequel::FALSE
|
186
|
+
end
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
98
190
|
rule integer
|
99
191
|
'-'? [0-9]+ {
|
100
192
|
def ruby_value
|
@@ -116,7 +208,7 @@ module UState
|
|
116
208
|
|
117
209
|
rule field
|
118
210
|
# [a-zA-Z] [a-zA-Z_0-9]*
|
119
|
-
("state" / "host" / "service" / "description" / "metric_f") {
|
211
|
+
("state" / "host" / "service" / "description" / "metric_f" / "time") {
|
120
212
|
def sql
|
121
213
|
text_value.to_sym
|
122
214
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module UState
|
2
|
+
class Reaper
|
3
|
+
# The reaper deletes old states from an index.
|
4
|
+
|
5
|
+
# By default, states die after
|
6
|
+
DEFAULT = 1000
|
7
|
+
# By default, scans for old states every
|
8
|
+
INTERVAL = 10
|
9
|
+
|
10
|
+
attr_reader :default
|
11
|
+
attr_accessor :index
|
12
|
+
attr_accessor :interval
|
13
|
+
attr_accessor :targets
|
14
|
+
|
15
|
+
def initialize(index, opts = {})
|
16
|
+
@index = index
|
17
|
+
@interval = opts[:interval] || INTERVAL
|
18
|
+
@server = opts[:server]
|
19
|
+
@targets = {}
|
20
|
+
@lock = Mutex.new
|
21
|
+
@compiled_targets = {}
|
22
|
+
self.default = opts[:default] || DEFAULT
|
23
|
+
|
24
|
+
start
|
25
|
+
end
|
26
|
+
|
27
|
+
# Transform targets into disjoint queries, ordered by age.
|
28
|
+
# This is kinda ugly; should do write an AST optimizer with boolean
|
29
|
+
# minimization if anyone starts using this feature heavily.
|
30
|
+
def compile
|
31
|
+
@lock.synchronize do
|
32
|
+
@compiled_targets = {}
|
33
|
+
|
34
|
+
ordered = @targets.sort do |a,b|
|
35
|
+
# The states with the longest lifetimes must be excluded from
|
36
|
+
# all the younger checks. Nil = +inf.
|
37
|
+
if b[1].nil?
|
38
|
+
1
|
39
|
+
elsif a[1].nil?
|
40
|
+
-1
|
41
|
+
else
|
42
|
+
b[1] <=> a[1]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
excluded = ordered.inject(nil) do |exclude, pair|
|
47
|
+
# Build up a set of all queries which should last *longer* than us.
|
48
|
+
query, age = pair
|
49
|
+
if exclude
|
50
|
+
if age
|
51
|
+
@compiled_targets["(#{query}) and not (#{exclude})"] = age
|
52
|
+
end
|
53
|
+
"(#{query}) or (#{exclude})"
|
54
|
+
else
|
55
|
+
if age
|
56
|
+
@compiled_targets[query] = age
|
57
|
+
end
|
58
|
+
query
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Add default
|
63
|
+
if @default
|
64
|
+
q = if excluded
|
65
|
+
"not (#{excluded})"
|
66
|
+
else
|
67
|
+
"true"
|
68
|
+
end
|
69
|
+
@compiled_targets[q] = @default
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def default=(d)
|
75
|
+
@default = d
|
76
|
+
compile
|
77
|
+
end
|
78
|
+
|
79
|
+
# Delete states matching query
|
80
|
+
def delete(query)
|
81
|
+
@index.query(Query.new(string: query)).each do |state|
|
82
|
+
@index.on_state_change(
|
83
|
+
state,
|
84
|
+
State.new(
|
85
|
+
host: state.host,
|
86
|
+
service: state.service,
|
87
|
+
state: 'unknown',
|
88
|
+
description: "ustate has not heard from this service since #{Time.at(state.time)}",
|
89
|
+
time: Time.now.to_i
|
90
|
+
)
|
91
|
+
)
|
92
|
+
@index.delete state
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Reap states matching query after age seconds.
|
97
|
+
#
|
98
|
+
# The reaper is gentle; it will give any state specified to reap() the
|
99
|
+
# maximum possible time to live.
|
100
|
+
def reap(query, age)
|
101
|
+
reap! query, age
|
102
|
+
compile
|
103
|
+
end
|
104
|
+
|
105
|
+
def reap!(query, age)
|
106
|
+
@targets[query] = age
|
107
|
+
end
|
108
|
+
|
109
|
+
def start
|
110
|
+
@runner = Thread.new do
|
111
|
+
loop do
|
112
|
+
begin
|
113
|
+
@lock.synchronize do
|
114
|
+
@compiled_targets.each do |query, age|
|
115
|
+
delete "(#{query}) and time < #{(Time.now - age).to_i}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
rescue Exception => e
|
119
|
+
@server.log.warn e
|
120
|
+
end
|
121
|
+
sleep @interval
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/ustate/server.rb
CHANGED
@@ -15,11 +15,13 @@ module UState
|
|
15
15
|
require 'ustate/query_string'
|
16
16
|
require 'ustate/query/ast'
|
17
17
|
require 'ustate/metric_thread'
|
18
|
+
require 'ustate/reaper'
|
18
19
|
require 'logger'
|
19
20
|
require 'mtrc'
|
20
21
|
|
21
22
|
attr_accessor :backends
|
22
23
|
attr_accessor :index
|
24
|
+
attr_accessor :reaper
|
23
25
|
attr_writer :aggregator
|
24
26
|
attr_writer :emailer
|
25
27
|
attr_writer :graphite
|
@@ -35,6 +37,8 @@ module UState
|
|
35
37
|
|
36
38
|
@index = Index.new :server => self
|
37
39
|
|
40
|
+
@reaper = UState::Reaper.new(@index, server: self)
|
41
|
+
|
38
42
|
@log = Logger.new('ustate.log', 4, 134217728)
|
39
43
|
@log.level = Logger::INFO
|
40
44
|
|
data/lib/ustate/server/index.rb
CHANGED
@@ -10,15 +10,12 @@ module UState
|
|
10
10
|
|
11
11
|
THREADS = 1000
|
12
12
|
BUFFER_SIZE = 10
|
13
|
-
# Forget about states after
|
14
|
-
EXPIRY = 1000
|
15
13
|
|
16
14
|
# Update metrics every
|
17
15
|
INSERT_RATE_INTERVAL = 5
|
18
16
|
INSERT_TIMES_INTERVAL = 5
|
19
17
|
|
20
18
|
attr_reader :db, :queue
|
21
|
-
attr_accessor :expiry
|
22
19
|
attr_accessor :insert_rate_interval
|
23
20
|
attr_accessor :insert_times_interval
|
24
21
|
|
@@ -33,8 +30,6 @@ module UState
|
|
33
30
|
@on_state_once = []
|
34
31
|
@on_state = []
|
35
32
|
|
36
|
-
@expiry = opts[:expiry] || EXPIRY
|
37
|
-
|
38
33
|
@insert_rate_interval = opts[:insert_rate_interval] || INSERT_RATE_INTERVAL
|
39
34
|
@insert_times_interval = opts[:insert_times_interval] || INSERT_TIMES_INTERVAL
|
40
35
|
setup_db
|
@@ -52,6 +47,15 @@ module UState
|
|
52
47
|
@insert_rate << 1
|
53
48
|
end
|
54
49
|
|
50
|
+
# Removes a state from the index.
|
51
|
+
#
|
52
|
+
# Right now state is anything which responds to #host and #service.
|
53
|
+
# I'll probably evolve the index to support arbitrary operations on all
|
54
|
+
# states matching a query, but haven't thought out the API.
|
55
|
+
def delete(state)
|
56
|
+
@db[:states].filter(host: state.host, service: state.service).delete
|
57
|
+
end
|
58
|
+
|
55
59
|
def thread(s)
|
56
60
|
Thread.new do
|
57
61
|
process s
|
@@ -146,36 +150,6 @@ module UState
|
|
146
150
|
end
|
147
151
|
end
|
148
152
|
|
149
|
-
# Remove states older than @expiry
|
150
|
-
def reap
|
151
|
-
@db[:states].filter { |s|
|
152
|
-
s.time < (Time.now - @expiry).to_i
|
153
|
-
}.each do |row|
|
154
|
-
on_state_change(
|
155
|
-
row_to_state(row),
|
156
|
-
row_to_state(
|
157
|
-
row.merge(
|
158
|
-
state: 'unknown',
|
159
|
-
description: "ustate has not heard from this service since #{Time.at(row[:time])}",
|
160
|
-
metric_f: nil,
|
161
|
-
time: Time.now.to_i
|
162
|
-
)
|
163
|
-
)
|
164
|
-
)
|
165
|
-
@db[:states].filter(host: row[:host], state: row[:state]).delete
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
# Periodically expire old states.
|
170
|
-
def reaper
|
171
|
-
Thread.new do
|
172
|
-
loop do
|
173
|
-
sleep 1
|
174
|
-
reap
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
153
|
# Converts a row to a State
|
180
154
|
def row_to_state(row)
|
181
155
|
State.new(row)
|
@@ -197,7 +171,6 @@ module UState
|
|
197
171
|
def start
|
198
172
|
stop!
|
199
173
|
@pool = []
|
200
|
-
@reaper = reaper
|
201
174
|
|
202
175
|
@insert_rate = MetricThread.new(Mtrc::Rate) do |r|
|
203
176
|
self << State.new(
|
data/lib/ustate/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ustate-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-05 00:00:00.000000000 -07:00
|
13
|
+
default_executable:
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: beefcake
|
16
|
-
requirement: &
|
17
|
+
requirement: &17908120 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
@@ -21,10 +22,10 @@ dependencies:
|
|
21
22
|
version: 0.3.5
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *17908120
|
25
26
|
- !ruby/object:Gem::Dependency
|
26
27
|
name: trollop
|
27
|
-
requirement: &
|
28
|
+
requirement: &17907540 !ruby/object:Gem::Requirement
|
28
29
|
none: false
|
29
30
|
requirements:
|
30
31
|
- - ! '>='
|
@@ -32,10 +33,10 @@ dependencies:
|
|
32
33
|
version: 1.16.2
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
+
version_requirements: *17907540
|
36
37
|
- !ruby/object:Gem::Dependency
|
37
38
|
name: mtrc
|
38
|
-
requirement: &
|
39
|
+
requirement: &17907040 !ruby/object:Gem::Requirement
|
39
40
|
none: false
|
40
41
|
requirements:
|
41
42
|
- - ! '>='
|
@@ -43,7 +44,7 @@ dependencies:
|
|
43
44
|
version: 0.0.4
|
44
45
|
type: :runtime
|
45
46
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
+
version_requirements: *17907040
|
47
48
|
description:
|
48
49
|
email: aphyr@aphyr.com
|
49
50
|
executables: []
|
@@ -51,44 +52,53 @@ extensions: []
|
|
51
52
|
extra_rdoc_files: []
|
52
53
|
files:
|
53
54
|
- lib/ustate.rb
|
54
|
-
- lib/ustate/
|
55
|
+
- lib/ustate/query/not_equals.rb
|
56
|
+
- lib/ustate/query/equals.rb
|
57
|
+
- lib/ustate/query/false.rb
|
58
|
+
- lib/ustate/query/node.rb
|
59
|
+
- lib/ustate/query/true.rb
|
60
|
+
- lib/ustate/query/or.rb
|
61
|
+
- lib/ustate/query/approximately.rb
|
62
|
+
- lib/ustate/query/greater.rb
|
63
|
+
- lib/ustate/query/and.rb
|
64
|
+
- lib/ustate/query/less.rb
|
65
|
+
- lib/ustate/query/ast.rb
|
66
|
+
- lib/ustate/query/less_equal.rb
|
67
|
+
- lib/ustate/query/greater_equal.rb
|
68
|
+
- lib/ustate/query/not.rb
|
55
69
|
- lib/ustate/query_string.treetop
|
56
|
-
- lib/ustate/
|
70
|
+
- lib/ustate/server.rb
|
57
71
|
- lib/ustate/auto_state.rb
|
58
|
-
- lib/ustate/
|
59
|
-
- lib/ustate/
|
72
|
+
- lib/ustate/emailer.rb
|
73
|
+
- lib/ustate/query.rb
|
60
74
|
- lib/ustate/version.rb
|
61
|
-
- lib/ustate/
|
75
|
+
- lib/ustate/aggregator.rb
|
76
|
+
- lib/ustate/state.rb
|
77
|
+
- lib/ustate/reaper.rb
|
78
|
+
- lib/ustate/graphite.rb
|
79
|
+
- lib/ustate/client/query.rb
|
80
|
+
- lib/ustate/metric_thread.rb
|
81
|
+
- lib/ustate/query_string.rb
|
82
|
+
- lib/ustate/server/index.rb
|
62
83
|
- lib/ustate/server/backends.rb
|
63
|
-
- lib/ustate/server/backends/base.rb
|
64
84
|
- lib/ustate/server/backends/tcp.rb
|
65
|
-
- lib/ustate/server/
|
85
|
+
- lib/ustate/server/backends/base.rb
|
86
|
+
- lib/ustate/server/graphite.rb
|
66
87
|
- lib/ustate/server/connection.rb
|
67
|
-
- lib/ustate/server.rb
|
68
|
-
- lib/ustate/dash.rb
|
69
|
-
- lib/ustate/state.rb
|
70
|
-
- lib/ustate/query.rb
|
71
|
-
- lib/ustate/client/query.rb
|
72
88
|
- lib/ustate/client.rb
|
73
|
-
- lib/ustate/
|
89
|
+
- lib/ustate/message.rb
|
90
|
+
- lib/ustate/dash/helper/renderer.rb
|
91
|
+
- lib/ustate/dash/views/css.scss
|
74
92
|
- lib/ustate/dash/views/index.erubis
|
75
93
|
- lib/ustate/dash/views/layout.erubis
|
76
|
-
- lib/ustate/dash/
|
94
|
+
- lib/ustate/dash/rack/static.rb
|
77
95
|
- lib/ustate/dash/controller/index.rb
|
78
96
|
- lib/ustate/dash/controller/css.rb
|
79
97
|
- lib/ustate/dash/config.rb
|
80
|
-
- lib/ustate/dash
|
81
|
-
- lib/ustate/query/or.rb
|
82
|
-
- lib/ustate/query/not_equals.rb
|
83
|
-
- lib/ustate/query/ast.rb
|
84
|
-
- lib/ustate/query/equals.rb
|
85
|
-
- lib/ustate/query/approximately.rb
|
86
|
-
- lib/ustate/query/not.rb
|
87
|
-
- lib/ustate/query/and.rb
|
88
|
-
- lib/ustate/query_string.rb
|
89
|
-
- lib/ustate/emailer.rb
|
98
|
+
- lib/ustate/dash.rb
|
90
99
|
- LICENSE
|
91
100
|
- README.markdown
|
101
|
+
has_rdoc: true
|
92
102
|
homepage: https://github.com/aphyr/ustate
|
93
103
|
licenses: []
|
94
104
|
post_install_message:
|
@@ -109,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
119
|
version: '0'
|
110
120
|
requirements: []
|
111
121
|
rubyforge_project: ustate-client
|
112
|
-
rubygems_version: 1.
|
122
|
+
rubygems_version: 1.6.2
|
113
123
|
signing_key:
|
114
124
|
specification_version: 3
|
115
125
|
summary: Client for the distributed state server ustate.
|