zuora_connect 2.1.1 → 3.0.0.pre.e

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.
@@ -2,6 +2,6 @@ module ZuoraConnect
2
2
  class ZuoraUser < ActiveRecord::Base
3
3
  self.table_name = "zuora_users"
4
4
  attr_accessor :session
5
-
5
+ cattr_accessor :current_user_id
6
6
  end
7
7
  end
@@ -1,9 +1,15 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  class PostgreSQLAdapter < AbstractAdapter
4
+
5
+ SCHEMA_ADDITIONAL_TYPES = 'SchemaAdditionalTypes'.freeze
6
+
4
7
  private
5
- def load_additional_types(type_map, oids = nil)
8
+ def load_additional_types_latest(oids = nil)
6
9
  initializer = OID::TypeMapInitializer.new(type_map)
10
+
11
+ return if loaded_from_cache?(initializer)
12
+
7
13
  if supports_ranges?
8
14
  query = <<-SQL
9
15
  SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
@@ -24,9 +30,73 @@ module ActiveRecord
24
30
  end
25
31
 
26
32
  execute_and_clear(query, "SCHEMA", []) do |records|
33
+ cache_additional_types(records)
27
34
  initializer.run(records)
28
35
  end
29
36
  end
37
+
38
+ def load_additional_types_deprecated(type_map, oids = nil)
39
+ initializer = OID::TypeMapInitializer.new(type_map)
40
+
41
+ return if loaded_from_cache?(initializer)
42
+
43
+ if supports_ranges?
44
+ query = <<-SQL
45
+ SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
46
+ FROM pg_type as t
47
+ LEFT JOIN pg_range as r ON oid = rngtypid
48
+ SQL
49
+ else
50
+ query = <<-SQL
51
+ SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
52
+ FROM pg_type as t
53
+ SQL
54
+ end
55
+
56
+ if oids
57
+ query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
58
+ else
59
+ query += initializer.query_conditions_for_initial_load(type_map)
60
+ end
61
+
62
+ execute_and_clear(query, "SCHEMA", []) do |records|
63
+ cache_additional_types(records)
64
+ initializer.run(records)
65
+ end
66
+ end
67
+
68
+ def loaded_from_cache?(initializer)
69
+ if defined?(Redis.current)
70
+ begin
71
+ if Redis.current.exists(SCHEMA_ADDITIONAL_TYPES)
72
+ initializer.run(JSON.parse(Redis.current.get(SCHEMA_ADDITIONAL_TYPES)))
73
+ return true
74
+ end
75
+ rescue => ex
76
+ Rails.logger.warn('Exception occurred while loading additional types', ex)
77
+ end
78
+ end
79
+
80
+ false
81
+ end
82
+
83
+ def cache_additional_types(records)
84
+ if defined?(Redis.current)
85
+ begin
86
+ Redis.current.setex(SCHEMA_ADDITIONAL_TYPES, 1.hour.to_i, records.to_json)
87
+ rescue => ex
88
+ Rails.logger.warn('Exception occurred while caching additional types', ex)
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ rails_version = Rails.version.split('.').map { |x| x.to_i }
95
+ if (rails_version <=> [5, 2, 0]) >= 1
96
+ alias :load_additional_types :load_additional_types_latest
97
+ else
98
+ alias :load_additional_types :load_additional_types_deprecated
99
+ end
30
100
  end
31
101
  end
32
102
  end
@@ -3,38 +3,95 @@ if defined? Prometheus
3
3
  require "zuora_connect/version"
4
4
  require "zuora_api/version"
5
5
 
