collective-metrics 0.1.10 → 0.2.1

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: 379c0c2d2acab801d80078737558b671ca1dae95
4
- data.tar.gz: 30738a23f12a71cdd9ae100364158a30843ab82e
3
+ metadata.gz: 8a1b7942a5478c2d4172906cb5b37a2f6646ab76
4
+ data.tar.gz: ed459633992d33f6d2d1378f689c057515ec9c60
5
5
  SHA512:
6
- metadata.gz: 346d61c9ceab426f7da3ecf1240e45b13202ad1884288a792fe0e34f5cff84adde525f063cf4a3986b12f5772e805fbdbe3415c2769e1f1b16d98d72e1f09aff
7
- data.tar.gz: 721dde8e9e5769c6de1dc8aefce6d64f72cdce8c403daf02ab614ec71e060ff860e706becb4fa91de05539b02319d9c65ffb20d83eab6beb93a220f2be506c5d
6
+ metadata.gz: 6ada75194ab9a260c3d74a5d62a95ddbb5755d9a10d5714fb80012664809d52544f6ceb17cd4596e413e0638ccb9bf8f85e33738ce5876d04ff04184d39680df
7
+ data.tar.gz: d7e65e934cb676c39da634e7a0ce3ae9ed1c7db19b8375f8c1598faebceb120486bb10594127abaf3d14cd5b85eb6148677ccb17c037f57732df632c9218bdd6
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .idea
data/Collectfile CHANGED
@@ -1,3 +1,7 @@
1
1
  use Collective::Collectors::Sidekiq
2
2
  use Collective::Collectors::Redis
3
3
  use Collective::Collectors::Memcached
4
+ unless ENV['NEWRELIC_API_KEY'].nil? || ENV['NEWRELIC_API_KEY'].empty?
5
+ use Collective::Collectors::Newrelic, api_key: ENV['NEWRELIC_API_KEY'], filter: ENV['NEWRELIC_APPLICATION_FILTER']
6
+ end
7
+
data/Gemfile CHANGED
@@ -7,4 +7,5 @@ group :development do
7
7
  gem 'dalli'
8
8
  gem 'sidekiq'
9
9
  gem 'mongoid', '~> 3.0'
10
+ gem 'pg'
10
11
  end
data/lib/collective.rb CHANGED
@@ -8,11 +8,14 @@ module Collective
8
8
  autoload :Builder, 'collective/builder'
9
9
 
10
10
  module Collectors
11
- autoload :Sidekiq, 'collective/collectors/sidekiq'
12
- autoload :Redis, 'collective/collectors/redis'
13
- autoload :Memcached, 'collective/collectors/memcached'
14
- autoload :RabbitMQ, 'collective/collectors/rabbitmq'
15
- autoload :Mongodb, 'collective/collectors/mongodb'
11
+ autoload :Sidekiq, 'collective/collectors/sidekiq'
12
+ autoload :Redis, 'collective/collectors/redis'
13
+ autoload :Memcached, 'collective/collectors/memcached'
14
+ autoload :RabbitMQ, 'collective/collectors/rabbitmq'
15
+ autoload :Mongodb, 'collective/collectors/mongodb'
16
+ autoload :Honeybadger, 'collective/collectors/honeybadger'
17
+ autoload :Newrelic, 'collective/collectors/newrelic'
18
+ autoload :PGBouncer, 'collective/collectors/pgbouncer'
16
19
  end
17
20
 
18
21
  class << self
