ganymed 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/ganymed CHANGED
@@ -3,10 +3,18 @@
3
3
  require 'rubygems'
4
4
  $:.unshift(File.join(File.expand_path("../..", __FILE__), 'lib'))
5
5
 
6
+ $0 = "ganymed"
7
+
8
+ require 'madvertise/ext/logging'
9
+ require 'madvertise/ext/environment'
10
+ Env.key = 'GANYMED_ENV'
11
+
6
12
  require 'ganymed/master'
7
13
  cli = Ganymed::Master::CLI.parse_options
8
14
  server = Ganymed::Master.new(cli.config)
9
15
 
16
+ log.level = :debug if cli.config[:debug]
17
+
10
18
  if cli.config[:daemonize] or cli.config[:kill]
11
19
  daemon = Servolux::Daemon.new(:server => server)
12
20
 
data/contrib/cpuhog ADDED
Binary file
data/contrib/cpuhog.c ADDED
@@ -0,0 +1,21 @@
1
+
2
+ /* do some CPU hogging */
3
+
4
+
5
+ int main(int argc, char *argv[])
6
+ {
7
+ int i;
8
+ unsigned long long v1,v2,v3;
9
+
10
+ while (1) {
11
+ v1 = 42;
12
+ v2 = v3 = -1;
13
+ for (i=0; i<1000; i++) {
14
+ v1 += i;
15
+ v2 = v1*i + v3;
16
+ v3 = v1 ^ v2;
17
+ }
18
+ }
19
+ return 0;
20
+ }
21
+
data/lib/ganymed.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'madvertise/ext/logging'
2
-
3
1
  module Ganymed
4
2
  GEM_ROOT = File.expand_path("../..", __FILE__).freeze
5
3
  LIB_DIR = File.join(GEM_ROOT, "lib").freeze
@@ -78,7 +78,7 @@ module Ganymed
78
78
  # Emit a new {Event}.
79
79
  #
80
80
  # @param [String] ns {Event} namespace.
81
- # @param [Fixnum, Float] value {Event} value.
81
+ # @param [Object] value {Event} value.
82
82
  # @param [Hash] opts Options
83
83
  # @option opts [String] cf Consolidation function used in this event.
84
84
  # @option opts [Time] now {Event} timestamp.
@@ -24,12 +24,29 @@ module Ganymed
24
24
  @client = Client.new(:processor => @config.collector.processor,
25
25
  :sampler => @config.collector.sampler)
26
26
 
27
+ load_collectors
27
28
  @config.collectors.each do |collector|
28
29
  log.info("initializing collector #{collector.klass.demodulize}")
29
30
  collector.klass.constantize.new(collector, self).run
30
31
  end
31
32
  end
32
33
 
34
+ def load_collectors
35
+ # collectors shipped with ganymed
36
+ Dir[File.join(Ganymed::LIB_DIR, 'ganymed/collector/*.rb')].each do |f|
37
+ log.debug("Loading collector from #{f}")
38
+ require f
39
+ end
40
+
41
+ # custom collectors
42
+ if @config.collector.path.tap{}
43
+ Dir[File.join(@config.collector.path, '*.rb')].each do |f|
44
+ log.debug("Loading collector from #{f}")
45
+ require f
46
+ end
47
+ end
48
+ end
49
+
33
50
  ##
34
51
  # A base class for collectors.
35
52
  #
@@ -83,7 +100,3 @@ module Ganymed
83
100
  end
84
101
  end
85
102
  end
86
-
87
- Dir[File.join(Ganymed::LIB_DIR, 'ganymed/collector/*.rb')].each do |f|
88
- require f
89
- end
@@ -4,8 +4,10 @@ module Ganymed
4
4
  class Collector
5
5
  class CPU < Base
6
6
  def collect!
7
- File.open('/proc/stat') do |f|
8
- cpu = f.readline.chomp.split[1,7].map do |x|
7
+ return if not File.readable?('/proc/stat')
8
+ File.open('/proc/stat').each do |line|
9
+ next if not line =~ /^cpu /
10
+ cpu = line.chomp.split[1,7].map do |x|
9
11
  x.to_i / hz
10
12
  end
11
13
  @sampler.emit(:derive, "os.cpu.user", cpu[0])
@@ -9,6 +9,7 @@ module Ganymed
9
9
  next if st.blocks == 0 or st.files == 0
10
10
 
11
11
  name = name(mount.mount_point)
12
+ next if @config.exclude.map {|e| Regexp.new(e).match(name)}.any?
12
13
 
13
14
  block_pc = 1.0 - (st.blocks_free.to_f / st.blocks.to_f)
14
15
  @processor.event("os.disk.#{name}.blocks", block_pc)
