dogapi 1.2.8 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -1
- data/lib/capistrano/README.md +13 -0
- data/lib/capistrano/datadog.rb +153 -0
- data/tests/{tc_client.rb → test_client.rb} +3 -2
- metadata +58 -37
- data/tests/ts_dogapi.rb +0 -3
data/README.rdoc
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
= Ruby client for Datadog API v1.
|
1
|
+
= Ruby client for Datadog API v1.3.0
|
2
2
|
|
3
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
4
|
|
5
5
|
= What's new?
|
6
6
|
|
7
|
+
== v1.3.0
|
8
|
+
|
9
|
+
* Capistrano integration. See https://github.com/DataDog/dogapi-rb/tree/master/lib/capistrano
|
10
|
+
|
7
11
|
== v1.2.x
|
8
12
|
|
9
13
|
* You can now manage host tags
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# capistrano/datadog
|
2
|
+
|
3
|
+
Instrument your [Capistrano](https://github.com/capistrano/capistrano) deploys, generating events in Datadog which you can correlate with metrics in order to figure out what caused production issues.
|
4
|
+
|
5
|
+
To set up your Capfile:
|
6
|
+
|
7
|
+
require "capistrano/datadog"
|
8
|
+
set :datadog_api_key, "my_api_key"
|
9
|
+
|
10
|
+
You can find your Datadog API key [here](https://app.datad0g.com/account/settings#api). If you don't have a Datadog account, you can sign up for one [here](http://www.datadoghq.com/).
|
11
|
+
|
12
|
+
`capistrano/datadog` will capture each Capistrano task that that Capfile runs, including the roles that the task applies to and any logging output that it emits and submits them as events to Datadog at the end of the execution of all the tasks. If sending to Datadog fails for any reason, your scripts will still succeed.
|
13
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require "benchmark"
|
2
|
+
require "etc"
|
3
|
+
require "md5"
|
4
|
+
require "socket"
|
5
|
+
require "time"
|
6
|
+
require "timeout"
|
7
|
+
|
8
|
+
require "dogapi"
|
9
|
+
|
10
|
+
# Monkeypatch capistrano to collect data about the tasks that it's running
|
11
|
+
module Capistrano
|
12
|
+
class Configuration
|
13
|
+
module Execution
|
14
|
+
# Attempts to locate the task at the given fully-qualified path, and
|
15
|
+
# execute it. If no such task exists, a Capistrano::NoSuchTaskError
|
16
|
+
# will be raised.
|
17
|
+
# Also, capture the time the task took to execute, and the logs it
|
18
|
+
# outputted for submission to Datadog
|
19
|
+
def find_and_execute_task(path, hooks={})
|
20
|
+
task = find_task(path) or raise NoSuchTaskError, "the task `#{path}' does not exist"
|
21
|
+
result = nil
|
22
|
+
reporter = Capistrano::Datadog.reporter
|
23
|
+
timing = Benchmark.measure(task.fully_qualified_name) do
|
24
|
+
# Set the current task so that the logger knows which task to
|
25
|
+
# associate the logs with
|
26
|
+
reporter.current_task = task.fully_qualified_name
|
27
|
+
trigger(hooks[:before], task) if hooks[:before]
|
28
|
+
result = execute_task(task)
|
29
|
+
trigger(hooks[:after], task) if hooks[:after]
|
30
|
+
reporter.current_task = nil
|
31
|
+
end
|
32
|
+
# Collect the timing in a list for later reporting
|
33
|
+
reporter.record_task task, timing
|
34
|
+
result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Logger
|
40
|
+
# Make the device attribute writeable so we can swap it out
|
41
|
+
# with something that captures logging out by task
|
42
|
+
attr_accessor :device
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
module Capistrano
|
48
|
+
module Datadog
|
49
|
+
# Singleton method for Reporter
|
50
|
+
def self.reporter()
|
51
|
+
@reporter || @reporter = Reporter.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# Collects info about the tasks that ran in order to submit to Datadog
|
55
|
+
class Reporter
|
56
|
+
attr_accessor :current_task
|
57
|
+
|
58
|
+
def initialize()
|
59
|
+
@tasks = []
|
60
|
+
@current_task = nil
|
61
|
+
@logging_output = {}
|
62
|
+
end
|
63
|
+
|
64
|
+
def record_task(task, timing)
|
65
|
+
@tasks << {
|
66
|
+
:name => task.fully_qualified_name,
|
67
|
+
:timing => timing.real,
|
68
|
+
:roles => task.options[:roles]
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def record_log(message)
|
73
|
+
if not @logging_output[@current_task]
|
74
|
+
@logging_output[@current_task] = []
|
75
|
+
end
|
76
|
+
@logging_output[@current_task] << message
|
77
|
+
end
|
78
|
+
|
79
|
+
def report()
|
80
|
+
hostname = Socket.gethostname
|
81
|
+
user = Etc.getlogin
|
82
|
+
|
83
|
+
# Lazy randomness
|
84
|
+
aggregation_key = Digest::MD5.hexdigest "#{Time.new}|#{rand}"
|
85
|
+
|
86
|
+
# Convert the tasks into Datadog events
|
87
|
+
@tasks.map do |task|
|
88
|
+
name = task[:name]
|
89
|
+
roles = (task[:roles] || []).sort
|
90
|
+
tags = ["#capistrano"] + (roles.map { |t| '#role:' + t })
|
91
|
+
title = "%s@%s ran %s on %s with capistrano in %.2f secs" % [user, hostname, name, roles.join(', '), task[:timing]]
|
92
|
+
type = "deploy"
|
93
|
+
alert_type = "success"
|
94
|
+
source_type = "capistrano"
|
95
|
+
message = "@@@" + "\n" + @logging_output[name].join('') + "@@@"
|
96
|
+
|
97
|
+
Dogapi::Event.new(message,
|
98
|
+
:msg_title => title,
|
99
|
+
:event_type => type,
|
100
|
+
:event_object => aggregation_key,
|
101
|
+
:alert_type => alert_type,
|
102
|
+
:source_type_name => source_type,
|
103
|
+
:tags => tags
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class LogCapture
|
110
|
+
def initialize(device)
|
111
|
+
@device = device
|
112
|
+
end
|
113
|
+
|
114
|
+
def puts(message)
|
115
|
+
Capistrano::Datadog::reporter.record_log message
|
116
|
+
@device.puts message
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Configuration.instance(:must_exist).load do
|
122
|
+
# Wrap the existing logging target with the Datadog capture class
|
123
|
+
logger.device = Datadog::LogCapture.new logger.device
|
124
|
+
|
125
|
+
# Trigger the Datadog submission once all the tasks have run
|
126
|
+
on :exit, "datadog:submit"
|
127
|
+
namespace :datadog do
|
128
|
+
desc "Submit the tasks that have run to Datadog as events"
|
129
|
+
task :submit do |ns|
|
130
|
+
begin
|
131
|
+
api_key = variables[:datadog_api_key]
|
132
|
+
if api_key
|
133
|
+
dog = Dogapi::Client.new(api_key)
|
134
|
+
Datadog::reporter.report.each do |event|
|
135
|
+
dog.emit_event event
|
136
|
+
end
|
137
|
+
else
|
138
|
+
puts "No api key set, not submitting to Datadog"
|
139
|
+
end
|
140
|
+
rescue Timeout::Error => e
|
141
|
+
puts "Could not submit to Datadog, request timed out."
|
142
|
+
rescue => e
|
143
|
+
puts "Could not submit to Datadog: #{e.inspect}\n#{e.backtrace.join("\n")}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
|
@@ -24,7 +24,8 @@ class TestClient < Test::Unit::TestCase
|
|
24
24
|
# post a metric to make sure the test host context exists
|
25
25
|
dog.emit_point('test.tag.metric', 1, :host => hostname)
|
26
26
|
|
27
|
-
|
27
|
+
# Disable this call until we fix the timeouts
|
28
|
+
# dog.all_tags()
|
28
29
|
|
29
30
|
dog.detach_tags(hostname)
|
30
31
|
code, resp = dog.host_tags(hostname)
|
@@ -72,9 +73,9 @@ class TestClient < Test::Unit::TestCase
|
|
72
73
|
|
73
74
|
code, resp = dog_r.emit_event(Dogapi::Event.new(now_message, :msg_title =>now_title, :date_happened => now_ts))
|
74
75
|
now_event_id = resp["event"]["id"]
|
75
|
-
sleep 1
|
76
76
|
code, resp = dog_r.emit_event(Dogapi::Event.new(before_message, :msg_title =>before_title, :date_happened => before_ts))
|
77
77
|
before_event_id = resp["event"]["id"]
|
78
|
+
sleep 3
|
78
79
|
|
79
80
|
code, resp = dog.stream(before_ts, now_ts + 1)
|
80
81
|
stream = resp["events"]
|
metadata
CHANGED
@@ -1,76 +1,97 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: dogapi
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 1.3.0
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Datadog, Inc.
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2012-04-30 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: json
|
16
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
24
|
none: false
|
18
|
-
requirements:
|
19
|
-
- -
|
20
|
-
- !ruby/object:Gem::Version
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 1
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 5
|
32
|
+
- 1
|
21
33
|
version: 1.5.1
|
22
34
|
type: :runtime
|
23
|
-
|
24
|
-
version_requirements: *9566260
|
35
|
+
version_requirements: *id001
|
25
36
|
description:
|
26
37
|
email: packages@datadoghq.com
|
27
38
|
executables: []
|
39
|
+
|
28
40
|
extensions: []
|
29
|
-
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
30
43
|
- README.rdoc
|
31
|
-
files:
|
32
|
-
- lib/
|
33
|
-
- lib/
|
34
|
-
- lib/dogapi/metric.rb
|
44
|
+
files:
|
45
|
+
- lib/capistrano/datadog.rb
|
46
|
+
- lib/capistrano/README.md
|
35
47
|
- lib/dogapi/common.rb
|
48
|
+
- lib/dogapi/event.rb
|
36
49
|
- lib/dogapi/facade.rb
|
50
|
+
- lib/dogapi/metric.rb
|
37
51
|
- lib/dogapi/v1/event.rb
|
38
|
-
- lib/dogapi/v1/tag.rb
|
39
52
|
- lib/dogapi/v1/metric.rb
|
53
|
+
- lib/dogapi/v1/tag.rb
|
54
|
+
- lib/dogapi/v1.rb
|
40
55
|
- lib/dogapi.rb
|
41
|
-
- tests/
|
42
|
-
- tests/ts_dogapi.rb
|
56
|
+
- tests/test_client.rb
|
43
57
|
- README.rdoc
|
44
58
|
homepage: http://datadoghq.com/
|
45
|
-
licenses:
|
59
|
+
licenses:
|
46
60
|
- BSD
|
47
61
|
post_install_message:
|
48
|
-
rdoc_options:
|
62
|
+
rdoc_options:
|
49
63
|
- --title
|
50
64
|
- DogAPI -- DataDog Client
|
51
65
|
- --main
|
52
66
|
- README.rdoc
|
53
67
|
- --line-numbers
|
54
68
|
- --inline-source
|
55
|
-
require_paths:
|
69
|
+
require_paths:
|
56
70
|
- lib
|
57
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
72
|
none: false
|
59
|
-
requirements:
|
60
|
-
- -
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
|
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
|
64
81
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
69
89
|
requirements: []
|
90
|
+
|
70
91
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.8.
|
92
|
+
rubygems_version: 1.8.11
|
72
93
|
signing_key:
|
73
94
|
specification_version: 3
|
74
95
|
summary: Ruby bindings for Datadog's API
|
75
|
-
test_files:
|
76
|
-
- tests/
|
96
|
+
test_files:
|
97
|
+
- tests/test_client.rb
|
data/tests/ts_dogapi.rb
DELETED