@@ -0,0 +1,62 @@
1
+ module Collective::Collectors
2
+ class Honeybadger < Collective::Collector
3
+ requires :faraday
4
+ requires :faraday_middleware
5
+ requires :json
6
+
7
+ resolution '60s'
8
+
9
+ collect do
10
+ instrument_exceptions
11
+ end
12
+
13
+ private
14
+
15
+ def instrument_exceptions
16
+ each_result('/v1/projects') do |project|
17
+ id = project['id']
18
+ totals_by_env = Hash.new { |hash, key| hash[key] = 0 }
19
+
20
+ each_result("/v1/projects/#{id}/faults", resolved: 'f') do |fault|
21
+ totals_by_env[fault['environment']] += fault['notices_count']
22
+ end
23
+
24
+ totals_by_env.each do |env, total|
25
+ instrument 'honeybadger.faults.notices', total, source: "%s.%s" % [project['name'], env], type: 'count'
26
+ end
27
+ end
28
+ end
29
+
30
+ def each_result(path, params={})
31
+ page = 1
32
+ resp = get_page(path, params, page)
33
+
34
+ while resp.body['num_pages'] > page do
35
+ resp.body['results'].each do |obj|
36
+ yield obj
37
+ end
38
+ page += 1
39
+ resp = get_page(path, params, page)
40
+ end
41
+ end
42
+
43
+ def get_page(path, params, page)
44
+ client.get(path, params.merge(auth_token: auth_token, page: page))
45
+ end
46
+
47
+ def client
48
+ @client ||= Faraday.new(url) do |builder|
49
+ builder.response :json, content_type: /\bjson$/
50
+ builder.adapter Faraday.default_adapter
51
+ end
52
+ end
53
+
54
+ def url
55
+ "https://api.honeybadger.io"
56
+ end
57
+
58
+ def auth_token
59
+ options[:auth_token]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,96 @@
1
+ module Collective::Collectors
2
+ class Newrelic < Collective::Collector
3
+ requires :faraday
4
+ requires :faraday_middleware
5
+ requires :json
6
+
7
+ resolution '60s'
8
+
9
+ collect do
10
+ instrument_applications 'newrelic'
11
+ instrument_key_transactions 'newrelic'
12
+ end
13
+
14
+ private
15
+
16
+ def instrument_applications(prefix)
17
+ paged('/v2/applications.json', 'applications').each do |app|
18
+ next unless app['name'].include? filter
19
+ next unless app['reporting']
20
+
21
+ group "#{prefix}.#{app['name']}" do |group|
22
+ instrument_apdex group, app
23
+ end
24
+ end
25
+ end
26
+
27
+ def instrument_key_transactions(prefix)
28
+ # max_pages is a workaround for a new relic bug, it's currently returning the first page
29
+ # if you ask for a non-existent page instead of returning an empty list (as it
30
+ # does for /v2/applications.json)
31
+ paged('/v2/key_transactions.json', 'key_transactions', max_pages=1).each do |key_transaction|
32
+ # Not sure if the names are quoted, replace
33
+ sanitized_name = key_transaction['name'].gsub(/ /, '_')
34
+ group "#{prefix}.key.#{sanitized_name}" do |group|
35
+ instrument_apdex group, key_transaction
36
+ end
37
+ end
38
+ end
39
+
40
+ # Given an `info` hash that contains appdex summaries, instruments the
41
+ # application and browser appdex scores
42
+ def instrument_apdex(group, info)
43
+ if info.include? 'application_summary'
44
+ group.instrument 'response_time', info['application_summary']['response_time'], units: 'ms'
45
+ group.instrument 'apdex_score', info['application_summary']['apdex_score']
46
+ end
47
+ if info.include? 'end_user_summary'
48
+ group.group 'browser' do |group|
49
+ group.instrument 'response_time', info['end_user_summary']['response_time'], units: 's'
50
+ group.instrument 'apdex_score', info['end_user_summary']['apdex_score']
51
+ end
52
+ end
53
+ end
54
+
55
+ # Pages through items specified by `json_key` and yields them one at a time
56
+ def paged(path, json_key, max_pages=3)
57
+ Enumerator.new do |yielder|
58
+ page = 1
59
+ resp = get path, page: page
60
+ while resp.body[json_key].length > 0 && page <= max_pages do
61
+ resp.body[json_key].each { |obj| yielder.yield obj }
62
+ page += 1
63
+ resp = get path, page: page
64
+ end
65
+ end
66
+ end
67
+
68
+ # Make an authenticated get request to the new relic api
69
+ def get(path, options={})
70
+ client.get(path, options) do |req|
71
+ req.headers['X-Api-Key'] = api_key
72
+ end
73
+ end
74
+
75
+ def client
76
+ @client ||= Faraday.new(api_url) do |builder|
77
+ builder.response :json, content_type: /\bjson$/
78
+ builder.response :raise_error
79
+ builder.adapter Faraday.default_adapter
80
+ end
81
+ end
82
+
83
+ def api_key
84
+ options[:api_key]
85
+ end
86
+
87
+ def api_url
88
+ options[:api_url] || 'https://api.newrelic.com/'
89
+ end
90
+
91
+ # Specify to filter only applications whose name contains this string
92
+ def filter
93
+ options[:filter] || ''
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,41 @@
1
+ module Collective::Collectors
2
+ class PGBouncer < Collective::Collector
3
+ requires :pg
4
+
5
+ collect do
6
+ group 'pgbouncer' do |group|
7
+ instrument group, 'stats'
8
+ instrument group, 'pools'
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def instrument(group, thing)
15
+ group.group thing do |group|
16
+ instrument_tuples group, show(thing)
17
+ end
18
+ end
19
+
20
+ def show(thing)
21
+ conn.exec "show #{thing};"
22
+ end
23
+
24
+ def instrument_tuples(group, tuples)
25
+ tuples.each do |tuple|
26
+ source = tuple.key?('database') ? tuple['database'] : ''
27
+ tuple.each do |k,v|
28
+ group.instrument(k, v, source: source) if instrumentable?(v)
29
+ end
30
+ end
31
+ end
32
+
33
+ def conn
34
+ @conn ||= PG.connect(connection_options)
35
+ end
36
+
37
+ def connection_options
38
+ (options[:connection] || {}).merge(dbname: 'pgbouncer')
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Collective
2
- VERSION = '0.1.10'
2
+ VERSION = '0.2.1'
3
3
  end
