bipbip 0.5.24 → 0.6.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.
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