bipbip 0.6.7 → 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/bin/bipbip +5 -6
- data/lib/bipbip.rb +6 -2
- data/lib/bipbip/agent.rb +2 -5
- data/lib/bipbip/config.rb +4 -7
- data/lib/bipbip/helper.rb +1 -2
- data/lib/bipbip/plugin.rb +21 -29
- data/lib/bipbip/plugin/apache2.rb +4 -6
- data/lib/bipbip/plugin/command.rb +10 -13
- data/lib/bipbip/plugin/elasticsearch.rb +56 -59
- data/lib/bipbip/plugin/fastcgi_php_apc.rb +4 -6
- data/lib/bipbip/plugin/fastcgi_php_fpm.rb +5 -7
- data/lib/bipbip/plugin/fastcgi_php_opcache.rb +15 -17
- data/lib/bipbip/plugin/gearman.rb +4 -6
- data/lib/bipbip/plugin/log_parser.rb +11 -15
- data/lib/bipbip/plugin/memcached.rb +5 -7
- data/lib/bipbip/plugin/mongodb.rb +39 -37
- data/lib/bipbip/plugin/monit.rb +12 -13
- data/lib/bipbip/plugin/mysql.rb +21 -23
- data/lib/bipbip/plugin/network.rb +3 -5
- data/lib/bipbip/plugin/nginx.rb +11 -13
- data/lib/bipbip/plugin/php_apc.rb +4 -6
- data/lib/bipbip/plugin/postfix.rb +2 -4
- data/lib/bipbip/plugin/puppet.rb +16 -18
- data/lib/bipbip/plugin/redis.rb +9 -11
- data/lib/bipbip/plugin/resque.rb +9 -9
- data/lib/bipbip/plugin/socket_redis.rb +7 -8
- data/lib/bipbip/storage.rb +5 -8
- data/lib/bipbip/storage/copperegg.rb +8 -11
- data/lib/bipbip/version.rb +1 -1
- data/lib/interruptible_sleep.rb +1 -1
- metadata +17 -3
@@ -1,11 +1,9 @@
|
|
1
1
|
module Bipbip
|
2
|
-
|
3
2
|
class Plugin::FastcgiPhpApc < Plugin
|
4
|
-
|
5
3
|
def metrics_schema
|
6
4
|
[
|
7
|
-
|
8
|
-
|
5
|
+
{ name: 'opcode_mem_size', type: 'gauge', unit: 'b' },
|
6
|
+
{ name: 'user_mem_size', type: 'gauge', unit: 'b' }
|
9
7
|
]
|
10
8
|
end
|
11
9
|
|
@@ -21,10 +19,10 @@ module Bipbip
|
|
21
19
|
ENV.replace(env_backup)
|
22
20
|
|
23
21
|
body = response.split(/\r?\n\r?\n/)[1]
|
24
|
-
|
22
|
+
fail "FastCGI response has no body: #{response}" unless body
|
25
23
|
stats = JSON.parse(body)
|
26
24
|
|
27
|
-
{:
|
25
|
+
{ opcode_mem_size: stats['opcode_mem_size'].to_i, user_mem_size: stats['user_mem_size'].to_i }
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module Bipbip
|
2
|
-
|
3
2
|
class Plugin::FastcgiPhpFpm < Plugin
|
4
|
-
|
5
3
|
def metrics_schema
|
6
4
|
[
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
{ name: 'accepted conn', type: 'counter', unit: 'Connections' },
|
6
|
+
{ name: 'listen queue', type: 'gauge', unit: 'Connections' },
|
7
|
+
{ name: 'active processes', type: 'gauge', unit: 'Processes' }
|
10
8
|
]
|
11
9
|
end
|
12
10
|
|
@@ -23,10 +21,10 @@ module Bipbip
|
|
23
21
|
ENV.replace(env_backup)
|
24
22
|
|
25
23
|
body = response.split(/\r?\n\r?\n/)[1]
|
26
|
-
|
24
|
+
fail "FastCGI response has no body: #{response}" unless body
|
27
25
|
status = JSON.parse(body)
|
28
26
|
|
29
|
-
status.reject{|k,
|
27
|
+
status.reject { |k, _v| !metrics_names.include?(k) }
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
module Bipbip
|
2
|
-
|
3
2
|
class Plugin::FastcgiPhpOpcache < Plugin
|
4
|
-
|
5
3
|
def metrics_schema
|
6
4
|
[
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
{ name: 'free_memory', type: 'gauge', unit: 'b' },
|
6
|
+
{ name: 'current_wasted_percentage', type: 'gauge', unit: '%' },
|
7
|
+
{ name: 'num_cached_keys', type: 'gauge', unit: 'Keys' },
|
8
|
+
{ name: 'hit_rate', type: 'gauge', unit: '%' },
|
9
|
+
{ name: 'misses', type: 'counter', unit: 'Misses' },
|
10
|
+
{ name: 'hits', type: 'counter', unit: 'Hits' },
|
11
|
+
{ name: 'oom_restarts', type: 'counter', unit: 'Restarts' }
|
14
12
|
]
|
15
13
|
end
|
16
14
|
|
@@ -26,7 +24,7 @@ module Bipbip
|
|
26
24
|
ENV.replace(env_backup)
|
27
25
|
|
28
26
|
body = response.split(/\r?\n\r?\n/)[1]
|
29
|
-
|
27
|
+
fail "FastCGI response has no body: #{response}" unless body
|
30
28
|
stats = JSON.parse(body)
|
31
29
|
@data_previous ||= stats
|
32
30
|
|
@@ -36,13 +34,13 @@ module Bipbip
|
|
36
34
|
|
37
35
|
@data_previous = stats
|
38
36
|
{
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
free_memory: stats_memory['free_memory'].to_i,
|
38
|
+
current_wasted_percentage: stats_memory['current_wasted_percentage'].to_i,
|
39
|
+
num_cached_keys: stats_statistics['num_cached_keys'].to_i,
|
40
|
+
hit_rate: hit_rate,
|
41
|
+
misses: stats_statistics['misses'].to_i,
|
42
|
+
hits: stats_statistics['hits'].to_i,
|
43
|
+
oom_restarts: stats_statistics['oom_restarts'].to_i
|
46
44
|
}
|
47
45
|
end
|
48
46
|
|
@@ -3,12 +3,10 @@ class GearmanServer < Gearman::Server
|
|
3
3
|
end
|
4
4
|
|
5
5
|
module Bipbip
|
6
|
-
|
7
6
|
class Plugin::Gearman < Plugin
|
8
|
-
|
9
7
|
def metrics_schema
|
10
8
|
[
|
11
|
-
|
9
|
+
{ name: 'jobs_queued_total', type: 'gauge', unit: 'Jobs' }
|
12
10
|
]
|
13
11
|
end
|
14
12
|
|
@@ -17,13 +15,13 @@ module Bipbip
|
|
17
15
|
stats = gearman.status
|
18
16
|
|
19
17
|
jobs_queued_total = 0
|
20
|
-
stats.each do |
|
21
|
-
data.each do |queue,
|
18
|
+
stats.each do |_function_name, data|
|
19
|
+
data.each do |queue, _stats|
|
22
20
|
jobs_queued_total += queue.to_i
|
23
21
|
end
|
24
22
|
end
|
25
23
|
|
26
|
-
{:jobs_queued_total
|
24
|
+
{ jobs_queued_total: jobs_queued_total }
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -1,12 +1,10 @@
|
|
1
1
|
require 'rb-inotify'
|
2
2
|
|
3
3
|
module Bipbip
|
4
|
-
|
5
4
|
class Plugin::LogParser < Plugin
|
6
|
-
|
7
5
|
def metrics_schema
|
8
6
|
config['matchers'].map do |matcher|
|
9
|
-
{:
|
7
|
+
{ name: matcher['name'], type: 'gauge', unit: 'Boolean' }
|
10
8
|
end
|
11
9
|
end
|
12
10
|
|
@@ -14,7 +12,7 @@ module Bipbip
|
|
14
12
|
begin
|
15
13
|
io = IO.select([notifier.to_io], [], [], 0)
|
16
14
|
rescue Errno::EBADF => e
|
17
|
-
log(Logger::WARN,
|
15
|
+
log(Logger::WARN, 'Selecting from inotify IO gives EBADF, resetting notifier')
|
18
16
|
reset_notifier
|
19
17
|
end
|
20
18
|
|
@@ -35,7 +33,7 @@ module Bipbip
|
|
35
33
|
config['matchers'].map do |matcher|
|
36
34
|
name = matcher['name']
|
37
35
|
regexp = Regexp.new(matcher['regexp'])
|
38
|
-
value = lines.
|
36
|
+
value = lines.count { |line| !line.match(regexp).nil? }
|
39
37
|
[name, value]
|
40
38
|
end
|
41
39
|
]
|
@@ -46,7 +44,7 @@ module Bipbip
|
|
46
44
|
def notifier
|
47
45
|
if @notifier.nil?
|
48
46
|
file_stat = File.stat(config['path'])
|
49
|
-
|
47
|
+
fail "Cannot read file `#{config['path']}`" unless file_stat.readable?
|
50
48
|
@lines = []
|
51
49
|
@size = file_stat.size
|
52
50
|
@notifier = create_notifier
|
@@ -70,15 +68,14 @@ module Bipbip
|
|
70
68
|
end
|
71
69
|
|
72
70
|
def reset_notifier
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
@notifier = nil
|
71
|
+
return if @notifier.nil?
|
72
|
+
@notifier.stop
|
73
|
+
begin
|
74
|
+
@notifier.close
|
75
|
+
rescue SystemCallError => e
|
76
|
+
log(Logger::WARN, "Cannot close notifier: `#{e.message}`")
|
81
77
|
end
|
78
|
+
@notifier = nil
|
82
79
|
end
|
83
80
|
|
84
81
|
def roll_file
|
@@ -90,6 +87,5 @@ module Bipbip
|
|
90
87
|
end
|
91
88
|
file.close
|
92
89
|
end
|
93
|
-
|
94
90
|
end
|
95
91
|
end
|
@@ -3,16 +3,14 @@ class MemcachedClient < Memcached
|
|
3
3
|
end
|
4
4
|
|
5
5
|
module Bipbip
|
6
|
-
|
7
6
|
class Plugin::Memcached < Plugin
|
8
|
-
|
9
7
|
def metrics_schema
|
10
8
|
[
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
{ name: 'cmd_get', type: 'counter' },
|
10
|
+
{ name: 'cmd_set', type: 'counter' },
|
11
|
+
{ name: 'get_misses', type: 'counter' },
|
12
|
+
{ name: 'bytes', type: 'gauge', unit: 'b' },
|
13
|
+
{ name: 'evictions', type: 'counter' }
|
16
14
|
]
|
17
15
|
end
|
18
16
|
|
@@ -1,28 +1,26 @@
|
|
1
1
|
require 'mongo'
|
2
2
|
|
3
3
|
module Bipbip
|
4
|
-
|
5
4
|
class Plugin::Mongodb < Plugin
|
6
|
-
|
7
5
|
def metrics_schema
|
8
6
|
[
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
7
|
+
{ name: 'flushing_last_ms', type: 'gauge', unit: 'ms' },
|
8
|
+
{ name: 'btree_misses', type: 'gauge', unit: 'misses' },
|
9
|
+
{ name: 'op_inserts', type: 'counter' },
|
10
|
+
{ name: 'op_queries', type: 'counter' },
|
11
|
+
{ name: 'op_updates', type: 'counter' },
|
12
|
+
{ name: 'op_deletes', type: 'counter' },
|
13
|
+
{ name: 'op_getmores', type: 'counter' },
|
14
|
+
{ name: 'op_commands', type: 'counter' },
|
15
|
+
{ name: 'connections_current', type: 'gauge' },
|
16
|
+
{ name: 'mem_resident', type: 'gauge', unit: 'MB' },
|
17
|
+
{ name: 'mem_mapped', type: 'gauge', unit: 'MB' },
|
18
|
+
{ name: 'mem_pagefaults', type: 'counter', unit: 'faults' },
|
19
|
+
{ name: 'globalLock_currentQueue', type: 'gauge' },
|
20
|
+
{ name: 'replication_lag', type: 'gauge', unit: 'Seconds' },
|
21
|
+
{ name: 'slow_queries_count', type: 'gauge_f', unit: 'Queries' },
|
22
|
+
{ name: 'slow_queries_time_avg', type: 'gauge_f', unit: 'Seconds' },
|
23
|
+
{ name: 'slow_queries_time_max', type: 'gauge_f', unit: 'Seconds' }
|
26
24
|
]
|
27
25
|
end
|
28
26
|
|
@@ -64,7 +62,7 @@ module Bipbip
|
|
64
62
|
end
|
65
63
|
|
66
64
|
data['slow_queries_count'] = slow_queries_status['total']['count']
|
67
|
-
data['slow_queries_time_avg'] = slow_queries_status['total']['
|
65
|
+
data['slow_queries_time_avg'] = slow_queries_status['total']['time'].to_f / (slow_queries_status['total']['count'].to_f.nonzero? || 1)
|
68
66
|
data['slow_queries_time_max'] = slow_queries_status['max']['time']
|
69
67
|
|
70
68
|
data
|
@@ -79,10 +77,10 @@ module Bipbip
|
|
79
77
|
# @return [Mongo::Client]
|
80
78
|
def mongodb_client
|
81
79
|
options = {
|
82
|
-
|
83
|
-
|
80
|
+
'hostname' => 'localhost',
|
81
|
+
'port' => 27_017
|
84
82
|
}.merge(config)
|
85
|
-
@mongodb_client ||= Mongo::Client.new([options['hostname'] + ':' + options['port'].to_s], :
|
83
|
+
@mongodb_client ||= Mongo::Client.new([options['hostname'] + ':' + options['port'].to_s], socket_timeout: 2, slave_ok: true)
|
86
84
|
end
|
87
85
|
|
88
86
|
# @return [Mongo::DB]
|
@@ -109,30 +107,34 @@ module Bipbip
|
|
109
107
|
timestamp_last_check = slow_query_last_check
|
110
108
|
time_period = Time.now - timestamp_last_check
|
111
109
|
|
112
|
-
database_names_ignore =
|
110
|
+
database_names_ignore = %w(admin system local)
|
113
111
|
database_list = (mongodb_client.database_names - database_names_ignore).map { |name| mongodb_database(name) }
|
114
112
|
|
115
|
-
stats = database_list.reduce(
|
116
|
-
|
113
|
+
stats = database_list.reduce('total' => { 'count' => 0, 'time' => 0 }, 'max' => { 'time' => 0 }) do |memo, database|
|
117
114
|
results = database['system.profile'].find.aggregate(
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
115
|
+
[
|
116
|
+
{ '$match' => { 'millis' => { '$gte' => slow_query_threshold }, 'ts' => { '$gt' => timestamp_last_check } } },
|
117
|
+
{ '$group' => {
|
118
|
+
'_id' => 'null',
|
119
|
+
'total_count' => { '$sum' => 1 },
|
120
|
+
'total_time' => { '$sum' => '$millis' },
|
121
|
+
'max_time' => { '$max' => '$millis' }
|
122
|
+
} }
|
123
|
+
])
|
122
124
|
|
123
125
|
unless results.count == 0
|
124
126
|
result = results.first
|
125
|
-
max_time = result['max_time'].to_f/1000
|
127
|
+
max_time = result['max_time'].to_f / 1000
|
126
128
|
|
127
129
|
memo['total']['count'] += result['total_count']
|
128
|
-
memo['total']['time'] += result['total_time'].to_f/1000
|
130
|
+
memo['total']['time'] += result['total_time'].to_f / 1000
|
129
131
|
memo['max']['time'] = max_time if memo['max']['time'] < max_time
|
130
132
|
end
|
131
133
|
|
132
134
|
memo
|
133
135
|
end
|
134
136
|
|
135
|
-
stats['total'].each { |metric, value| stats['total'][metric] = value/time_period }
|
137
|
+
stats['total'].each { |metric, value| stats['total'][metric] = value / time_period }
|
136
138
|
|
137
139
|
stats
|
138
140
|
end
|
@@ -140,11 +142,11 @@ module Bipbip
|
|
140
142
|
def replication_lag
|
141
143
|
status = fetch_replica_status
|
142
144
|
member_list = status['members']
|
143
|
-
primary = member_list.
|
144
|
-
secondary = member_list.
|
145
|
+
primary = member_list.find { |member| member['stateStr'] == 'PRIMARY' }
|
146
|
+
secondary = member_list.find { |member| member['stateStr'] == 'SECONDARY' && member['self'] == true }
|
145
147
|
|
146
|
-
|
147
|
-
|
148
|
+
fail "No primary member in replica `#{status['set']}`" if primary.nil?
|
149
|
+
fail "Cannot find itself as secondary member in replica `#{status['set']}`" if secondary.nil?
|
148
150
|
|
149
151
|
(secondary['optime'].seconds - primary['optime'].seconds)
|
150
152
|
end
|
data/lib/bipbip/plugin/monit.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'monit'
|
2
2
|
|
3
3
|
module Bipbip
|
4
|
-
|
5
4
|
class Plugin::Monit < Plugin
|
6
|
-
|
7
5
|
# See https://bitbucket.org/tildeslash/monit/src/d60968cf7972cc902e5b6e2961d44456e1d9b736/src/monit.h?at=master#monit.h-145
|
8
6
|
STATE_FAILED = '1'
|
9
7
|
|
@@ -12,27 +10,28 @@ module Bipbip
|
|
12
10
|
|
13
11
|
def metrics_schema
|
14
12
|
[
|
15
|
-
|
16
|
-
|
13
|
+
{ name: 'Running', type: 'gauge', unit: 'Boolean' },
|
14
|
+
{ name: 'All_Services_ok', type: 'gauge', unit: 'Boolean' }
|
17
15
|
]
|
18
16
|
end
|
19
17
|
|
20
18
|
def monitor
|
21
|
-
status =
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
19
|
+
status = ::Monit::Status.new({
|
20
|
+
host: 'localhost',
|
21
|
+
port: 2812,
|
22
|
+
ssl: false,
|
23
|
+
auth: false,
|
24
|
+
username: nil,
|
25
|
+
password: nil
|
28
26
|
}.merge(config))
|
29
27
|
|
30
28
|
data = Hash.new(0)
|
31
29
|
|
32
30
|
begin
|
33
31
|
data['Running'] = status.get ? 1 : 0
|
34
|
-
data['All_Services_ok'] = status.services.any?
|
35
|
-
service.monitor == MONITOR_NOT || service.status == STATE_FAILED
|
32
|
+
data['All_Services_ok'] = status.services.any? do |service|
|
33
|
+
service.monitor == MONITOR_NOT || service.status == STATE_FAILED
|
34
|
+
end ? 0 : 1
|
36
35
|
rescue
|
37
36
|
data['Running'] = 0
|
38
37
|
data['All_Services_ok'] = 0
|
data/lib/bipbip/plugin/mysql.rb
CHANGED
@@ -1,43 +1,41 @@
|
|
1
1
|
require 'mysql2'
|
2
2
|
|
3
3
|
module Bipbip
|
4
|
-
|
5
4
|
class Plugin::Mysql < Plugin
|
6
|
-
|
7
5
|
def metrics_schema
|
8
6
|
[
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
{ name: 'Max_used_connections', type: 'gauge', unit: 'Connections' },
|
8
|
+
{ name: 'Connections', type: 'counter', unit: 'Connections' },
|
9
|
+
{ name: 'Threads_connected', type: 'gauge', unit: 'Threads' },
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
{ name: 'Slave_running', type: 'gauge', unit: 'Boolean' },
|
12
|
+
{ name: 'Seconds_Behind_Master', type: 'gauge', unit: 'Seconds' },
|
15
13
|
|
16
|
-
|
14
|
+
{ name: 'Created_tmp_disk_tables', type: 'counter', unit: 'Tables' },
|
17
15
|
|
18
|
-
|
19
|
-
|
16
|
+
{ name: 'Queries', type: 'counter', unit: 'Queries' },
|
17
|
+
{ name: 'Slow_queries', type: 'counter', unit: 'Queries' },
|
20
18
|
|
21
|
-
|
22
|
-
|
19
|
+
{ name: 'Table_locks_immediate', type: 'counter', unit: 'Locks' },
|
20
|
+
{ name: 'Table_locks_waited', type: 'counter', unit: 'Locks' },
|
23
21
|
|
24
|
-
|
25
|
-
|
22
|
+
{ name: 'Processlist', type: 'gauge', unit: 'Processes' },
|
23
|
+
{ name: 'Processlist_Locked', type: 'gauge', unit: 'Processes' },
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
{ name: 'Com_select', type: 'counter', unit: 'Commands' },
|
26
|
+
{ name: 'Com_delete', type: 'counter', unit: 'Commands' },
|
27
|
+
{ name: 'Com_insert', type: 'counter', unit: 'Commands' },
|
28
|
+
{ name: 'Com_update', type: 'counter', unit: 'Commands' },
|
29
|
+
{ name: 'Com_replace', type: 'counter', unit: 'Commands' }
|
32
30
|
]
|
33
31
|
end
|
34
32
|
|
35
33
|
def monitor
|
36
34
|
mysql = Mysql2::Client.new(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
host: config['hostname'],
|
36
|
+
port: config['port'],
|
37
|
+
username: config['username'],
|
38
|
+
password: config['password']
|
41
39
|
)
|
42
40
|
|
43
41
|
stats = Hash.new(0)
|