6
+ resque_path = "#{ENV['RESQUE_EXPORTER_PATH'] || Rails.root.join('tmp/resque_exporter')}/*.prom"
7
+ prometheus_path = Rails.root.join("tmp/prometheus")
8
+
9
+ Dir[resque_path, "#{prometheus_path}/*.bin"].each do |file_path|
10
+ File.unlink(file_path)
11
+ end
12
+
13
+ require 'prometheus/client/data_stores/direct_file_store'
14
+ Prometheus::Client.config.data_store = Prometheus::Client::DataStores::DirectFileStore.new(
15
+ dir: prometheus_path
16
+ )
17
+
18
+ class ResqueExporter
19
+ require 'prometheus/client/formats/text'
20
+ require 'fileutils'
21
+
22
+ def initialize
23
+ @lock = Monitor.new
24
+ @registry = Prometheus::Client.registry
25
+ @path = ENV['RESQUE_EXPORTER_PATH'] || Rails.root.join('tmp/resque_exporter')
26
+ FileUtils.mkdir_p(@path)
27
+ end
28
+
29
+ def export
30
+ filename = File.join(@path, 'resque_export.prom')
31
+ @lock.synchronize do
32
+ File.open(filename, 'w+') do |file|
33
+ file.write(Prometheus::Client::Formats::Text.marshal(@registry))
34
+ end
35
+ end
36
+ rescue
37
+ # Ignored
38
+ end
39
+ end
40
+
41
+ most_recent_aggregation = {}
42
+ sum_aggregation = {}
43
+ if defined?(Unicorn)
44
+ most_recent_aggregation[:aggregation] = :most_recent
45
+ sum_aggregation[:aggregation] = :sum
46
+ end
47
+
6
48
  # Create a default Prometheus registry for our metrics.
7
49
  prometheus = Prometheus::Client.registry
8
50
 
9
51
  # Create your metrics.
10
- ZUORA_VERSION = Prometheus::Client::Gauge.new(:zuora_version, 'The current Zuora Gem version.')
11
- CONNECT_VERSION = Prometheus::Client::Gauge.new(:gem_version, 'The current Connect Gem version.')
12
- RAILS_VERSION = Prometheus::Client::Gauge.new(:rails_version, 'The current Rails version.')
13
- RUBY_V = Prometheus::Client::Gauge.new(:ruby_version, 'The current Ruby version.')
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)
14
56
 
15
- # Register your metrics with the registry we previously created.
16
- prometheus.register(ZUORA_VERSION);ZUORA_VERSION.set({version: ZuoraAPI::VERSION, name: ZuoraConnect::Telegraf.app_name},0)
17
- prometheus.register(CONNECT_VERSION);CONNECT_VERSION.set({version: ZuoraConnect::VERSION, name: ZuoraConnect::Telegraf.app_name},0)
18
- prometheus.register(RAILS_VERSION);RAILS_VERSION.set({version: Rails.version, name: ZuoraConnect::Telegraf.app_name},0)
19
- prometheus.register(RUBY_V);RUBY_V.set({version: RUBY_VERSION, name: ZuoraConnect::Telegraf.app_name},0)
57
+ ZUORA_VERSION.set(0)
58
+ CONNECT_VERSION.set(0)
59
+ RAILS_VERSION.set(0)
60
+ RUBY_V.set(0)
20
61
 
21
62
  # Do they have resque jobs?
22
63
  if defined? Resque.redis
23
- REDIS_CONNECTION = Prometheus::Client::Gauge.new(:redis_connection, 'The status of the redis connection, 0 or 1')
24
- FINISHED_JOBS = Prometheus::Client::Gauge.new(:finished_jobs, 'Done resque jobs')
25
- WORKERS = Prometheus::Client::Gauge.new(:workers, 'Total resque workers')
26
- ACTIVE_WORKERS = Prometheus::Client::Gauge.new(:active_workers, 'Active resque workers')
27
- FAILED_JOBS = Prometheus::Client::Gauge.new(:failed_jobs, 'Failed resque jobs')
28
- PENDING_JOBS = Prometheus::Client::Gauge.new(:pending_jobs, 'Pending resque jobs')
29
-
30
- prometheus.register(REDIS_CONNECTION)
31
- prometheus.register(FINISHED_JOBS)
32
- prometheus.register(ACTIVE_WORKERS)
33
- prometheus.register(WORKERS)
34
- prometheus.register(FAILED_JOBS)
35
- prometheus.register(PENDING_JOBS)
36
-
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)
37
70
  end
38
71
 
72
+ if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
73
+ UNICORN_KILLS = prometheus.gauge(
74
+ :unicorn_kills,
75
+ docstring: 'Unicorn Kills',
76
+ labels: %i(type name),
77
+ preset_labels: {type:'Unicorn-Killer', name: ZuoraObservability::Env.app_name},
78
+ store_settings: sum_aggregation
79
+ )
80
+
81
+ ZuoraObservability::Metrics.unicorn_listener.each do |key, _|
82
+ gauge_name = "unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_')
83
+ gauge = prometheus.gauge(
84
+ gauge_name.to_sym,
85
+ docstring: 'Unicorn Stats',
86
+ labels: %i(type name),
87
+ preset_labels: { type: 'unicorn', name: ZuoraObservability::Env.app_name },
88
+ store_settings: most_recent_aggregation
89
+ )
90
+ Prometheus.const_set(
91
+ gauge_name.upcase,
92
+ gauge
93
+ )
94
+ end
95
+ end
39
96
  end
