ganymed 0.3.4 → 0.4.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 (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