bipbip 0.5.24 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ebd236b49b6ae015737b235b91ccc37957c4e003
4
- data.tar.gz: e11213f8f95ea6d62e4f074ae1a51d4926139f3f
3
+ metadata.gz: 3dad495dcac92d89bce9202405e212fc5395cdc2
4
+ data.tar.gz: 63e38ea535ac06437ab9f15bcb916f74d8b6fc1a
5
5
  SHA512:
6
- metadata.gz: a299ac1d5dd426a73b07f32a68bed3035289347895b7902a41a7951017bebb0aa5bb37f237f5ca8e2f34cdd0e68b3db25225842b1e9bf4cd79383f41c0b9af92
7
- data.tar.gz: a2f6f16f4e0bf25f49f195ef00ce794e9fb9f12b6a12050431a8752d4fae2f836395252577ec3070c3f8df7eab1a8181d218cad2c34ec754eaab61e9b86843cb
6
+ metadata.gz: 18dfce67a0feeb23f8370ff3d20c49dd574f2087a2e6f9fc6e3a9cd215144bff93bb73e6b887fd156396492542e74aed87c3b914a54b711c48b159996ef09fd0
7
+ data.tar.gz: 80f6389027697b47ed98bad817bea8335cee6ef8ee0f741eadf44626dc73e65e86ac3252615aa96aa615e75fc26ce7fb71ac02e45135462ba3359f685a3aa3e1
data/bin/bipbip CHANGED
@@ -29,7 +29,7 @@ end
29
29
 
30
30
  begin
31
31
  optparse.parse!
32
- if not options[:config]
32
+ unless options[:config]
33
33
  puts "Missing options: config file [-c PATH]"
34
34
  exit
35
35
  end
@@ -40,8 +40,10 @@ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
40
40
  end
41
41
 
42
42
  begin
43
- Bipbip::Agent.new(options[:config]).run
43
+ config = Bipbip::Config.factory_from_file(options[:config])
44
+ agent = Bipbip::Agent.new(config)
45
+ agent.run
44
46
  rescue => e
45
- Bipbip.logger.fatal e.message + "\n" + e.backtrace.map{|s| "\t#{s}"}.join("\n")
47
+ Bipbip.logger.fatal e.message + "\n" + e.backtrace.map { |s| "\t#{s}" }.join("\n")
46
48
  exit 1
47
49
  end
@@ -7,12 +7,14 @@ module Bipbip
7
7
  require 'logger'
8
8
  require 'socket'
9
9
  require 'shellwords'
10
+ require 'thwait'
11
+ require 'timeout'
10
12
 
11
13
  require 'interruptible_sleep'
12
- require 'process_exists'
13
14
 
14
15
  require 'bipbip/version'
15
16
  require 'bipbip/helper'
17
+ require 'bipbip/config'
16
18
  require 'bipbip/agent'
17
19
  require 'bipbip/storage'
18
20
  require 'bipbip/plugin'
@@ -1,17 +1,21 @@
1
1
  module Bipbip
2
2
 
3
3
  class Agent
4
+ include InterruptibleSleep
4
5
 
5
6
  PLUGIN_RESPAWN_DELAY = 5
6
7
 
7
8
  attr_accessor :plugins
8
9
  attr_accessor :storages
10
+ attr_accessor :threads
9
11
 
10
- def initialize(config_file = nil)
11
- @plugins = []
12
- @storages = []
12
+ # @param [Bipbip::Config] config
13
+ def initialize(config)
14
+ @plugins = config.plugins
15
+ @storages = config.storages
16
+ Bipbip.logger = config.logger
13
17
 
14
- load_config(config_file) if config_file
18
+ @threads = []
15
19
  end
16
20
 
17
21
  def run
@@ -29,88 +33,53 @@ module Bipbip
29
33
  end
30
34
  end
31
35
 
32
- ['INT', 'TERM'].each { |sig| trap(sig) {
33
- Thread.new do
36
+ ['INT', 'TERM'].each do |sig|
37
+ trap(sig) do
38
+ Bipbip.logger.info "Received signal #{sig}, interrupting..."
34
39
  interrupt
35
- exit
36
40
  end
37
- } }
41
+ end
38
42
 
39
43
  @plugins.each do |plugin|