40
97
  end
@@ -12,21 +12,21 @@ class RedisFlash
12
12
  end
13
13
 
14
14
  if defined?(Redis.current)
15
- Redis.current = Redis.new(:id => "#{ZuoraConnect::Telegraf.full_process_name(process_name: 'Redis')}", :url => redis_url, :timeout => 6, :reconnect_attempts => 2)
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 => "#{ZuoraConnect::Telegraf.full_process_name(process_name: 'Resque')}", :url => resque_url, :timeout => 6, :reconnect_attempts => 2)
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 => "#{ZuoraConnect::Telegraf.full_process_name(process_name: 'Flash')}", :url => flash_url, :timeout => 6, :reconnect_attempts => 2)
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
@@ -5,6 +5,20 @@ if defined?(Resque::Worker)
5
5
  Resque::Job.send(:include, Resque::SelfLookup)
6
6
  end
7
7
 
8
+ if defined?(Resque::Job) && defined?(Prometheus)
9
+ module ResquePrometheusExtensions
10
+ EXPORTER = Prometheus::ResqueExporter.new
11
+ def perform
12
+ super
13
+ EXPORTER.export
14
+ end
15
+ end
16
+
17
+ class Resque::Job
18
+ prepend ResquePrometheusExtensions
19
+ end
20
+ end
21
+
8
22
  Resque.module_eval do
9
23
  # Returns a hash, mapping queue names to queue sizes
10
24
  def queue_sizes
@@ -20,15 +34,3 @@ Resque.module_eval do
20
34
  Hash[queue_names.zip(sizes)]
21
35
  end
22
36
  end
23
-
24
- if defined?(Resque.logger)
25
- Resque.logger = ZuoraConnect.custom_logger(name: "Resque", type: 'Monologger', level: MonoLogger::INFO)
26
- Resque::Scheduler.logger = ZuoraConnect.custom_logger(name: "ResqueScheduler") if defined?(Resque::Scheduler)
27
- end
28
- if defined?(Delayed::Worker.logger)
29
- Delayed::Worker.logger = ZuoraConnect.custom_logger(name: "DelayedJob", type: 'Monologger', level: MonoLogger::INFO)
30
- end
31
-
32
- Makara::Logging::Logger.logger = ZuoraConnect.custom_logger(name: "Makara") if defined?(Makara)
33
- ElasticAPM.agent.config.logger = ZuoraConnect.custom_logger(name: "ElasticAPM", level: MonoLogger::WARN) if defined?(ElasticAPM) && ElasticAPM.running?
34
- ActionMailer::Base.logger = ZuoraConnect.custom_logger(name: "ActionMailer", type: 'Monologger') if defined?(ActionMailer)
@@ -3,7 +3,35 @@ if defined?(Unicorn::WorkerKiller)
3
3
  self.singleton_class.send(:alias_method, :kill_self_old, :kill_self)
4
4
  def self.kill_self(logger, start_time)
5
5
  self.kill_self_old(logger, start_time)
6
- ZuoraConnect::AppInstance.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
6
+ if defined?(Prometheus)
7
+ Prometheus::UNICORN_KILLS.set(1)
8
+ else
9
+ ZuoraObservability::Metrics.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
10
+ end
7
11
  end
8
12
  end
9
- end
13
+ end
14
+
15
+ if defined?(Unicorn::HttpServer) && defined?(Prometheus)
16
+ module HttpServerExtensions
17
+ def kill_worker(signal, wpid)
18
+ Prometheus::UNICORN_KILLS.increment
19
+ super
20
+ end
21
+ end
22
+
23
+ module WorkerExtensions
24
+ def soft_kill(sig)
25
+ Prometheus::UNICORN_KILLS.increment
26
+ super
27
+ end
28
+ end
29
+
30
+ class Unicorn::HttpServer
31
+ prepend HttpServerExtensions
32
+ end
33
+
34
+ class Unicorn::Worker
35
+ prepend WorkerExtensions
36
+ end
37
+ end
@@ -1,8 +1,12 @@
1
1
  ZuoraConnect::Engine.routes.draw do