@@ -8,12 +8,13 @@ module Ganymed
8
8
  class Collector
9
9
  class IOStat < Base
10
10
  def collect!
11
- File.open('/proc/diskstats') do |f|
12
- f.each do |line|
13
- ios = Struct::IOStat.new(*line.strip.split(/\s+/))
14
- @sampler.emit(:derive, "os.iostat.#{ios.dev}.rsect", ios.rsect)
15
- @sampler.emit(:derive, "os.iostat.#{ios.dev}.wsect", ios.wsect)
16
- end
11
+ return if not File.readable?('/proc/diskstats')
12
+ File.open('/proc/diskstats').each do |line|
13
+ ios = Struct::IOStat.new(*line.strip.split(/\s+/))
14
+ next if @config.skip_numbered.tap{} and ios.dev =~ /\d+$/
15
+ next if @config.exclude.map {|e| Regexp.new(e).match(ios.dev)}.any?
16
+ @sampler.emit(:derive, "os.iostat.#{ios.dev}.rsect", ios.rsect)
17
+ @sampler.emit(:derive, "os.iostat.#{ios.dev}.wsect", ios.wsect)
17
18
  end
18
19
  end
19
20
 
@@ -4,6 +4,7 @@ module Ganymed
4
4
  class Collector
5
5
  class Load < Base
6
6
  def collect!
7
+ return if not File.readable?('/proc/loadavg')
7
8
  File.open('/proc/loadavg') do |f|
8
9
  loadavg = f.read.chomp.split[0,3].map(&:to_f)
9
10
  @sampler.emit(:gauge, "os.loadavg", loadavg[0])
@@ -20,6 +20,9 @@ module Ganymed
20
20
  ohai.require_plugin(plugin)
21
21
  end
22
22
  @processor.metadata(ohai.data)
23
+
24
+ # ohai doesn't cleanup after itself
25
+ true while Process.wait(-1, Process::WNOHANG) rescue nil
23
26
  end
24
27
  end
25
28
 
@@ -7,11 +7,17 @@ module Ganymed
7
7
  class Collector
8
8
  class Network < Base
9
9
  def collect!
10
+ return if not File.readable?('/proc/net/dev')
11
+
10
12
  File.open('/proc/net/dev') do |f|
11
13
  f.each do |line|
12
14
  next unless line =~ /:/
15
+
13
16
  ns = Struct::NetworkStat.new(*line.strip.split(/\s+/))
14
17
  ns.dev.sub!(/:$/, '')
18
+
19
+ next if @config.exclude.map {|e| Regexp.new(e).match(ns.dev)}.any?
20
+
15
21
  @sampler.emit(:derive, "os.net.#{ns.dev}.rbytes", ns.rbytes)
16
22
  @sampler.emit(:derive, "os.net.#{ns.dev}.wbytes", ns.wbytes)
17
23
  @sampler.emit(:derive, "os.net.#{ns.dev}.rpackets", ns.rpackets)
@@ -0,0 +1,22 @@
1
+ module Ganymed
2
+ class Collector
3
+ class Procs < Base
4
+ def collect!
5
+ return if not File.readable?('/proc/stat')
6
+ File.open('/proc/stat').each do |line|
7
+ next if not line =~ /^procs_/
8
+ key, value = line.chomp.split
9
+ if key == "procs_running"
10
+ @sampler.emit(:gauge, "os.procs.running", value.to_i)
11
+ elsif key == "procs_blocked"
12
+ @sampler.emit(:gauge, "os.procs.blocked", value.to_i)
13
+ end
14
+ end
15
+ end
16
+
17
+ def interval
18
+ @config.interval.tap{} or 0.2
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,9 +4,10 @@ module Ganymed
4
4
  class Collector
5
5
  class Uptime < Base
6
6
  def collect!
7
- File.open('/proc/uptime') do |f|
8
- uptime = f.read.chomp.split.first.to_f
9
- boottime = Time.now - uptime
7
+ return if not File.readable?('/proc/stat')
8
+ File.open('/proc/stat').each do |line|
9
+ next if not line =~ /^btime /
10
+ boottime = Time.at(line.chomp.split[1].to_i)
10
11
  @processor.event("os.reboot", 1, :now => boottime)
11
12
  end
12
13
  end
@@ -1,8 +1,9 @@
1
1
  generic:
2
- pid_file: /tmp/ganymed.pid
3
-
4
2
  resolution: 300
5
3
 
4
+ eventmachine:
5
+ threadpool_size: 2
6
+
6
7
  profiling:
7
8
  perftools: false
8
9
  gcprofiler: false
@@ -44,6 +45,18 @@ generic:
44
45
  - klass: Ganymed::Collector::Uptime