40
44
  Bipbip.logger.info "Starting plugin #{plugin.name} with config #{plugin.config}"
41
- plugin.run(@storages)
45
+ start_plugin(plugin, @storages)
42
46
  end
43
47
 
44
48
  @interrupted = false
45
49
  until @interrupted
46
- pid = Process.wait(-1)
50
+ thread = ThreadsWait.new(@threads).next_wait
51
+ @threads.delete(thread)
52
+ plugin = thread['plugin']
47
53
  next if @interrupted
48
- plugin = plugin_by_pid(pid)
49
- Bipbip.logger.error "Plugin #{plugin.name} with config #{plugin.config} died. Respawning..."
50
- sleep(PLUGIN_RESPAWN_DELAY)
51
- plugin.run(@storages)
52
- end
53
- end
54
54
 
55
- def load_config(config_file)
56
- config = YAML.load(File.open(config_file))
57
- config = {
58
- 'logfile' => STDOUT,
59
- 'loglevel' => 'INFO',
60
- 'frequency' => 60,
61
- 'include' => nil,
62
- 'services' => [],
63
- 'tags' => [],
64
- }.merge(config)
65
-
66
- Bipbip.logger = Logger.new(config['logfile'])
67
- Bipbip.logger.level = Logger::const_get(config['loglevel'])
68
-
69
- services = config['services'].to_a
70
- if config['include']
71
- include_path = File.expand_path(config['include'].to_s, File.dirname(config_file))
72
-
73
- files = Dir[include_path + '/**/*.yaml', include_path + '/**/*.yml']
74
- services += files.map { |file| YAML.load(File.open(file)) }
75
- end
76
-
77
- @plugins = services.map do |service|
78
- plugin_name = service['plugin']
79
- metric_group = service['metric_group']
80
- frequency = service['frequency'].nil? ? config['frequency'] : service['frequency']
81
- tags = config['tags'].to_a + service['tags'].to_a
82
- plugin_config = service.reject { |key, value| ['plugin', 'frequency', 'tags', 'metric_group'].include?(key) }
83
- Bipbip::Plugin.factory(plugin_name, plugin_config, frequency, tags, metric_group)
84
- end
55
+ Bipbip.logger.error "Plugin #{plugin.name} with config #{plugin.config} terminated. Restarting..."
56
+ interruptible_sleep(PLUGIN_RESPAWN_DELAY)
57
+ next if @interrupted
85
58
 
86
- storages = config['storages'].to_a
87
- @storages = storages.map do |storage|
88
- storage_name = storage['name'].to_s
89
- storage_config = storage.reject { |key, value| ['name'].include?(key) }
90
- Bipbip::Storage.factory(storage_name, storage_config)
59
+ # Re-instantiate plugin to get rid of existing database-connections etc
60
+ plugin_new = Bipbip::Plugin.factory_from_plugin(plugin)
61
+ @plugins.delete(plugin)
62
+ @plugins.push(plugin_new)
63
+ start_plugin(plugin_new, @storages)
91
64
  end
92
65
  end
93
66
 
94
67
  def interrupt
95
68
  @interrupted = true
96
-
97
- Bipbip.logger.info 'Interrupt, killing plugin processes...'
98
- @plugins.each do |plugin|
99
- Process.kill('TERM', plugin.pid) if Process.exists?(plugin.pid)
69
+ @threads.each do |thread|
70
+ thread.terminate
100
71
  end
101
-
102
- Bipbip.logger.info 'Waiting for all plugin processes to exit...'
103
- Process.waitall
72
+ interrupt_sleep
104
73
  end
105
74
 
106
75
  private
107
76
 
108
- def plugin_by_pid(pid)
109
- plugin = @plugins.find { |plugin| plugin.pid == pid }
110
- if plugin.nil?
111
- raise "Cannot find plugin with pid #{pid}"
112
- end
113
- plugin
77
+ # @param [Bipbip::Plugin] plugin
78
+ # @param [Array<Bipbip::Storage>] storages
79
+ def start_plugin(plugin, storages)
80
+ thread = Thread.new { plugin.run(storages) }
81
+ thread['plugin'] = plugin
82
+ @threads.push(thread)
114
83
  end
115
84
  end
116
85
  end
