datadog-notifications 0.3.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 +7 -0
- data/.editorconfig +9 -0
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/MIT-LICENCE +22 -0
- data/README.md +34 -0
- data/Rakefile +20 -0
- data/datadog-notifications.gemspec +29 -0
- data/lib/datadog-notifications.rb +1 -0
- data/lib/datadog/notifications.rb +77 -0
- data/lib/datadog/notifications/config.rb +35 -0
- data/lib/datadog/notifications/plugins.rb +10 -0
- data/lib/datadog/notifications/plugins/action_controller.rb +39 -0
- data/lib/datadog/notifications/plugins/active_job.rb +33 -0
- data/lib/datadog/notifications/plugins/active_record.rb +43 -0
- data/lib/datadog/notifications/plugins/base.rb +13 -0
- data/lib/datadog/notifications/plugins/grape.rb +43 -0
- data/lib/datadog/notifications/reporter.rb +6 -0
- data/lib/datadog/notifications/version.rb +5 -0
- data/spec/datadog/notifications/config_spec.rb +15 -0
- data/spec/datadog/notifications/plugins/active_record_spec.rb +26 -0
- data/spec/datadog/notifications/plugins/grape_spec.rb +62 -0
- data/spec/datadog/notifications_spec.rb +33 -0
- data/spec/spec_helper.rb +66 -0
- metadata +198 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fadcae3b1ef25818ba7aa40d9da48019e1ce3f40
|
4
|
+
data.tar.gz: b64e1b4672ed2cfaea03590f1ba4fd7e1e6e2d1e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4fb5671f2f94651db09531be28a407eddb4ab75cbcc8ccf36639fd01d40acd4eec2c335d4cd365c5611531c688b742b34871b73014440272c759ce894e4e505
|
7
|
+
data.tar.gz: a7ae41851bfbbb16463b6f73d92f3e548147d22691819e6afd7416edb33a7669f501dba35ef268c3f7797f199ac41fdcb70fe4faaabbd8487653ab166d7be98d
|
data/.editorconfig
ADDED
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/MIT-LICENCE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Black Square Media
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
datadog-notifications
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Datadog intrumentation for [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html).
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'datadog-notifications'
|
11
|
+
|
12
|
+
Or install:
|
13
|
+
|
14
|
+
$ gem install datadog-notifications
|
15
|
+
|
16
|
+
Configure it in an initializer:
|
17
|
+
|
18
|
+
Datadog::Notifications.configure do |c|
|
19
|
+
c.hostname = "my-host"
|
20
|
+
c.tags = ["my:tag"]
|
21
|
+
|
22
|
+
c.use Datadog::Notifications::Plugins::ActionController
|
23
|
+
c.use Datadog::Notifications::Plugins::ActiveRecord, tags: ["more:tags"]
|
24
|
+
end
|
25
|
+
|
26
|
+
For full configuration options, please see the [Documentation](http://www.rubydoc.info/gems/datadog-notifications).
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
1. Fork it
|
31
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
32
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
33
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
34
|
+
5. Make a pull request
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rake'
|
12
|
+
|
13
|
+
require 'rspec/core'
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
|
16
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
17
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
18
|
+
end
|
19
|
+
|
20
|
+
task :default => :spec
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'datadog/notifications/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "datadog-notifications"
|
8
|
+
s.version = Datadog::Notifications::VERSION.dup
|
9
|
+
s.authors = ["Dimitrij Denissenko"]
|
10
|
+
s.email = ["dimitrij@blacksquaremedia.com"]
|
11
|
+
s.description = %q{Datadog instrumnetation for ActiveSupport::Notifications}
|
12
|
+
s.summary = %q{Generic ActiveSupport::Notifications Datadog handler}
|
13
|
+
s.homepage = "https://github.com/bsm/datadog-notifications"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split($/)
|
16
|
+
s.test_files = s.files.grep(%r{^(spec)/})
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency(%q<activesupport>)
|
20
|
+
s.add_runtime_dependency(%q<dogstatsd-ruby>)
|
21
|
+
|
22
|
+
s.add_development_dependency(%q<rack-test>)
|
23
|
+
s.add_development_dependency(%q<grape>)
|
24
|
+
s.add_development_dependency(%q<sqlite3>)
|
25
|
+
s.add_development_dependency(%q<activerecord>)
|
26
|
+
s.add_development_dependency(%q<rake>)
|
27
|
+
s.add_development_dependency(%q<bundler>)
|
28
|
+
s.add_development_dependency(%q<rspec>)
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "datadog/notifications"
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'statsd'
|
2
|
+
require 'socket'
|
3
|
+
require 'singleton'
|
4
|
+
require 'active_support/notifications'
|
5
|
+
require 'active_support/core_ext/string/inflections'
|
6
|
+
|
7
|
+
require 'datadog/notifications/version'
|
8
|
+
require 'datadog/notifications/reporter'
|
9
|
+
require 'datadog/notifications/config'
|
10
|
+
require 'datadog/notifications/plugins'
|
11
|
+
|
12
|
+
module Datadog
|
13
|
+
class Notifications
|
14
|
+
include Singleton
|
15
|
+
|
16
|
+
# Configure and install datadog instrumentation. Example:
|
17
|
+
#
|
18
|
+
# Datadog::Notifications.configure do |c|
|
19
|
+
# c.hostname = "my-host"
|
20
|
+
# c.tags = ["app:mine"]
|
21
|
+
#
|
22
|
+
# c.use Datadog::Notifications::Plugins::Grape, metric_name: "api.request", tags: ["grape:specific"]
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Settings:
|
26
|
+
# * <tt>hostname</tt> - the hostname used for instrumentation, defaults to system hostname, respects +INSTRUMENTATION_HOSTNAME+ env variable
|
27
|
+
# * <tt>namespace</tt> - set a namespace to be prepended to every metric name
|
28
|
+
# * <tt>tags</tt> - set an array of tags to be added to every metric
|
29
|
+
# * <tt>statsd_host</tt> - the statsD host, defaults to "localhost", respects +STATSD_HOST+ env variable
|
30
|
+
# * <tt>statsd_port</tt> - the statsD port, defaults to 8125, respects +STATSD_PORT+ env variable
|
31
|
+
# * <tt>reporter</tt> - custom reporter class, defaults to `Datadog::Notifications::Reporter`
|
32
|
+
def self.configure(&block)
|
33
|
+
if instance.instance_variable_defined?(:@reporter)
|
34
|
+
warn "#{self.name} cannot be reconfigured once it has subscribed to notifications, called from: #{caller[1]}"
|
35
|
+
return
|
36
|
+
end
|
37
|
+
block.call instance.config if block
|
38
|
+
end
|
39
|
+
|
40
|
+
# You can subscribe to events exactly as with ActiveSupport::Notifications, but there will be an
|
41
|
+
# additional `statsd` block parameter available:
|
42
|
+
#
|
43
|
+
# Datadog::Notifications.subscribe('render') do |reporter, event|
|
44
|
+
# reporter # => Reporter instance
|
45
|
+
# event # => ActiveSupport::Notifications::Event object
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
#
|
50
|
+
# Datadog::Notifications.subscribe('render') do |reporter, _, start, finish, _, payload|
|
51
|
+
# status = payload[:status]
|
52
|
+
# reporter.seconds('myapp.render', finish-start, tags: ["status:#{status}"])
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
def self.subscribe(pattern, &block)
|
56
|
+
instance.subscribe(pattern, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
attr_reader :config
|
60
|
+
|
61
|
+
def initialize
|
62
|
+
@config = Config.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def subscribe(pattern, &block)
|
66
|
+
ActiveSupport::Notifications.subscribe(pattern) do |*args|
|
67
|
+
block.call reporter, ActiveSupport::Notifications::Event.new(*args)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def reporter
|
72
|
+
@reporter ||= config.send(:connect!)
|
73
|
+
end
|
74
|
+
private :reporter
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Datadog
|
2
|
+
class Notifications
|
3
|
+
class Config
|
4
|
+
attr_accessor :hostname, :namespace, :tags, :statsd_host, :statsd_port, :reporter
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@hostname = ENV['INSTRUMENTATION_HOSTNAME'] || Socket.gethostname
|
8
|
+
@statsd_host = ENV['STATSD_HOST'] || ::Statsd::DEFAULT_HOST
|
9
|
+
@statsd_port = (ENV['STATSD_PORT'] || ::Statsd::DEFAULT_PORT).to_i
|
10
|
+
@reporter = Datadog::Notifications::Reporter
|
11
|
+
@tags = []
|
12
|
+
@plugins = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Use a plugin
|
16
|
+
def use(klass, opts = {})
|
17
|
+
@plugins.push [klass, opts]
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect!
|
21
|
+
@plugins.each do |klass, opts|
|
22
|
+
klass.new(opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
env = ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
26
|
+
tags.push("env:#{env}") if env && tags.none? {|t| t =~ /^env\:/ }
|
27
|
+
tags.push("host:#{hostname}") if tags.none? {|t| t =~ /^host\:/ }
|
28
|
+
|
29
|
+
reporter.new statsd_host, statsd_port, namespace: namespace, tags: tags
|
30
|
+
end
|
31
|
+
protected :connect!
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Datadog::Notifications::Plugins
|
2
|
+
class ActionController < Base
|
3
|
+
|
4
|
+
attr_reader :metric_name
|
5
|
+
|
6
|
+
# Options:
|
7
|
+
#
|
8
|
+
# *<tt>:metric_name</tt> - the metric name, defaults to "rails.request"
|
9
|
+
# *<tt>:tags</tt> - additional tags
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
@metric_name = opts[:metric_name] || "rails.request"
|
13
|
+
|
14
|
+
Datadog::Notifications.subscribe 'process_action.action_controller' do |reporter, event|
|
15
|
+
record reporter, event
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def record(reporter, event)
|
22
|
+
payload = event.payload
|
23
|
+
method = payload[:method].downcase
|
24
|
+
status = payload[:status]
|
25
|
+
action = payload[:action]
|
26
|
+
ctrl = payload[:controller].sub(/Controller$/, '').underscore
|
27
|
+
format = payload[:format]
|
28
|
+
tags = self.tags + %W|method:#{method} status:#{status} action:#{action} controller:#{ctrl} format:#{format}|
|
29
|
+
|
30
|
+
reporter.batch do
|
31
|
+
reporter.increment metric_name, tags: tags
|
32
|
+
reporter.timing "#{metric_name}.time", event.duration, tags: tags
|
33
|
+
reporter.timing "#{metric_name}.time.db", to_millis(payload[:db_runtime]), tags: tags
|
34
|
+
reporter.timing "#{metric_name}.time.view", to_millis(payload[:view_runtime]), tags: tags
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Datadog::Notifications::Plugins
|
2
|
+
class ActiveJob < Base
|
3
|
+
|
4
|
+
attr_reader :metric_name
|
5
|
+
|
6
|
+
# Options:
|
7
|
+
#
|
8
|
+
# *<tt>:metric_name</tt> - the metric name, defaults to "activejob.perform"
|
9
|
+
# *<tt>:tags</tt> - additional tags
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
@metric_name = opts[:metric_name] || "activejob.perform"
|
13
|
+
|
14
|
+
Datadog::Notifications.subscribe 'perform.active_job' do |reporter, event|
|
15
|
+
record reporter, event
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def record(reporter, event)
|
22
|
+
job = event.payload[:job]
|
23
|
+
name = job.class.name.sub(/Job$/, '').underscore
|
24
|
+
tags = self.tags + %W|name:#{name} queue:#{job.queue_name}|
|
25
|
+
|
26
|
+
reporter.batch do
|
27
|
+
reporter.increment metric_name, tags: tags
|
28
|
+
reporter.timing "#{metric_name}.time", event.duration, tags: tags
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Datadog::Notifications::Plugins
|
2
|
+
class ActiveRecord < Base
|
3
|
+
|
4
|
+
attr_reader :metric_name
|
5
|
+
|
6
|
+
# Options:
|
7
|
+
#
|
8
|
+
# *<tt>:metric_name</tt> - the metric name, defaults to "activerecord.query"
|
9
|
+
# *<tt>:include_schema</tt> - record schema queries, off by default
|
10
|
+
# *<tt>:include_generic</tt> - record general (nameless) queries, off by default
|
11
|
+
# *<tt>:tags</tt> - additional tags
|
12
|
+
def initialize(opts = {})
|
13
|
+
super
|
14
|
+
@metric_name = opts[:metric_name] || "activerecord.sql"
|
15
|
+
@include_schema = opts[:include_schema] == true
|
16
|
+
@include_generic = opts[:include_generic] == true
|
17
|
+
@include_raw = opts[:include_raw] == true
|
18
|
+
|
19
|
+
Datadog::Notifications.subscribe 'sql.active_record' do |reporter, event|
|
20
|
+
record reporter, event
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def record(reporter, event)
|
27
|
+
payload = event.payload
|
28
|
+
name = payload[:name]
|
29
|
+
return if (name.nil? || name == "SQL") && !@include_generic
|
30
|
+
return if name == "SCHEMA" && !@include_schema
|
31
|
+
|
32
|
+
name = name.downcase.split(/\W/).join(".") if name
|
33
|
+
tags = self.tags.dup
|
34
|
+
tags.push "query:#{name}" if name
|
35
|
+
|
36
|
+
reporter.batch do
|
37
|
+
reporter.increment metric_name, tags: tags
|
38
|
+
reporter.timing "#{metric_name}.time", event.duration, tags: tags
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Datadog::Notifications::Plugins
|
2
|
+
class Grape < Base
|
3
|
+
|
4
|
+
attr_reader :metric_name
|
5
|
+
|
6
|
+
# Options:
|
7
|
+
#
|
8
|
+
# *<tt>:metric_name</tt> - the metric name, defaults to "grape.request"
|
9
|
+
# *<tt>:tags</tt> - additional tags
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
@metric_name = opts[:metric_name] || "grape.request"
|
13
|
+
|
14
|
+
Datadog::Notifications.subscribe 'endpoint_run.grape' do |reporter, event|
|
15
|
+
record reporter, event
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def record(reporter, event)
|
22
|
+
payload = event.payload
|
23
|
+
endpoint = payload[:endpoint]
|
24
|
+
route = endpoint.route
|
25
|
+
version = route.route_version
|
26
|
+
method = route.route_method
|
27
|
+
|
28
|
+
path = route.route_path
|
29
|
+
path.sub!("(.:format)", "")
|
30
|
+
path.sub!(":version/", "") if version
|
31
|
+
path.gsub!(/\(?:(\w+)\)?/) {|m| "_#{m[1..-1]}_" }
|
32
|
+
|
33
|
+
tags = self.tags + %W|method:#{method} path:#{path} status:#{endpoint.status}|
|
34
|
+
tags.push "version:#{version}" if version
|
35
|
+
|
36
|
+
reporter.batch do
|
37
|
+
reporter.increment metric_name, tags: tags
|
38
|
+
reporter.timing "#{metric_name}.time", event.duration, tags: tags
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Datadog::Notifications::Config do
|
4
|
+
|
5
|
+
it 'should be connect!' do
|
6
|
+
subject.reporter = Mock::Reporter
|
7
|
+
subject.hostname = "test.host"
|
8
|
+
subject.tags = ["custom:tag"]
|
9
|
+
|
10
|
+
client = subject.send(:connect!)
|
11
|
+
expect(client).to be_instance_of(Mock::Reporter)
|
12
|
+
expect(subject.tags).to eq(["custom:tag", "env:test", "host:test.host"])
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Datadog::Notifications::Plugins::ActiveRecord do
|
4
|
+
|
5
|
+
it 'should send an increment and timing event for each query' do
|
6
|
+
Post.all.to_a
|
7
|
+
expect(buffered).to eq([
|
8
|
+
"activerecord.sql:1|c|#custom:tag,env:test,host:test.host,query:post.load",
|
9
|
+
"activerecord.sql.time:333|ms|#custom:tag,env:test,host:test.host,query:post.load",
|
10
|
+
])
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should skip unnamed by default' do
|
14
|
+
Post.create!(title: "Hello!")
|
15
|
+
expect(buffered).to eq([])
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should support custom queries' do
|
19
|
+
Post.find_by_sql("SELECT * FROM posts LIMIT 1").to_a
|
20
|
+
expect(buffered).to eq([
|
21
|
+
"activerecord.sql:1|c|#custom:tag,env:test,host:test.host,query:post.load",
|
22
|
+
"activerecord.sql.time:333|ms|#custom:tag,env:test,host:test.host,query:post.load",
|
23
|
+
])
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Datadog::Notifications::Plugins::Grape do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
let(:app) do
|
7
|
+
sub_api = Class.new(Grape::API) do
|
8
|
+
version 'v1'
|
9
|
+
prefix 'api'
|
10
|
+
|
11
|
+
get('versioned') { "OK" }
|
12
|
+
end
|
13
|
+
|
14
|
+
Class.new(Grape::API) do
|
15
|
+
get 'echo/:key1/:key2' do
|
16
|
+
"#{params['key1']} #{params['key2']}"
|
17
|
+
end
|
18
|
+
|
19
|
+
namespace :sub do
|
20
|
+
mount sub_api
|
21
|
+
|
22
|
+
namespace :secure do
|
23
|
+
get("/resource") { error!("forbidden", 403) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should send an increment and timing event for each request' do
|
30
|
+
get '/echo/1/1234'
|
31
|
+
expect(last_response.status).to eq(200)
|
32
|
+
expect(last_response.body).to eq('1 1234')
|
33
|
+
|
34
|
+
expect(buffered).to eq([
|
35
|
+
"api.request:1|c|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/echo/_key1_/_key2_,status:200",
|
36
|
+
"api.request.time:333|ms|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/echo/_key1_/_key2_,status:200",
|
37
|
+
])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should support namespaces and versioning' do
|
41
|
+
get '/api/v1/sub/versioned'
|
42
|
+
expect(last_response.status).to eq(200)
|
43
|
+
expect(last_response.body).to eq('OK')
|
44
|
+
|
45
|
+
expect(buffered).to eq([
|
46
|
+
"api.request:1|c|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/api/sub/versioned,status:200,version:v1",
|
47
|
+
"api.request.time:333|ms|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/api/sub/versioned,status:200,version:v1",
|
48
|
+
])
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should support deep nesting' do
|
52
|
+
get '/sub/secure/resource'
|
53
|
+
expect(last_response.status).to eq(403)
|
54
|
+
expect(last_response.body).to eq('forbidden')
|
55
|
+
|
56
|
+
expect(buffered).to eq([
|
57
|
+
"api.request:1|c|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/sub/secure/resource,status:403",
|
58
|
+
"api.request.time:333|ms|#custom:tag,env:test,host:test.host,more:tags,method:GET,path:/sub/secure/resource,status:403",
|
59
|
+
])
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Datadog::Notifications do
|
4
|
+
|
5
|
+
subject { described_class.instance }
|
6
|
+
after { ActiveSupport::Notifications.unsubscribe(subscription) }
|
7
|
+
|
8
|
+
let!(:subscription) do
|
9
|
+
subject.subscribe("mock.perform") do |reporter, event|
|
10
|
+
status = event.payload[:status]
|
11
|
+
method = event.payload[:method]
|
12
|
+
tags = ["status:#{status}", "method:#{method}"]
|
13
|
+
|
14
|
+
reporter.batch do
|
15
|
+
reporter.increment "web.render", tags: tags
|
16
|
+
reporter.timing "web.render.time", event.duration, tags: tags
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should have a reporter' do
|
22
|
+
expect(subject.send(:reporter)).to be_instance_of(Mock::Reporter)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should subscribe and report' do
|
26
|
+
Mock::Instrumentable.new(method: 'GET').perform
|
27
|
+
expect(buffered).to eq([
|
28
|
+
"web.render:1|c|#custom:tag,env:test,host:test.host,status:200,method:GET",
|
29
|
+
"web.render.time:333|ms|#custom:tag,env:test,host:test.host,status:200,method:GET",
|
30
|
+
])
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
ENV['RACK_ENV'] ||= 'test'
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'datadog-notifications'
|
5
|
+
require 'rspec'
|
6
|
+
require 'rack/test'
|
7
|
+
require 'grape'
|
8
|
+
require 'active_record'
|
9
|
+
require 'sqlite3'
|
10
|
+
|
11
|
+
### Active-record test preparation
|
12
|
+
|
13
|
+
ActiveRecord::Base.configurations["test"] = { 'adapter' => 'sqlite3', 'database' => ':memory:' }
|
14
|
+
ActiveRecord::Base.establish_connection(:test)
|
15
|
+
ActiveRecord::Base.connection.create_table :posts do |t|
|
16
|
+
t.string :title
|
17
|
+
end
|
18
|
+
class Post < ActiveRecord::Base
|
19
|
+
end
|
20
|
+
|
21
|
+
### Mocks
|
22
|
+
|
23
|
+
module Mock
|
24
|
+
class Reporter < Datadog::Notifications::Reporter
|
25
|
+
def timing(stat, ms, opts={}); super(stat, 333, opts); end
|
26
|
+
def flush_buffer; end
|
27
|
+
alias :send_stat :send_to_buffer
|
28
|
+
end
|
29
|
+
|
30
|
+
class Instrumentable
|
31
|
+
def initialize(opts = {})
|
32
|
+
@opts = opts
|
33
|
+
end
|
34
|
+
|
35
|
+
def perform
|
36
|
+
ActiveSupport::Notifications.instrument("mock.start", @opts)
|
37
|
+
ActiveSupport::Notifications.instrument("mock.perform", @opts) do |payload|
|
38
|
+
payload[:status] = 200
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
### Configuration
|
45
|
+
|
46
|
+
RSpec.configure do |c|
|
47
|
+
helpers = Module.new do
|
48
|
+
def buffered
|
49
|
+
Datadog::Notifications.instance.send(:reporter).buffer
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
c.include helpers
|
54
|
+
c.before do
|
55
|
+
buffered.clear
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Datadog::Notifications.configure do |c|
|
60
|
+
c.hostname = "test.host"
|
61
|
+
c.reporter = Mock::Reporter
|
62
|
+
c.tags = ["custom:tag"]
|
63
|
+
|
64
|
+
c.use Datadog::Notifications::Plugins::ActiveRecord
|
65
|
+
c.use Datadog::Notifications::Plugins::Grape, tags: ["more:tags"], metric_name: "api.request"
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: datadog-notifications
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dimitrij Denissenko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-08 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: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dogstatsd-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: grape
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
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: activerecord
|
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: rake
|
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
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bundler
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Datadog instrumnetation for ActiveSupport::Notifications
|
140
|
+
email:
|
141
|
+
- dimitrij@blacksquaremedia.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".editorconfig"
|
147
|
+
- ".gitignore"
|
148
|
+
- ".travis.yml"
|
149
|
+
- Gemfile
|
150
|
+
- MIT-LICENCE
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- datadog-notifications.gemspec
|
154
|
+
- lib/datadog-notifications.rb
|
155
|
+
- lib/datadog/notifications.rb
|
156
|
+
- lib/datadog/notifications/config.rb
|
157
|
+
- lib/datadog/notifications/plugins.rb
|
158
|
+
- lib/datadog/notifications/plugins/action_controller.rb
|
159
|
+
- lib/datadog/notifications/plugins/active_job.rb
|
160
|
+
- lib/datadog/notifications/plugins/active_record.rb
|
161
|
+
- lib/datadog/notifications/plugins/base.rb
|
162
|
+
- lib/datadog/notifications/plugins/grape.rb
|
163
|
+
- lib/datadog/notifications/reporter.rb
|
164
|
+
- lib/datadog/notifications/version.rb
|
165
|
+
- spec/datadog/notifications/config_spec.rb
|
166
|
+
- spec/datadog/notifications/plugins/active_record_spec.rb
|
167
|
+
- spec/datadog/notifications/plugins/grape_spec.rb
|
168
|
+
- spec/datadog/notifications_spec.rb
|
169
|
+
- spec/spec_helper.rb
|
170
|
+
homepage: https://github.com/bsm/datadog-notifications
|
171
|
+
licenses: []
|
172
|
+
metadata: {}
|
173
|
+
post_install_message:
|
174
|
+
rdoc_options: []
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
requirements: []
|
188
|
+
rubyforge_project:
|
189
|
+
rubygems_version: 2.4.7
|
190
|
+
signing_key:
|
191
|
+
specification_version: 4
|
192
|
+
summary: Generic ActiveSupport::Notifications Datadog handler
|
193
|
+
test_files:
|
194
|
+
- spec/datadog/notifications/config_spec.rb
|
195
|
+
- spec/datadog/notifications/plugins/active_record_spec.rb
|
196
|
+
- spec/datadog/notifications/plugins/grape_spec.rb
|
197
|
+
- spec/datadog/notifications_spec.rb
|
198
|
+
- spec/spec_helper.rb
|