2
2
  get '/health' => 'static#health'
3
- get '/internal/data' => 'static#metrics'
4
3
  post '/initialize_app' => 'static#initialize_app'
5
4
 
5
+ if ENV['PROVISION_USER'].present? && ENV['PROVISION_SECRET'].present?
6
+ post '/provision' => 'static#provision'
7
+ get '/instance/:id/user' => 'static#instance_user'
8
+ end
9
+
6
10
  namespace :api do
7
11
  namespace :v1 do
8
12
  resources :app_instance, :only => [:index], defaults: {format: :json} do
@@ -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
- ZuoraConnect::AppInstance.write_to_telegraf(direction: :outbound, tags: tags, values: values)
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
@@ -7,7 +7,7 @@ module ZuoraConnect
7
7
  def call(env)
8
8
  begin
9
9
  @app.call(env)
10
- rescue ActionDispatch::ParamsParser::ParseError => error
10
+ rescue DynamicRailsError => error
11
11
  if env['HTTP_ACCEPT'] =~ /application\/json/ || env['CONTENT_TYPE'] =~ /application\/json/
12
12
  return [
13
13
  400, { "Content-Type" => "application/json" },
@@ -18,5 +18,16 @@ module ZuoraConnect
18
18
  end
19
19
  end
20
20
  end
21
+
22
+ # Note(hartley): remove once the minimum supported version of Rails is 5.2
23
+ class DynamicRailsError < StandardError
24
+ def self.===(exception)
25
+ if Rails.version >= "5.2"
26
+ exception.is_a?(ActionDispatch::Http::Parameters::ParseError)
27
+ else
28
+ exception.is_a?(ActionDispatch::ParamsParser::ParseError)
29
+ end
30
+ end
31
+ end
21
32
  end
22
- end
33
+ end
@@ -1,37 +1,6 @@
1
1
  module ZuoraConnect
2
2
  require 'uri'
3
3
 
4
- # Object of this class is passed to the ActiveSupport::Notification hook
5
- class PageRequest
6
-
7
- # This method is triggered when a non error page is loaded (not 404)
8
- def call(name, started, finished, unique_id, payload)
9
- # If the url contains any css or JavaScript files then do not collect metrics for them
10
- return nil if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| payload[:path].include?(word) }
11
-
12
- # Getting the endpoint and the content_type
13
- content_hash = {:html => "text/html", :js => "application/javascript", :json => "application/json", :csv => "text/csv"}
14
- content_type = content_hash.key?(payload[:format]) ? content_hash[payload[:format]] : payload[:format]
15
- content_type = content_type.to_s.gsub('text/javascript', 'application/javascript')
16
-
17
- # payloads with 500 requests do not have status as it is not set by the controller
18
- # https://github.com/rails/rails/issues/33335
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
25
-
26
- tags = {method: payload[:method], status: status_code, error_type: exception, content_type: content_type, controller: payload[:controller], action: payload[:action]}.compact
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)
32
- end
33
- end
34
-
35
4
  class MetricsMiddleware
36
5
 
37
6
  require "zuora_connect/version"
@@ -42,7 +11,7 @@ module ZuoraConnect
42
11
  end
43
12
 
44
13
  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"]
14
+ @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
15
  if !ActionDispatch::Request::HTTP_METHODS.include?(env["REQUEST_METHOD"].upcase)
47
16
  [405, {"Content-Type" => "text/plain"}, ["Method Not Allowed"]]
48
17
  else
@@ -64,47 +33,27 @@ module ZuoraConnect
64
33
  #Remove bad headers
65
34
  @bad_headers.each { |header| env.delete(header) }
66
35
 