@@ -0,0 +1,62 @@
1
+ module Bipbip
2
+
3
+ class Config
4
+
5
+ attr_reader :plugins
6
+ attr_reader :storages
7
+ attr_reader :logger
8
+
9
+ # @param [String] file_path
10
+ # @return [Bipbip::Config]
11
+ def self.factory_from_file(file_path)
12
+ config = YAML.load(File.open(file_path))
13
+ config = {
14
+ 'logfile' => STDOUT,
15
+ 'loglevel' => 'INFO',
16
+ 'frequency' => 60,
17
+ 'include' => nil,
18
+ 'services' => [],
19
+ 'tags' => [],
20
+ }.merge(config)
21
+
22
+ logger = Logger.new(config['logfile'])
23
+ logger.level = Logger::const_get(config['loglevel'])
24
+
25
+ plugins_config = config['services'].to_a
26
+ if config['include']
27
+ include_path = File.expand_path(config['include'].to_s, File.dirname(file_path))
28
+
29
+ files = Dir[include_path + '/**/*.yaml', include_path + '/**/*.yml']
30
+ plugins_config += files.map { |file| YAML.load(File.open(file)) }
31
+ end
32
+
33
+ plugins = plugins_config.map do |service|
34
+ plugin_name = service['plugin']
35
+ metric_group = service['metric_group']
36
+ frequency = service['frequency'].nil? ? config['frequency'] : service['frequency']
37
+ tags = config['tags'].to_a + service['tags'].to_a
38
+ plugin_config = service.reject { |key, value| ['plugin', 'frequency', 'tags', 'metric_group'].include?(key) }
39
+ Bipbip::Plugin.factory(plugin_name, plugin_config, frequency, tags, metric_group)
40
+ end
41
+
42
+ storages_config = config['storages'].to_a
43
+ storages = storages_config.map do |storage|
44
+ storage_name = storage['name'].to_s
45
+ storage_config = storage.reject { |key, value| ['name'].include?(key) }
46
+ Bipbip::Storage.factory(storage_name, storage_config)
47
+ end
48
+
49
+ Bipbip::Config.new(plugins, storages, logger)
50
+ end
51
+
52
+ # @param [Array<Bipbip::Plugin>] [plugins]
53
+ # @param [Array<Bipbip::Storage>] [storages]
54
+ # @param [Logger] [logger]
55
+ def initialize(plugins = nil, storages = nil, logger = nil)
56
+ @plugins = plugins || []
57
+ @storages = storages || []
58
+ @logger = logger || Logger.new(STDOUT)
59
+ end
60
+
61
+ end
62
+ end
@@ -1,19 +1,30 @@
1
1
  module Bipbip
2
2
 
3
3
  class Plugin
4
+
5
+ class MeasurementTimeout < RuntimeError
6
+ end
7
+
4
8
  include InterruptibleSleep
5
9
 
6
10
  attr_accessor :name
7
11
  attr_accessor :config
8
- attr_accessor :metric_group
12
+ attr_accessor :frequency
9
13
  attr_accessor :tags
10
- attr_accessor :pid
14
+ attr_accessor :metric_group
11
15
 
12
16
  def self.factory(name, config, frequency, tags, metric_group = nil)
13
17
  require "bipbip/plugin/#{Bipbip::Helper.name_to_filename(name)}"
14
18
  Plugin::const_get(Bipbip::Helper.name_to_classname(name)).new(name, config, frequency, tags, metric_group)
15
19
  end
16
20
 
21
+ # @param [Bipbip::Plugin] plugin
22
+ # @return [Bipbip::Plugin]
23
+ def self.factory_from_plugin(plugin)
24
+ class_name = plugin.class.name.gsub(/^Bipbip::/, '')
25
+ Bipbip::const_get(class_name).new(plugin.name, plugin.config, plugin.frequency, plugin.tags, plugin.metric_group)
26
+ end
27
+
17
28
  def initialize(name, config, frequency, tags = nil, metric_group = nil)
18
29
  @name = name.to_s
19
30
  @config = config.to_hash
@@ -22,49 +33,30 @@ module Bipbip
22
33
  @metric_group = (metric_group || name).to_s
23
34
  end
24
35
 
36
+ # @param [Array] storages
25
37
  def run(storages)