45
46
  - klass: Ganymed::Collector::Load
46
47
  - klass: Ganymed::Collector::CPU
48
+ - klass: Ganymed::Collector::Procs
47
49
  - klass: Ganymed::Collector::Network
50
+ exclude:
51
+ - ^lo$
52
+ - ^sit
48
53
  - klass: Ganymed::Collector::Disk
54
+ exclude:
55
+ - ^dev$
56
+ - ^dev-shm$
57
+ - rc-init-d$
58
+ - ^run$
59
+ - ^sys-fs-cgroup$
49
60
  - klass: Ganymed::Collector::IOStat
61
+ skip_numbered: true
62
+ exclude: []
data/lib/ganymed/event.rb CHANGED
@@ -34,7 +34,7 @@ module Ganymed
34
34
  attr_accessor :timestamp
35
35
 
36
36
  # The actual value of this sample.
37
- # @return [Fixnum, Float]
37
+ # @return [Object]
38
38
  attr_accessor :value
39
39
 
40
40
  # Create a new {Event} instance from +obj+.
@@ -93,10 +93,6 @@ module Ganymed
93
93
  if @timestamp < 0
94
94
  raise "invalid timestamp: #{@timestamp.inspect}"
95
95
  end
96
-
97
- unless @value.is_a?(Fixnum) or @value.is_a?(Float)
98
- raise "invalid value in #{@ns}: #{@value.inspect} (#{@value.class.name})"
99
- end
100
96
  end
101
97
  end
102
98
  end
@@ -1,6 +1,5 @@
1
1
  require 'eventmachine'
2
2
  require 'madvertise/ext/config'
3
- require 'madvertise/ext/environment'
4
3
  require 'mixlib/cli'
5
4
  require 'servolux'
6
5
  require 'socket'
@@ -17,22 +16,26 @@ module Ganymed
17
16
  include Configuration::Helpers
18
17
 
19
18
  def initialize(cli)
20
- $0 = "ganymed"
21
-
22
- log.level = :debug if cli[:debug]
23
-
19
+ # load config file
24
20
  @default_config_file = File.join(LIB_DIR, 'ganymed/config.yml')
25
21
  @config_file = cli[:config_file]
26
22
 
27
- @pid_file = config.pid_file.tap{}
28
-
29
- super('ganymed', :interval => 1, :logger => log, :pid_file => @pid_file)
23
+ # initialize servolux
24
+ super('ganymed',
25
+ :interval => 1,
26
+ :logger => log,
27
+ :pid_file => cli[:pidfile])
30
28
  end
31
29
 
32
30
  def run
33
31
  unless EventMachine.reactor_running?
34
32
  @reactor.join if @reactor.is_a?(Thread)
35
33
  log.info("starting Ganymed reactor in #{Env.mode} mode")
34
+
35
+ # configure eventmachine
36
+ log.debug("EventMachine threadpool_size=#{config.eventmachine.threadpool_size}")
37
+ EventMachine.threadpool_size = config.eventmachine.threadpool_size
38
+
36
39
  @reactor = Thread.new do
37
40
  begin
38
41
  EventMachine.run { setup_reactor }
@@ -105,6 +108,12 @@ module Ganymed
105
108
  :long => '--config CONFIG',
106
109
  :description => "The configuration file to use"
107
110
 
111
+ option :pidfile,
112
+ :short => '-p PIDFILE',
113
+ :long => '--pidfile PIDFILE',
114
+ :description => "The daemon pidfile",
115
+ :default => "ganymed.pid"
116
+
108
117
  option :debug,
109
118
  :short => '-D',
110
119
  :long => '--debug',
@@ -128,7 +137,7 @@ module Ganymed
128
137
  :long => '--environment ENVIRONMENT',
129
138
  :description => "Set the daemon environment",
130
139
  :default => "development",
131
- :proc => Proc.new { |value| ENV[Env.key] = value }
140
+ :proc => ->(value) { ENV[Env.key] = value }
132
141
 
133
142
  option :help,
134
143
  :short => '-h',
@@ -140,7 +149,6 @@ module Ganymed
140
149
  :exit => 0
141
150
 
142
151
  def self.parse_options
143
- Env.key = 'GANYMED_ENV'
144
152
  new.tap do |cli|
145
153
  cli.parse_options
146
154
  end
@@ -53,8 +53,10 @@ module Ganymed
53
53
  def flush(tick)
54
54
  modifiers = tick == 1 ? ['realtime'] : []
55
55
  datasources.each do |_, datasource|
56
- datasource.flush(tick) do |ns, origin, values|
57
- emit(ns, modifiers, origin, values)
56
+ EM.defer do
57
+ datasource.flush(tick) do |ns, origin, values|
58
+ emit(ns, modifiers, origin, values)
59
+ end
58
60
  end
