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 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.