26
- @pid = fork do
27
- ['INT', 'TERM'].each { |sig| trap(sig) {
28
- Thread.new { interrupt } if !@interrupted
29
- } }
30
-
31
- retry_delay = frequency
32
- begin
33
- until interrupted? do
34
- time = Time.now
35
- data = monitor
36
- if data.empty?
37
- raise "#{name} #{source_identifier}: Empty data"
38
- end
39
- log(Logger::DEBUG, "Data: #{data}")
40
- storages.each do |storage|
41
- storage.store_sample(self, time, data)
42
- end
43
- retry_delay = frequency
44
- interruptible_sleep (frequency - (Time.now - time))
38
+ begin
39
+ timeout = frequency * 2
40
+ while true
41
+ time = Time.now
42
+ Timeout::timeout(timeout, MeasurementTimeout) do
43
+ run_measurement(frequency, storages)
45
44
  end
46
- rescue => e
47
- log_exception(Logger::ERROR, e)
48
- interruptible_sleep retry_delay
49
- retry_delay += frequency if retry_delay < frequency * 10
50
- retry
51
- rescue Exception => e
52
- log_exception(Logger::FATAL, e)
53
- raise e
45
+ interruptible_sleep (frequency - (Time.now - time))
54
46
  end
47
+ rescue MeasurementTimeout => e
48
+ log(Logger::ERROR, "Measurement timeout of #{timeout} seconds reached.")
49
+ retry
50
+ rescue StandardError => e
51
+ log_exception(Logger::ERROR, e)
52
+ interruptible_sleep frequency
53
+ retry
54
+ rescue Exception => e
55
+ log_exception(Logger::FATAL, e)
56
+ raise e
55
57
  end
56
58
  end
57
59
 
58
- def interrupt
59
- log(Logger::INFO, "Interrupting plugin process #{Process.pid}")
60
- @interrupted = true
61
- interrupt_sleep
62
- end
63
-
64
- def interrupted?
65
- @interrupted || Process.getpgid(Process.ppid) != Process.getpgrp
66
- end
67
-
68
60
  def frequency
69
61
  @frequency
70
62
  end
@@ -91,6 +83,17 @@ module Bipbip
91
83
 
92
84
  private
93
85
 
86
+ def run_measurement(time, storages)
87
+ data = monitor
88
+ if data.empty?
89
+ raise "#{name} #{source_identifier}: Empty data"
90
+ end
91
+ log(Logger::DEBUG, "Data: #{data}")
92
+ storages.each do |storage|
93
+ storage.store_sample(self, time, data)
94
+ end
95
+ end
96
+
94
97
  def log(severity, message)
95
98
  Bipbip.logger.add(severity, message, "#{name} #{source_identifier}")
96
99
  end
@@ -1,3 +1,3 @@
1
1
  module Bipbip
2
- VERSION = '0.5.24'
2
+ VERSION = '0.6.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bipbip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.24
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cargo Media
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-03-10 00:00:00.000000000 Z
13
+ date: 2015-04-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: copperegg-revealmetrics
@@ -138,20 +138,6 @@ dependencies:
138
138
  - - "~>"
139
139
  - !ruby/object:Gem::Version
140
140
  version: '1.10'
141
- - !ruby/object:Gem::Dependency
142
- name: process_exists
143
- requirement: !ruby/object:Gem::Requirement
144
- requirements:
145
- - - "~>"
146
- - !ruby/object:Gem::Version
147
- version: 0.1.3
148
- type: :runtime
149
- prerelease: false
150
- version_requirements: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - "~>"
153
- - !ruby/object:Gem::Version
154
- version: 0.1.3
155
141
  - !ruby/object:Gem::Dependency
156
142
  name: rb-inotify
157
143
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +208,7 @@ files:
222
208
  - data/php-opcache-status.php
223
209
  - lib/bipbip.rb
224
210
  - lib/bipbip/agent.rb
211
+ - lib/bipbip/config.rb
225
212
  - lib/bipbip/helper.rb
226
213
  - lib/bipbip/plugin.rb
227
214
  - lib/bipbip/plugin/apache2.rb
@@ -268,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
255
  version: '0'
269
256
  requirements: []
270
257
  rubyforge_project:
271
- rubygems_version: 2.4.5
258
+ rubygems_version: 2.4.6
272
259
  signing_key:
273
260
  specification_version: 4
274
261
  summary: Gather services data and store in CopperEgg