zuora_connect 2.1.1 → 3.0.0.pre.a

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -22,13 +36,13 @@ Resque.module_eval do
22
36
  end
23
37
 
24
38
  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)
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)
27
41
  end
28
42
  if defined?(Delayed::Worker.logger)
29
- Delayed::Worker.logger = ZuoraConnect.custom_logger(name: "DelayedJob", type: 'Monologger', level: MonoLogger::INFO)
43
+ Delayed::Worker.logger = ZuoraObservability::Logger.custom_logger(name: "DelayedJob", type: 'Monologger', level: MonoLogger::INFO)
30
44
  end
31
45
 
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)
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)
@@ -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
@@ -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
- ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
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
@@ -64,46 +64,33 @@ module ZuoraConnect
64
64
  #Remove bad headers
65
65
  @bad_headers.each { |header| env.delete(header) }
66
66
 
67
+ if defined?(Prometheus) && env['PATH_INFO'] == '/connect/internal/metrics'
68
+ # Prometheus Stuff
69
+ metrics = ZuoraObservability::Metrics.resque
70
+ redis_up = metrics.present? && metrics.dig(:Resque, :Workers_Total).present? ? 1 : 0
71
+ Prometheus::REDIS_CONNECTION.set(redis_up)
72
+
73
+ process_prometheus_metric(metrics: metrics)
74
+
75
+ if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
76
+ ZuoraObservability::Metrics.unicorn_listener.each do |key, value|
77
+ gauge = Prometheus.const_get("unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_').upcase)
78
+ gauge.set(value) if gauge.present?
79
+ end
80
+ end
81
+ end
82
+
67
83
  #Thread.current[:appinstance] = nil
68
84
  start_time = Time.now
69
85
  begin
70
86
  @status, @headers, @response = @app.call(env)
71
- ensure
72
-
87
+ ensure
88
+
73
89
  # If the url contains any CSS or JavaScript files then do not collect metrics for them
74
90
  if ["css", "assets", "jpg", "png", "jpeg", "ico"].any? { |word| env['PATH_INFO'].include?(word) } || /.*\.js$/.match(env['PATH_INFO'])
75
91
  tags = {status: @status, controller: 'ActionController', action: 'Assets', app_instance: 0}
76
92
  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])
96
-
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
105
-
106
- end
93
+ ZuoraObservability::Metrics.write_to_telegraf(direction: 'request-inbound-assets', tags: tags, values: values)
107
94
  end
108
95
 
109
96
  # Uncomment following block of code for handling engine requests/requests without controller
@@ -119,13 +106,13 @@ module ZuoraConnect
119
106
  content_type = @headers['Content-Type'].split(';')[0] if @headers['Content-Type']
120
107
  content_type = content_type.gsub('text/javascript', 'application/javascript')
121
108
  tags = {status: @status, content_type: content_type}
122
-
109
+
123
110
  tags = tags.merge({controller: 'ActionController'})
124
111
  tags = tags.merge({action: 'RoutingError' }) if @status == 404
125
-
112
+
126
113
  values = {response_time: ((Time.now - start_time)*1000).round(2) }
127
114
 
128
- ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
115
+ ZuoraObservability::Metrics.write_to_telegraf(direction: :inbound, tags: tags, values: values)
129
116
  end
130
117
  end
131
118
  Thread.current[:inbound_metric] = nil
@@ -133,5 +120,32 @@ module ZuoraConnect
133
120
  [@status, @headers, @response]
134
121
  end
135
122
  end
123
+
124
+ def process_prometheus_metric(type: 'none', metrics: {})
125
+ return if metrics.blank?
126
+
127
+ prometheus = Prometheus::Client.registry
128
+ most_recent_aggregation = {}
129
+ if Prometheus::Client.config.data_store.is_a?(Prometheus::Client::DataStores::DirectFileStore)
130
+ most_recent_aggregation[:aggregation] = :most_recent
131
+ end
132
+ metrics.each do |key, value|
133
+ next if %w[app_name url].include?(key.to_s)
134
+
135
+ if value.is_a?(Hash)
136
+ process_prometheus_metric(type: key.to_s, metrics: value)
137
+ else
138
+ gauge_name = key.to_s.downcase.gsub(/[^a-z0-9_]/, '_')
139
+ gauge = prometheus.get(gauge_name.to_sym) || prometheus.gauge(
140
+ gauge_name.to_sym,
141
+ docstring: "#{key} metric",
142
+ labels: %i(type name),
143
+ preset_labels: { type: type, name: ZuoraObservability::Env.app_name },
144
+ store_settings: most_recent_aggregation
145
+ )
146
+ gauge.set(value)
147
+ end
148
+ end
149
+ end
136
150
  end
137
151
  end