zuora_connect 1.6.05 → 1.6.06
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/app/controllers/zuora_connect/api/v1/app_instance_controller.rb +16 -8
- data/app/models/zuora_connect/app_instance_base.rb +51 -93
- data/app/models/zuora_connect/login.rb +3 -3
- data/config/initializers/postgresql_adapter.rb +32 -0
- data/lib/metrics/influx/point_value.rb +79 -0
- data/lib/metrics/net.rb +218 -0
- data/lib/middleware/metrics_middleware.rb +36 -40
- data/lib/zuora_connect/configuration.rb +14 -6
- data/lib/zuora_connect/controllers/helpers.rb +1 -1
- data/lib/zuora_connect/version.rb +1 -1
- data/lib/zuora_connect.rb +2 -1
- metadata +9 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aab6b6790b92249ea03f26bf79222ec77720566
|
4
|
+
data.tar.gz: 5f09e4567ab8a4bdac1defe735a5b43809295dd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b20a0da49a4ee3ff62950fb04419a5d3a98fe1d381ed9b9bcc04c7564c8e9d053db136740a82ff74ad950ce47e094aa63b66739dc35ba1a7d4924c95ab4541b
|
7
|
+
data.tar.gz: fe902be31ee9eb458cc92204cc4addb4ea50a973973247b6a1d44fb1b670a0d0dc35b1644ac5ff8248741b1926dd589e8d17372b1199975530fb98ddbc65a2b9
|
@@ -13,17 +13,25 @@ module ZuoraConnect
|
|
13
13
|
def drop
|
14
14
|
instance_id = @appinstance.id
|
15
15
|
if session["#{instance_id}::destroy"] && ZuoraConnect::AppInstance.where(:id => instance_id).size != 0
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
if @appinstance.drop_instance
|
17
|
+
ZuoraConnect::AppInstance.destroy(instance_id)
|
18
|
+
msg = Apartment::Tenant.drop(instance_id)
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
if msg.error_message.present?
|
22
|
+
format.json {render json: {"message" => msg.error_message}, status: :bad_request }
|
23
|
+
else
|
24
|
+
format.json {render json: {}, status: :ok}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
respond_to do |format|
|
29
|
+
format.json {render json: {"message" => @appinstance.drop_message}, status: :bad_request}
|
30
|
+
end
|
23
31
|
end
|
24
32
|
else
|
25
33
|
respond_to do |format|
|
26
|
-
format.json {render :
|
34
|
+
format.json { render json: { "message" => "Unauthorized"}, status: :unauthorized }
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
@@ -4,8 +4,8 @@ module ZuoraConnect
|
|
4
4
|
default_scope {select(ZuoraConnect::AppInstance.column_names.delete_if {|x| ["catalog_mapping", "catalog"].include?(x) }) }
|
5
5
|
after_initialize :init
|
6
6
|
self.table_name = "zuora_connect_app_instances"
|
7
|
-
attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version
|
8
|
-
|
7
|
+
attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message
|
8
|
+
@@telegraf_host = nil
|
9
9
|
REFRESH_TIMEOUT = 2.minute #Used to determine how long to wait on current refresh call before executing another
|
10
10
|
INSTANCE_REFRESH_WINDOW = 30.minutes #Used to set how how long till app starts attempting to refresh cached task connect data
|
11
11
|
INSTANCE_REDIS_CACHE_PERIOD = 60.minutes #Used to determine how long to cached task data will live for
|
@@ -25,12 +25,31 @@ module ZuoraConnect
|
|
25
25
|
self.apartment_switch(nil, true)
|
26
26
|
end
|
27
27
|
|
28
|
+
def self.write_metric(series: 'Unknown', tags: {}, values: {})
|
29
|
+
begin
|
30
|
+
if @@telegraf_host.blank?
|
31
|
+
Rails.logger.debug('Need new connection') if ZuoraConnect.configuration.telegraf_debug
|
32
|
+
uri = URI.parse(ZuoraConnect.configuration.telegraf_endpoint)
|
33
|
+
@@telegraf_host = UDPSocket.new.tap do |socket|
|
34
|
+
socket.connect uri.host, uri.port
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@@telegraf_host.write InfluxDB::PointValue.new({series: series, tags: tags, values: values}).dump
|
38
|
+
rescue => ex
|
39
|
+
@@telegraf_host = nil
|
40
|
+
Rails.logger.tagged("Telegraf") do
|
41
|
+
logger.warn('Failed to write')
|
42
|
+
logger.warn(ex.class)
|
43
|
+
logger.warn(ex.message)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
28
47
|
|
29
48
|
# Methods for writing Telegraf metrics
|
30
49
|
|
31
50
|
# Returns the process type if any
|
32
51
|
def self.get_process_type
|
33
|
-
p_type =
|
52
|
+
p_type = 'Unknown'
|
34
53
|
if ENV['HOSTNAME'] && ENV['DEIS_APP']
|
35
54
|
temp = ENV['HOSTNAME'].split(ENV['DEIS_APP'])[1]
|
36
55
|
temp = temp.split(/(-[0-9a-zA-Z]{5})$/)[0] # remove the 5 char hash
|
@@ -40,57 +59,31 @@ module ZuoraConnect
|
|
40
59
|
end
|
41
60
|
|
42
61
|
# Write to telegraf
|
43
|
-
def self.write_to_telegraf(
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
ZuoraConnect.configuration.
|
58
|
-
|
59
|
-
values: {response_time: response_time, db_time: db_runtime, view_time: view_runtime})
|
60
|
-
rescue => e
|
61
|
-
raise e
|
62
|
-
end
|
63
|
-
else
|
64
|
-
# non 200 requests
|
65
|
-
begin
|
66
|
-
ZuoraConnect.configuration.telegraf_client.write(ZuoraConnect.configuration.influxdb_series_name_inbound,
|
67
|
-
tags: {"app_name": "#{ZuoraConnect.configuration.app_name}", "controller": endpoint_name.split("#")[0] , "action": endpoint_name.split("#")[1], "content-type": content_type, method: method_name, status: status_code, process_type: p_type, "app_instance": app_instance},
|
68
|
-
values: {response_time: response_time})
|
69
|
-
rescue=> e
|
70
|
-
raise e
|
62
|
+
def self.write_to_telegraf(direction: nil, tags: {}, values: {})
|
63
|
+
Rails.logger.tagged("Telegraf") do
|
64
|
+
time = Benchmark.measure do |bench|
|
65
|
+
# To avoid writing metrics from rspec tests
|
66
|
+
if ENV['DEIS_APP'] || true
|
67
|
+
# Getting the process type
|
68
|
+
p_type = self.get_process_type
|
69
|
+
app_instance = Thread.current[:appinstance].present? ? Thread.current[:appinstance].id : 0
|
70
|
+
tags = tags.merge({ app_name: ZuoraConnect.configuration.app_name, process_type: p_type, app_instance: app_instance})
|
71
|
+
|
72
|
+
if direction == :inbound && ZuoraConnect.configuration.enable_inbound_metrics_flag
|
73
|
+
series = ZuoraConnect.configuration.influxdb_series_name_inbound
|
74
|
+
self.write_metric(series: series, tags: tags, values: values)
|
75
|
+
elsif direction == :outbound && ZuoraConnect.configuration.enable_outbound_metrics_flag
|
76
|
+
series = ZuoraConnect.configuration.influxdb_series_name_outbound
|
77
|
+
self.write_metric(series: series, tags: tags, values: values)
|
71
78
|
end
|
72
|
-
end
|
73
79
|
|
74
|
-
elsif direction == "outbound" && ZuoraConnect.configuration.enable_outbound_metrics_flag
|
75
|
-
# if there is an error
|
76
|
-
if error_type
|
77
|
-
begin
|
78
|
-
ZuoraConnect.configuration.telegraf_client.write(ZuoraConnect.configuration.influxdb_series_name_outbound,
|
79
|
-
tags: {"app_name": "#{ZuoraConnect.configuration.app_name}", endpoint: endpoint_name, status: status_code, process_type: p_type, "app_instance": app_instance, "function_name": function_name, method: method_name, "error_type": error_type},
|
80
|
-
values: {response_time: response_time})
|
81
|
-
rescue => e
|
82
|
-
raise e
|
83
|
-
end
|
84
|
-
else
|
85
|
-
begin
|
86
|
-
ZuoraConnect.configuration.telegraf_client.write(ZuoraConnect.configuration.influxdb_series_name_outbound,
|
87
|
-
tags: {"app_name": "#{ZuoraConnect.configuration.app_name}", endpoint: endpoint_name, status: status_code, process_type: p_type, "app_instance": app_instance, "function_name": function_name, method: method_name},
|
88
|
-
values: {response_time: response_time})
|
89
|
-
rescue => e
|
90
|
-
raise e
|
91
|
-
end
|
92
80
|
end
|
93
81
|
end
|
82
|
+
if ZuoraConnect.configuration.telegraf_debug
|
83
|
+
Rails.logger.debug(tags.to_s)
|
84
|
+
Rails.logger.debug(values.to_s)
|
85
|
+
Rails.logger.debug("Writing #{direction.capitalize}: #{time.real.round(4)}")
|
86
|
+
end
|
94
87
|
end
|
95
88
|
end
|
96
89
|
|
@@ -223,7 +216,6 @@ module ZuoraConnect
|
|
223
216
|
|
224
217
|
def refresh(session = nil)
|
225
218
|
refresh_count ||= 0
|
226
|
-
error_type = ""
|
227
219
|
start = Time.now
|
228
220
|
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
|
229
221
|
response_time = Time.now - start
|
@@ -243,7 +235,6 @@ module ZuoraConnect
|
|
243
235
|
Rails.logger.info("[#{self.id}] REFRESH TASK - #{ex.class} Retrying(#{refresh_count})")
|
244
236
|
retry
|
245
237
|
else
|
246
|
-
error_type = "#{ex.class}"
|
247
238
|
Rails.logger.fatal("[#{self.id}] REFRESH TASK - #{ex.class} Failed #{refresh_count}x")
|
248
239
|
raise
|
249
240
|
end
|
@@ -255,16 +246,9 @@ module ZuoraConnect
|
|
255
246
|
end
|
256
247
|
retry
|
257
248
|
else
|
258
|
-
error_type = "#{ex.class}"
|
259
249
|
Rails.logger.fatal("[#{self.id}] REFRESH TASK - Failed #{refresh_count}x")
|
260
250
|
raise
|
261
251
|
end
|
262
|
-
ensure
|
263
|
-
# Writing to telegraf
|
264
|
-
status_code = response.code if response
|
265
|
-
endpoint_name = URI(ZuoraConnect.configuration.url).host
|
266
|
-
Thread.current[:appinstance].present? ? app_instance = Thread.current[:appinstance].id : app_instance = 0
|
267
|
-
ZuoraConnect::AppInstanceBase.write_to_telegraf("response_time": response_time, "status_code": status_code, "endpoint_name": endpoint_name, "direction": "outbound", "error_type": error_type, "function_name": "#{self.class}##{__method__}", "method_name": "GET", "app_instance": app_instance)
|
268
252
|
end
|
269
253
|
|
270
254
|
#### START Task Mathods ####
|
@@ -304,28 +288,13 @@ module ZuoraConnect
|
|
304
288
|
end
|
305
289
|
|
306
290
|
def updateOption(optionId, value)
|
307
|
-
|
308
|
-
start_time = Time.now
|
309
|
-
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/application_options/#{optionId}/edit?value=#{value}",:body => {:access_token => self.username})
|
310
|
-
rescue => e
|
311
|
-
error_type = "#{e.class}"
|
312
|
-
ensure
|
313
|
-
end_time = Time.now
|
314
|
-
response_time = end_time - start_time
|
315
|
-
status_code = response.code if response
|
316
|
-
endpoint_name = URI(ZuoraConnect.configuration.url).host
|
317
|
-
Thread.current[:appinstance].present? ? app_instance = Thread.current[:appinstance].id : app_instance = 0
|
318
|
-
ZuoraConnect::AppInstanceBase.write_to_telegraf("response_time": response_time, "status_code": status_code, "endpoint_name": endpoint_name, "direction": "outbound", "error_type": error_type, "function_name": "#{self.class}##{__method__}", "method_name": "GET", "app_instance": app_instance)
|
319
|
-
return response
|
320
|
-
end
|
291
|
+
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/application_options/#{optionId}/edit?value=#{value}",:body => {:access_token => self.username})
|
321
292
|
end
|
322
293
|
|
323
294
|
#This can update an existing login, add a new login, change to another existing login
|
324
295
|
#EXAMPLE: {"name": "ftp_login_14","username": "ftplogin7","tenant_type": "Custom","password": "test2","url": "www.ftp.com","custom_data": { "path": "/var/usr/test"}}
|
325
296
|
def update_logins(options)
|
326
297
|
update_login_count ||= 0
|
327
|
-
start_time = Time.now
|
328
|
-
error_type = ""
|
329
298
|
response = HTTParty.post(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}/logins",:body => {:access_token => self.username}.merge(options))
|
330
299
|
parsed_json = JSON.parse(response.body)
|
331
300
|
if response.code == 200
|
@@ -344,7 +313,6 @@ module ZuoraConnect
|
|
344
313
|
if (update_login_count += 1) < 3
|
345
314
|
retry
|
346
315
|
else
|
347
|
-
error_type = "#{ex.class}"
|
348
316
|
raise
|
349
317
|
end
|
350
318
|
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
@@ -354,16 +322,8 @@ module ZuoraConnect
|
|
354
322
|
end
|
355
323
|
retry
|
356
324
|
else
|
357
|
-
error_type = "#{ex.class}"
|
358
325
|
raise
|
359
326
|
end
|
360
|
-
ensure
|
361
|
-
end_time = Time.now
|
362
|
-
response_time = end_time - start_time
|
363
|
-
status_code = response.code if response
|
364
|
-
endpoint_name = URI(ZuoraConnect.configuration.url).host
|
365
|
-
Thread.current[:appinstance].present? ? app_instance = Thread.current[:appinstance].id : app_instance = 0
|
366
|
-
ZuoraConnect::AppInstanceBase.write_to_telegraf("response_time": response_time, "status_code": status_code, "endpoint_name": endpoint_name, "direction": "outbound", "error_type": error_type, "function_name": "#{self.class}##{__method__}", "method_name": "POST", "app_instance": app_instance)
|
367
327
|
end
|
368
328
|
#### END Task Mathods ####
|
369
329
|
|
@@ -382,7 +342,6 @@ module ZuoraConnect
|
|
382
342
|
|
383
343
|
def refresh_oauth
|
384
344
|
refresh_oauth_count ||= 0
|
385
|
-
error_type = ""
|
386
345
|
start = Time.now
|
387
346
|
params = {
|
388
347
|
:grant_type => "refresh_token",
|
@@ -409,7 +368,6 @@ module ZuoraConnect
|
|
409
368
|
Rails.logger.info("[#{self.id}] REFRESH OAUTH - #{ex.class} Retrying(#{refresh_oauth_count})")
|
410
369
|
retry
|
411
370
|
else
|
412
|
-
error_type = "#{ex.class}"
|
413
371
|
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - #{ex.class} Failed #{refresh_oauth_count}x")
|
414
372
|
raise
|
415
373
|
end
|
@@ -424,15 +382,9 @@ module ZuoraConnect
|
|
424
382
|
Rails.logger.info("[#{self.id}] REFRESH OAUTH - Failed Retrying(#{refresh_oauth_count})")
|
425
383
|
retry
|
426
384
|
else
|
427
|
-
error_type = "#{ex.class}"
|
428
385
|
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed #{refresh_oauth_count}x")
|
429
386
|
raise
|
430
387
|
end
|
431
|
-
ensure
|
432
|
-
status_code = response.code if response
|
433
|
-
endpoint_name = URI(ZuoraConnect.configuration.url).host
|
434
|
-
Thread.current[:appinstance].present? ? app_instance = Thread.current[:appinstance].id : app_instance = 0
|
435
|
-
ZuoraConnect::AppInstanceBase.write_to_telegraf("response_time": response_time, "status_code": status_code, "endpoint_name": endpoint_name, "direction": "outbound", "error_type": error_type, "function_name": "#{self.class}##{__method__}", "method_name": "POST", "app_instance": app_instance)
|
436
388
|
end
|
437
389
|
#### END Connect OAUTH methods ####
|
438
390
|
|
@@ -479,7 +431,7 @@ module ZuoraConnect
|
|
479
431
|
if defined?(Redis.current)
|
480
432
|
#Task data must be present and the last refresh cannot be old. We dont want to overwite new cache data with old
|
481
433
|
if self.task_data.present? && (self.last_refresh.to_i > INSTANCE_REFRESH_WINDOW.ago.to_i)
|
482
|
-
Rails.logger.
|
434
|
+
Rails.logger.debug("[#{self.id}] Caching AppInstance")
|
483
435
|
Redis.current.setex("AppInstance:#{self.id}", INSTANCE_REDIS_CACHE_PERIOD.to_i, encrypt_data(data: self.save_data))
|
484
436
|
end
|
485
437
|
Redis.current.del("Deleted:#{self.id}")
|
@@ -846,6 +798,12 @@ module ZuoraConnect
|
|
846
798
|
return true
|
847
799
|
end
|
848
800
|
|
801
|
+
#Method for overiding droping of an app instance
|
802
|
+
def drop_instance
|
803
|
+
self.drop_message = 'Ok to drop'
|
804
|
+
return true
|
805
|
+
end
|
806
|
+
|
849
807
|
def reload_attributes(selected_attributes)
|
850
808
|
raise "Attibutes must be array" if selected_attributes.class != Array
|
851
809
|
value_attributes = self.class.unscoped.where(:id=>id).select(selected_attributes).first.attributes
|
@@ -4,15 +4,15 @@ module ZuoraConnect
|
|
4
4
|
def initialize (fields)
|
5
5
|
@clients = {}
|
6
6
|
if fields["tenant_type"] == "Zuora" && fields["entities"] && fields["entities"].size > 0
|
7
|
-
@clients["Default"] = ::ZuoraAPI::
|
7
|
+
@clients["Default"] = ::ZuoraAPI::Basic.new(fields.map{|k,v| [k.to_sym, v]}.to_h)
|
8
8
|
@default_entity = fields["entities"][0]["id"] if fields["entities"].size == 1
|
9
9
|
fields["entities"].each do |entity|
|
10
10
|
login_fields = fields.map{|k,v| [k.to_sym, v]}.to_h
|
11
11
|
login_fields[:entity_id] = entity["id"]
|
12
|
-
@clients[entity["id"]] = ::ZuoraAPI::
|
12
|
+
@clients[entity["id"]] = ::ZuoraAPI::Basic.new(login_fields)
|
13
13
|
end
|
14
14
|
elsif fields["tenant_type"] == "Zuora"
|
15
|
-
@clients["Default"] = ::ZuoraAPI::
|
15
|
+
@clients["Default"] = ::ZuoraAPI::Basic.new(fields.map{|k,v| [k.to_sym, v]}.to_h)
|
16
16
|
end
|
17
17
|
|
18
18
|
self.attr_builder("available_entities",@clients.keys) if fields["tenant_type"] == "Zuora"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class PostgreSQLAdapter < AbstractAdapter
|
4
|
+
private
|
5
|
+
def load_additional_types(type_map, oids = nil)
|
6
|
+
initializer = OID::TypeMapInitializer.new(type_map)
|
7
|
+
if supports_ranges?
|
8
|
+
query = <<-SQL
|
9
|
+
SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
10
|
+
FROM pg_type as t
|
11
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
12
|
+
SQL
|
13
|
+
else
|
14
|
+
query = <<-SQL
|
15
|
+
SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
|
16
|
+
FROM pg_type as t
|
17
|
+
SQL
|
18
|
+
end
|
19
|
+
|
20
|
+
if oids
|
21
|
+
query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
|
22
|
+
else
|
23
|
+
query += initializer.query_conditions_for_initial_load(type_map)
|
24
|
+
end
|
25
|
+
|
26
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
27
|
+
initializer.run(records)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module InfluxDB
|
2
|
+
# Convert data point to string using Line protocol
|
3
|
+
class PointValue
|
4
|
+
attr_reader :series, :values, :tags, :timestamp
|
5
|
+
|
6
|
+
def initialize(data)
|
7
|
+
@series = escape data[:series], :measurement
|
8
|
+
@values = escape_values data[:values]
|
9
|
+
@tags = escape_tags data[:tags]
|
10
|
+
@timestamp = data[:timestamp]
|
11
|
+
end
|
12
|
+
|
13
|
+
def dump
|
14
|
+
dump = @series.dup
|
15
|
+
dump << ",#{@tags}" if @tags
|
16
|
+
dump << " #{@values}"
|
17
|
+
dump << " #{@timestamp}" if @timestamp
|
18
|
+
dump
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
ESCAPES = {
|
24
|
+
measurement: [' '.freeze, ','.freeze],
|
25
|
+
tag_key: ['='.freeze, ' '.freeze, ','.freeze],
|
26
|
+
tag_value: ['='.freeze, ' '.freeze, ','.freeze],
|
27
|
+
field_key: ['='.freeze, ' '.freeze, ','.freeze, '"'.freeze],
|
28
|
+
field_value: ["\\".freeze, '"'.freeze],
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
private_constant :ESCAPES
|
32
|
+
|
33
|
+
def escape(str, type)
|
34
|
+
# rubocop:disable Layout/AlignParameters
|
35
|
+
str = str.encode "UTF-8".freeze, "UTF-8".freeze,
|
36
|
+
invalid: :replace,
|
37
|
+
undef: :replace,
|
38
|
+
replace: "".freeze
|
39
|
+
# rubocop:enable Layout/AlignParameters
|
40
|
+
|
41
|
+
ESCAPES[type].each do |ch|
|
42
|
+
str = str.gsub(ch) { "\\#{ch}" }
|
43
|
+
end
|
44
|
+
str
|
45
|
+
end
|
46
|
+
|
47
|
+
def escape_values(values)
|
48
|
+
return if values.nil?
|
49
|
+
values.map do |k, v|
|
50
|
+
key = escape(k.to_s, :field_key)
|
51
|
+
val = escape_value(v)
|
52
|
+
"#{key}=#{val}"
|
53
|
+
end.join(",".freeze)
|
54
|
+
end
|
55
|
+
|
56
|
+
def escape_value(value)
|
57
|
+
if value.is_a?(String)
|
58
|
+
'"'.freeze + escape(value, :field_value) + '"'.freeze
|
59
|
+
elsif value.is_a?(Integer)
|
60
|
+
"#{value}i"
|
61
|
+
else
|
62
|
+
value.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def escape_tags(tags)
|
67
|
+
return if tags.nil?
|
68
|
+
|
69
|
+
tags = tags.map do |k, v|
|
70
|
+
key = escape(k.to_s, :tag_key)
|
71
|
+
val = escape(v.to_s, :tag_value)
|
72
|
+
|
73
|
+
"#{key}=#{val}" unless key == "".freeze || val == "".freeze
|
74
|
+
end.compact
|
75
|
+
|
76
|
+
tags.join(",") unless tags.empty?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/metrics/net.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# require 'http_logger'
|
8
|
+
#
|
9
|
+
# == Setup logger
|
10
|
+
#
|
11
|
+
# HttpLogger.logger = Logger.new('/tmp/all.log')
|
12
|
+
# HttpLogger.log_headers = true
|
13
|
+
#
|
14
|
+
# == Do request
|
15
|
+
#
|
16
|
+
# res = Net::HTTP.start(url.host, url.port) { |http|
|
17
|
+
# http.request(req)
|
18
|
+
# }
|
19
|
+
# ...
|
20
|
+
#
|
21
|
+
# == View the log
|
22
|
+
#
|
23
|
+
# cat /tmp/all.log
|
24
|
+
class HttpLogger
|
25
|
+
class << self
|
26
|
+
attr_accessor :collapse_body_limit
|
27
|
+
attr_accessor :log_headers
|
28
|
+
attr_accessor :log_request_body
|
29
|
+
attr_accessor :log_response_body
|
30
|
+
attr_accessor :logger
|
31
|
+
attr_accessor :colorize
|
32
|
+
attr_accessor :ignore
|
33
|
+
attr_accessor :level
|
34
|
+
end
|
35
|
+
|
36
|
+
self.log_headers = false
|
37
|
+
self.log_request_body = true
|
38
|
+
self.log_response_body = true
|
39
|
+
self.colorize = true
|
40
|
+
self.collapse_body_limit = 5000
|
41
|
+
self.ignore = []
|
42
|
+
self.level = :debug
|
43
|
+
|
44
|
+
def self.perform(*args, &block)
|
45
|
+
instance.perform(*args, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.instance
|
49
|
+
@instance ||= HttpLogger.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.deprecate_config(option)
|
53
|
+
warn "Net::HTTP.#{option} is deprecated. Use HttpLogger.#{option} instead."
|
54
|
+
end
|
55
|
+
|
56
|
+
def perform(http, request, request_body)
|
57
|
+
start_time = Time.now
|
58
|
+
tags = {}
|
59
|
+
response = yield
|
60
|
+
rescue => ex
|
61
|
+
tags = tags.merge({error_type: ex.class})
|
62
|
+
raise
|
63
|
+
ensure
|
64
|
+
values = {response_time: ((Time.now - start_time)*1000).round(2)}
|
65
|
+
if require_logging?(http, request)
|
66
|
+
tags = tags.merge({endpoint: http.address, method: request.method})
|
67
|
+
log_request_url(http, request, start_time)
|
68
|
+
log_request_body(request)
|
69
|
+
log_request_headers(request)
|
70
|
+
if defined?(response) && response
|
71
|
+
tags = tags.merge({status: response.code.to_i})
|
72
|
+
log_response_code(response)
|
73
|
+
log_response_headers(response)
|
74
|
+
log_response_body(response.body)
|
75
|
+
end
|
76
|
+
ZuoraConnect::AppInstance.write_to_telegraf(direction: :outbound, tags: tags, values: values)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def log_request_url(http, request, start_time)
|
83
|
+
ofset = Time.now - start_time
|
84
|
+
log("HTTP #{request.method} (%0.2fms)" % (ofset * 1000), request_url(http, request))
|
85
|
+
end
|
86
|
+
|
87
|
+
def request_url(http, request)
|
88
|
+
URI.decode("http#{"s" if http.use_ssl?}://#{http.address}:#{http.port}#{request.path}")
|
89
|
+
end
|
90
|
+
|
91
|
+
def log_request_headers(request)
|
92
|
+
if self.class.log_headers
|
93
|
+
request.each_capitalized { |k,v| log("HTTP request header", "#{k}: #{v}") }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
HTTP_METHODS_WITH_BODY = Set.new(%w(POST PUT GET PATCH))
|
98
|
+
|
99
|
+
def log_request_body(request)
|
100
|
+
if self.class.log_request_body
|
101
|
+
if HTTP_METHODS_WITH_BODY.include?(request.method)
|
102
|
+
if (body = request.body) && !body.empty?
|
103
|
+
log("Request body", truncate_body(body))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def log_response_code(response)
|
110
|
+
log("Response status", "#{response.class} (#{response.code})")
|
111
|
+
end
|
112
|
+
|
113
|
+
def log_response_headers(response)
|
114
|
+
if self.class.log_headers
|
115
|
+
response.each_capitalized { |k,v| log("HTTP response header", "#{k}: #{v}") }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def log_response_body(body)
|
120
|
+
if self.class.log_response_body
|
121
|
+
if body.is_a?(Net::ReadAdapter)
|
122
|
+
log("Response body", "<impossible to log>")
|
123
|
+
else
|
124
|
+
if body && !body.empty?
|
125
|
+
log("Response body", truncate_body(body))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def require_logging?(http, request)
|
132
|
+
self.logger && !ignored?(http, request) && (http.started? || fakeweb?(http, request))
|
133
|
+
end
|
134
|
+
|
135
|
+
def ignored?(http, request)
|
136
|
+
url = request_url(http, request)
|
137
|
+
self.class.ignore.any? do |pattern|
|
138
|
+
url =~ pattern
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def fakeweb?(http, request)
|
143
|
+
return false unless defined?(::FakeWeb)
|
144
|
+
uri = ::FakeWeb::Utility.request_uri_as_string(http, request)
|
145
|
+
method = request.method.downcase.to_sym
|
146
|
+
::FakeWeb.registered_uri?(method, uri)
|
147
|
+
end
|
148
|
+
|
149
|
+
def truncate_body(body)
|
150
|
+
if collapse_body_limit && collapse_body_limit > 0 && body && body.size >= collapse_body_limit
|
151
|
+
body_piece_size = collapse_body_limit / 2
|
152
|
+
body[0..body_piece_size] +
|
153
|
+
"\n\n<some data truncated>\n\n" +
|
154
|
+
body[(body.size - body_piece_size)..body.size]
|
155
|
+
else
|
156
|
+
body
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def log(message, dump)
|
161
|
+
self.logger.send(self.class.level, format_log_entry(message, dump)) if Rails.env.to_sym == :development
|
162
|
+
end
|
163
|
+
|
164
|
+
def format_log_entry(message, dump = nil)
|
165
|
+
if self.class.colorize
|
166
|
+
message_color, dump_color = "4;32;1", "0;1"
|
167
|
+
log_entry = " \e[#{message_color}m#{message}\e[0m "
|
168
|
+
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
|
169
|
+
log_entry
|
170
|
+
else
|
171
|
+
"%s %s" % [message, dump]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def logger
|
176
|
+
self.class.logger
|
177
|
+
end
|
178
|
+
|
179
|
+
def collapse_body_limit
|
180
|
+
self.class.collapse_body_limit
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class Net::HTTP
|
185
|
+
|
186
|
+
def self.log_headers=(value)
|
187
|
+
HttpLogger.deprecate_config("log_headers")
|
188
|
+
HttpLogger.log_headers = value
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.colorize=(value)
|
192
|
+
HttpLogger.deprecate_config("colorize")
|
193
|
+
HttpLogger.colorize = value
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.logger=(value)
|
197
|
+
HttpLogger.deprecate_config("logger")
|
198
|
+
HttpLogger.logger = value
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
alias_method :request_without_logging, :request
|
203
|
+
|
204
|
+
def request(request, body = nil, &block)
|
205
|
+
HttpLogger.perform(self, request, body) do
|
206
|
+
request_without_logging(request, body, &block)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
if defined?(Rails)
|
212
|
+
if defined?(ActiveSupport) && ActiveSupport.respond_to?(:on_load)
|
213
|
+
# Rails3
|
214
|
+
ActiveSupport.on_load(:after_initialize) do
|
215
|
+
HttpLogger.logger = Rails.logger unless HttpLogger.logger
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -6,38 +6,37 @@ module Middleware
|
|
6
6
|
|
7
7
|
# This method is triggered when a non error page is loaded (not 404)
|
8
8
|
def call(name, started, finished, unique_id, payload)
|
9
|
-
|
10
9
|
if ZuoraConnect.configuration.enable_inbound_metrics_flag == true
|
11
|
-
|
12
10
|
# If the url contains any css or JavaScript files then do not collect metrics for them
|
13
|
-
|
14
|
-
if block_words.any? { |word| payload[:path].include?(word) }
|
15
|
-
return nil
|
16
|
-
end
|
11
|
+
return nil if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| payload[:path].include?(word) }
|
17
12
|
|
18
13
|
# Getting the endpoint and the content_type
|
19
14
|
content_hash = {:html => "text/html", :js => "application/javascript", :json => "application/json"}
|
20
|
-
content_hash.key?(payload[:format]) ?
|
21
|
-
request_path = "#{payload[:controller]}##{payload[:action]}"
|
22
|
-
response_time = finished-started
|
15
|
+
content_type = content_hash.key?(payload[:format]) ? content_hash[payload[:format]] : payload[:format]
|
23
16
|
|
24
17
|
# payloads with 500 requests do not have status as it is not set by the controller
|
25
18
|
# https://github.com/rails/rails/issues/33335
|
26
|
-
status_code = payload[:status] ? payload[:status] : payload[:exception_object].present? ? 500 : ""
|
19
|
+
#status_code = payload[:status] ? payload[:status] : payload[:exception_object].present? ? 500 : ""
|
20
|
+
if payload[:exception].present?
|
21
|
+
status_code, exception = [500, payload[:exception].first]
|
22
|
+
else
|
23
|
+
status_code, exception = [payload[:status], nil]
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
ZuoraConnect::AppInstanceBase.write_to_telegraf("endpoint_name": request_path, "method_name": payload[:method], "status_code": status_code, "response_time": response_time, "db_runtime": payload[:db_runtime].to_f, "view_runtime": payload[:view_runtime], "content_type": content_type, "direction": "inbound")
|
26
|
+
tags = {method: payload[:method], status: status_code, error_type: exception, content_type: content_type, controller: payload[:controller], action: payload[:action]}.compact
|
30
27
|
|
28
|
+
values = {view_time: payload[:view_runtime], db_time: payload[:db_runtime], response_time: ((finished-started)*1000)}.compact
|
29
|
+
values = values.map{ |k,v| [k,v.round(2)]}.to_h
|
30
|
+
|
31
|
+
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
|
-
|
36
36
|
class MetricsMiddleware
|
37
37
|
|
38
38
|
require "zuora_connect/version"
|
39
39
|
require "zuora_api/version"
|
40
|
-
require "telegraf"
|
41
40
|
|
42
41
|
def initialize(app)
|
43
42
|
@app = app
|
@@ -46,15 +45,10 @@ module Middleware
|
|
46
45
|
def call(env)
|
47
46
|
start_time = Time.now
|
48
47
|
@status, @headers, @response = @app.call(env)
|
49
|
-
|
48
|
+
|
50
49
|
if ZuoraConnect.configuration.enable_inbound_metrics_flag == true
|
51
50
|
# If the url contains any CSS or JavaScript files then do not collect metrics for them
|
52
|
-
|
53
|
-
if block_words.any? { |word| env['PATH_INFO'].include?(word) }
|
54
|
-
return [@status, @headers, @response]
|
55
|
-
end
|
56
|
-
|
57
|
-
response_time = end_time - start_time
|
51
|
+
return [@status, @headers, @response] if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| env['PATH_INFO'].include?(word) }
|
58
52
|
|
59
53
|
if defined? Prometheus
|
60
54
|
#Prometheus Stuff
|
@@ -86,28 +80,30 @@ module Middleware
|
|
86
80
|
|
87
81
|
end
|
88
82
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
#
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
83
|
+
|
84
|
+
# Uncomment following block of code for handling engine requests/requests without controller
|
85
|
+
# else
|
86
|
+
# # Handling requests which do not have controllers (engines)
|
87
|
+
if env["SCRIPT_NAME"].present?
|
88
|
+
controller_path = "#{env['SCRIPT_NAME'][1..-1]}"
|
89
|
+
controller_path = controller_path.sub("/", "::")
|
90
|
+
request_path = "#{controller_path}#UnknownAction"
|
91
|
+
else
|
92
|
+
# Writing to telegraf: Handle 404
|
93
|
+
if [404].include?(@status)
|
94
|
+
content_type = @headers['Content-Type'].split(';')[0] if @headers['Content-Type']
|
95
|
+
|
96
|
+
tags = {status: @status, content_type: content_type}
|
97
|
+
|
98
|
+
tags = tags.merge({controller: 'ActionController', action: 'RoutingError' })
|
99
|
+
|
100
|
+
values = {response_time: ((Time.now - start_time)*1000).round(2) }
|
101
|
+
|
102
|
+
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
103
|
+
end
|
105
104
|
end
|
106
105
|
end
|
107
106
|
[@status, @headers, @response]
|
108
|
-
|
109
107
|
end
|
110
|
-
|
111
108
|
end
|
112
|
-
|
113
109
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module ZuoraConnect
|
2
2
|
class Configuration
|
3
|
-
|
3
|
+
|
4
|
+
attr_accessor :default_locale, :default_time_zone, :url, :mode, :delayed_job,:private_key, :additional_apartment_models
|
5
|
+
|
6
|
+
attr_accessor :telegraf_endpoint, :telegraf_debug, :enable_inbound_metrics_flag, :enable_outbound_metrics_flag, :custom_prometheus_update_block, :app_name, :influxdb_series_name_inbound, :influxdb_series_name_outbound
|
7
|
+
|
8
|
+
attr_accessor :oauth_client_id, :oauth_client_secret, :oauth_client_redirect_uri
|
9
|
+
|
10
|
+
attr_accessor :dev_mode_logins, :dev_mode_options, :dev_mode_mode, :dev_mode_appinstance, :dev_mode_user, :dev_mode_pass, :dev_mode_admin, :dev_mode_secret_access_key,:dev_mode_access_key_id,:aws_region, :s3_bucket_name, :s3_folder_name
|
4
11
|
|
5
12
|
def initialize
|
6
13
|
@default_locale = :en
|
@@ -8,19 +15,20 @@ module ZuoraConnect
|
|
8
15
|
@url = "https://connect.zuora.com"
|
9
16
|
@mode = "Production"
|
10
17
|
@delayed_job = false
|
11
|
-
@use_s3 = false
|
12
18
|
@private_key = ENV["CONNECT_KEY"]
|
13
19
|
@additional_apartment_models = []
|
20
|
+
|
21
|
+
|
22
|
+
# Setting the app name for telegraf write
|
14
23
|
@telegraf_endpoint = 'udp://telegraf-app-metrics.monitoring.svc.cluster.local:8094'
|
24
|
+
@telegraf_debug = false
|
15
25
|
@enable_inbound_metrics_flag = false
|
16
26
|
@enable_outbound_metrics_flag = false
|
17
|
-
@telegraf_client = Telegraf::Agent.new @telegraf_endpoint
|
18
|
-
|
19
|
-
# Setting the app name for telegraf write
|
20
|
-
@app_name = ENV['DEIS_APP'].present? ? "#{ENV['DEIS_APP']}" : "#{Rails.application.class.parent_name}"
|
21
27
|
@influxdb_series_name_inbound = "request-inbound"
|
22
28
|
@influxdb_series_name_outbound = "request-outbound"
|
23
29
|
|
30
|
+
@app_name = ENV['DEIS_APP'].present? ? "#{ENV['DEIS_APP']}" : "#{Rails.application.class.parent_name}"
|
31
|
+
|
24
32
|
# OAuth Settings
|
25
33
|
@oauth_client_id = ""
|
26
34
|
@oauth_client_secret = ""
|
@@ -21,7 +21,7 @@ module ZuoraConnect
|
|
21
21
|
check_instance
|
22
22
|
end
|
23
23
|
end
|
24
|
-
Rails.logger.
|
24
|
+
Rails.logger.debug("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App API Request Completed In - #{(Time.now - start_time).round(2)}s")
|
25
25
|
end
|
26
26
|
|
27
27
|
def authenticate_connect_app_request
|
data/lib/zuora_connect.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zuora_connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.06
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Connect Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: apartment
|
@@ -36,20 +36,20 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 1.
|
39
|
+
version: 1.6.0
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 1.
|
42
|
+
version: 1.6.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: 1.
|
49
|
+
version: 1.6.0
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 1.
|
52
|
+
version: 1.6.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: httparty
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,20 +106,6 @@ dependencies:
|
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: telegraf
|
111
|
-
requirement: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - "~>"
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: 0.4.0
|
116
|
-
type: :runtime
|
117
|
-
prerelease: false
|
118
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - "~>"
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: 0.4.0
|
123
109
|
- !ruby/object:Gem::Dependency
|
124
110
|
name: railties
|
125
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -252,6 +238,7 @@ files:
|
|
252
238
|
- app/views/zuora_connect/static/session_error.html.erb
|
253
239
|
- config/initializers/apartment.rb
|
254
240
|
- config/initializers/object_method_hooks.rb
|
241
|
+
- config/initializers/postgresql_adapter.rb
|
255
242
|
- config/initializers/prometheus.rb
|
256
243
|
- config/initializers/redis.rb
|
257
244
|
- config/initializers/resque.rb
|
@@ -267,6 +254,8 @@ files:
|
|
267
254
|
- db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb
|
268
255
|
- db/migrate/20110503003604_catalog_default.rb
|
269
256
|
- db/migrate/20180301052853_add_catalog_attempted_at.rb
|
257
|
+
- lib/metrics/influx/point_value.rb
|
258
|
+
- lib/metrics/net.rb
|
270
259
|
- lib/middleware/metrics_middleware.rb
|
271
260
|
- lib/resque/additions.rb
|
272
261
|
- lib/resque/dynamic_queues.rb
|