metadata CHANGED
@@ -1,131 +1,131 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: collective-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric J. Holmes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-11 00:00:00.000000000 Z
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rufus-scheduler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.18'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.18'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: formatted-metrics
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.2.1
48
- - - <
48
+ - - "<"
49
49
  - !ruby/object:Gem::Version
50
50
  version: '2.0'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - '>='
55
+ - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: 0.2.1
58
- - - <
58
+ - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '2.0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: faraday
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - '>='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - '>='
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: faraday_middleware
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - '>='
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - '>='
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: bundler
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ~>
93
+ - - "~>"
94
94
  - !ruby/object:Gem::Version
95
95
  version: '1.3'
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ~>
100
+ - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '1.3'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: rake
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - '>='
107
+ - - ">="
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - '>='
114
+ - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: rspec
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - '>='
121
+ - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  type: :development
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - '>='
128
+ - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  description: Collect and output metrics
@@ -136,7 +136,7 @@ executables:
136
136
  extensions: []
137
137
  extra_rdoc_files: []
138
138
  files:
139
- - .gitignore
139
+ - ".gitignore"
140
140
  - Collectfile
141
141
  - Gemfile
142
142
  - LICENSE.txt
@@ -150,8 +150,11 @@ files:
150
150
  - lib/collective/cli.rb
151
151
  - lib/collective/collector.rb
152
152
  - lib/collective/collector/dsl.rb
153
+ - lib/collective/collectors/honeybadger.rb
153
154
  - lib/collective/collectors/memcached.rb
154
155
  - lib/collective/collectors/mongodb.rb
156
+ - lib/collective/collectors/newrelic.rb
157
+ - lib/collective/collectors/pgbouncer.rb
155
158
  - lib/collective/collectors/rabbitmq.rb
156
159
  - lib/collective/collectors/redis.rb
157
160
  - lib/collective/collectors/sidekiq.rb
@@ -166,17 +169,17 @@ require_paths:
166
169
  - lib
167
170
  required_ruby_version: !ruby/object:Gem::Requirement
168
171
  requirements:
169
- - - '>='
172
+ - - ">="
170
173
  - !ruby/object:Gem::Version
171
174
  version: '0'
172
175
  required_rubygems_version: !ruby/object:Gem::Requirement
173
176
  requirements:
174
- - - '>='
177
+ - - ">="
175
178
  - !ruby/object:Gem::Version
176
179
  version: '0'
177
180
  requirements: []
178
181
  rubyforge_project:
179
- rubygems_version: 2.0.14
182
+ rubygems_version: 2.4.5
180
183
  signing_key:
181
184
  specification_version: 4
182
185
  summary: Collect and output metrics