zuora_connectD 1.7.09
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +38 -0
- data/app/assets/javascripts/zuora_connect/api/v1/app_instance.js +2 -0
- data/app/assets/javascripts/zuora_connect/application.js +13 -0
- data/app/assets/stylesheets/zuora_connect/api/v1/app_instance.css +4 -0
- data/app/assets/stylesheets/zuora_connect/application.css +15 -0
- data/app/controllers/zuora_connect/admin/tenant_controller.rb +11 -0
- data/app/controllers/zuora_connect/api/v1/app_instance_controller.rb +45 -0
- data/app/controllers/zuora_connect/application_controller.rb +8 -0
- data/app/controllers/zuora_connect/static_controller.rb +32 -0
- data/app/helpers/zuora_connect/api/v1/app_instance_helper.rb +4 -0
- data/app/helpers/zuora_connect/application_helper.rb +5 -0
- data/app/models/zuora_connect/app_instance.rb +5 -0
- data/app/models/zuora_connect/app_instance_base.rb +811 -0
- data/app/models/zuora_connect/login.rb +36 -0
- data/app/models/zuora_connect/telegraf.rb +88 -0
- data/app/views/layouts/zuora_connect/application.html.erb +14 -0
- data/app/views/sql/refresh_aggregate_table.txt +84 -0
- data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +65 -0
- data/app/views/zuora_connect/static/session_error.html.erb +63 -0
- data/config/initializers/apartment.rb +95 -0
- data/config/initializers/object_method_hooks.rb +27 -0
- data/config/initializers/postgresql_adapter.rb +32 -0
- data/config/initializers/prometheus.rb +41 -0
- data/config/initializers/redis.rb +10 -0
- data/config/initializers/resque.rb +6 -0
- data/config/initializers/to_bool.rb +24 -0
- data/config/initializers/unicorn.rb +9 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20100718151733_create_connect_app_instances.rb +9 -0
- data/db/migrate/20101024162319_add_tokens_to_app_instance.rb +6 -0
- data/db/migrate/20101024220705_add_token_to_app_instance.rb +5 -0
- data/db/migrate/20110131211919_add_sessions_table.rb +13 -0
- data/db/migrate/20110411200303_add_expiration_to_app_instance.rb +5 -0
- data/db/migrate/20110413191512_add_new_api_token.rb +5 -0
- data/db/migrate/20110503003602_add_catalog_data_to_app_instance.rb +6 -0
- data/db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb +5 -0
- data/db/migrate/20110503003604_catalog_default.rb +5 -0
- data/db/migrate/20180301052853_add_catalog_attempted_at.rb +5 -0
- data/lib/metrics/influx/point_value.rb +79 -0
- data/lib/metrics/net.rb +218 -0
- data/lib/middleware/metrics_middleware.rb +110 -0
- data/lib/resque/additions.rb +53 -0
- data/lib/resque/dynamic_queues.rb +142 -0
- data/lib/resque/self_lookup.rb +19 -0
- data/lib/resque/silence_done.rb +71 -0
- data/lib/tasks/zuora_connect_tasks.rake +24 -0
- data/lib/zuora_connectD.rb +41 -0
- data/lib/zuora_connectD/configuration.rb +52 -0
- data/lib/zuora_connectD/controllers/helpers.rb +165 -0
- data/lib/zuora_connectD/engine.rb +30 -0
- data/lib/zuora_connectD/exceptions.rb +67 -0
- data/lib/zuora_connectD/railtie.rb +59 -0
- data/lib/zuora_connectD/version.rb +3 -0
- data/lib/zuora_connectD/views/helpers.rb +9 -0
- data/test/controllers/zuora_connect/api/v1/app_instance_controller_test.rb +13 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +2 -0
- data/test/dummy/log/test.log +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/zuora_connect/app_instances.yml +11 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/lib/generators/zuora_connect/datatable_generator_test.rb +16 -0
- data/test/models/zuora_connect/app_instance_test.rb +9 -0
- data/test/test_helper.rb +21 -0
- data/test/zuora_connect_test.rb +7 -0
- metadata +416 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
def self.method_hook(*args)
|
|
3
|
+
options = args.extract_options!
|
|
4
|
+
return unless (options[:before].present? or options[:after].present?)
|
|
5
|
+
args.each do |method_name|
|
|
6
|
+
old_method = instance_method(method_name) rescue next
|
|
7
|
+
|
|
8
|
+
define_method(method_name) do |*args|
|
|
9
|
+
# invoke before callback
|
|
10
|
+
if options[:before].present?
|
|
11
|
+
options[:before].is_a?(Proc) ? options[:before].call(method_name, self):
|
|
12
|
+
send(options[:before], method_name)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# you can modify the code to call after callback
|
|
16
|
+
# only when the old method returns true etc..
|
|
17
|
+
old_method.bind(self).call(*args)
|
|
18
|
+
|
|
19
|
+
# invoke after callback
|
|
20
|
+
if options[:after].present?
|
|
21
|
+
options[:after].is_a?(Proc) ? options[:after].call(method_name, self):
|
|
22
|
+
send(options[:after], method_name)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
class PostgreSQLAdapter < AbstractAdapter
|
|
4
|
+
private
|
|
5
|
+
def load_additional_types(type_map, oids = nil)
|
|
6
|
+
initializer = OID::TypeMapInitializer.new(type_map)
|
|
7
|
+
if supports_ranges?
|
|
8
|
+
query = <<-SQL
|
|
9
|
+
SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
|
10
|
+
FROM pg_type as t
|
|
11
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
|
12
|
+
SQL
|
|
13
|
+
else
|
|
14
|
+
query = <<-SQL
|
|
15
|
+
SELECT DISTINCT on (t.typname) t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
|
|
16
|
+
FROM pg_type as t
|
|
17
|
+
SQL
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if oids
|
|
21
|
+
query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
|
|
22
|
+
else
|
|
23
|
+
query += initializer.query_conditions_for_initial_load(type_map)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
|
27
|
+
initializer.run(records)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
if defined? Prometheus
|
|
2
|
+
module Prometheus
|
|
3
|
+
require "zuora_connectD/version"
|
|
4
|
+
require "zuora_api/version"
|
|
5
|
+
|
|
6
|
+
app_name = ENV['DEIS_APP'].present? ? "#{ENV['DEIS_APP']}" : "#{Rails.application.class.parent_name}"
|
|
7
|
+
# Create a default Prometheus registry for our metrics.
|
|
8
|
+
prometheus = Prometheus::Client.registry
|
|
9
|
+
|
|
10
|
+
# Create your metrics.
|
|
11
|
+
ZUORA_VERSION = Prometheus::Client::Gauge.new(:zuora_version, 'The current Zuora Gem version.')
|
|
12
|
+
CONNECT_VERSION = Prometheus::Client::Gauge.new(:gem_version, 'The current Connect Gem version.')
|
|
13
|
+
RAILS_VERSION = Prometheus::Client::Gauge.new(:rails_version, 'The current Rails version.')
|
|
14
|
+
RUBY_V = Prometheus::Client::Gauge.new(:ruby_version, 'The current Ruby version.')
|
|
15
|
+
|
|
16
|
+
# Register your metrics with the registry we previously created.
|
|
17
|
+
prometheus.register(ZUORA_VERSION);ZUORA_VERSION.set({version:ZuoraAPI::VERSION,name:app_name},0)
|
|
18
|
+
prometheus.register(CONNECT_VERSION);CONNECT_VERSION.set({version:ZuoraConnect::VERSION,name:app_name},0)
|
|
19
|
+
prometheus.register(RAILS_VERSION);RAILS_VERSION.set({version:Rails.version,name:app_name},0)
|
|
20
|
+
prometheus.register(RUBY_V);RUBY_V.set({version:RUBY_VERSION,name:app_name},0)
|
|
21
|
+
|
|
22
|
+
# Do they have resque jobs?
|
|
23
|
+
if defined? Resque.redis
|
|
24
|
+
REDIS_CONNECTION = Prometheus::Client::Gauge.new(:redis_connection, 'The status of the redis connection, 0 or 1')
|
|
25
|
+
FINISHED_JOBS = Prometheus::Client::Gauge.new(:finished_jobs, 'Done resque jobs')
|
|
26
|
+
WORKERS = Prometheus::Client::Gauge.new(:workers, 'Total resque workers')
|
|
27
|
+
ACTIVE_WORKERS = Prometheus::Client::Gauge.new(:active_workers, 'Active resque workers')
|
|
28
|
+
FAILED_JOBS = Prometheus::Client::Gauge.new(:failed_jobs, 'Failed resque jobs')
|
|
29
|
+
PENDING_JOBS = Prometheus::Client::Gauge.new(:pending_jobs, 'Pending resque jobs')
|
|
30
|
+
|
|
31
|
+
prometheus.register(REDIS_CONNECTION)
|
|
32
|
+
prometheus.register(FINISHED_JOBS)
|
|
33
|
+
prometheus.register(ACTIVE_WORKERS)
|
|
34
|
+
prometheus.register(WORKERS)
|
|
35
|
+
prometheus.register(FAILED_JOBS)
|
|
36
|
+
prometheus.register(PENDING_JOBS)
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
redis_url = ENV["REDIS_URL"].present? ? ENV["REDIS_URL"] : defined?(Rails.application.secrets.redis) ? Rails.application.secrets.redis : 'redis://localhost:6379/1'
|
|
2
|
+
if defined?(Redis.current)
|
|
3
|
+
Redis.current = Redis.new(:url => redis_url, :timeout => 10, :reconnect_attempts => 2)
|
|
4
|
+
if defined?(Resque.redis)
|
|
5
|
+
Resque.redis = Redis.current
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
if defined?(RedisBrowser)
|
|
9
|
+
RedisBrowser.configure("connections" => { "default" => { "url" => redis_url } })
|
|
10
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
if defined?(Resque::Worker)
|
|
2
|
+
Resque.send(:extend, Resque::Additions)
|
|
3
|
+
Resque::Worker.send(:include, Resque::DynamicQueues)
|
|
4
|
+
Resque::Worker.send(:include, Resque::SilenceDone) if ZuoraConnect.configuration.silencer_resque_finish == true
|
|
5
|
+
Resque::Job.send(:include, Resque::SelfLookup)
|
|
6
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class String
|
|
2
|
+
def to_bool
|
|
3
|
+
return self if (self.class == TrueClass || self.class == FalseClass)
|
|
4
|
+
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
|
5
|
+
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
|
6
|
+
return false
|
|
7
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
class TrueClass
|
|
11
|
+
def to_bool
|
|
12
|
+
return self
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
class FalseClass
|
|
16
|
+
def to_bool
|
|
17
|
+
return self
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
class NilClass
|
|
21
|
+
def to_bool
|
|
22
|
+
return false
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
if defined?(Unicorn::WorkerKiller)
|
|
2
|
+
Unicorn::WorkerKiller.module_eval do
|
|
3
|
+
self.singleton_class.send(:alias_method, :kill_self_old, :kill_self)
|
|
4
|
+
def self.kill_self(logger, start_time)
|
|
5
|
+
self.kill_self_old(logger, start_time)
|
|
6
|
+
ZuoraConnect::AppInstance.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ZuoraConnect::Engine.routes.draw do
|
|
2
|
+
get '/health' => 'static#health'
|
|
3
|
+
get '/internal/data' => 'static#metrics'
|
|
4
|
+
get '/invalid_session' => 'static#session_error', :as => :invalid_session
|
|
5
|
+
get '/invalid_instance' => "static#invalid_app_instance_error", :as => :invalid_instance
|
|
6
|
+
namespace :api do
|
|
7
|
+
namespace :v1 do
|
|
8
|
+
resources :app_instance, :only => [:index], defaults: {format: :json} do
|
|
9
|
+
match "drop", via: [:get, :post], on: :collection
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
class AddTokensToAppInstance < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
add_column :zuora_connect_app_instances, :access_token, :string unless column_exists? :zuora_connect_app_instances, :access_token
|
|
4
|
+
add_column :zuora_connect_app_instances, :refresh_token, :string unless column_exists? :zuora_connect_app_instances, :refresh_token
|
|
5
|
+
end
|
|
6
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class AddSessionsTable < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
if !ActiveRecord::Base.connection.table_exists?('sessions')
|
|
4
|
+
create_table :sessions do |t|
|
|
5
|
+
t.string :session_id, :null => false
|
|
6
|
+
t.text :data
|
|
7
|
+
t.timestamps
|
|
8
|
+
end
|
|
9
|
+
add_index :sessions, :session_id, :unique => true
|
|
10
|
+
add_index :sessions, :updated_at
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
class AddCatalogDataToAppInstance < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
add_column :zuora_connect_app_instances, :catalog_updated_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_updated_at
|
|
4
|
+
add_column :zuora_connect_app_instances, :catalog, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog
|
|
5
|
+
end
|
|
6
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module InfluxDB
|
|
2
|
+
# Convert data point to string using Line protocol
|
|
3
|
+
class PointValue
|
|
4
|
+
attr_reader :series, :values, :tags, :timestamp
|
|
5
|
+
|
|
6
|
+
def initialize(data)
|
|
7
|
+
@series = escape data[:series], :measurement
|
|
8
|
+
@values = escape_values data[:values]
|
|
9
|
+
@tags = escape_tags data[:tags]
|
|
10
|
+
@timestamp = data[:timestamp]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def dump
|
|
14
|
+
dump = @series.dup
|
|
15
|
+
dump << ",#{@tags}" if @tags
|
|
16
|
+
dump << " #{@values}"
|
|
17
|
+
dump << " #{@timestamp}" if @timestamp
|
|
18
|
+
dump
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
ESCAPES = {
|
|
24
|
+
measurement: [' '.freeze, ','.freeze],
|
|
25
|
+
tag_key: ['='.freeze, ' '.freeze, ','.freeze],
|
|
26
|
+
tag_value: ['='.freeze, ' '.freeze, ','.freeze],
|
|
27
|
+
field_key: ['='.freeze, ' '.freeze, ','.freeze, '"'.freeze],
|
|
28
|
+
field_value: ["\\".freeze, '"'.freeze],
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
private_constant :ESCAPES
|
|
32
|
+
|
|
33
|
+
def escape(str, type)
|
|
34
|
+
# rubocop:disable Layout/AlignParameters
|
|
35
|
+
str = str.encode "UTF-8".freeze, "UTF-8".freeze,
|
|
36
|
+
invalid: :replace,
|
|
37
|
+
undef: :replace,
|
|
38
|
+
replace: "".freeze
|
|
39
|
+
# rubocop:enable Layout/AlignParameters
|
|
40
|
+
|
|
41
|
+
ESCAPES[type].each do |ch|
|
|
42
|
+
str = str.gsub(ch) { "\\#{ch}" }
|
|
43
|
+
end
|
|
44
|
+
str
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def escape_values(values)
|
|
48
|
+
return if values.nil?
|
|
49
|
+
values.map do |k, v|
|
|
50
|
+
key = escape(k.to_s, :field_key)
|
|
51
|
+
val = escape_value(v)
|
|
52
|
+
"#{key}=#{val}"
|
|
53
|
+
end.join(",".freeze)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def escape_value(value)
|
|
57
|
+
if value.is_a?(String)
|
|
58
|
+
'"'.freeze + escape(value, :field_value) + '"'.freeze
|
|
59
|
+
elsif value.is_a?(Integer)
|
|
60
|
+
"#{value}i"
|
|
61
|
+
else
|
|
62
|
+
value.to_s
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def escape_tags(tags)
|
|
67
|
+
return if tags.nil?
|
|
68
|
+
|
|
69
|
+
tags = tags.map do |k, v|
|
|
70
|
+
key = escape(k.to_s, :tag_key)
|
|
71
|
+
val = escape(v.to_s, :tag_value)
|
|
72
|
+
|
|
73
|
+
"#{key}=#{val}" unless key == "".freeze || val == "".freeze
|
|
74
|
+
end.compact
|
|
75
|
+
|
|
76
|
+
tags.join(",") unless tags.empty?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/metrics/net.rb
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
# Usage:
|
|
6
|
+
#
|
|
7
|
+
# require 'http_logger'
|
|
8
|
+
#
|
|
9
|
+
# == Setup logger
|
|
10
|
+
#
|
|
11
|
+
# HttpLogger.logger = Logger.new('/tmp/all.log')
|
|
12
|
+
# HttpLogger.log_headers = true
|
|
13
|
+
#
|
|
14
|
+
# == Do request
|
|
15
|
+
#
|
|
16
|
+
# res = Net::HTTP.start(url.host, url.port) { |http|
|
|
17
|
+
# http.request(req)
|
|
18
|
+
# }
|
|
19
|
+
# ...
|
|
20
|
+
#
|
|
21
|
+
# == View the log
|
|
22
|
+
#
|
|
23
|
+
# cat /tmp/all.log
|
|
24
|
+
class HttpLogger
|
|
25
|
+
class << self
|
|
26
|
+
attr_accessor :collapse_body_limit
|
|
27
|
+
attr_accessor :log_headers
|
|
28
|
+
attr_accessor :log_request_body
|
|
29
|
+
attr_accessor :log_response_body
|
|
30
|
+
attr_accessor :logger
|
|
31
|
+
attr_accessor :colorize
|
|
32
|
+
attr_accessor :ignore
|
|
33
|
+
attr_accessor :level
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
self.log_headers = false
|
|
37
|
+
self.log_request_body = true
|
|
38
|
+
self.log_response_body = true
|
|
39
|
+
self.colorize = true
|
|
40
|
+
self.collapse_body_limit = 5000
|
|
41
|
+
self.ignore = []
|
|
42
|
+
self.level = :debug
|
|
43
|
+
|
|
44
|
+
def self.perform(*args, &block)
|
|
45
|
+
instance.perform(*args, &block)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.instance
|
|
49
|
+
@instance ||= HttpLogger.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.deprecate_config(option)
|
|
53
|
+
warn "Net::HTTP.#{option} is deprecated. Use HttpLogger.#{option} instead."
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def perform(http, request, request_body)
|
|
57
|
+
start_time = Time.now
|
|
58
|
+
tags = {}
|
|
59
|
+
response = yield
|
|
60
|
+
rescue => ex
|
|
61
|
+
tags = tags.merge({error_type: ex.class})
|
|
62
|
+
raise
|
|
63
|
+
ensure
|
|
64
|
+
values = {response_time: ((Time.now - start_time)*1000).round(2)}
|
|
65
|
+
if require_logging?(http, request)
|
|
66
|
+
tags = tags.merge({endpoint: http.address, method: request.method})
|
|
67
|
+
log_request_url(http, request, start_time)
|
|
68
|
+
log_request_body(request)
|
|
69
|
+
log_request_headers(request)
|
|
70
|
+
if defined?(response) && response
|
|
71
|
+
tags = tags.merge({status: response.code.to_i})
|
|
72
|
+
log_response_code(response)
|
|
73
|
+
log_response_headers(response)
|
|
74
|
+
log_response_body(response.body)
|
|
75
|
+
end
|
|
76
|
+
ZuoraConnect::AppInstance.write_to_telegraf(direction: :outbound, tags: tags, values: values)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
protected
|
|
81
|
+
|
|
82
|
+
def log_request_url(http, request, start_time)
|
|
83
|
+
ofset = Time.now - start_time
|
|
84
|
+
log("HTTP #{request.method} (%0.2fms)" % (ofset * 1000), request_url(http, request))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def request_url(http, request)
|
|
88
|
+
URI.decode("http#{"s" if http.use_ssl?}://#{http.address}:#{http.port}#{request.path}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def log_request_headers(request)
|
|
92
|
+
if self.class.log_headers
|
|
93
|
+
request.each_capitalized { |k,v| log("HTTP request header", "#{k}: #{v}") }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
HTTP_METHODS_WITH_BODY = Set.new(%w(POST PUT GET PATCH))
|
|
98
|
+
|
|
99
|
+
def log_request_body(request)
|
|
100
|
+
if self.class.log_request_body
|
|
101
|
+
if HTTP_METHODS_WITH_BODY.include?(request.method)
|
|
102
|
+
if (body = request.body) && !body.empty?
|
|
103
|
+
log("Request body", truncate_body(body))
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def log_response_code(response)
|
|
110
|
+
log("Response status", "#{response.class} (#{response.code})")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def log_response_headers(response)
|
|
114
|
+
if self.class.log_headers
|
|
115
|
+
response.each_capitalized { |k,v| log("HTTP response header", "#{k}: #{v}") }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def log_response_body(body)
|
|
120
|
+
if self.class.log_response_body
|
|
121
|
+
if body.is_a?(Net::ReadAdapter)
|
|
122
|
+
log("Response body", "<impossible to log>")
|
|
123
|
+
else
|
|
124
|
+
if body && !body.empty?
|
|
125
|
+
log("Response body", truncate_body(body))
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def require_logging?(http, request)
|
|
132
|
+
self.logger && !ignored?(http, request) && (http.started? || fakeweb?(http, request))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def ignored?(http, request)
|
|
136
|
+
url = request_url(http, request)
|
|
137
|
+
self.class.ignore.any? do |pattern|
|
|
138
|
+
url =~ pattern
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def fakeweb?(http, request)
|
|
143
|
+
return false unless defined?(::FakeWeb)
|
|
144
|
+
uri = ::FakeWeb::Utility.request_uri_as_string(http, request)
|
|
145
|
+
method = request.method.downcase.to_sym
|
|
146
|
+
::FakeWeb.registered_uri?(method, uri)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def truncate_body(body)
|
|
150
|
+
if collapse_body_limit && collapse_body_limit > 0 && body && body.size >= collapse_body_limit
|
|
151
|
+
body_piece_size = collapse_body_limit / 2
|
|
152
|
+
body[0..body_piece_size] +
|
|
153
|
+
"\n\n<some data truncated>\n\n" +
|
|
154
|
+
body[(body.size - body_piece_size)..body.size]
|
|
155
|
+
else
|
|
156
|
+
body
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def log(message, dump)
|
|
161
|
+
self.logger.send(self.class.level, format_log_entry(message, dump)) if Rails.env.to_sym == :development
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def format_log_entry(message, dump = nil)
|
|
165
|
+
if self.class.colorize
|
|
166
|
+
message_color, dump_color = "4;32;1", "0;1"
|
|
167
|
+
log_entry = " \e[#{message_color}m#{message}\e[0m "
|
|
168
|
+
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
|
|
169
|
+
log_entry
|
|
170
|
+
else
|
|
171
|
+
"%s %s" % [message, dump]
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def logger
|
|
176
|
+
self.class.logger
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def collapse_body_limit
|
|
180
|
+
self.class.collapse_body_limit
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
class Net::HTTP
|
|
185
|
+
|
|
186
|
+
def self.log_headers=(value)
|
|
187
|
+
HttpLogger.deprecate_config("log_headers")
|
|
188
|
+
HttpLogger.log_headers = value
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def self.colorize=(value)
|
|
192
|
+
HttpLogger.deprecate_config("colorize")
|
|
193
|
+
HttpLogger.colorize = value
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def self.logger=(value)
|
|
197
|
+
HttpLogger.deprecate_config("logger")
|
|
198
|
+
HttpLogger.logger = value
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
alias_method :request_without_logging, :request
|
|
203
|
+
|
|
204
|
+
def request(request, body = nil, &block)
|
|
205
|
+
HttpLogger.perform(self, request, body) do
|
|
206
|
+
request_without_logging(request, body, &block)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
if defined?(Rails)
|
|
212
|
+
if defined?(ActiveSupport) && ActiveSupport.respond_to?(:on_load)
|
|
213
|
+
# Rails3
|
|
214
|
+
ActiveSupport.on_load(:after_initialize) do
|
|
215
|
+
HttpLogger.logger = Rails.logger unless HttpLogger.logger
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|