ganymed 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Gemfile +1 -2
  2. data/README.md +6 -14
  3. data/ganymed.gemspec +4 -17
  4. data/lib/ganymed/collector.rb +6 -30
  5. data/lib/ganymed/collectors/cpu.rb +8 -8
  6. data/lib/ganymed/collectors/disk.rb +2 -2
  7. data/lib/ganymed/collectors/iostat.rb +2 -2
  8. data/lib/ganymed/collectors/load.rb +1 -1
  9. data/lib/ganymed/collectors/memory.rb +8 -8
  10. data/lib/ganymed/collectors/network.rb +6 -6
  11. data/lib/ganymed/collectors/process.rb +4 -4
  12. data/lib/ganymed/config.yml +0 -32
  13. data/lib/ganymed/master.rb +9 -8
  14. data/lib/ganymed/version.rb +1 -1
  15. metadata +8 -152
  16. data/contrib/cpuhog +0 -0
  17. data/contrib/cpuhog.c +0 -21
  18. data/lib/ganymed/collectors/uptime.rb +0 -10
  19. data/lib/ganymed/console.rb +0 -147
  20. data/lib/ganymed/event.rb +0 -97
  21. data/lib/ganymed/ext/array.rb +0 -38
  22. data/lib/ganymed/mongodb.rb +0 -44
  23. data/lib/ganymed/processor.rb +0 -137
  24. data/lib/ganymed/sampler/counter.rb +0 -19
  25. data/lib/ganymed/sampler/datasource.rb +0 -85
  26. data/lib/ganymed/sampler/derive.rb +0 -27
  27. data/lib/ganymed/sampler/gauge.rb +0 -20
  28. data/lib/ganymed/sampler.rb +0 -94
  29. data/lib/ganymed/websocket/authentication.rb +0 -37
  30. data/lib/ganymed/websocket/connection.rb +0 -71
  31. data/lib/ganymed/websocket/filter.rb +0 -23
  32. data/lib/ganymed/websocket/metadata.rb +0 -21
  33. data/lib/ganymed/websocket/query.rb +0 -30
  34. data/lib/ganymed/websocket/subscribe.rb +0 -45
  35. data/lib/ganymed/websocket.rb +0 -45
  36. data/spec/sampler/counter_spec.rb +0 -11
  37. data/spec/sampler/datasource_examples.rb +0 -49
  38. data/spec/sampler/datasource_spec.rb +0 -23
  39. data/spec/sampler/derive_spec.rb +0 -34
  40. data/spec/sampler/gauge_spec.rb +0 -35
  41. data/spec/sampler_spec.rb +0 -5
