zuora_connectD 1.7.09
Sign up to get free protection for your applications and to get access to all the features.
- 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
|