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.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +38 -0
  4. data/app/assets/javascripts/zuora_connect/api/v1/app_instance.js +2 -0
  5. data/app/assets/javascripts/zuora_connect/application.js +13 -0
  6. data/app/assets/stylesheets/zuora_connect/api/v1/app_instance.css +4 -0
  7. data/app/assets/stylesheets/zuora_connect/application.css +15 -0
  8. data/app/controllers/zuora_connect/admin/tenant_controller.rb +11 -0
  9. data/app/controllers/zuora_connect/api/v1/app_instance_controller.rb +45 -0
  10. data/app/controllers/zuora_connect/application_controller.rb +8 -0
  11. data/app/controllers/zuora_connect/static_controller.rb +32 -0
  12. data/app/helpers/zuora_connect/api/v1/app_instance_helper.rb +4 -0
  13. data/app/helpers/zuora_connect/application_helper.rb +5 -0
  14. data/app/models/zuora_connect/app_instance.rb +5 -0
  15. data/app/models/zuora_connect/app_instance_base.rb +811 -0
  16. data/app/models/zuora_connect/login.rb +36 -0
  17. data/app/models/zuora_connect/telegraf.rb +88 -0
  18. data/app/views/layouts/zuora_connect/application.html.erb +14 -0
  19. data/app/views/sql/refresh_aggregate_table.txt +84 -0
  20. data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +65 -0
  21. data/app/views/zuora_connect/static/session_error.html.erb +63 -0
  22. data/config/initializers/apartment.rb +95 -0
  23. data/config/initializers/object_method_hooks.rb +27 -0
  24. data/config/initializers/postgresql_adapter.rb +32 -0
  25. data/config/initializers/prometheus.rb +41 -0
  26. data/config/initializers/redis.rb +10 -0
  27. data/config/initializers/resque.rb +6 -0
  28. data/config/initializers/to_bool.rb +24 -0
  29. data/config/initializers/unicorn.rb +9 -0
  30. data/config/routes.rb +13 -0
  31. data/db/migrate/20100718151733_create_connect_app_instances.rb +9 -0
  32. data/db/migrate/20101024162319_add_tokens_to_app_instance.rb +6 -0
  33. data/db/migrate/20101024220705_add_token_to_app_instance.rb +5 -0
  34. data/db/migrate/20110131211919_add_sessions_table.rb +13 -0
  35. data/db/migrate/20110411200303_add_expiration_to_app_instance.rb +5 -0
  36. data/db/migrate/20110413191512_add_new_api_token.rb +5 -0
  37. data/db/migrate/20110503003602_add_catalog_data_to_app_instance.rb +6 -0
  38. data/db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb +5 -0
  39. data/db/migrate/20110503003604_catalog_default.rb +5 -0
  40. data/db/migrate/20180301052853_add_catalog_attempted_at.rb +5 -0
  41. data/lib/metrics/influx/point_value.rb +79 -0
  42. data/lib/metrics/net.rb +218 -0
  43. data/lib/middleware/metrics_middleware.rb +110 -0
  44. data/lib/resque/additions.rb +53 -0
  45. data/lib/resque/dynamic_queues.rb +142 -0
  46. data/lib/resque/self_lookup.rb +19 -0
  47. data/lib/resque/silence_done.rb +71 -0
  48. data/lib/tasks/zuora_connect_tasks.rake +24 -0
  49. data/lib/zuora_connectD.rb +41 -0
  50. data/lib/zuora_connectD/configuration.rb +52 -0
  51. data/lib/zuora_connectD/controllers/helpers.rb +165 -0
  52. data/lib/zuora_connectD/engine.rb +30 -0
  53. data/lib/zuora_connectD/exceptions.rb +67 -0
  54. data/lib/zuora_connectD/railtie.rb +59 -0
  55. data/lib/zuora_connectD/version.rb +3 -0
  56. data/lib/zuora_connectD/views/helpers.rb +9 -0
  57. data/test/controllers/zuora_connect/api/v1/app_instance_controller_test.rb +13 -0
  58. data/test/dummy/README.rdoc +28 -0
  59. data/test/dummy/Rakefile +6 -0
  60. data/test/dummy/app/assets/javascripts/application.js +13 -0
  61. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  62. data/test/dummy/app/controllers/application_controller.rb +5 -0
  63. data/test/dummy/app/helpers/application_helper.rb +2 -0
  64. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  65. data/test/dummy/bin/bundle +3 -0
  66. data/test/dummy/bin/rails +4 -0
  67. data/test/dummy/bin/rake +4 -0
  68. data/test/dummy/bin/setup +29 -0
  69. data/test/dummy/config.ru +4 -0
  70. data/test/dummy/config/application.rb +26 -0
  71. data/test/dummy/config/boot.rb +5 -0
  72. data/test/dummy/config/database.yml +25 -0
  73. data/test/dummy/config/environment.rb +5 -0
  74. data/test/dummy/config/environments/development.rb +41 -0
  75. data/test/dummy/config/environments/production.rb +79 -0
  76. data/test/dummy/config/environments/test.rb +42 -0
  77. data/test/dummy/config/initializers/assets.rb +11 -0
  78. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  80. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  81. data/test/dummy/config/initializers/inflections.rb +16 -0
  82. data/test/dummy/config/initializers/mime_types.rb +4 -0
  83. data/test/dummy/config/initializers/session_store.rb +3 -0
  84. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  85. data/test/dummy/config/locales/en.yml +23 -0
  86. data/test/dummy/config/routes.rb +4 -0
  87. data/test/dummy/config/secrets.yml +22 -0
  88. data/test/dummy/db/development.sqlite3 +0 -0
  89. data/test/dummy/db/test.sqlite3 +0 -0
  90. data/test/dummy/log/development.log +2 -0
  91. data/test/dummy/log/test.log +0 -0
  92. data/test/dummy/public/404.html +67 -0
  93. data/test/dummy/public/422.html +67 -0
  94. data/test/dummy/public/500.html +66 -0
  95. data/test/dummy/public/favicon.ico +0 -0
  96. data/test/fixtures/zuora_connect/app_instances.yml +11 -0
  97. data/test/integration/navigation_test.rb +8 -0
  98. data/test/lib/generators/zuora_connect/datatable_generator_test.rb +16 -0
  99. data/test/models/zuora_connect/app_instance_test.rb +9 -0
  100. data/test/test_helper.rb +21 -0
  101. data/test/zuora_connect_test.rb +7 -0
  102. 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,9 @@
1
+ class CreateConnectAppInstances < ActiveRecord::Migration
2
+ def change
3
+ if !ActiveRecord::Base.connection.table_exists?('zuora_connect_app_instances')
4
+ create_table :zuora_connect_app_instances do |t|
5
+ t.timestamps null: false
6
+ end
7
+ end
8
+ end
9
+ 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,5 @@
1
+ class AddTokenToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :token, :string unless column_exists? :zuora_connect_app_instances, :token
4
+ end
5
+ 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,5 @@
1
+ class AddExpirationToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :oauth_expires_at, :datetime unless column_exists? :zuora_connect_app_instances, :oauth_expires_at
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNewApiToken < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :api_token, :string unless column_exists? :zuora_connect_app_instances, :api_token
4
+ end
5
+ 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,5 @@
1
+ class AddCatalogMappingsToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :catalog_mapping, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog_mapping
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class CatalogDefault < ActiveRecord::Migration
2
+ def change
3
+ change_column :zuora_connect_app_instances, :catalog, :jsonb, default: {}
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddCatalogAttemptedAt < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :catalog_update_attempt_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_update_attempt_at
4
+ end
5
+ 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
@@ -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