ffwd-google-cloud 0.4.0 → 0.4.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.
- 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.
|