59
61
  end
60
62
  end
@@ -37,7 +37,7 @@ module Ganymed
37
37
  #
38
38
  # @param [String] ns The namespace for this value.
39
39
  # @param [String] origin The origin of this value.
40
- # @param [Fixnum,Float] ts The timestamp of this value.
40
+ # @param [Time] ts The timestamp of this value.
41
41
  # @param [Fixnum,Float] value The actual value.
42
42
  # @return [void]
43
43
  def feed(ns, origin, ts, value)
@@ -1,3 +1,3 @@
1
1
  module Ganymed
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ganymed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-22 00:00:00.000000000 Z
12
+ date: 2012-05-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &10633280 !ruby/object:Gem::Requirement
16
+ requirement: &11641160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *10633280
24
+ version_requirements: *11641160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: eventmachine
27
- requirement: &10629700 !ruby/object:Gem::Requirement
27
+ requirement: &11637760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.12.10
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *10629700
35
+ version_requirements: *11637760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: madvertise-ext
38
- requirement: &10628060 !ruby/object:Gem::Requirement
38
+ requirement: &11636500 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.1.2
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *10628060
46
+ version_requirements: *11636500
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: madvertise-logging
49
- requirement: &10626000 !ruby/object:Gem::Requirement
49
+ requirement: &11634080 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.3.2
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *10626000
57
+ version_requirements: *11634080
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: mixlib-cli
60
- requirement: &10642620 !ruby/object:Gem::Requirement
60
+ requirement: &11650400 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *10642620
68
+ version_requirements: *11650400
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: servolux
71
- requirement: &10640980 !ruby/object:Gem::Requirement
71
+ requirement: &11648860 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *10640980
79
+ version_requirements: *11648860
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: msgpack
82
- requirement: &10640020 !ruby/object:Gem::Requirement
82
+ requirement: &11647780 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *10640020
90
+ version_requirements: *11647780
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: mongo
93
- requirement: &10639220 !ruby/object:Gem::Requirement
93
+ requirement: &11647060 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '1.6'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *10639220
101
+ version_requirements: *11647060
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: em-websocket
104
- requirement: &10638060 !ruby/object:Gem::Requirement
104
+ requirement: &11645980 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *10638060
112
+ version_requirements: *11645980
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: yajl-ruby
115
- requirement: &10635980 !ruby/object:Gem::Requirement
115
+ requirement: &11644260 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :runtime
122
122
  prerelease: false
123
- version_requirements: *10635980
123
+ version_requirements: *11644260
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: sys-filesystem
126
- requirement: &10652440 !ruby/object:Gem::Requirement
126
+ requirement: &11660200 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: '0'
132
132
  type: :runtime
133
133
  prerelease: false
134
- version_requirements: *10652440
134
+ version_requirements: *11660200
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: ohai
137
- requirement: &10650420 !ruby/object:Gem::Requirement
137
+ requirement: &11658260 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ! '>='
@@ -142,7 +142,7 @@ dependencies:
142
142
  version: 0.6.12
143
143
  type: :runtime
144
144
  prerelease: false
145
- version_requirements: *10650420
145
+ version_requirements: *11658260
146
146
  description: Ganymed is an event collection daemon
147
147
  email:
148
148
  - bb@xnull.de
@@ -160,6 +160,8 @@ files:
160
160
  - README.md
161
161
  - Rakefile
162
162
  - bin/ganymed
163
+ - contrib/cpuhog
164
+ - contrib/cpuhog.c
163
165
  - ganymed.gemspec
164
166
  - lib/ganymed.rb
165
167
  - lib/ganymed/client.rb
@@ -170,6 +172,7 @@ files:
170
172
  - lib/ganymed/collector/load.rb
171
173
  - lib/ganymed/collector/metadata.rb
172
174
  - lib/ganymed/collector/network.rb
175
+ - lib/ganymed/collector/procs.rb
173
176
  - lib/ganymed/collector/uptime.rb
174
177
  - lib/ganymed/config.yml
175
178
  - lib/ganymed/event.rb
@@ -214,7 +217,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
214
217
  version: '0'
215
218
  segments:
216
219
  - 0
217
- hash: 3690408133288017606
220
+ hash: 3485584446673225312
218
221
  required_rubygems_version: !ruby/object:Gem::Requirement
219
222
  none: false
220
223
  requirements:
@@ -223,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
226
  version: '0'
224
227
  segments:
225
228
  - 0
226
- hash: 3690408133288017606
229
+ hash: 3485584446673225312
227
230
  requirements: []
228
231
  rubyforge_project:
229
232
  rubygems_version: 1.8.17