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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c105cd9903f52b23602bfb3b6c21aa0a25e02294
4
- data.tar.gz: 41cc39f9192c0301fb2c450e9b5c214b4254b824
3
+ metadata.gz: 67ce27fdf5b4be025672e1f9976f65b8f0cf6b20
4
+ data.tar.gz: 73692e2a3c6ed2f31cd7a1a282d447ecb122cc57
5
5
  SHA512:
6
- metadata.gz: 2b4cb5bdf6522e2e2b3a318fd57077f5962e7a3d8666ecd847e5abb6d41f03080466ad45532aa0844f5be38847c4511c44eb7309a94ab9f7c3931b4811abd729
7
- data.tar.gz: 48ed69dc4005e1d82935c73894210ded2df4071136b682ee4d42ef6f16db4cc9e5482a72e7421b91774dba56460138d92f3f8bbeb2b1b041c7dc42738c5cee7a
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
- @api = "/cloudmonitoring/v2beta2/projects/#{@project_id}/timeseries:write"
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
- request = {
115
- "timeseries" => Utils.make_timeseries(metrics)
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
- with_token do |token|
121
- head = Hash[HEADER_BASE]
122
- head['Authorization'] = "Bearer #{token}"
215
+ verify_descriptors(request) do
216
+ with_token do |token|
217
+ head = Hash[HEADER_BASE]
218
+ head['Authorization'] = "Bearer #{token}"
123
219
 
124
- if log.debug?
125
- log.debug "Sending: #{metrics}"
126
- end
220
+ if log.debug?
221
+ log.debug "Sending: #{metrics}"
222
+ end
127
223
 
128
- new_proxy @api_c.post(:path => @api, :head => head, :body => metrics)
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
- @errbacks.each(&:call).clear
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
- buffer.map do |m|
20
- {:timeseriesDesc => make_desc(m), :point => make_point(m)}
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.key, :labels => make_labels(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
- labels["host"] = m.host
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
@@ -16,7 +16,7 @@
16
16
  module FFWD
17
17
  module Plugin
18
18
  module GoogleCloud
19
- VERSION = "0.4.0"
19
+ VERSION = "0.4.1"
20
20
  end
21
21
  end
22
22
  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.0
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-10 00:00:00.000000000 Z
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.0
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.0
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.0.14
100
+ rubygems_version: 2.2.2
101
101
  signing_key:
102
102
  specification_version: 4
103
103
  summary: Google Cloud Monitoring support for FFWD.