ffwd-google-cloud 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ffwd/plugin/google_cloud/hook.rb +152 -12
- data/lib/ffwd/plugin/google_cloud/utils.rb +42 -5
- data/lib/ffwd/plugin/google_cloud/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67ce27fdf5b4be025672e1f9976f65b8f0cf6b20
|
4
|
+
data.tar.gz: 73692e2a3c6ed2f31cd7a1a282d447ecb122cc57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05ee2f2a30305b29b0755b04b1ca591ba11e7d6121f3dfd0307ed5e730c0323b95f04663b234cdd18c776c578debbe390f22500061d78d808cdae51e89c0af10
|
7
|
+
data.tar.gz: a826644b2b8c4a1ceb3a12ed50ebae350bd6c0bc77e71a0a8571264c31f8903a1ee661a3366c0d1a7136680939f7ab70ded31a2be53124ca2589a7f11fc2f06f
|
@@ -15,6 +15,8 @@
|
|
15
15
|
|
16
16
|
require 'json'
|
17
17
|
|
18
|
+
require 'em/all'
|
19
|
+
|
18
20
|
require_relative 'utils'
|
19
21
|
|
20
22
|
require 'ffwd/flushing_output_hook'
|
@@ -42,9 +44,13 @@ module FFWD::Plugin::GoogleCloud
|
|
42
44
|
# list of blocks waiting for a token.
|
43
45
|
@pending = []
|
44
46
|
|
45
|
-
@
|
47
|
+
@write_api = "/cloudmonitoring/v2beta2/projects/#{@project_id}/timeseries:write"
|
48
|
+
@md_api = "/cloudmonitoring/v2beta2/projects/#{@project_id}/metricDescriptors"
|
46
49
|
@acquire = "/0.1/meta-data/service-accounts/default/acquire"
|
47
50
|
@expire_threshold = 10
|
51
|
+
|
52
|
+
# cache of seen metric descriptors
|
53
|
+
@md_cache = {}
|
48
54
|
end
|
49
55
|
|
50
56
|
def with_token &block
|
@@ -97,9 +103,95 @@ module FFWD::Plugin::GoogleCloud
|
|
97
103
|
not @api_c.nil? and not @metadata_c.nil?
|
98
104
|
end
|
99
105
|
|
106
|
+
def verify_descriptors(metrics, &block)
|
107
|
+
missing = []
|
108
|
+
|
109
|
+
metrics[:timeseries].each do |ts|
|
110
|
+
desc = ts[:timeseriesDesc]
|
111
|
+
name = desc[:metric]
|
112
|
+
missing << desc unless @md_cache[name]
|
113
|
+
end
|
114
|
+
|
115
|
+
if missing.empty?
|
116
|
+
return block.call
|
117
|
+
end
|
118
|
+
|
119
|
+
all = EM::All.new
|
120
|
+
|
121
|
+
# Example: {:metric=>"custom.cloudmonitoring.googleapis.com/lol", :labels=>{}}
|
122
|
+
missing.each do |m|
|
123
|
+
name = m[:metric]
|
124
|
+
|
125
|
+
body = {
|
126
|
+
:name => m[:metric], :description => m[:metric], :labels => Utils.extract_labels(m[:labels]),
|
127
|
+
:typeDescriptor => {:metricType => "gauge", :valueType => "double"}
|
128
|
+
}
|
129
|
+
|
130
|
+
log.info "Creating descriptor for: #{name}"
|
131
|
+
|
132
|
+
all << with_token{|token|
|
133
|
+
head = Hash[HEADER_BASE]
|
134
|
+
head['Authorization'] = "Bearer #{token}"
|
135
|
+
p = new_proxy(api_c.post(:path => @md_api, :head => head, :body => JSON.dump(body)))
|
136
|
+
|
137
|
+
p.callback do
|
138
|
+
log.info "Created (caching): #{name}"
|
139
|
+
@md_cache[name] = true
|
140
|
+
end
|
141
|
+
|
142
|
+
p.errback do |error|
|
143
|
+
log.error "Failed to create descriptor (#{error}): #{body}"
|
144
|
+
end
|
145
|
+
|
146
|
+
p
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
# TODO: call block _after_ descriptors have been verified.
|
151
|
+
all.callback do
|
152
|
+
block.call
|
153
|
+
end
|
154
|
+
|
155
|
+
all.errback do |errors|
|
156
|
+
log.error "Failed to create descriptors: #{errors}"
|
157
|
+
end
|
158
|
+
|
159
|
+
SingleProxy.new all
|
160
|
+
end
|
161
|
+
|
162
|
+
# avoid pipelining requests by creating a new handle for each
|
163
|
+
def api_c
|
164
|
+
EM::HttpRequest.new(@api_url)
|
165
|
+
end
|
166
|
+
|
100
167
|
def connect
|
101
168
|
@metadata_c = EM::HttpRequest.new(@metadata_url)
|
102
169
|
@api_c = EM::HttpRequest.new(@api_url)
|
170
|
+
|
171
|
+
with_token do |token|
|
172
|
+
log.info "Downloading metric descriptors"
|
173
|
+
|
174
|
+
head = Hash[HEADER_BASE]
|
175
|
+
head['Authorization'] = "Bearer #{token}"
|
176
|
+
req = @api_c.get(:path => @md_api, :head => head)
|
177
|
+
p = new_proxy(req)
|
178
|
+
|
179
|
+
p.callback do
|
180
|
+
res = JSON.load(req.response)
|
181
|
+
|
182
|
+
log.info "Downloaded #{res["metrics"].length} descriptor(s)"
|
183
|
+
|
184
|
+
res["metrics"].each do |d|
|
185
|
+
@md_cache[d["name"]] = true
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
p.errback do |error|
|
190
|
+
log.error "Failed to download metric descriptors: #{error}"
|
191
|
+
end
|
192
|
+
|
193
|
+
p
|
194
|
+
end
|
103
195
|
end
|
104
196
|
|
105
197
|
def close
|
@@ -111,21 +203,26 @@ module FFWD::Plugin::GoogleCloud
|
|
111
203
|
end
|
112
204
|
|
113
205
|
def send metrics
|
114
|
-
|
115
|
-
|
116
|
-
|
206
|
+
dropped, timeseries = Utils.make_timeseries(metrics)
|
207
|
+
|
208
|
+
if dropped > 0
|
209
|
+
log.warning "Dropped #{dropped} points (duplicate entries)"
|
210
|
+
end
|
117
211
|
|
212
|
+
request = {:timeseries => timeseries}
|
118
213
|
metrics = JSON.dump(request)
|
119
214
|
|
120
|
-
|
121
|
-
|
122
|
-
|
215
|
+
verify_descriptors(request) do
|
216
|
+
with_token do |token|
|
217
|
+
head = Hash[HEADER_BASE]
|
218
|
+
head['Authorization'] = "Bearer #{token}"
|
123
219
|
|
124
|
-
|
125
|
-
|
126
|
-
|
220
|
+
if log.debug?
|
221
|
+
log.debug "Sending: #{metrics}"
|
222
|
+
end
|
127
223
|
|
128
|
-
|
224
|
+
new_proxy api_c.post(:path => @write_api, :head => head, :body => metrics)
|
225
|
+
end
|
129
226
|
end
|
130
227
|
end
|
131
228
|
|
@@ -157,6 +254,45 @@ module FFWD::Plugin::GoogleCloud
|
|
157
254
|
end
|
158
255
|
end
|
159
256
|
|
257
|
+
class SingleProxy
|
258
|
+
attr_reader :error
|
259
|
+
|
260
|
+
def initialize p
|
261
|
+
@callbacks = []
|
262
|
+
@errbacks = []
|
263
|
+
|
264
|
+
p.callback do
|
265
|
+
call
|
266
|
+
end
|
267
|
+
|
268
|
+
p.errback do |error|
|
269
|
+
err error
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def callback &block
|
274
|
+
@callbacks << block
|
275
|
+
end
|
276
|
+
|
277
|
+
def errback &block
|
278
|
+
@errbacks << block
|
279
|
+
end
|
280
|
+
|
281
|
+
def call
|
282
|
+
@callbacks.each(&:call).clear
|
283
|
+
end
|
284
|
+
|
285
|
+
def err error
|
286
|
+
return if @errbacks.empty?
|
287
|
+
|
288
|
+
@error = error
|
289
|
+
|
290
|
+
@errbacks.each do |cb|
|
291
|
+
cb.call error
|
292
|
+
end.clear
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
160
296
|
class CallbackProxy
|
161
297
|
attr_reader :error
|
162
298
|
|
@@ -179,8 +315,12 @@ module FFWD::Plugin::GoogleCloud
|
|
179
315
|
|
180
316
|
def err error
|
181
317
|
return if @errbacks.empty?
|
318
|
+
|
182
319
|
@error = error
|
183
|
-
|
320
|
+
|
321
|
+
@errbacks.each do |cb|
|
322
|
+
cb.call error
|
323
|
+
end.clear
|
184
324
|
end
|
185
325
|
|
186
326
|
def into other
|
@@ -12,13 +12,32 @@
|
|
12
12
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
13
|
# License for the specific language governing permissions and limitations under
|
14
14
|
# the License.
|
15
|
+
require 'set'
|
15
16
|
|
16
17
|
module FFWD::Plugin::GoogleCloud
|
18
|
+
CUSTOM_PREFIX = "custom.cloudmonitoring.googleapis.com"
|
19
|
+
|
17
20
|
module Utils
|
18
21
|
def self.make_timeseries buffer
|
19
|
-
|
20
|
-
|
22
|
+
# we are not allowed to send duplicate data.
|
23
|
+
seen = Set.new
|
24
|
+
|
25
|
+
result = []
|
26
|
+
dropped = 0
|
27
|
+
|
28
|
+
buffer.each do |m|
|
29
|
+
d = make_desc(m)
|
30
|
+
|
31
|
+
if seen.member?(d[:metric])
|
32
|
+
dropped += 1
|
33
|
+
next
|
34
|
+
end
|
35
|
+
|
36
|
+
seen.add(d[:metric])
|
37
|
+
result << {:timeseriesDesc => make_desc(m), :point => make_point(m)}
|
21
38
|
end
|
39
|
+
|
40
|
+
[dropped, result]
|
22
41
|
end
|
23
42
|
|
24
43
|
def self.make_point m
|
@@ -27,13 +46,31 @@ module FFWD::Plugin::GoogleCloud
|
|
27
46
|
end
|
28
47
|
|
29
48
|
def self.make_desc m
|
30
|
-
{:metric => m
|
49
|
+
{:metric => make_key(m), :labels => make_labels(m)}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.make_key m
|
53
|
+
what ||= m.attributes[:what]
|
54
|
+
what ||= m.attributes["what"]
|
55
|
+
|
56
|
+
if what.nil?
|
57
|
+
"#{CUSTOM_PREFIX}/#{m.key}"
|
58
|
+
else
|
59
|
+
"#{CUSTOM_PREFIX}/#{m.key}.#{what}"
|
60
|
+
end
|
31
61
|
end
|
32
62
|
|
33
63
|
def self.make_labels m
|
34
|
-
labels = Hash[m.attributes
|
35
|
-
|
64
|
+
labels = Hash[m.attributes.select{|k, v| k.to_s != "what"}.map{|k, v|
|
65
|
+
["#{CUSTOM_PREFIX}/#{k}", v]
|
66
|
+
}]
|
67
|
+
|
68
|
+
#labels["#{CUSTOM_PREFIX}/host"] = m.host
|
36
69
|
labels
|
37
70
|
end
|
71
|
+
|
72
|
+
def self.extract_labels source
|
73
|
+
source.map{|k, v| {:key => k, :description => k}}
|
74
|
+
end
|
38
75
|
end
|
39
76
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffwd-google-cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John-John Tedro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-http-request
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.4.
|
33
|
+
version: 0.4.1
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.4.
|
40
|
+
version: 0.4.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,10 +73,10 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- lib/ffwd/plugin/google_cloud.rb
|
76
77
|
- lib/ffwd/plugin/google_cloud/hook.rb
|
77
78
|
- lib/ffwd/plugin/google_cloud/utils.rb
|
78
79
|
- lib/ffwd/plugin/google_cloud/version.rb
|
79
|
-
- lib/ffwd/plugin/google_cloud.rb
|
80
80
|
homepage: https://github.com/spotify/ffwd
|
81
81
|
licenses:
|
82
82
|
- Apache 2.0
|
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
97
|
version: '0'
|
98
98
|
requirements: []
|
99
99
|
rubyforge_project:
|
100
|
-
rubygems_version: 2.
|
100
|
+
rubygems_version: 2.2.2
|
101
101
|
signing_key:
|
102
102
|
specification_version: 4
|
103
103
|
summary: Google Cloud Monitoring support for FFWD.
|