zuora_connect 2.0.60t → 3.0.0.pre.a
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/static_controller.rb +3 -7
- data/app/models/zuora_connect/app_instance_base.rb +80 -132
- data/config/initializers/prometheus.rb +13 -13
- data/config/initializers/redis.rb +4 -4
- data/config/initializers/resque.rb +6 -6
- data/config/initializers/unicorn.rb +2 -2
- data/config/routes.rb +0 -1
- data/lib/metrics/net.rb +7 -7
- data/lib/middleware/metrics_middleware.rb +10 -10
- data/lib/zuora_connect.rb +3 -63
- data/lib/zuora_connect/controllers/helpers.rb +2 -6
- data/lib/zuora_connect/engine.rb +2 -1
- data/lib/zuora_connect/railtie.rb +0 -63
- data/lib/zuora_connect/version.rb +1 -1
- metadata +16 -5
- data/app/models/zuora_connect/telegraf.rb +0 -97
- data/lib/logging/connect_formatter.rb +0 -44
- data/lib/metrics/influx/point_value.rb +0 -79
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e63c10c8405375ad7cb2c28073c6181ed055266fb8d61e3ac5725e8f5b8ca8d5
|
|
4
|
+
data.tar.gz: c5124fe3590fd14c0acdad0cfe6e567997195eaa728245f620bfff5bbda285fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1beb3e3c0531b3035051711670de269814122c20269086ffd31257b02dc4e6ff8c515ac812abc436360ebc9f1506e3ae8e15e859d6098913e08f2dfed67e1284
|
|
7
|
+
data.tar.gz: bff9fca90e302be4fe97b3cac4ac54bb8dc6c841ad6762939f9b0b2c6c7e66417bb108105d6d8372965ae9090d813c97cff8a4a4a6b513665beed63c9229f0e4
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
module ZuoraConnect
|
|
2
2
|
class StaticController < ApplicationController
|
|
3
|
-
before_action :authenticate_connect_app_request, :except => [:
|
|
4
|
-
before_action :clear_connect_app_session, :only => [:
|
|
5
|
-
after_action :persist_connect_app_session, :except => [:
|
|
3
|
+
before_action :authenticate_connect_app_request, :except => [:health, :initialize_app, :provision, :instance_user]
|
|
4
|
+
before_action :clear_connect_app_session, :only => [:health, :initialize_app, :provision, :instance_user]
|
|
5
|
+
after_action :persist_connect_app_session, :except => [:health, :initialize_app, :provision, :instance_user]
|
|
6
6
|
|
|
7
7
|
skip_before_action :verify_authenticity_token, :only => [:initialize_app, :provision]
|
|
8
8
|
http_basic_authenticate_with name: ENV['PROVISION_USER'], password: ENV['PROVISION_SECRET'], :only => [:provision, :instance_user]
|
|
9
9
|
|
|
10
|
-
def metrics
|
|
11
|
-
type = params[:type].present? ? params[:type] : "versions"
|
|
12
|
-
render json: ZuoraConnect::AppInstance.get_metrics(type).to_json, status: 200
|
|
13
|
-
end
|
|
14
10
|
|
|
15
11
|
def health
|
|
16
12
|
if params[:error].present?
|
|
@@ -12,7 +12,6 @@ module ZuoraConnect
|
|
|
12
12
|
|
|
13
13
|
self.table_name = "zuora_connect_app_instances"
|
|
14
14
|
attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems, :user_timezone
|
|
15
|
-
@@telegraf_host = nil
|
|
16
15
|
REFRESH_TIMEOUT = 2.minute #Used to determine how long to wait on current refresh call before executing another
|
|
17
16
|
INSTANCE_REFRESH_WINDOW = 1.hours #Used to set how how long till app starts attempting to refresh cached task connect data
|
|
18
17
|
INSTANCE_REDIS_CACHE_PERIOD = 24.hours #Used to determine how long to cached task data will live for
|
|
@@ -25,6 +24,8 @@ module ZuoraConnect
|
|
|
25
24
|
CATALOG_LOOKUP_CACHE_TIME_KEY = 'CatalogCachedAt'
|
|
26
25
|
CATALOG_LOOKUP_TTL = 60.seconds
|
|
27
26
|
CATALOG_LOOKUP_CACHE_RESULT_KEY = 'CatalogCache'
|
|
27
|
+
TIMEZONE_LOG_RATE_LIMIT_KEY = 'TimezoneLoggedAt'
|
|
28
|
+
TIMEZONE_LOG_PERIOD = 4.hours
|
|
28
29
|
IGNORED_LOCALS = ['fr', 'ja', 'es', 'zh', 'de']
|
|
29
30
|
INTERNAL_HOSTS = []
|
|
30
31
|
LOGIN_TENANT_DESTINATION = 'target_login'
|
|
@@ -33,7 +34,7 @@ module ZuoraConnect
|
|
|
33
34
|
Aws::Errors::MissingCredentialsError,
|
|
34
35
|
Aws::S3::Errors::AccessDenied,
|
|
35
36
|
Aws::SES::Errors::AccessDenied,
|
|
36
|
-
Aws::KMS::Errors::AccessDeniedException
|
|
37
|
+
Aws::KMS::Errors::AccessDeniedException
|
|
37
38
|
].freeze
|
|
38
39
|
AWS_AUTH_ERRORS_MSG = "AWS Auth Errors".freeze
|
|
39
40
|
|
|
@@ -245,48 +246,7 @@ module ZuoraConnect
|
|
|
245
246
|
ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
|
246
247
|
end
|
|
247
248
|
|
|
248
|
-
|
|
249
|
-
sql = <<-eos
|
|
250
|
-
SELECT zuora_users.zuora_identity_response
|
|
251
|
-
FROM "#{self.id}".zuora_users
|
|
252
|
-
ORDER BY zuora_users.updated_at DESC
|
|
253
|
-
LIMIT 1;
|
|
254
|
-
eos
|
|
255
|
-
user = ActiveRecord::Base.connection.execute(sql).to_a.first
|
|
256
|
-
|
|
257
|
-
if user.present?
|
|
258
|
-
zuora_identity_response = JSON.parse(user.fetch('zuora_identity_response', '{}'))
|
|
259
|
-
self.user_timezone = zuora_identity_response.values.first&.dig('timeZone')
|
|
260
|
-
end
|
|
261
|
-
rescue => ex
|
|
262
|
-
Rails.logger.error('Failed to get users while setting app instance timezone', ex)
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
if self.user_timezone.present?
|
|
266
|
-
# connect instance which has a custom timezone
|
|
267
|
-
if !self.auto_deployed? && (
|
|
268
|
-
ActiveSupport::TimeZone[self.task_data.dig('user_settings', 'timezone') || '']&.utc_offset !=
|
|
269
|
-
ActiveSupport::TimeZone[self.user_timezone]&.utc_offset
|
|
270
|
-
)
|
|
271
|
-
if self.environment == 'Production'
|
|
272
|
-
ZuoraConnect.logger.error(
|
|
273
|
-
"Instance and user timezones are different. User has '#{self.user_timezone}' and " \
|
|
274
|
-
"instance has '#{self.task_data.dig('user_settings', 'timezone')}'",
|
|
275
|
-
app_instance_id: self.id
|
|
276
|
-
)
|
|
277
|
-
end
|
|
278
|
-
self.user_timezone = nil
|
|
279
|
-
Time.zone = self.timezone
|
|
280
|
-
else
|
|
281
|
-
begin
|
|
282
|
-
Time.zone = self.user_timezone
|
|
283
|
-
rescue ArgumentError
|
|
284
|
-
Time.zone = self.timezone
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
else
|
|
288
|
-
Time.zone = self.timezone
|
|
289
|
-
end
|
|
249
|
+
self.set_timezone
|
|
290
250
|
|
|
291
251
|
if self.task_data.present?
|
|
292
252
|
tenants = self.task_data.fetch('tenant_ids', [])
|
|
@@ -302,7 +262,7 @@ module ZuoraConnect
|
|
|
302
262
|
end
|
|
303
263
|
|
|
304
264
|
params = {
|
|
305
|
-
name: self.task_data.dig('name'),
|
|
265
|
+
name: self.task_data.dig('name'),
|
|
306
266
|
zuora_entity_ids: (self.task_data.dig(LOGIN_TENANT_DESTINATION,'entities') || []).map{|e| e['id']}.uniq,
|
|
307
267
|
zuora_tenant_ids: tenants.map(&:to_s).uniq,
|
|
308
268
|
organizations: organizations
|
|
@@ -311,7 +271,7 @@ module ZuoraConnect
|
|
|
311
271
|
client = self.send(LOGIN_TENANT_DESTINATION).client
|
|
312
272
|
if defined?(client.rest_domain)
|
|
313
273
|
ZuoraConnect::RequestIdMiddleware.zuora_rest_domain = client.rest_domain
|
|
314
|
-
params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
|
|
274
|
+
params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
|
|
315
275
|
end
|
|
316
276
|
end
|
|
317
277
|
params = params.reject{|k,v| !self.attributes.keys.member?(k.to_s) || self[k] == v}
|
|
@@ -319,16 +279,80 @@ module ZuoraConnect
|
|
|
319
279
|
end
|
|
320
280
|
end
|
|
321
281
|
|
|
282
|
+
def set_timezone(timezone: self.timezone, type: :default)
|
|
283
|
+
if timezone.blank?
|
|
284
|
+
timezone = self.timezone
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
if type == :default
|
|
288
|
+
Time.zone = timezone
|
|
289
|
+
elsif type == :user
|
|
290
|
+
begin
|
|
291
|
+
sql = <<-eos
|
|
292
|
+
SELECT zuora_users.zuora_identity_response
|
|
293
|
+
FROM "#{self.id}".zuora_users
|
|
294
|
+
ORDER BY zuora_users.updated_at DESC
|
|
295
|
+
LIMIT 1;
|
|
296
|
+
eos
|
|
297
|
+
user = ActiveRecord::Base.connection.execute(sql).to_a.first
|
|
298
|
+
|
|
299
|
+
if user.present?
|
|
300
|
+
zuora_identity_response = JSON.parse(user.fetch('zuora_identity_response', '{}'))
|
|
301
|
+
self.user_timezone = zuora_identity_response.values.first&.dig('timeZone')
|
|
302
|
+
else
|
|
303
|
+
if (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
|
|
304
|
+
Rails.logger.error('Cannot find any user to set the timezone', app_instance_id: self.id)
|
|
305
|
+
Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
rescue => ex
|
|
309
|
+
Rails.logger.error('There is an error while getting timezone users', ex)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
if self.user_timezone.present?
|
|
313
|
+
# connect instance which has a custom timezone
|
|
314
|
+
if !self.auto_deployed? && (
|
|
315
|
+
ActiveSupport::TimeZone[self.task_data.dig('user_settings', 'timezone') || '']&.utc_offset !=
|
|
316
|
+
ActiveSupport::TimeZone[self.user_timezone]&.utc_offset
|
|
317
|
+
)
|
|
318
|
+
if self.environment == 'Production' &&
|
|
319
|
+
(Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
|
|
320
|
+
ZuoraConnect.logger.error(
|
|
321
|
+
"Instance and user timezones are different. User has '#{self.user_timezone}' and " \
|
|
322
|
+
"instance has '#{self.task_data.dig('user_settings', 'timezone')}'",
|
|
323
|
+
app_instance_id: self.id
|
|
324
|
+
)
|
|
325
|
+
Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
|
|
326
|
+
end
|
|
327
|
+
self.user_timezone = nil
|
|
328
|
+
Time.zone = timezone
|
|
329
|
+
else
|
|
330
|
+
begin
|
|
331
|
+
Time.zone = self.user_timezone
|
|
332
|
+
rescue ArgumentError
|
|
333
|
+
Rails.logger.error('Malformed user timezone', app_instance_id: self.id)
|
|
334
|
+
Time.zone = timezone
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
else
|
|
338
|
+
Time.zone = timezone
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
rescue => e
|
|
342
|
+
Rails.logger.error('Malformed timezone used', e, app_instance_id: self.id)
|
|
343
|
+
Time.zone = self.timezone
|
|
344
|
+
end
|
|
345
|
+
|
|
322
346
|
def auto_deployed?
|
|
323
347
|
self.id >= 25000000
|
|
324
348
|
end
|
|
325
349
|
|
|
326
|
-
def refresh(session: {})
|
|
350
|
+
def refresh(session: {})
|
|
327
351
|
refresh_count ||= 0
|
|
328
352
|
skip_connect ||= false
|
|
329
353
|
begin
|
|
330
354
|
#Check how app was deployed
|
|
331
|
-
if self.id < 25000000 && !skip_connect
|
|
355
|
+
if self.id < 25000000 && !skip_connect
|
|
332
356
|
self.check_oauth_state
|
|
333
357
|
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
|
|
334
358
|
|
|
@@ -339,7 +363,7 @@ module ZuoraConnect
|
|
|
339
363
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("JSON parse error", response.body, response.code)
|
|
340
364
|
end
|
|
341
365
|
|
|
342
|
-
self.build_task(task_data: parsed_json, session: session)
|
|
366
|
+
self.build_task(task_data: parsed_json, session: session)
|
|
343
367
|
if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/)
|
|
344
368
|
begin
|
|
345
369
|
self.zuora_logins = self.strip_cache_data(object: parsed_json.dup, keys: ['applications', 'tokens', 'user_settings'])
|
|
@@ -349,7 +373,7 @@ module ZuoraConnect
|
|
|
349
373
|
rescue => ex
|
|
350
374
|
Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
|
|
351
375
|
end
|
|
352
|
-
end
|
|
376
|
+
end
|
|
353
377
|
else
|
|
354
378
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
|
355
379
|
end
|
|
@@ -455,82 +479,6 @@ module ZuoraConnect
|
|
|
455
479
|
end
|
|
456
480
|
Thread.current[:appinstance] = self
|
|
457
481
|
end
|
|
458
|
-
|
|
459
|
-
def self.write_to_telegraf(*args)
|
|
460
|
-
if ZuoraConnect.configuration.enable_metrics && !defined?(Prometheus)
|
|
461
|
-
@@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
|
|
462
|
-
unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
|
463
|
-
@@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
|
|
464
|
-
return @@telegraf_host.write(*args)
|
|
465
|
-
end
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
def self.unicorn_listener_stats ()
|
|
469
|
-
stats_hash = {}
|
|
470
|
-
stats_hash["total_active"] = 0
|
|
471
|
-
stats_hash["total_queued"] = 0
|
|
472
|
-
|
|
473
|
-
begin
|
|
474
|
-
tmp = Unicorn.listener_names
|
|
475
|
-
unix = tmp.grep(%r{\A/})
|
|
476
|
-
tcp = tmp.grep(/\A.+:\d+\z/)
|
|
477
|
-
tcp = nil if tcp.empty?
|
|
478
|
-
unix = nil if unix.empty?
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
|
|
482
|
-
stats_hash["active_#{addr}"] = stats.active
|
|
483
|
-
stats_hash["queued_#{addr}"] = stats.queued
|
|
484
|
-
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
|
485
|
-
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
|
486
|
-
end if tcp
|
|
487
|
-
|
|
488
|
-
Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
|
|
489
|
-
stats_hash["active_#{addr}"] = stats.active
|
|
490
|
-
stats_hash["queued_#{addr}"] = stats.queued
|
|
491
|
-
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
|
492
|
-
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
|
493
|
-
end if unix
|
|
494
|
-
rescue IOError => ex
|
|
495
|
-
rescue => ex
|
|
496
|
-
ZuoraConnect.logger.error(ex)
|
|
497
|
-
end
|
|
498
|
-
return stats_hash
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
def self.get_metrics(type)
|
|
502
|
-
@data = {}
|
|
503
|
-
|
|
504
|
-
if type == "versions"
|
|
505
|
-
@data = {
|
|
506
|
-
app_name: ZuoraConnect::Telegraf.app_name,
|
|
507
|
-
url: "dummy",
|
|
508
|
-
Version_Gem: ZuoraConnect::VERSION,
|
|
509
|
-
Version_Zuora: ZuoraAPI::VERSION ,
|
|
510
|
-
Version_Ruby: RUBY_VERSION,
|
|
511
|
-
Version_Rails: Rails.version,
|
|
512
|
-
hold: 1
|
|
513
|
-
}
|
|
514
|
-
elsif type == "stats"
|
|
515
|
-
begin
|
|
516
|
-
Resque.redis.ping
|
|
517
|
-
@resque = Resque.info
|
|
518
|
-
@data = {
|
|
519
|
-
app_name: ZuoraConnect::Telegraf.app_name,
|
|
520
|
-
url: "dummy",
|
|
521
|
-
Resque:{
|
|
522
|
-
Jobs_Finished: @resque[:processed] ,
|
|
523
|
-
Jobs_Failed: @resque[:failed],
|
|
524
|
-
Jobs_Pending: @resque[:pending],
|
|
525
|
-
Workers_Active: @resque[:working],
|
|
526
|
-
Workers_Total: @resque[:workers]
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
rescue
|
|
530
|
-
end
|
|
531
|
-
end
|
|
532
|
-
return @data
|
|
533
|
-
end
|
|
534
482
|
#### END Task Methods ####
|
|
535
483
|
|
|
536
484
|
#### START Task Methods ####
|
|
@@ -573,7 +521,7 @@ module ZuoraConnect
|
|
|
573
521
|
end
|
|
574
522
|
rescue ZuoraConnect::Exceptions::MissMatch => ex
|
|
575
523
|
raise
|
|
576
|
-
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
|
|
524
|
+
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
|
|
577
525
|
raise
|
|
578
526
|
rescue => ex
|
|
579
527
|
ZuoraConnect.logger.error("Build Task Error", ex)
|
|
@@ -629,10 +577,10 @@ module ZuoraConnect
|
|
|
629
577
|
self.refresh if !defined?(self.target_login)
|
|
630
578
|
|
|
631
579
|
response = HTTParty.get("#{ZuoraConnect.configuration.url}/api/#{self.api_version}/tenants/search?hostname=#{self.target_login.client.hostname}&node_id=#{self.zuora_entity_ids.first}")
|
|
632
|
-
|
|
580
|
+
|
|
633
581
|
if response.success?
|
|
634
582
|
parsed_json = JSON.parse(response.body)
|
|
635
|
-
|
|
583
|
+
|
|
636
584
|
#Set Org
|
|
637
585
|
if self.id >= 25000000 && parsed_json['organization'].present?
|
|
638
586
|
login_cache = self.zuora_logins
|
|
@@ -654,7 +602,7 @@ module ZuoraConnect
|
|
|
654
602
|
end
|
|
655
603
|
end
|
|
656
604
|
self.save(:validate => false)
|
|
657
|
-
|
|
605
|
+
|
|
658
606
|
return parsed_json
|
|
659
607
|
end
|
|
660
608
|
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
@@ -708,7 +656,7 @@ module ZuoraConnect
|
|
|
708
656
|
end
|
|
709
657
|
|
|
710
658
|
def refresh_oauth
|
|
711
|
-
refresh_oauth_count ||= 0
|
|
659
|
+
refresh_oauth_count ||= 0
|
|
712
660
|
response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token", body: {
|
|
713
661
|
:grant_type => "refresh_token",
|
|
714
662
|
:redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
|
|
@@ -1344,7 +1292,7 @@ module ZuoraConnect
|
|
|
1344
1292
|
|
|
1345
1293
|
def self.without_sticking
|
|
1346
1294
|
if self.connection.respond_to?(:without_sticking)
|
|
1347
|
-
self.connection.without_sticking do
|
|
1295
|
+
self.connection.without_sticking do
|
|
1348
1296
|
yield
|
|
1349
1297
|
end
|
|
1350
1298
|
else
|
|
@@ -49,10 +49,10 @@ if defined? Prometheus
|
|
|
49
49
|
prometheus = Prometheus::Client.registry
|
|
50
50
|
|
|
51
51
|
# Create your metrics.
|
|
52
|
-
ZUORA_VERSION = prometheus.gauge(:zuora_version, docstring: 'The current Zuora Gem version.', labels: %i(version name), preset_labels: { version: ZuoraAPI::VERSION, name:
|
|
53
|
-
CONNECT_VERSION = prometheus.gauge(:gem_version, docstring: 'The current Connect Gem version.', labels: %i(version name), preset_labels: { version: ZuoraConnect::VERSION, name:
|
|
54
|
-
RAILS_VERSION = prometheus.gauge(:rails_version, docstring: 'The current Rails version.', labels: %i(version name), preset_labels: { version: Rails.version, name:
|
|
55
|
-
RUBY_V = prometheus.gauge(:ruby_version, docstring: 'The current Ruby version.', labels: %i(version name), preset_labels: { version: RUBY_VERSION, name:
|
|
52
|
+
ZUORA_VERSION = prometheus.gauge(:zuora_version, docstring: 'The current Zuora Gem version.', labels: %i(version name), preset_labels: { version: ZuoraAPI::VERSION, name: ZuoraObservability::Env.app_name }, store_settings: most_recent_aggregation)
|
|
53
|
+
CONNECT_VERSION = prometheus.gauge(:gem_version, docstring: 'The current Connect Gem version.', labels: %i(version name), preset_labels: { version: ZuoraConnect::VERSION, name: ZuoraObservability::Env.app_name }, store_settings: most_recent_aggregation)
|
|
54
|
+
RAILS_VERSION = prometheus.gauge(:rails_version, docstring: 'The current Rails version.', labels: %i(version name), preset_labels: { version: Rails.version, name: ZuoraObservability::Env.app_name }, store_settings: most_recent_aggregation)
|
|
55
|
+
RUBY_V = prometheus.gauge(:ruby_version, docstring: 'The current Ruby version.', labels: %i(version name), preset_labels: { version: RUBY_VERSION, name: ZuoraObservability::Env.app_name }, store_settings: most_recent_aggregation)
|
|
56
56
|
|
|
57
57
|
ZUORA_VERSION.set(0)
|
|
58
58
|
CONNECT_VERSION.set(0)
|
|
@@ -61,12 +61,12 @@ if defined? Prometheus
|
|
|
61
61
|
|
|
62
62
|
# Do they have resque jobs?
|
|
63
63
|
if defined? Resque.redis
|
|
64
|
-
REDIS_CONNECTION = prometheus.gauge(:redis_connection, docstring: 'The status of the redis connection, 0 or 1', labels: %i(connection name), preset_labels: {connection:'redis', name:
|
|
65
|
-
JOBS_FINISHED = prometheus.gauge(:jobs_finished, docstring: 'Done resque jobs', labels: %i(type name), preset_labels: {type:'resque', name:
|
|
66
|
-
WORKERS_TOTAL = prometheus.gauge(:workers_total, docstring: 'Total resque workers', labels: %i(type name), preset_labels: {type:'resque', name:
|
|
67
|
-
WORKERS_ACTIVE = prometheus.gauge(:workers_active, docstring: 'Active resque workers', labels: %i(type name), preset_labels: {type:'resque', name:
|
|
68
|
-
JOBS_FAILED = prometheus.gauge(:jobs_failed, docstring: 'Failed resque jobs', labels: %i(type name), preset_labels: {type:'resque', name:
|
|
69
|
-
JOBS_PENDING = prometheus.gauge(:jobs_pending, docstring: 'Pending resque jobs', labels: %i(type name), preset_labels: {type:'resque', name:
|
|
64
|
+
REDIS_CONNECTION = prometheus.gauge(:redis_connection, docstring: 'The status of the redis connection, 0 or 1', labels: %i(connection name), preset_labels: {connection:'redis', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
65
|
+
JOBS_FINISHED = prometheus.gauge(:jobs_finished, docstring: 'Done resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
66
|
+
WORKERS_TOTAL = prometheus.gauge(:workers_total, docstring: 'Total resque workers', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
67
|
+
WORKERS_ACTIVE = prometheus.gauge(:workers_active, docstring: 'Active resque workers', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
68
|
+
JOBS_FAILED = prometheus.gauge(:jobs_failed, docstring: 'Failed resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
69
|
+
JOBS_PENDING = prometheus.gauge(:jobs_pending, docstring: 'Pending resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraObservability::Env.app_name}, store_settings: most_recent_aggregation)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
|
@@ -74,17 +74,17 @@ if defined? Prometheus
|
|
|
74
74
|
:unicorn_kills,
|
|
75
75
|
docstring: 'Unicorn Kills',
|
|
76
76
|
labels: %i(type name),
|
|
77
|
-
preset_labels: {type:'Unicorn-Killer', name:
|
|
77
|
+
preset_labels: {type:'Unicorn-Killer', name: ZuoraObservability::Env.app_name},
|
|
78
78
|
store_settings: sum_aggregation
|
|
79
79
|
)
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
ZuoraObservability::Metrics.unicorn_listener.each do |key, _|
|
|
82
82
|
gauge_name = "unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_')
|
|
83
83
|
gauge = prometheus.gauge(
|
|
84
84
|
gauge_name.to_sym,
|
|
85
85
|
docstring: 'Unicorn Stats',
|
|
86
86
|
labels: %i(type name),
|
|
87
|
-
preset_labels: { type: 'unicorn', name:
|
|
87
|
+
preset_labels: { type: 'unicorn', name: ZuoraObservability::Env.app_name },
|
|
88
88
|
store_settings: most_recent_aggregation
|
|
89
89
|
)
|
|
90
90
|
Prometheus.const_set(
|
|
@@ -12,21 +12,21 @@ class RedisFlash
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
if defined?(Redis.current)
|
|
15
|
-
Redis.current = Redis.new(:id => "#{
|
|
15
|
+
Redis.current = Redis.new(:id => "#{ZuoraObservability::Env.full_process_name(process_name: 'Redis')}", :url => redis_url, :timeout => 6, :reconnect_attempts => 2)
|
|
16
16
|
browser_urls['Redis'] = { "url" => redis_url }
|
|
17
17
|
if defined?(Resque.redis)
|
|
18
18
|
if resque_url != redis_url
|
|
19
|
-
Resque.redis = Redis.new(:id => "#{
|
|
19
|
+
Resque.redis = Redis.new(:id => "#{ZuoraObservability::Env.full_process_name(process_name: 'Resque')}", :url => resque_url, :timeout => 6, :reconnect_attempts => 2)
|
|
20
20
|
browser_urls['Resque'] = { "url" => resque_url }
|
|
21
21
|
else
|
|
22
22
|
Resque.redis = Redis.current
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
if defined?(flash_url.present?)
|
|
26
|
-
RedisFlash.current = Redis.new(:id => "#{
|
|
26
|
+
RedisFlash.current = Redis.new(:id => "#{ZuoraObservability::Env.full_process_name(process_name: 'Flash')}", :url => flash_url, :timeout => 6, :reconnect_attempts => 2)
|
|
27
27
|
browser_urls['Flash'] = { "url" => flash_url }
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
if defined?(RedisBrowser)
|
|
31
31
|
RedisBrowser.configure("connections" => browser_urls)
|
|
32
|
-
end
|
|
32
|
+
end
|
|
@@ -36,13 +36,13 @@ Resque.module_eval do
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
if defined?(Resque.logger)
|
|
39
|
-
Resque.logger =
|
|
40
|
-
Resque::Scheduler.logger =
|
|
39
|
+
Resque.logger = ZuoraObservability::Logger.custom_logger(name: "Resque", type: 'Monologger', level: MonoLogger::INFO)
|
|
40
|
+
Resque::Scheduler.logger = ZuoraObservability::Logger.custom_logger(name: "ResqueScheduler") if defined?(Resque::Scheduler)
|
|
41
41
|
end
|
|
42
42
|
if defined?(Delayed::Worker.logger)
|
|
43
|
-
Delayed::Worker.logger =
|
|
43
|
+
Delayed::Worker.logger = ZuoraObservability::Logger.custom_logger(name: "DelayedJob", type: 'Monologger', level: MonoLogger::INFO)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
Makara::Logging::Logger.logger =
|
|
47
|
-
ElasticAPM.agent.config.logger =
|
|
48
|
-
ActionMailer::Base.logger =
|
|
46
|
+
Makara::Logging::Logger.logger = ZuoraObservability::Logger.custom_logger(name: "Makara") if defined?(Makara)
|
|
47
|
+
ElasticAPM.agent.config.logger = ZuoraObservability::Logger.custom_logger(name: "ElasticAPM", level: MonoLogger::WARN) if defined?(ElasticAPM) && ElasticAPM.running?
|
|
48
|
+
ActionMailer::Base.logger = ZuoraObservability::Logger.custom_logger(name: "ActionMailer", type: 'Monologger') if defined?(ActionMailer)
|
|
@@ -6,7 +6,7 @@ if defined?(Unicorn::WorkerKiller)
|
|
|
6
6
|
if defined?(Prometheus)
|
|
7
7
|
Prometheus::UNICORN_KILLS.set(1)
|
|
8
8
|
else
|
|
9
|
-
|
|
9
|
+
ZuoraObservability::Metrics.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -34,4 +34,4 @@ if defined?(Unicorn::HttpServer) && defined?(Prometheus)
|
|
|
34
34
|
class Unicorn::Worker
|
|
35
35
|
prepend WorkerExtensions
|
|
36
36
|
end
|
|
37
|
-
end
|
|
37
|
+
end
|
data/config/routes.rb
CHANGED
data/lib/metrics/net.rb
CHANGED
|
@@ -68,12 +68,12 @@ class HttpLogger
|
|
|
68
68
|
log_request_body(request)
|
|
69
69
|
log_request_headers(request)
|
|
70
70
|
if defined?(response) && response
|
|
71
|
-
tags = tags.merge({status: response.code.to_i})
|
|
71
|
+
tags = tags.merge({status: response.code.to_i})
|
|
72
72
|
log_response_code(response)
|
|
73
73
|
log_response_headers(response)
|
|
74
74
|
log_response_body(response.body)
|
|
75
75
|
end
|
|
76
|
-
|
|
76
|
+
ZuoraObservability::Metrics.write_to_telegraf(direction: :outbound, tags: tags, values: values)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -95,7 +95,7 @@ class HttpLogger
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
HTTP_METHODS_WITH_BODY = Set.new(%w(POST PUT GET PATCH))
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
def log_request_body(request)
|
|
100
100
|
if self.class.log_request_body
|
|
101
101
|
if HTTP_METHODS_WITH_BODY.include?(request.method)
|
|
@@ -149,8 +149,8 @@ class HttpLogger
|
|
|
149
149
|
def truncate_body(body)
|
|
150
150
|
if collapse_body_limit && collapse_body_limit > 0 && body && body.size >= collapse_body_limit
|
|
151
151
|
body_piece_size = collapse_body_limit / 2
|
|
152
|
-
body[0..body_piece_size] +
|
|
153
|
-
"\n\n<some data truncated>\n\n" +
|
|
152
|
+
body[0..body_piece_size] +
|
|
153
|
+
"\n\n<some data truncated>\n\n" +
|
|
154
154
|
body[(body.size - body_piece_size)..body.size]
|
|
155
155
|
else
|
|
156
156
|
body
|
|
@@ -203,7 +203,7 @@ class Net::HTTP
|
|
|
203
203
|
|
|
204
204
|
def request(request, body = nil, &block)
|
|
205
205
|
HttpLogger.perform(self, request, body) do
|
|
206
|
-
request_without_logging(request, body, &block)
|
|
206
|
+
request_without_logging(request, body, &block)
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
end
|
|
@@ -215,4 +215,4 @@ if defined?(Rails)
|
|
|
215
215
|
HttpLogger.logger = ZuoraConnect.logger unless HttpLogger.logger
|
|
216
216
|
end
|
|
217
217
|
end
|
|
218
|
-
end
|
|
218
|
+
end
|
|
@@ -17,7 +17,7 @@ module ZuoraConnect
|
|
|
17
17
|
# payloads with 500 requests do not have status as it is not set by the controller
|
|
18
18
|
# https://github.com/rails/rails/issues/33335
|
|
19
19
|
#status_code = payload[:status] ? payload[:status] : payload[:exception_object].present? ? 500 : ""
|
|
20
|
-
if payload[:exception].present?
|
|
20
|
+
if payload[:exception].present?
|
|
21
21
|
status_code, exception = [500, payload[:exception].first]
|
|
22
22
|
else
|
|
23
23
|
status_code, exception = [payload[:status], nil]
|
|
@@ -28,7 +28,7 @@ module ZuoraConnect
|
|
|
28
28
|
values = {view_time: payload[:view_runtime], db_time: payload[:db_runtime], response_time: ((finished-started)*1000)}.compact
|
|
29
29
|
values = values.map{ |k,v| [k,v.round(2)]}.to_h
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
ZuoraObservability::Metrics.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -42,7 +42,7 @@ module ZuoraConnect
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def call(env)
|
|
45
|
-
@bad_headers = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST", "HTTP_X_FORWARDED_PORT", "HTTP_X_FORWARDED_PROTO", "HTTP_X_FORWARDED_SCHEME", "HTTP_X_FORWARDED_SSL"]
|
|
45
|
+
@bad_headers = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST", "HTTP_X_FORWARDED_PORT", "HTTP_X_FORWARDED_PROTO", "HTTP_X_FORWARDED_SCHEME", "HTTP_X_FORWARDED_SSL"]
|
|
46
46
|
if !ActionDispatch::Request::HTTP_METHODS.include?(env["REQUEST_METHOD"].upcase)
|
|
47
47
|
[405, {"Content-Type" => "text/plain"}, ["Method Not Allowed"]]
|
|
48
48
|
else
|
|
@@ -66,14 +66,14 @@ module ZuoraConnect
|
|
|
66
66
|
|
|
67
67
|
if defined?(Prometheus) && env['PATH_INFO'] == '/connect/internal/metrics'
|
|
68
68
|
# Prometheus Stuff
|
|
69
|
-
metrics =
|
|
69
|
+
metrics = ZuoraObservability::Metrics.resque
|
|
70
70
|
redis_up = metrics.present? && metrics.dig(:Resque, :Workers_Total).present? ? 1 : 0
|
|
71
71
|
Prometheus::REDIS_CONNECTION.set(redis_up)
|
|
72
72
|
|
|
73
73
|
process_prometheus_metric(metrics: metrics)
|
|
74
74
|
|
|
75
75
|
if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
|
76
|
-
|
|
76
|
+
ZuoraObservability::Metrics.unicorn_listener.each do |key, value|
|
|
77
77
|
gauge = Prometheus.const_get("unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_').upcase)
|
|
78
78
|
gauge.set(value) if gauge.present?
|
|
79
79
|
end
|
|
@@ -84,13 +84,13 @@ module ZuoraConnect
|
|
|
84
84
|
start_time = Time.now
|
|
85
85
|
begin
|
|
86
86
|
@status, @headers, @response = @app.call(env)
|
|
87
|
-
ensure
|
|
88
|
-
|
|
87
|
+
ensure
|
|
88
|
+
|
|
89
89
|
# If the url contains any CSS or JavaScript files then do not collect metrics for them
|
|
90
90
|
if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| env['PATH_INFO'].include?(word) } || /.*\.js$/.match(env['PATH_INFO'])
|
|
91
91
|
tags = {status: @status, controller: 'ActionController', action: 'Assets', app_instance: 0}
|
|
92
92
|
values = {response_time: ((Time.now - start_time)*1000).round(2) }
|
|
93
|
-
|
|
93
|
+
ZuoraObservability::Metrics.write_to_telegraf(direction: 'request-inbound-assets', tags: tags, values: values)
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
# Uncomment following block of code for handling engine requests/requests without controller
|
|
@@ -112,7 +112,7 @@ module ZuoraConnect
|
|
|
112
112
|
|
|
113
113
|
values = {response_time: ((Time.now - start_time)*1000).round(2) }
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
ZuoraObservability::Metrics.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
Thread.current[:inbound_metric] = nil
|
|
@@ -140,7 +140,7 @@ module ZuoraConnect
|
|
|
140
140
|
gauge_name.to_sym,
|
|
141
141
|
docstring: "#{key} metric",
|
|
142
142
|
labels: %i(type name),
|
|
143
|
-
preset_labels: { type: type, name:
|
|
143
|
+
preset_labels: { type: type, name: ZuoraObservability::Env.app_name },
|
|
144
144
|
store_settings: most_recent_aggregation
|
|
145
145
|
)
|
|
146
146
|
gauge.set(value)
|
data/lib/zuora_connect.rb
CHANGED
|
@@ -9,12 +9,11 @@ require 'resque/silence_done'
|
|
|
9
9
|
require 'resque/self_lookup'
|
|
10
10
|
require 'resque/plugins/custom_logger'
|
|
11
11
|
require 'resque/plugins/app_instance_job'
|
|
12
|
-
require 'logging/connect_formatter'
|
|
13
|
-
require 'metrics/influx/point_value'
|
|
14
12
|
require 'metrics/net'
|
|
15
13
|
require 'mono_logger'
|
|
16
14
|
require 'zuora_connect/zuora_audit'
|
|
17
15
|
require 'active_record'
|
|
16
|
+
require 'zuora_observability'
|
|
18
17
|
::ActiveRecord::Base.send :include, ZuoraConnect::ZuoraAudit
|
|
19
18
|
|
|
20
19
|
module ZuoraConnect
|
|
@@ -29,68 +28,9 @@ module ZuoraConnect
|
|
|
29
28
|
when 'test'
|
|
30
29
|
Rails.logger
|
|
31
30
|
else
|
|
32
|
-
@logger ||= custom_logger(name: "Connect", level: Rails.logger.level)
|
|
31
|
+
@logger ||= ZuoraObservability::Logger.custom_logger(name: "Connect", level: Rails.logger.level)
|
|
33
32
|
end
|
|
34
33
|
end
|
|
35
|
-
|
|
36
|
-
def custom_logger(name: "", level: Rails.logger.present? ? Rails.logger.level : MonoLogger::INFO, type: :ougai)
|
|
37
|
-
#puts name + ' - ' + {Logger::WARN => 'Logger::WARN', Logger::ERROR => 'Logger::ERROR', Logger::DEBUG => 'Logger::DEBUG', Logger::INFO => 'Logger::INFO' }[level] + ' - '
|
|
38
|
-
if type == :ougai
|
|
39
|
-
require 'ougai'
|
|
40
|
-
require "ougai/formatters/customizable"
|
|
41
|
-
#logger = Ougai::Logger.new(MonoLogger.new(STDOUT))
|
|
42
|
-
logger = Ougai::Logger.new(STDOUT)
|
|
43
|
-
logger.level = level
|
|
44
|
-
if ZuoraConnect.configuration.json_logging
|
|
45
|
-
logger.formatter = Ougai::Formatters::ConnectFormatter.new(name)
|
|
46
|
-
logger.before_log = lambda do |data|
|
|
47
|
-
data[:trace_id] = ZuoraConnect::RequestIdMiddleware.request_id if ZuoraConnect::RequestIdMiddleware.request_id.present?
|
|
48
|
-
data[:zuora_trace_id] = ZuoraConnect::RequestIdMiddleware.zuora_request_id if ZuoraConnect::RequestIdMiddleware.zuora_request_id.present?
|
|
49
|
-
#data[:traces] = {amazon_id: data[:trace_id], zuora_id: data[:zuora_trace_id]}
|
|
50
|
-
end
|
|
51
|
-
else
|
|
52
|
-
logger.formatter = Ougai::Formatters::Customizable.new(
|
|
53
|
-
format_err: proc do |data|
|
|
54
|
-
next nil unless data.key?(:err)
|
|
55
|
-
err = data.delete(:err)
|
|
56
|
-
" #{err[:name]} (#{err[:message]})\n #{err[:stack]}"
|
|
57
|
-
end,
|
|
58
|
-
format_data: proc do |data|
|
|
59
|
-
data.delete(:app_instance_id); data.delete(:tenant_ids); data.delete(:organization); data.delete(:environment)
|
|
60
|
-
format('%s %s: %s', 'DATA'.ljust(6), Time.now.strftime('%FT%T.%6NZ'), "#{data.to_json}") if data.present?
|
|
61
|
-
end,
|
|
62
|
-
format_msg: proc do |severity, datetime, _progname, data|
|
|
63
|
-
msg = data.delete(:msg)
|
|
64
|
-
format('%s %s: %s', severity.ljust(6), datetime, msg)
|
|
65
|
-
end
|
|
66
|
-
)
|
|
67
|
-
logger.formatter.datetime_format = '%FT%T.%6NZ'
|
|
68
|
-
end
|
|
69
|
-
else
|
|
70
|
-
logger = MonoLogger.new(STDOUT)
|
|
71
|
-
logger.level = level
|
|
72
|
-
logger.formatter = proc do |serverity, datetime, progname, msg|
|
|
73
|
-
begin
|
|
74
|
-
msg = JSON.parse(msg)
|
|
75
|
-
rescue JSON::ParserError => ex
|
|
76
|
-
end
|
|
77
|
-
if ZuoraConnect.configuration.json_logging
|
|
78
|
-
require 'json'
|
|
79
|
-
store = {
|
|
80
|
-
name: name,
|
|
81
|
-
level: serverity,
|
|
82
|
-
timestamp: datetime.strftime('%FT%T.%6NZ'),
|
|
83
|
-
pid: Process.pid,
|
|
84
|
-
message: name == "ActionMailer" ? msg.strip : msg
|
|
85
|
-
}
|
|
86
|
-
JSON.dump(store) + "\n"
|
|
87
|
-
else
|
|
88
|
-
format('%s %s: %s', serverity.ljust(6), datetime, msg) + "\n"
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
return logger
|
|
93
|
-
end
|
|
94
34
|
end
|
|
95
35
|
|
|
96
36
|
module Controllers
|
|
@@ -147,7 +87,7 @@ module ZuoraConnect
|
|
|
147
87
|
verify_server_cert: false,
|
|
148
88
|
log_level: Logger::INFO,
|
|
149
89
|
service_name: ENV['DEIS_APP'].present? ? ENV['DEIS_APP'] : Rails.application.class.parent_name,
|
|
150
|
-
logger:
|
|
90
|
+
logger: ZuoraObservability::Logger.custom_logger(name: "ElasticAPM", level: MonoLogger::WARN)
|
|
151
91
|
})
|
|
152
92
|
defaults.merge!({disable_send: true}) if defined?(Rails::Console)
|
|
153
93
|
|
|
@@ -138,12 +138,8 @@ module ZuoraConnect
|
|
|
138
138
|
end
|
|
139
139
|
ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
|
140
140
|
end
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
|
144
|
-
end
|
|
145
|
-
rescue
|
|
146
|
-
ZuoraConnect.logger.error(ex)
|
|
141
|
+
if @appinstance.user_timezone.blank?
|
|
142
|
+
@appinstance.set_timezone(timezone: session["#{@appinstance.id}::user::timezone"], type: :default)
|
|
147
143
|
end
|
|
148
144
|
end
|
|
149
145
|
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
|
data/lib/zuora_connect/engine.rb
CHANGED
|
@@ -10,9 +10,10 @@ module ZuoraConnect
|
|
|
10
10
|
|
|
11
11
|
initializer "connect", before: :load_config_initializers do |app|
|
|
12
12
|
Rails.application.routes.prepend do
|
|
13
|
+
get '/connect/internal/data' => 'zuora_observability/metrics#metrics'
|
|
13
14
|
mount ZuoraConnect::Engine, at: "/connect"
|
|
14
15
|
match '/api/connect/health', via: :all, to: 'zuora_connect/static#health'
|
|
15
|
-
match '/api/connect/internal/data', via: :all, to: '
|
|
16
|
+
match '/api/connect/internal/data', via: :all, to: 'zuora_observability/metrics#metrics'
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
|
|
@@ -46,68 +46,5 @@ module ZuoraConnect
|
|
|
46
46
|
|
|
47
47
|
# hook to process_action
|
|
48
48
|
ActiveSupport::Notifications.subscribe('process_action.action_controller', ZuoraConnect::PageRequest.new)
|
|
49
|
-
|
|
50
|
-
initializer(:rails_stdout_logging, before: :initialize_logger) do
|
|
51
|
-
require 'lograge'
|
|
52
|
-
|
|
53
|
-
Rails.configuration.logger = ZuoraConnect.custom_logger(name: "Rails")
|
|
54
|
-
if !Rails.env.test? && !Rails.env.development?
|
|
55
|
-
Rails.configuration.lograge.enabled = true
|
|
56
|
-
Rails.configuration.colorize_logging = false
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
if Rails.configuration.lograge.enabled
|
|
60
|
-
if Rails.configuration.logger.class.to_s == 'Ougai::Logger'
|
|
61
|
-
Rails.configuration.lograge.formatter = Class.new do |fmt|
|
|
62
|
-
def fmt.call(data)
|
|
63
|
-
{ msg: 'Rails Request', request: data }
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
#Rails.configuration.lograge.formatter = Lograge::Formatters::Json.new
|
|
68
|
-
Rails.configuration.lograge.custom_options = lambda do |event|
|
|
69
|
-
exceptions = %w(controller action format)
|
|
70
|
-
items = {
|
|
71
|
-
#time: event.time.strftime('%FT%T.%6N'),
|
|
72
|
-
params: event.payload[:params].as_json(except: exceptions).to_json.to_s
|
|
73
|
-
}
|
|
74
|
-
items.merge!({exception_object: event.payload[:exception_object]}) if event.payload[:exception_object].present?
|
|
75
|
-
items.merge!({exception: event.payload[:exception]}) if event.payload[:exception].present?
|
|
76
|
-
|
|
77
|
-
if event.payload[:headers].present?
|
|
78
|
-
# By convertion, headers usually do not have dots. Nginx even rejects headers with dots
|
|
79
|
-
# All Rails headers are namespaced, like 'rack.input'.
|
|
80
|
-
# Thus, we can obtain the client headers by rejecting dots
|
|
81
|
-
request_headers =
|
|
82
|
-
event.payload[:headers].env.
|
|
83
|
-
reject { |key| key.to_s.include?('.') || REQUEST_HEADERS_TO_IGNORE.include?(key.to_s) }
|
|
84
|
-
begin
|
|
85
|
-
if request_headers["HTTP_AUTHORIZATION"].present?
|
|
86
|
-
if request_headers["HTTP_AUTHORIZATION"].include?("Basic")
|
|
87
|
-
user_password = request_headers["HTTP_AUTHORIZATION"].split("Basic").last.strip
|
|
88
|
-
user, password = Base64.decode64(user_password).split(":")
|
|
89
|
-
request_headers["HTTP_AUTHORIZATION"] = "Basic #{user}:ValueFiltered"
|
|
90
|
-
elsif
|
|
91
|
-
request_headers["HTTP_AUTHORIZATION"] = "ValueFiltered"
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
request_headers["HTTP_API_TOKEN"] = "ValueFiltered" if request_headers["HTTP_API_TOKEN"].present?
|
|
95
|
-
rescue
|
|
96
|
-
request_headers.delete("HTTP_API_TOKEN")
|
|
97
|
-
request_headers.delete("HTTP_AUTHORIZATION")
|
|
98
|
-
end
|
|
99
|
-
items.merge!({ headers: request_headers.to_s })
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
if Thread.current[:appinstance].present?
|
|
103
|
-
items.merge!({connect_user: Thread.current[:appinstance].connect_user, new_session: Thread.current[:appinstance].new_session_message})
|
|
104
|
-
if Thread.current[:appinstance].logitems.present? && Thread.current[:appinstance].logitems.class == Hash
|
|
105
|
-
items.merge!(Thread.current[:appinstance].logitems)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
return items
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
49
|
end
|
|
113
50
|
end
|
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:
|
|
4
|
+
version: 3.0.0.pre.a
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Connect Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-11-
|
|
11
|
+
date: 2020-11-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: apartment
|
|
@@ -182,6 +182,20 @@ dependencies:
|
|
|
182
182
|
- - ">="
|
|
183
183
|
- !ruby/object:Gem::Version
|
|
184
184
|
version: '0'
|
|
185
|
+
- !ruby/object:Gem::Dependency
|
|
186
|
+
name: zuora_observability
|
|
187
|
+
requirement: !ruby/object:Gem::Requirement
|
|
188
|
+
requirements:
|
|
189
|
+
- - ">="
|
|
190
|
+
- !ruby/object:Gem::Version
|
|
191
|
+
version: '0'
|
|
192
|
+
type: :runtime
|
|
193
|
+
prerelease: false
|
|
194
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
195
|
+
requirements:
|
|
196
|
+
- - ">="
|
|
197
|
+
- !ruby/object:Gem::Version
|
|
198
|
+
version: '0'
|
|
185
199
|
- !ruby/object:Gem::Dependency
|
|
186
200
|
name: rspec
|
|
187
201
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -318,7 +332,6 @@ files:
|
|
|
318
332
|
- app/models/zuora_connect/app_instance.rb
|
|
319
333
|
- app/models/zuora_connect/app_instance_base.rb
|
|
320
334
|
- app/models/zuora_connect/login.rb
|
|
321
|
-
- app/models/zuora_connect/telegraf.rb
|
|
322
335
|
- app/models/zuora_connect/zuora_user.rb
|
|
323
336
|
- app/views/layouts/zuora_connect/application.html.erb
|
|
324
337
|
- app/views/sql/refresh_aggregate_table.txt
|
|
@@ -353,8 +366,6 @@ files:
|
|
|
353
366
|
- db/migrate/20190520232222_add_unique_index.rb
|
|
354
367
|
- db/migrate/20190520232223_add_provisioning_fields.rb
|
|
355
368
|
- db/migrate/20190520232224_add_environment_fields.rb
|
|
356
|
-
- lib/logging/connect_formatter.rb
|
|
357
|
-
- lib/metrics/influx/point_value.rb
|
|
358
369
|
- lib/metrics/net.rb
|
|
359
370
|
- lib/middleware/bad_multipart_form_data_sanitizer.rb
|
|
360
371
|
- lib/middleware/json_parse_errors.rb
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
module ZuoraConnect
|
|
2
|
-
class Telegraf
|
|
3
|
-
attr_accessor :host
|
|
4
|
-
|
|
5
|
-
OUTBOUND_METRICS = true
|
|
6
|
-
OUTBOUND_METRICS_NAME = "request-outbound"
|
|
7
|
-
INBOUND_METRICS = true
|
|
8
|
-
INBOUND_METRICS_NAME = "request-inbound"
|
|
9
|
-
|
|
10
|
-
def initialize
|
|
11
|
-
self.connect
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def connect
|
|
15
|
-
ZuoraConnect.logger.debug(self.format_metric_log('Telegraf','Need new connection')) if ZuoraConnect.configuration.telegraf_debug
|
|
16
|
-
uri = URI.parse(ZuoraConnect.configuration.telegraf_endpoint)
|
|
17
|
-
self.host = UDPSocket.new.tap do |socket|
|
|
18
|
-
socket.connect uri.host, uri.port
|
|
19
|
-
end
|
|
20
|
-
rescue => ex
|
|
21
|
-
self.host = nil
|
|
22
|
-
ZuoraConnect.logger.warn(self.format_metric_log('Telegraf', "Failed to connect: #{ex.class}")) if Rails.env.to_s != 'production'
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def write(direction: 'Unknown', tags: {}, values: {})
|
|
26
|
-
time = Benchmark.measure do |bench|
|
|
27
|
-
# To avoid writing metrics from rspec tests
|
|
28
|
-
if Rails.env.to_sym != :test
|
|
29
|
-
app_instance = Thread.current[:appinstance].present? ? Thread.current[:appinstance].id : 0
|
|
30
|
-
tags = { app_name: self.class.app_name, process_type: self.class.process_type, app_instance: app_instance, pod_name: self.class.pod_name}.merge(tags)
|
|
31
|
-
|
|
32
|
-
if direction == :inbound
|
|
33
|
-
if INBOUND_METRICS && !Thread.current[:inbound_metric].to_bool
|
|
34
|
-
self.write_udp(series: INBOUND_METRICS_NAME, tags: tags, values: values)
|
|
35
|
-
Thread.current[:inbound_metric] = true
|
|
36
|
-
else
|
|
37
|
-
return
|
|
38
|
-
end
|
|
39
|
-
elsif direction == :outbound
|
|
40
|
-
self.write_udp(series: OUTBOUND_METRICS_NAME, tags: tags, values: values) if OUTBOUND_METRICS
|
|
41
|
-
else
|
|
42
|
-
self.write_udp(series: direction, tags: tags, values: values)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
if ZuoraConnect.configuration.telegraf_debug
|
|
47
|
-
ZuoraConnect.logger.debug(self.format_metric_log('Telegraf', tags.to_s))
|
|
48
|
-
ZuoraConnect.logger.debug(self.format_metric_log('Telegraf', values.to_s))
|
|
49
|
-
ZuoraConnect.logger.debug(self.format_metric_log('Telegraf', "Writing '#{direction.capitalize}': #{time.real.round(5)} ms"))
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def write_udp(series: '', tags: {}, values: {})
|
|
55
|
-
return if !values.present?
|
|
56
|
-
self.host.write InfluxDB::PointValue.new({series: series, tags: tags, values: values}).dump
|
|
57
|
-
rescue => ex
|
|
58
|
-
self.connect
|
|
59
|
-
ZuoraConnect.logger.warn(self.format_metric_log('Telegraf',"Failed to write udp: #{ex.class}")) if Rails.env.to_s != 'production'
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def format_metric_log(message, dump = nil)
|
|
63
|
-
message_color, dump_color = "1;91", "0;1"
|
|
64
|
-
log_entry = " \e[#{message_color}m#{message}\e[0m "
|
|
65
|
-
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
|
|
66
|
-
if Rails.env == :development
|
|
67
|
-
log_entry
|
|
68
|
-
else
|
|
69
|
-
[message, dump].compact.join(' - ')
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def self.app_name
|
|
74
|
-
return ENV['DEIS_APP'].present? ? ENV['DEIS_APP'] : Rails.application.class.parent_name
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def self.pod_name
|
|
78
|
-
return ENV['HOSTNAME'].present? ? ENV['HOSTNAME'] : Socket.gethostname
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def self.full_process_name(process_name: nil, function: nil)
|
|
82
|
-
keys = [self.pod_name, process_name.present? ? process_name : self.process_type, Process.pid, function]
|
|
83
|
-
return keys.compact.join('][').prepend('[').concat(']')
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Returns the process type if any
|
|
87
|
-
def self.process_type(default: 'Unknown')
|
|
88
|
-
p_type = default
|
|
89
|
-
if ENV['HOSTNAME'] && ENV['DEIS_APP']
|
|
90
|
-
temp = ENV['HOSTNAME'].split(ENV['DEIS_APP'])[1]
|
|
91
|
-
temp = temp.split(/(-[0-9a-zA-Z]{5})$/)[0] # remove the 5 char hash
|
|
92
|
-
p_type = temp[1, temp.rindex("-")-1]
|
|
93
|
-
end
|
|
94
|
-
return p_type
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
require 'ougai/formatters/base'
|
|
2
|
-
require 'ougai/formatters/for_json'
|
|
3
|
-
|
|
4
|
-
module Ougai
|
|
5
|
-
module Formatters
|
|
6
|
-
# A JSON formatter compatible with node-bunyan
|
|
7
|
-
class ConnectFormatter < Base
|
|
8
|
-
include ForJson
|
|
9
|
-
|
|
10
|
-
# Intialize a formatter
|
|
11
|
-
# @param [String] app_name application name (execution program name if nil)
|
|
12
|
-
# @param [String] hostname hostname (hostname if nil)
|
|
13
|
-
# @param [Hash] opts the initial values of attributes
|
|
14
|
-
# @option opts [String] :trace_indent (2) the value of trace_indent attribute
|
|
15
|
-
# @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
|
|
16
|
-
# @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
|
|
17
|
-
# @option opts [String] :jsonize (true) the value of jsonize attribute
|
|
18
|
-
# @option opts [String] :with_newline (true) the value of with_newline attribute
|
|
19
|
-
def initialize(app_name = nil, hostname = nil, opts = {})
|
|
20
|
-
aname, hname, opts = Base.parse_new_params([app_name, hostname, opts])
|
|
21
|
-
super(aname, hname, opts)
|
|
22
|
-
init_opts_for_json(opts)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def _call(severity, time, progname, data)
|
|
26
|
-
data.merge!({message: data.delete(:msg)})
|
|
27
|
-
if data[:timestamp].present?
|
|
28
|
-
time = data[:timestamp]
|
|
29
|
-
data.delete(:timestamp)
|
|
30
|
-
end
|
|
31
|
-
dump({
|
|
32
|
-
name: progname || @app_name,
|
|
33
|
-
pid: $$,
|
|
34
|
-
level: severity,
|
|
35
|
-
timestamp: time.utc.strftime('%FT%T.%6NZ'),
|
|
36
|
-
}.merge(data))
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def convert_time(data)
|
|
40
|
-
#data[:timestamp] = format_datetime(data[:time])
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,79 +0,0 @@
|
|
|
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
|