ustate-client 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.primary }.inject(first.query) do |a, sub|
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.primary }.
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
@@ -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
 
@@ -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(
@@ -1,3 +1,3 @@
1
1
  module UState
2
- VERSION = '0.0.6'
2
+ VERSION = '0.0.7'
3
3
  end
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.6
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-09-20 00:00:00.000000000Z
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: &76033910 !ruby/object:Gem::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: *76033910
25
+ version_requirements: *17908120
25
26
  - !ruby/object:Gem::Dependency
26
27
  name: trollop
27
- requirement: &76033510 !ruby/object:Gem::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: *76033510
36
+ version_requirements: *17907540
36
37
  - !ruby/object:Gem::Dependency
37
38
  name: mtrc
38
- requirement: &76033170 !ruby/object:Gem::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: *76033170
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/graphite.rb
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/message.rb
70
+ - lib/ustate/server.rb
57
71
  - lib/ustate/auto_state.rb
58
- - lib/ustate/metric_thread.rb
59
- - lib/ustate/aggregator.rb
72
+ - lib/ustate/emailer.rb
73
+ - lib/ustate/query.rb
60
74
  - lib/ustate/version.rb
61
- - lib/ustate/server/graphite.rb
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/index.rb
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/dash/rack/static.rb
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/views/css.scss
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/helper/renderer.rb
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.8.10
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.