nsa 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 911dad2e98c8f5fbd1f15023ed5c547930c2e2ec
4
+ data.tar.gz: 6c2123585565c8eb5eb41f54a141f3be57431d11
5
+ SHA512:
6
+ metadata.gz: ad14487a0c6ed7a63c8ea14f734775faaa0729412e7dc150601620e967503c20300bb2829901784f275412634c88fd70aff471c62a47e9cf4585b412dbd61764
7
+ data.tar.gz: c6ae6b0d35649f93f735ea3d995f7b8a86bcbd40667f72334e803369ef1c6bc8ac809c4c861f4aa2bce798db5b5acba02587d97686628632a93f02bbd740350a
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nsa.gemspec
4
+ gemspec
@@ -0,0 +1,155 @@
1
+ # NSA (National Statsd Agency)
2
+
3
+ Listen to your Rails ActiveSupport::Notifications and deliver to a Statsd backend.
4
+ Support for writing your own custom collectors.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "nsa"
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install nsa
21
+
22
+ ## Usage
23
+
24
+ NSA comes packaged with collectors for ActionController, ActiveRecord, ActiveSupport Caching,
25
+ and Sidekiq.
26
+
27
+ To use this gem, simply get a reference to a statsd backend, then indicate which
28
+ collectors you'd like to run. Each `collect` method specifies a Collector to use
29
+ and the additional key namespace.
30
+
31
+ ```ruby
32
+ $statsd = ::Statsd.new(ENV["STATSD_HOST"], ENV["STATSD_PORT"])
33
+ application_name = ::Rails.application.class.parent_name.underscore
34
+ application_env = ENV["PLATFORM_ENV"] || ::Rails.env
35
+ $statsd.namespace = [ application_name, application_env ].join(".")
36
+
37
+ ::NSA.inform_statsd($statsd) do |informant|
38
+ # Load :action_controller collector with a key prefix of :web
39
+ informant.collect(:action_controller, :web)
40
+ informant.collect(:active_record, :db)
41
+ informant.collect(:cache, :cache)
42
+ informant.collect(:sidekiq, :sidekiq)
43
+ end
44
+ ```
45
+
46
+ ## Built-in Collectors
47
+
48
+ ### `:action_controller`
49
+
50
+ Listens to: `process_action.action_controller
51
+
52
+ Metrics recorded:
53
+
54
+ + Timing: `{ns}.{prefix}.{controller}.{action}.{format}.total_duration`
55
+ + Timing: `{ns}.{prefix}.{controller}.{action}.{format}.db_time`
56
+ + Timing: `{ns}.{prefix}.{controller}.{action}.{format}.view_time`
57
+ + Increment: `{ns}.{prefix}.{controller}.{action}.{format}.status.{status_code}`
58
+
59
+ ### `:active_record`
60
+
61
+ Listens to: `sql.active_record`
62
+
63
+ Metrics recorded:
64
+
65
+ + Timing: `{ns}.{prefix}.tables.{table_name}.queries.delete.duration`
66
+ + Timing: `{ns}.{prefix}.tables.{table_name}.queries.insert.duration`
67
+ + Timing: `{ns}.{prefix}.tables.{table_name}.queries.select.duration`
68
+ + Timing: `{ns}.{prefix}.tables.{table_name}.queries.update.duration`
69
+
70
+ ### `:active_support_cache`
71
+
72
+ Listens to: `cache_*.active_suppport`
73
+
74
+ Metrics recorded:
75
+
76
+ + Timing: `{ns}.{prefix}.delete.duration`
77
+ + Timing: `{ns}.{prefix}.exist?.duration`
78
+ + Timing: `{ns}.{prefix}.fetch_hit.duration`
79
+ + Timing: `{ns}.{prefix}.generate.duration`
80
+ + Timing: `{ns}.{prefix}.read_hit.duration`
81
+ + Timing: `{ns}.{prefix}.read_miss.duration`
82
+ + Timing: `{ns}.{prefix}.read_miss.duration`
83
+
84
+ ### `:sidekiq`
85
+
86
+ Listens to: Sidekiq middleware, run before each job that is processed
87
+
88
+ Metrics recorded:
89
+
90
+ + Time: `{ns}.{prefix}.{WorkerName}.processing_time`
91
+ + Increment: `{ns}.{prefix}.{WorkerName}.success`
92
+ + Increment: `{ns}.{prefix}.{WorkerName}.failure`
93
+ + Gauge: `{ns}.{prefix}.queues.{queue_name}.enqueued`
94
+ + Gauge: `{ns}.{prefix}.queues.{queue_name}.latency`
95
+ + Gauge: `{ns}.{prefix}.dead_size`
96
+ + Gauge: `{ns}.{prefix}.enqueued`
97
+ + Gauge: `{ns}.{prefix}.failed`
98
+ + Gauge: `{ns}.{prefix}.processed`
99
+ + Gauge: `{ns}.{prefix}.processes_size`
100
+ + Gauge: `{ns}.{prefix}.retry_size`
101
+ + Gauge: `{ns}.{prefix}.scheduled_size`
102
+ + Gauge: `{ns}.{prefix}.workers_size`
103
+
104
+ ## Writing your own collector
105
+
106
+ Writing your own collector is very simple. To take advantage of the keyspace handling you must:
107
+
108
+ 1. Create an object/module which responds to `collect`, taking the `key_prefix` as its only argument.
109
+ 2. Include or extend your class/module with `NSA::Statsd::Publisher`.
110
+
111
+ For example:
112
+
113
+ ```ruby
114
+ module UsersCollector
115
+ extend ::NSA::Statsd::Publisher
116
+
117
+ def self.collect(key_prefix)
118
+ loop do
119
+ statsd_gauge("count", ::User.count)
120
+ sleep 10 # don't do this, obvi
121
+ end
122
+ end
123
+ end
124
+ ```
125
+
126
+ Then let the informant know about it:
127
+
128
+ ```ruby
129
+ # $statsd =
130
+ NSA.inform_statsd($statsd) do |informant|
131
+ # ...
132
+ informant.collect(UserCollector, :users)
133
+ end
134
+ ```
135
+
136
+ The `NSA::Statsd::Publisher` module exposes the following methods:
137
+
138
+ + `statsd_count(key, value = 1, sample_rate = nil)`
139
+ + `statsd_decrement(key, sample_rate = nil)`
140
+ + `statsd_gauge(key, value = 1, sample_rate = nil)`
141
+ + `statsd_increment(key, sample_rate = nil)`
142
+ + `statsd_set(key, value = 1, sample_rate = nil)`
143
+ + `statsd_time(key, sample_rate = nil, &block)`
144
+ + `statsd_timing(key, value = 1, sample_rate = nil)`
145
+
146
+ ## Development
147
+
148
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
149
+
150
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
151
+
152
+ ## Contributing
153
+
154
+ Bug reports and pull requests are welcome on GitHub at https://github.com/localshred/nsa.
155
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nsa"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require "nsa/version"
2
+ require "nsa/statsd_informant"
3
+
4
+ module NSA
5
+
6
+ def self.inform_statsd(backend)
7
+ yield ::NSA::StatsdInformant
8
+ ::NSA::StatsdInformant.listen(backend)
9
+ end
10
+
11
+ end
@@ -0,0 +1,29 @@
1
+ require "active_support/notifications"
2
+ require "nsa/statsd/publisher"
3
+
4
+ module NSA
5
+ module Collectors
6
+ module ActionController
7
+ extend ::NSA::Statsd::Publisher
8
+
9
+ def self.collect(key_prefix)
10
+ ::ActiveSupport::Notifications.subscribe(/process_action.action_controller/) do |*args|
11
+ event = ::ActiveSupport::Notifications::Event.new(*args)
12
+ controller = event.payload[:controller]
13
+ action = event.payload[:action]
14
+ format = event.payload[:format] || "all"
15
+ format = "all" if format == "*/*"
16
+ status = event.payload[:status]
17
+ key = "#{key_prefix}.#{controller}.#{action}.#{format}"
18
+
19
+ statsd_timing("#{key}.total_duration", event.duration)
20
+ statsd_timing("#{key}.db_time", event.payload[:db_runtime])
21
+ statsd_timing("#{key}.view_time", event.payload[:view_runtime])
22
+ statsd_increment("#{key}.status.#{status}")
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,34 @@
1
+ require "nsa/statsd/publisher"
2
+
3
+ module NSA
4
+ module Collectors
5
+ module ActiveRecord
6
+ extend ::NSA::Statsd::Publisher
7
+
8
+ DELETE_SQL_REGEX = /^DELETE.+FROM\s+"([^"]+)"/
9
+ INSERT_SQL_REGEX = /^INSERT INTO\s+"([^"]+)"/
10
+ SELECT_SQL_REGEX = /^SELECT.+FROM\s+"([^"]+)"/
11
+ UPDATE_SQL_REGEX = /^UPDATE\s+"([^"]+)"/
12
+
13
+ def self.collect(key_prefix)
14
+ ::ActiveSupport::Notifications.subscribe("sql.active_record") do |_, start, finish, _id, payload|
15
+ query_type, table_name = case payload[:sql]
16
+ when DELETE_SQL_REGEX then [ :delete, $1 ]
17
+ when INSERT_SQL_REGEX then [ :insert, $1 ]
18
+ when SELECT_SQL_REGEX then [ :select, $1 ]
19
+ when UPDATE_SQL_REGEX then [ :update, $1 ]
20
+ else nil
21
+ end
22
+
23
+ unless query_type.nil?
24
+ stat_name = "#{key_prefix}.tables.#{table_name}.queries.#{query_type}.duration"
25
+ duration_ms = (finish - start) * 1000
26
+ statsd_timing(stat_name, duration_ms)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,37 @@
1
+ require "active_support/notifications"
2
+ require "nsa/statsd/publisher"
3
+
4
+ module NSA
5
+ module Collectors
6
+ module ActiveSupportCache
7
+ extend ::NSA::Statsd::Publisher
8
+
9
+ CACHE_TYPES = {
10
+ "cache_delete.active_support" => :delete,
11
+ "cache_exist?.active_support" => :exist?,
12
+ "cache_fetch_hit.active_support" => :fetch_hit,
13
+ "cache_generate.active_support" => :generate,
14
+ "cache_read.active_support" => :read,
15
+ "cache_write.active_support" => :write,
16
+ }.freeze
17
+
18
+ def self.collect(key_prefix)
19
+ ::ActiveSupport::Notifications.subscribe(/cache_[^.]+.active_support/) do |*event_args|
20
+ event = ::ActiveSupport::Notifications::Event.new(*event_args)
21
+ cache_type = CACHE_TYPES.fetch(event.name) do
22
+ event.name.split(".").first.gsub(/^cache_/, "")
23
+ end
24
+
25
+ if cache_type == :read
26
+ cache_type = event.payload[:hit] ? :read_hit : :read_miss
27
+ end
28
+
29
+ stat_name = "#{key_prefix}.#{cache_type}.duration"
30
+ statsd_timing(stat_name, event.duration)
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,11 @@
1
+ module NSA
2
+ module Collectors
3
+ module Null
4
+
5
+ def self.collect(*_)
6
+ end
7
+
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,72 @@
1
+ require "nsa/statsd/publisher"
2
+
3
+ module NSA
4
+ module Collectors
5
+ class Sidekiq
6
+ include ::NSA::Statsd::Publisher
7
+
8
+ def self.collect(key_prefix)
9
+ require "sidekiq"
10
+
11
+ ::Sidekiq.configure_server do |config|
12
+ config.server_middleware do |chain|
13
+ chain.add(::NSA::Collectors::Sidekiq, key_prefix)
14
+ end
15
+ end
16
+ rescue ::LoadError => exception
17
+ $stderr.puts("[LoadError] Failed to load sidekiq!", exception.message, *(exception.backtrace))
18
+ end
19
+
20
+ attr_accessor :key_prefix
21
+ private :key_prefix=
22
+
23
+ def initialize(key_prefix)
24
+ self.key_prefix = key_prefix.to_s.split(".")
25
+ end
26
+
27
+ def call(worker, message, queue_name)
28
+ worker_name = worker.class.name.tr("::", ".")
29
+
30
+ statsd_time(make_key(worker_name, :processing_time)) do
31
+ yield
32
+ end
33
+
34
+ statsd_increment(make_key(worker_name, :success))
35
+ rescue => exception
36
+ statsd_increment(make_key(worker_name, :failure))
37
+ fail exception
38
+ ensure
39
+ publish_overall_stats
40
+ publish_queue_size_and_latency(queue_name)
41
+ end
42
+
43
+ private
44
+
45
+ def publish_overall_stats
46
+ stats = ::Sidekiq::Stats.new
47
+ statsd_gauge(make_key(:dead_size), stats.dead_size)
48
+ statsd_gauge(make_key(:enqueued), stats.enqueued)
49
+ statsd_gauge(make_key(:failed), stats.failed)
50
+ statsd_gauge(make_key(:processed), stats.processed)
51
+ statsd_gauge(make_key(:processes_size), stats.processes_size)
52
+ statsd_gauge(make_key(:retry_size), stats.retry_size)
53
+ statsd_gauge(make_key(:scheduled_size), stats.scheduled_size)
54
+ statsd_gauge(make_key(:workers_size), stats.workers_size)
55
+ end
56
+
57
+ def publish_queue_size_and_latency(queue_name)
58
+ queue = ::Sidekiq::Queue.new(queue_name)
59
+ statsd_gauge(make_key(:queues, queue_name, :enqueued), queue.size)
60
+
61
+ if queue.respond_to?(:latency)
62
+ statsd_gauge(make_key(:queues, queue_name, :latency), queue.latency)
63
+ end
64
+ end
65
+
66
+ def make_key(*args)
67
+ (key_prefix + args).compact.join(".")
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,44 @@
1
+ module NSA
2
+ module Statsd
3
+ module Publisher
4
+
5
+ def statsd_count(key, value = 1, sample_rate = nil)
6
+ __statsd_publish(:count, key, value, sample_rate)
7
+ end
8
+
9
+ def statsd_decrement(key, sample_rate = nil)
10
+ __statsd_publish(:decrement, key, 1, sample_rate)
11
+ end
12
+
13
+ def statsd_gauge(key, value = 1, sample_rate = nil)
14
+ __statsd_publish(:gauge, key, value, sample_rate)
15
+ end
16
+
17
+ def statsd_increment(key, sample_rate = nil)
18
+ __statsd_publish(:increment, key, 1, sample_rate)
19
+ end
20
+
21
+ def statsd_set(key, value = 1, sample_rate = nil)
22
+ __statsd_publish(:set, key, value, sample_rate)
23
+ end
24
+
25
+ def statsd_time(key, sample_rate = nil, &block)
26
+ __statsd_publish(:time, key, nil, sample_rate, &block)
27
+ end
28
+
29
+ def statsd_timing(key, value = 1, sample_rate = nil)
30
+ __statsd_publish(:timing, key, value, sample_rate)
31
+ end
32
+
33
+ def __statsd_publish(stat_type, key, value = nil, sample_rate = nil, &block)
34
+ payload = { :key => key }
35
+ payload.merge!({ :value => value }) if value
36
+ payload.merge!({ :sample_rate => sample_rate }) if sample_rate
37
+ payload.merge!({ :block => block }) if block_given?
38
+
39
+ ::ActiveSupport::Notifications.instrument("#{stat_type}.statsd", payload)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ module NSA
2
+ module Statsd
3
+ module Subscriber
4
+
5
+ def statsd_subscribe(backend)
6
+ ::ActiveSupport::Notifications.subscribe(/.statsd$/) do |name, start, finish, id, payload|
7
+ __send_event_to_statsd(backend, name, start, finish, id, payload)
8
+ end
9
+ end
10
+
11
+ def __send_event_to_statsd(backend, name, start, finish, id, payload)
12
+ action = name.to_s.split(".").first || :count
13
+
14
+ key_name = payload[:key]
15
+ sample_rate = payload.fetch(:sample_rate, 1)
16
+ block = payload[:block]
17
+
18
+ case action.to_sym
19
+ when :count, :timing, :set, :gauge then
20
+ value = payload.fetch(:value) { 1 }
21
+ backend.__send__(action, key_name, value, sample_rate, &block)
22
+ when :increment, :decrement, :time then
23
+ backend.__send__(action, key_name, sample_rate, &block)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,31 @@
1
+ require "nsa/statsd/subscriber"
2
+
3
+ require "nsa/collectors/action_controller"
4
+ require "nsa/collectors/active_record"
5
+ require "nsa/collectors/active_support_cache"
6
+ require "nsa/collectors/null"
7
+ require "nsa/collectors/sidekiq"
8
+
9
+ module NSA
10
+ module StatsdInformant
11
+ extend ::NSA::Statsd::Subscriber
12
+
13
+ COLLECTOR_TYPES = ::Hash.new(::NSA::Collectors::Null).merge({
14
+ :action_controller => ::NSA::Collectors::ActionController,
15
+ :active_record => ::NSA::Collectors::ActiveRecord,
16
+ :active_support_cache => ::NSA::Collectors::ActiveSupportCache,
17
+ :sidekiq => ::NSA::Collectors::Sidekiq
18
+ }).freeze
19
+
20
+ def self.collect(collector, key_prefix)
21
+ collector = COLLECTOR_TYPES[collector.to_sym] unless collector.respond_to?(:collect)
22
+ collector.collect(key_prefix)
23
+ end
24
+
25
+ def self.listen(backend)
26
+ statsd_subscribe(backend)
27
+ end
28
+
29
+ end
30
+ end
31
+
@@ -0,0 +1,3 @@
1
+ module NSA
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "nsa/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nsa"
8
+ spec.version = ::NSA::VERSION
9
+ spec.authors = ["BJ Neilsen"]
10
+ spec.email = ["bj.neilsen@gmail.com"]
11
+
12
+ spec.summary = %q{Listen to your Rails ActiveSupport::Notifications and deliver to a Statsd backend.}
13
+ spec.description = spec.summary
14
+ spec.homepage = "https://www.github.com/localshred/nsa"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", "~> 4.2.0"
22
+ spec.add_dependency "sidekiq", "~> 3.5.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ spec.add_development_dependency "mocha"
28
+ spec.add_development_dependency "byebug"
29
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nsa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - BJ Neilsen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sidekiq
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mocha
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Listen to your Rails ActiveSupport::Notifications and deliver to a Statsd
112
+ backend.
113
+ email:
114
+ - bj.neilsen@gmail.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".travis.yml"
121
+ - Gemfile
122
+ - README.md
123
+ - Rakefile
124
+ - bin/console
125
+ - bin/setup
126
+ - lib/nsa.rb
127
+ - lib/nsa/collectors/action_controller.rb
128
+ - lib/nsa/collectors/active_record.rb
129
+ - lib/nsa/collectors/active_support_cache.rb
130
+ - lib/nsa/collectors/null.rb
131
+ - lib/nsa/collectors/sidekiq.rb
132
+ - lib/nsa/statsd/publisher.rb
133
+ - lib/nsa/statsd/subscriber.rb
134
+ - lib/nsa/statsd_informant.rb
135
+ - lib/nsa/version.rb
136
+ - nsa.gemspec
137
+ homepage: https://www.github.com/localshred/nsa
138
+ licenses: []
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.4.5
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Listen to your Rails ActiveSupport::Notifications and deliver to a Statsd
160
+ backend.
161
+ test_files: []