67
- #Thread.current[:appinstance] = nil
68
- start_time = Time.now
69
- begin
70
- @status, @headers, @response = @app.call(env)
71
- ensure
72
-
73
- # If the url contains any CSS or JavaScript files then do not collect metrics for them
74
- if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| env['PATH_INFO'].include?(word) } || /.*\.js$/.match(env['PATH_INFO'])
75
- tags = {status: @status, controller: 'ActionController', action: 'Assets', app_instance: 0}
76
- values = {response_time: ((Time.now - start_time)*1000).round(2) }
77
- ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: 'request-inbound-assets', tags: tags, values: values)
78
- end
79
-
80
- if defined? Prometheus
81
- #Prometheus Stuff
82
- if env['PATH_INFO'] == '/connect/internal/metrics'
83
-
84
- #Do something before each scrape
85
- if defined? Resque.redis
86
- begin
87
-
88
- Resque.redis.ping
89
-
90
- Prometheus::REDIS_CONNECTION.set({connection:'redis',name: ZuoraConnect::Telegraf.app_name},1)
91
- Prometheus::FINISHED_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:processed])
92
- Prometheus::PENDING_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:pending])
93
- Prometheus::ACTIVE_WORKERS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:working])
94
- Prometheus::WORKERS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:workers])
95
- Prometheus::FAILED_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:failed])
36
+ if defined?(Prometheus) && env['PATH_INFO'] == '/connect/internal/metrics'
37
+ # Prometheus Stuff
38
+ metrics = ZuoraObservability::Metrics.resque
39
+ redis_up = metrics.present? && metrics.dig(:Resque, :Workers_Total).present? ? 1 : 0
40
+ Prometheus::REDIS_CONNECTION.set(redis_up)
96
41
 
97
- rescue Redis::CannotConnectError
98
- Prometheus::REDIS_CONNECTION.set({connection:'redis',name: ZuoraConnect::Telegraf.app_name},0)
99
- end
100
-
101
- if ZuoraConnect.configuration.custom_prometheus_update_block != nil
102
- ZuoraConnect.configuration.custom_prometheus_update_block.call()
103
- end
104
- end
42
+ process_prometheus_metric(metrics: metrics)
105
43
 
44
+ if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
45
+ ZuoraObservability::Metrics.unicorn_listener.each do |key, value|
46
+ gauge = Prometheus.const_get("unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_').upcase)
47
+ gauge.set(value) if gauge.present?
106
48
  end
107
49
  end
50
+ end
51
+
52
+ #Thread.current[:appinstance] = nil
53
+ start_time = Time.now
54
+ begin
55
+ @status, @headers, @response = @app.call(env)
56
+ ensure
108
57
 
109
58
  # Uncomment following block of code for handling engine requests/requests without controller
110
59
  # else
@@ -119,13 +68,13 @@ module ZuoraConnect
119
68
  content_type = @headers['Content-Type'].split(';')[0] if @headers['Content-Type']
120
69
  content_type = content_type.gsub('text/javascript', 'application/javascript')
121
70
  tags = {status: @status, content_type: content_type}
122
-
71
+
123
72
  tags = tags.merge({controller: 'ActionController'})
124
73
  tags = tags.merge({action: 'RoutingError' }) if @status == 404
125
-
74
+
126
75
  values = {response_time: ((Time.now - start_time)*1000).round(2) }
127
76
 
128
- ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
77
+ ZuoraObservability::Metrics.write_to_telegraf(direction: :inbound, tags: tags, values: values)
129
78
  end
130
79
  end
131
80
  Thread.current[:inbound_metric] = nil
@@ -133,5 +82,32 @@ module ZuoraConnect
133
82
  [@status, @headers, @response]
134
83
  end
135
84
  end
85
+
86
+ def process_prometheus_metric(type: 'none', metrics: {})
87
+ return if metrics.blank?
88
+
89
+ prometheus = Prometheus::Client.registry
90
+ most_recent_aggregation = {}
91
+ if Prometheus::Client.config.data_store.is_a?(Prometheus::Client::DataStores::DirectFileStore)
92
+ most_recent_aggregation[:aggregation] = :most_recent
93
+ end
94
+ metrics.each do |key, value|
95
+ next if %w[app_name url].include?(key.to_s)
96
+
97
+ if value.is_a?(Hash)
98
+ process_prometheus_metric(type: key.to_s, metrics: value)
99
+ else
100
+ gauge_name = key.to_s.downcase.gsub(/[^a-z0-9_]/, '_')
101
+ gauge = prometheus.get(gauge_name.to_sym) || prometheus.gauge(
102
+ gauge_name.to_sym,
103
+ docstring: "#{key} metric",
104
+ labels: %i(type name),
105
+ preset_labels: { type: type, name: ZuoraObservability::Env.app_name },
106
+ store_settings: most_recent_aggregation
107
+ )
108
+ gauge.set(value)
109
+ end
110
+ end
111
+ end
136
112
  end
137
113
  end