dogapi 1.0.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.
@@ -0,0 +1,34 @@
1
+ Ruby client for Datadog API v1.0.0
2
+
3
+ The Ruby client is a library suitable for inclusion in existing Ruby projects or for development of standalone scripts. It provides an abstraction on top of Datadog's raw HTTP interface for reporting events and metrics.
4
+
5
+ = Installation
6
+
7
+ == Source
8
+
9
+ Available at: https://github.com/DataDog/dogapi-rb
10
+
11
+ $ cd dogapi-rb
12
+ $ rake gem
13
+ $ gem install pkg/dogapi-1.0.0.gem
14
+
15
+ == RubyGems
16
+
17
+ Gem page: https://rubygems.org/gems/dogapi
18
+
19
+ $ gem install dogapi
20
+
21
+ = Usage
22
+
23
+ The client expects the +DATADOG_HOST+ environment variable to be set to the host you will be submitting data to:
24
+
25
+ $ export DATADOG_HOST=http://app.datadoghq.com/
26
+
27
+ Minimal example:
28
+
29
+ require 'dogapi'
30
+
31
+ dog = Dogapi::Client.new(@api_key)
32
+ dog.emit_point 'some.metric.name', 50.0
33
+
34
+ Further usage examples are available in the source distribution under <code>examples/</code> and <code>tests/</code>.
@@ -0,0 +1,4 @@
1
+ require 'dogapi/common'
2
+ require 'dogapi/facade'
3
+ require 'dogapi/event'
4
+ require 'dogapi/metric'
@@ -0,0 +1,86 @@
1
+ require 'cgi'
2
+ require 'net/http'
3
+ require 'pp'
4
+ require 'socket'
5
+ require 'uri'
6
+
7
+ require 'rubygems'
8
+ require 'json'
9
+
10
+ module Dogapi
11
+
12
+ # Metadata class to hold the scope of an API call
13
+ class Scope
14
+ attr_reader :host, :device
15
+ def initialize(host=nil, device=nil)
16
+ @host = host
17
+ @device = device
18
+ end
19
+ end
20
+
21
+ # Superclass that deals with the details of communicating with the DataDog API
22
+ class Service
23
+ def initialize(api_host=find_datadog_host)
24
+ @host = api_host
25
+ end
26
+
27
+ # Manages the HTTP connection
28
+ def connect(api_key=nil, host=nil)
29
+
30
+ @api_key = api_key
31
+ host = host || @host
32
+
33
+ uri = URI.parse(host)
34
+ Net::HTTP.start(uri.host, uri.port) do |conn|
35
+ if 'https' == uri.scheme
36
+ conn.use_ssl = true
37
+ end
38
+ yield(conn)
39
+ end
40
+ end
41
+
42
+ # Prepares the request and handles the response
43
+ #
44
+ # +method+ is an implementation of Net::HTTP::Request (e.g. Net::HTTP::Post)
45
+ #
46
+ # +params+ is a Hash that will be converted to request parameters
47
+ def request(method, url, params)
48
+ if !params.has_key? :api_key
49
+ params[:api_key] = @api_key
50
+ end
51
+
52
+ resp_obj = nil
53
+ connect do |conn|
54
+ req = method.new(url)
55
+ req.set_form_data params
56
+ resp = conn.request(req)
57
+ begin
58
+ resp_obj = JSON.parse(resp.body)
59
+ rescue
60
+ raise 'Invalid JSON Response: ' + resp.body
61
+ end
62
+
63
+ if resp_obj.has_key? 'error'
64
+ request_string = params.pretty_inspect
65
+ error_string = resp_obj['error']
66
+ raise "Failed request\n#{request_string}#{error_string}"
67
+ end
68
+ end
69
+ resp_obj
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def Dogapi.find_datadog_host
76
+ ENV['DATADOG_HOST'] rescue nil
77
+ end
78
+
79
+ def Dogapi.find_api_key
80
+ ENV['DATADOG_KEY'] rescue nil
81
+ end
82
+
83
+ def Dogapi.find_localhost
84
+ Socket.gethostname
85
+ end
86
+ end
@@ -0,0 +1,119 @@
1
+ require 'net/http'
2
+
3
+ require 'rubygems'
4
+ require 'json'
5
+
6
+ module Dogapi
7
+
8
+ # Metadata class for storing the details of an event
9
+ class Event
10
+ attr_reader :metric,
11
+ :date_detected,
12
+ :date_happened,
13
+ :alert_type,
14
+ :event_type,
15
+ :event_object,
16
+ :msg_title,
17
+ :msg_text,
18
+ :json_payload
19
+
20
+ # Optional arguments:
21
+ # :metric => String
22
+ # :date_detected => time in seconds since the epoch (defaults to now)
23
+ # :date_happened => time in seconds since the epoch (defaults to now)
24
+ # :alert_type => String
25
+ # :event_type => String
26
+ # :event_object => String
27
+ # :msg_title => String
28
+ # :json_payload => String
29
+ def initialize(msg_text, options={})
30
+ defaults = {
31
+ :metric => '',
32
+ :date_detected => Time.now.to_i,
33
+ :date_happened => Time.now.to_i,
34
+ :alert_type => '',
35
+ :event_type => '',
36
+ :event_object => '',
37
+ :msg_title => '',
38
+ :json_payload => ''
39
+ }
40
+ options = defaults.merge(options)
41
+
42
+ @msg_text = msg_text
43
+ @metric = options[:metric]
44
+ @date_detected = options[:date_detected]
45
+ @date_happened = options[:date_happened]
46
+ @alert_type = options[:alert_type]
47
+ @event_type = options[:event_type]
48
+ @event_object = options[:event_object]
49
+ @msg_title = options[:msg_title]
50
+ @json_payload = options[:json_payload]
51
+ end
52
+ end
53
+
54
+ # Event-specific client affording more granular control than the simple Dogapi::Client
55
+ class EventService < Dogapi::Service
56
+
57
+ API_VERSION = "1.0.0"
58
+
59
+ # Records an Event with no duration
60
+ def submit(api_key, event, scope=nil, source_type=nil)
61
+ scope = scope || Dogapi::Scope.new()
62
+ params = {
63
+ :api_key => api_key,
64
+ :api_version => API_VERSION,
65
+
66
+ :host => scope.host,
67
+ :device => scope.device,
68
+
69
+ :metric => event.metric,
70
+ :date_detected => event.date_detected,
71
+ :date_happened => event.date_happened,
72
+ :alert_type => event.alert_type,
73
+ :event_type => event.event_type,
74
+ :event_object => event.event_object,
75
+ :msg_title => event.msg_title,
76
+ :msg_text => event.msg_text,
77
+ :json_payload => event.json_payload,
78
+ }
79
+
80
+ if source_type
81
+ params[:source_type] = source_type
82
+ end
83
+
84
+ request Net::HTTP::Post, '/event/submit', params
85
+ end
86
+
87
+ # Manages recording an event with a duration
88
+ #
89
+ # 0. The start time is recorded immediately
90
+ # 0. The given block is executed with access to the response of the start request
91
+ # 0. The end time is recorded once the block completes execution
92
+ def start(api_key, event, scope, source_type=nil)
93
+ response = submit api_key, event, scope, source_type
94
+ success = nil
95
+
96
+ begin
97
+ yield response
98
+ rescue
99
+ success = false
100
+ raise
101
+ else
102
+ success = true
103
+ ensure
104
+ return finish api_key, response['id'], success
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def finish(api_key, event_id, successful=nil)
111
+ params = {
112
+ :api_key => api_key,
113
+ :event_id => event_id
114
+ }
115
+
116
+ request Net::HTTP::Post, '/event/ended', params
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,125 @@
1
+ require 'time'
2
+ require 'dogapi/metric'
3
+
4
+ module Dogapi
5
+
6
+ # A simple DogAPI client
7
+ #
8
+ # See Dogapi::EventService and Dogapi::MetricService for the thick underlying clients
9
+ class Client
10
+
11
+ # Create a new Client optionally specifying a default host and device
12
+ def initialize(api_key, host=nil, device=nil)
13
+
14
+ if api_key
15
+ @api_key = api_key
16
+ else
17
+ raise 'Please provide an API key to submit your data'
18
+ end
19
+
20
+ @datadog_host = Dogapi.find_datadog_host()
21
+ if !@datadog_host
22
+ raise 'DATADOG_HOST env variable not set'
23
+ end
24
+
25
+ @host = host
26
+ @device = device
27
+
28
+ @metric_svc = Dogapi::MetricService.new(@datadog_host)
29
+ @event_svc = Dogapi::EventService.new(@datadog_host)
30
+ end
31
+
32
+ # Record a single point of metric data
33
+ #
34
+ # Optional arguments:
35
+ # :timestamp => Ruby stdlib Time
36
+ # :host => String
37
+ # :device => String
38
+ def emit_point(metric, value, options={})
39
+ defaults = {:timestamp => Time.now, :host => nil, :device => nil}
40
+ options = defaults.merge(options)
41
+
42
+ self.emit_points metric,
43
+ [[options[:timestamp], value]],
44
+ :host => options[:host],
45
+ :device => options[:device]
46
+ end
47
+
48
+ # Record a set of points of metric data
49
+ #
50
+ # +points+ is an array of <tt>[Time, value]</tt> doubles
51
+ #
52
+ # Optional arguments:
53
+ # :host => String
54
+ # :device => String
55
+ def emit_points(metric, points, options={})
56
+ defaults = {:host => nil, :device => nil}
57
+ options = defaults.merge(options)
58
+
59
+ scope = override_scope options[:host], options[:device]
60
+
61
+ points.each do |p|
62
+ p[0].kind_of? Time or raise "Not a Time"
63
+ p[1].to_f # TODO: stupid to_f will never raise and exception
64
+ end
65
+
66
+ @metric_svc.submit @api_key, scope, metric, points
67
+ end
68
+
69
+ # Record an event with no duration
70
+ #
71
+ # If <tt>:source_type</tt> is unset, a generic "system" event will be reported
72
+ #
73
+ # Optional arguments:
74
+ # :host => String
75
+ # :device => String
76
+ # :source_type => String
77
+ def emit_event(event, options={})
78
+ defaults = {:host => nil, :device => nil, :source_type => nil}
79
+ options = defaults.merge(options)
80
+
81
+ scope = override_scope options[:host], options[:device]
82
+
83
+ @event_svc.submit(@api_key, event, scope, options[:source_type])
84
+ end
85
+
86
+ # Record an event with a duration
87
+ #
88
+ # 0. The start time is recorded immediately
89
+ # 0. The given block is executed
90
+ # 0. The end time is recorded once the block completes execution
91
+ #
92
+ # If <tt>:source_type</tt> is unset, a generic "system" event will be reported
93
+ #
94
+ # Optional arguments:
95
+ # :host => String
96
+ # :device => String
97
+ # :source_type => String
98
+ def start_event(event, options={})
99
+ defaults = {:host => nil, :device => nil, :source_type => nil}
100
+ options = defaults.merge(options)
101
+
102
+ scope = override_scope options[:host], options[:device]
103
+
104
+ @event_svc.start(@api_key, event, scope, options[:source_type]) do
105
+ yield
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def override_scope(host, device)
112
+ if host
113
+ h = host
114
+ else
115
+ h = @host
116
+ end
117
+ if device
118
+ d = device
119
+ else
120
+ d = @device
121
+ end
122
+ Scope.new(h, d)
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,30 @@
1
+ require 'net/http'
2
+
3
+ require 'rubygems'
4
+ require 'json'
5
+
6
+ module Dogapi
7
+
8
+ class MetricService < Dogapi::Service
9
+
10
+ API_VERSION = "1.0.0"
11
+
12
+ # Records some number of points for a given metric
13
+ def submit(api_key, scope, metric, points)
14
+ series = [{
15
+ :host => scope.host,
16
+ :device => scope.device,
17
+ :metric => metric,
18
+ :points => points.map { |p| [p[0].to_i, p[1]] }
19
+ }]
20
+
21
+ params = {
22
+ :api_key => api_key,
23
+ :api_version => API_VERSION,
24
+ :series => series.to_json
25
+ }
26
+
27
+ request Net::HTTP::Post, '/series/submit', params
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/unit'
2
+ require 'dogapi'
3
+
4
+ class TestClient < Test::Unit::TestCase
5
+
6
+ def config_client_test_env
7
+ @api_key = Dogapi.find_api_key
8
+ if !@api_key
9
+ @api_key = 'apikey_2'
10
+ ENV['DATADOG_KEY'] = @api_key
11
+ end
12
+
13
+ @host = Dogapi.find_datadog_host
14
+ if !@host
15
+ @host = 'localhost:5000'
16
+ ENV['DATADOG_HOST'] = @host
17
+ end
18
+ end
19
+
20
+ def setup
21
+ config_client_test_env
22
+ end
23
+
24
+ def test_simple_client
25
+ dog = Dogapi::Client.new(@api_key)
26
+
27
+ dog.emit_point 'test.dogclient.emit_point',
28
+ 999,
29
+ :host => 'test.dogclient.fake',
30
+ :device => 'eth0'
31
+
32
+ dog.emit_points 'test.dogclient.emit_points',
33
+ [[Time.now - 60, 10], [Time.now - 30, 20], [Time.now, 30]],
34
+ :host => 'test.dogclient.fake',
35
+ :device => 'eth0'
36
+
37
+ my_event = Dogapi::Event.new('Testing Event API')
38
+ dog.emit_event my_event,
39
+ :host => 'test.dogclient.fake',
40
+ :device => 'eth0'
41
+
42
+ my_event = Dogapi::Event.new('Testing Event API with a duration')
43
+ dog.start_event(my_event, :host =>'test.dogclient.fake', :device => 'eth0') do
44
+ sleep 1
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ require 'test/unit'
2
+ require 'dogapi'
3
+
4
+ class TestEnvironment < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @host = ENV['DATADOG_HOST']
8
+ @key = ENV['DATADOG_KEY']
9
+ end
10
+
11
+ def teardown
12
+ ENV['DATADOG_HOST'] = @host
13
+ ENV['DATADOG_KEY'] = @key
14
+ end
15
+
16
+ def test_unset
17
+ ENV['DATADOG_HOST'] = nil
18
+ ENV['DATADOG_KEY'] = nil
19
+ assert_equal nil, Dogapi.find_datadog_host
20
+ assert_equal nil, Dogapi.find_api_key
21
+ end
22
+
23
+ def test_set
24
+ ENV['DATADOG_HOST'] = 'test.host'
25
+ ENV['DATADOG_KEY'] = 'test_key'
26
+ assert_equal 'test.host', Dogapi.find_datadog_host
27
+ assert_equal 'test_key', Dogapi.find_api_key
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ require 'test/unit'
2
+ require 'dogapi'
3
+
4
+ class TestEventClient < Test::Unit::TestCase
5
+
6
+ def config_client_test_env
7
+ @api_key = Dogapi.find_api_key
8
+ if !@api_key
9
+ @api_key = 'apikey_2'
10
+ ENV['DATADOG_KEY'] = @api_key
11
+ end
12
+
13
+ @host = Dogapi.find_datadog_host
14
+ if !@host
15
+ @host = 'localhost:5000'
16
+ ENV['DATADOG_HOST'] = @host
17
+ end
18
+ end
19
+
20
+ def setup
21
+ config_client_test_env
22
+ end
23
+
24
+ def submit_event(scope=nil, source_type=nil)
25
+ event_service = Dogapi::EventService.new(@host)
26
+ tok = '#' + (rand(10000)+1).to_s
27
+ test_message = 'event_test_' + tok
28
+ event = Dogapi::Event.new(test_message, :event_type => 'test-event-type')
29
+ res = event_service.submit(@api_key, event, scope, source_type)
30
+ assert_not_equal(res['id'], nil)
31
+ end
32
+
33
+ def test_submit_event
34
+ submit_event
35
+ end
36
+
37
+ def test_submit_scoped_event
38
+ submit_event(Dogapi::Scope.new('scoped-testhost', 'testdevice'))
39
+ end
40
+
41
+ def test_submit_event
42
+ submit_event(Dogapi::Scope.new('typed-testhost', 'testdevice'), 'Nagios')
43
+ submit_event(Dogapi::Scope.new('typed-testhost', 'testdevice'), 'GitHub')
44
+ end
45
+
46
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/unit'
2
+ require 'time'
3
+ require 'dogapi'
4
+
5
+ class TestEnvironment < Test::Unit::TestCase
6
+
7
+ def config_client_test_env
8
+ @api_key = Dogapi.find_api_key
9
+ if !@api_key
10
+ @api_key = 'apikey_2'
11
+ ENV['DATADOG_KEY'] = @api_key
12
+ end
13
+
14
+ @host = Dogapi.find_datadog_host
15
+ if !@host
16
+ @host = 'localhost:5000'
17
+ ENV['DATADOG_HOST'] = @host
18
+ end
19
+ end
20
+
21
+ def setup
22
+ config_client_test_env
23
+ end
24
+
25
+ def test_submit_metric
26
+ metric_service = Dogapi::MetricService.new(@host)
27
+ scope = Dogapi::Scope.new('test.dogclient.fake', 'eth0')
28
+ metric = 'test.dogclient.metric.submit_metric'
29
+ points = [
30
+ [Time.now-90, 1.0],
31
+ [Time.now-60, 2.0],
32
+ [Time.now-30, 4.0],
33
+ [Time.now, 8.0]
34
+ ]
35
+ res = metric_service.submit(@api_key, scope, metric, points)
36
+ assert_equal(res['status'], 'ok')
37
+ assert_equal(res['results'].size, 1)
38
+ r = res['results'][0]
39
+ assert_equal(r['host'], scope.host)
40
+ if scope.device
41
+ assert_equal(r['device'], scope.device)
42
+ end
43
+ assert_equal(r['metric'], metric)
44
+ assert_equal(r['length'], points.size)
45
+ end
46
+
47
+ end
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+
3
+ require 'tc_env'
4
+ require 'tc_client'
5
+ require 'tc_event'
6
+ require 'tc_metric'
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dogapi
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Datadog, Inc.
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-21 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 1
30
+ segments:
31
+ - 1
32
+ - 5
33
+ - 1
34
+ version: 1.5.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description:
38
+ email: packages@datadoghq.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README.rdoc
45
+ files:
46
+ - lib/dogapi/common.rb
47
+ - lib/dogapi/event.rb
48
+ - lib/dogapi/facade.rb
49
+ - lib/dogapi/metric.rb
50
+ - lib/dogapi.rb
51
+ - tests/tc_client.rb
52
+ - tests/tc_env.rb
53
+ - tests/tc_event.rb
54
+ - tests/tc_metric.rb
55
+ - tests/ts_dogapi.rb
56
+ - README.rdoc
57
+ has_rdoc: true
58
+ homepage: http://datadoghq.com/
59
+ licenses:
60
+ - BSD
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --title
64
+ - DogAPI -- DataDog Client
65
+ - --main
66
+ - README.rdoc
67
+ - --line-numbers
68
+ - --inline-source
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.6.2
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Ruby bindings for Datadog's API
96
+ test_files:
97
+ - tests/ts_dogapi.rb