@@ -1,94 +0,0 @@
1
- require 'active_support/inflector'
2
- require 'eventmachine'
3
-
4
- require 'ganymed'
5
- require 'ganymed/client'
6
- require 'ganymed/ext/array'
7
-
8
- module Ganymed
9
-
10
- ##
11
- # The Sampler processes samples from a UDP socket, stores these samples into
12
- # memory and flushes a possibly interpolated and consolidated value to the
13
- # {Processor}.
14
- #
15
- class Sampler
16
- def initialize(config)
17
- @config = config
18
- listen!
19
- emit!
20
- end
21
-
22
- def listen!
23
- @config.sampler.listen.tap do |listen|
24
- log.info("processing samples on udp##{listen.host}:#{listen.port}")
25
- EM.open_datagram_socket(listen.host, listen.port, Connection) do |connection|
26
- connection.fqdn = @config.fqdn
27
- connection.datasources = datasources
28
- end
29
- end
30
- end
31
-
32
- def emit!
33
- @config.client.processor.tap do |processor|
34
- log.info("emitting consolidated samples to tcp##{processor.host}:#{processor.port}")
35
- @processor = Ganymed::Client::Processor.connect(processor.host, processor.port)
36
- end
37
-
38
- # emit consolidated samples 5 times per window
39
- interval = [1, @config.sampler.window / 5].max
40
- EM.add_periodic_timer(interval) { flush }
41
- end
42
-
43
- def datasources
44
- @datasources ||= Hash.new do |hsh, key|
45
- klass = "Ganymed::Sampler::#{key.classify}".constantize
46
- hsh[key] = klass.new(@config.sampler.window)
47
- end
48
- end
49
-
50
- def flush
51
- datasources.each do |_, datasource|
52
- datasource.flush do |ns, origin, values|
53
- next if values.empty?
54
- emit(ns, origin, values)
55
- end
56
- end
57
- end
58
-
59
- def emit(ns, origin, values)
60
- @config.sampler.consolidations.each do |cf, args|
61
- begin
62
- @processor.event(ns, values.send(*args), {
63
- :cf => cf,
64
- :origin => origin,
65
- :resolution => @config.sampler.window,
66
- })
67
- rescue Exception => exc
68
- log.warn("failed to emit #{ns}@#{origin}")
69
- log.exception(exc)
70
- end
71
- end
72
- end
73
-
74
- # @private
75
- module Connection
76
- attr_accessor :datasources, :fqdn
77
-
78
- def receive_data(data)
79
- begin
80
- # pack format: <datasource><namespace><origin><value>
81
- data = data.unpack("Z*Z*Z*G")
82
- datasources[data.slice!(0)].feed(*data)
83
- datasources['counter'].feed('ganymed.sampler.samples', fqdn, 1)
84
- rescue Exception => exc
85
- log.exception(exc)
86
- end
87
- end
88
- end
89
- end
90
- end
91
-
92
- Dir[File.join(Ganymed::LIB_DIR, 'ganymed/sampler/*.rb')].each do |f|
93
- require f
94
- end
@@ -1,37 +0,0 @@
1
- require 'digest'
2
-
3
- require 'ganymed/websocket'
4
-
5
- module Ganymed
6
- class Websocket
7
- module Authentication
8
- def self.included(base)
9
- base.command :authenticate
10
- end
11
-
12
- def authenticate(data)
13
- @authenticated = db['users'].find({
14
- :_id => data['username'],
15
- :password => Digest::SHA256.hexdigest(data['password'])
16
- }).count > 0
17
-
18
- if authenticated?
19
- log.info("successful auth for #{data['username']} from #{peer}")
20
- send(:state, {authenticated: true})
21
- metadata # trigger metadata push
22
- else
23
- log.warn("bad auth for #{data['username']} from #{peer}")
24
- send(:state, {authenticated: false})
25
- end
26
- rescue Exception => exc
27
- log.warn("failed to authenticate #{peer}")
28
- log.exception(exc)
29
- send(:state, {authenticated: false})
30
- end
31
-
32
- def authenticated?
33
- @authenticated ||= false
34
- end
35
- end
36
- end
37
- end
@@ -1,71 +0,0 @@
1
- require 'em-websocket'
2
- require 'yajl'
3
-
4
- require 'ganymed/websocket'
5
- require 'ganymed/websocket/authentication'
6
- require 'ganymed/websocket/subscribe'
7
- require 'ganymed/websocket/metadata'
8
- require 'ganymed/websocket/query'
9
-
10
- module Ganymed
11
- class Websocket
12
- class Connection < EventMachine::WebSocket::Connection
13
- attr_accessor :config, :db
14
-
15
- def self.command(command)
16
- @commands ||= []
17
- @commands << command
18
- end
19
-
20
- def self.commands
21
- @commands
22
- end
23
-
24
- include Authentication
25
- include Metadata
26
- include Subscribe
27
- include Query
28
-
29
- def peer
30
- sin = Socket.unpack_sockaddr_in(get_peername)
31
- "#{sin[1]}:#{sin[0]}"
32
- rescue
33
- "unknown"
34
- end
35
-
36
- def convert(data)
37
- if data.is_a?(Hash)
38
- data
39
- elsif data.is_a?(Array)
40
- data.map {|elem| convert(elem)}
41
- else
42
- if data.respond_to?(:as_json)
43
- data.as_json
44
- elsif data.respond_to?(:to_h)
45
- data.to_h
46
- elsif data.respond_to?(:to_a)
47
- data.to_a
48
- else
49
- data
50
- end
51
- end
52
- end
53
-
54
- def send(type, data)
55
- super(Yajl::Encoder.encode({type.to_s => convert(data)}))
56
- end
57
-
58
- def trigger_on_message(data)
59
- data = Yajl::Parser.parse(data)
60
- data.each do |command, data|
61
- log.debug("command #{command}(#{data.inspect})")
62
- if self.class.commands.include?(command.to_sym)
63
- __send__(command.to_sym, data)
64
- else
65
- send(:error, "invalid command")
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
@@ -1,23 +0,0 @@
1
- require 'ganymed/websocket'
2
-
3
- module Ganymed
4
- class Websocket
5
- class Filter
6
- def initialize(spec)
7
- @spec = spec
8
- end
9
-
10
- def match?(event)
11
- @spec.map do |skey, svalue|
12
- evalue = event.send(skey.to_sym)
13
- case svalue
14
- when Array
15
- svalue.include?(evalue)
16
- else
17
- svalue == evalue
18
- end
19
- end.all?
20
- end
21
- end
22
- end
23
- end
@@ -1,21 +0,0 @@
1
- require 'digest'
2
-
3
- require 'ganymed/websocket'
4
-
5
- module Ganymed
6
- class Websocket
7
- module Metadata
8
- def self.included(base)
9
- base.command :metadata
10
- end
11
-
12
- def metadata(data=nil)
13
- metadata = db['metadata'].find()
14
- send(:metadata, metadata)
15
- rescue Exception => exc
16
- log.warn("failed to send metadata to #{peer}")
17
- log.exception(exc)
18
- end
19
- end
20
- end
21
- end
@@ -1,30 +0,0 @@
1
- require 'ganymed/websocket'
2
- require 'ganymed/websocket/filter'
3
-
4
- module Ganymed
5
- class Websocket
6
- module Query
7
- def self.included(base)
8
- base.command :query
9
- end
10
-
11
- def query(data)
12
- return if not authenticated?
13
- data.each do |ns, query|
14
- query_id = query.delete('_id')
15
-
16
- log.debug("query #{query_id} from #{peer}: #{ns}(#{query.inspect})")
17
- t = Time.now
18
-
19
- events = db.collection(ns).find(query).map do |event|
20
- Event.parse(event.merge({'n' => ns}))
21
- end
22
-
23
- log.debug("query #{query_id} returned #{events.length} results in #{Time.now - t}s")
24
-
25
- send(:result, {query_id => convert(events)})
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,45 +0,0 @@
1
- require 'ganymed/websocket'
2
- require 'ganymed/websocket/filter'
3
-
4
- module Ganymed
5
- class Websocket
6
- module Subscribe
7
- def self.included(base)
8
- base.command :subscribe
9
- base.command :unsubscribe
10
- end
11
-
12
- def filters
13
- @filters ||= {}
14
- end
15
-
16
- def subscribe(data)
17
- return if not authenticated?
18
- data.each do |ns, filter|
19
- log.debug("client #{peer} subscribed to #{ns} with filter=#{filter.inspect}")
20
- filters[ns] = Filter.new(filter)
21
- end
22
- end
23
-
24
- def unsubscribe(data)
25
- return if not authenticated?
26
- data.each do |ns, filter|
27
- log.debug("client #{peer} unsubscribed namespace #{ns}")
28
- filters.delete(ns)
29
- end
30
- end
31
-
32
- def subscribed?(event)
33
- filters.map do |ns, filter|
34
- filter if ns == "all" or event.ns == ns
35
- end.compact.map do |filter|
36
- filter.match?(event)
37
- end.any?
38
- end
39
-
40
- def publish(event)
41
- send(:event, [event]) if subscribed?(event)
42
- end
43
- end
44
- end
45
- end
@@ -1,45 +0,0 @@
1
- require 'em-websocket'
2
- require 'yajl'
3
-
4
- require 'ganymed'
5
- require 'ganymed/websocket/connection'
6
-
7
- module Ganymed
8
- class Websocket
9
- attr_accessor :config, :db
10
-
11
- def initialize(config, db)
12
- @config, @db = config, db
13
- @connections = []
14
- run
15
- end
16
-
17
- def run
18
- log.info("accepting WebSocket connections on tcp##{config.host}:#{config.port}")
19
- EM.start_server(config.host, config.port, Connection, {}) do |connection|
20
- connection.config = config
21
- connection.db = db
22
-
23
- connection.onopen do
24
- log.info("new connection from #{connection.peer}")
25
- @connections << connection
26
- end
27
-
28
- connection.onclose do
29
- log.info("#{connection.peer} has closed the connection")
30
- @connections.delete(connection)
31
- end
32
- end
33
- end
34
-
35
- def each(&block)
36
- @connections.each(&block)
37
- end
38
-
39
- def send(type, data)
40
- each do |connection|
41
- connection.send(type, data)
42
- end
43
- end
44
- end
45
- end
@@ -1,11 +0,0 @@
1
- require 'ganymed/sampler/counter'
2
- require 'sampler/datasource_examples'
3
-
4
- describe Ganymed::Sampler::Counter do
5
- include_context 'DataSource'
6
- subject { Ganymed::Sampler::Counter.new(ticks) }
7
-
8
- let(:values) { 10.times.collect { rand } }
9
-
10
- it_behaves_like Ganymed::Sampler::DataSource
11
- end
@@ -1,49 +0,0 @@
1
- require 'ganymed/sampler/datasource'
2
-
3
- shared_context 'DataSource' do
4
- let(:ns) { 'foo.bar' }
5
- let(:origin) { 'example.com' }
6
- let(:ticks) { [300, 1] }
7
- let(:value) { rand }
8
- end
9
-
10
- shared_examples Ganymed::Sampler::DataSource do
11
- %w(
12
- add
13
- buffer
14
- each
15
- feed
16
- flush
17
- ticks
18
- ).each do |method|
19
- it { should respond_to method }
20
- end
21
-
22
- describe "#add" do
23
- it "should add the given value to each tick buffer" do
24
- subject.add(ns, origin, value)
25
- ticks.each do |tick|
26
- subject.buffer[tick][ns][origin].should include(value)
27
- end
28
- end
29
- end
30
-
31
- describe "#each" do
32
- before(:each) do
33
- values.each do |value|
34
- subject.add(ns, origin, value)
35
- end
36
- end
37
-
38
- it "should clear the buffer" do
39
- subject.each(1) { |ns, origin, values| }
40
- subject.buffer[1].should be_empty
41
- end
42
-
43
- it "should yield all values" do
44
- subject.should_receive(:each).with(1).once.and_yield(ns, origin, values).once
45
- subject.each(1) { |ns, origin, values| }
46
- end
47
- end
48
-
49
- end
@@ -1,23 +0,0 @@
1
- require 'ganymed/sampler/derive'
2
- require 'sampler/datasource_examples'
3
-
4
- describe Ganymed::Sampler::DataSource do
5
- include_context 'DataSource'
6
- subject { Ganymed::Sampler::DataSource.new(ticks) }
7
-
8
- let(:values) { 10.times.collect { rand } }
9
-
10
- it_behaves_like Ganymed::Sampler::DataSource
11
-
12
- describe "#flush" do
13
- it "is not implemented" do
14
- expect { subject.flush(1) }.to raise_error(NotImplementedError)
15
- end
16
- end
17
-
18
- describe "#feed" do
19
- it "is not implemented" do
20
- expect { subject.feed(ns, origin, nil, value) }.to raise_error(NotImplementedError)
21
- end
22
- end
23
- end
@@ -1,34 +0,0 @@
1
- require 'ganymed/sampler/derive'
2
- require 'sampler/datasource_examples'
3
-
4
- describe Ganymed::Sampler::Derive do
5
- include_context 'DataSource'
6
- subject { Ganymed::Sampler::Derive.new(ticks) }
7
-
8
- let(:ts) { now = Time.now.utc; now.to_i + (now.usec * 1e-6) }
9
- let(:values) { 10.times.collect { rand } }
10
-
11
- it_behaves_like Ganymed::Sampler::DataSource
12
-
13
- describe "#flush" do
14
- before(:each) do
15
- values.each do |value|
16
- subject.feed(ns, origin, ts, value)
17
- end
18
- end
19
-
20
- it "should call each" do
21
- subject.should_receive(:each).with(1).once
22
- subject.flush(1)
23
- end
24
-
25
- it "should yield derived values"
26
- end
27
-
28
- describe "#feed" do
29
- it "should add fed samples" do
30
- subject.should_receive(:add).with(ns, origin, [ts, value])
31
- subject.feed(ns, origin, ts, value)
32
- end
33
- end
34
- end
@@ -1,35 +0,0 @@
1
- require 'ganymed/sampler/gauge'
2
- require 'sampler/datasource_examples'
3
-
4
- describe Ganymed::Sampler::Gauge do
5
- include_context 'DataSource'
6
- subject { Ganymed::Sampler::Gauge.new(ticks) }
7
-
8
- let(:values) { 10.times.collect { rand } }
9
-
10
- it_behaves_like Ganymed::Sampler::DataSource
11
-
12
- describe "#flush" do
13
- before(:each) do
14
- values.each do |value|
15
- subject.feed(ns, origin, nil, value)
16
- end
17
- end
18
-
19
- it "should call each" do
20
- subject.should_receive(:each).with(1).once
21
- subject.flush(1)
22
- end
23
-
24
- it "should yield all values" do
25
- expect { |b| subject.flush(1, &b) }.to yield_with_args(ns, origin, values)
26
- end
27
- end
28
-
29
- describe "#feed" do
30
- it "should add fed samples" do
31
- subject.should_receive(:add).with(ns, origin, value)
32
- subject.feed(ns, origin, nil, value)
33
- end
34
- end
35
- end
data/spec/sampler_spec.rb DELETED
@@ -1,5 +0,0 @@
1
- require 'ganymed/sampler'
2
-
3
- describe Ganymed::Sampler do
4
-
5
- end