rest-client-jogger 0.3.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ecd6f48719589c8f47c7e92403107cd44aa6d72c
4
- data.tar.gz: d64c118b0c6e7c9d895e8c5702435170636a78d9
3
+ metadata.gz: 1b29dc3193cd558f466136f495d7ea42a94d0953
4
+ data.tar.gz: 43728ec66a9b0793099dd2bbd62929be94f9f477
5
5
  SHA512:
6
- metadata.gz: dca84f7028099bfaa5e29752a823aaeda30918fe2ac9c702a8e5cd7f626e53178c57f5e2b6900c00a0d42715099a0e29c5bccf5fc342e193cac36057b24de351
7
- data.tar.gz: 985b32ef827f83d61f779e7bf08c20238c7074ede4ad10f15a75fdec44059add01c3878a8e6bccdd626577beeb29bf6916bf2c960699a7bf9a7d8a0385070a21
6
+ metadata.gz: 91ebfb31dd64d8a640cc74411d5b80034ab923b21bc5de164df4c0d75a9c3556f4dc241b8b1c115e3eb1171b9fde1226acff6cf016bdd58b9e92ec8ccc7ea357
7
+ data.tar.gz: 3058eb900be88211bd950a75bf91fec49bd22af6cf3fa815a370601fc90293f0a633191e765149e84fa4228d31e9d94955dfa658129396d98a732bf1c317a1ff
data/.travis.yml CHANGED
@@ -7,4 +7,5 @@ rvm:
7
7
  - 2.2.2
8
8
  - 2.2.3
9
9
  - 2.3.0
10
+ - 2.5.1
10
11
  before_install: gem install bundler -v 1.12.3
data/README.md CHANGED
@@ -35,6 +35,20 @@ RestClient::Jogger::EventSubscriber.new.subscribe
35
35
 
36
36
  This will log all requests made with the `logged_request` method to a logfile in `log/rest_client.log`.
37
37
 
38
+ ## Configuration
39
+
40
+ Some of the parameters used in this gem can be configured in the host application:
41
+
42
+ ```ruby
43
+ # in an initializer somewhere
44
+ RestClient::Jogger.configure do |config|
45
+ config.request_pattern = 'my.request' # optional
46
+ config.response_pattern = 'my.response' # optional
47
+ config.default_content_type = 'application/json' # optional
48
+ config.default_filter_replacement = '[SECRET]' # optional
49
+ end
50
+ ```
51
+
38
52
  ## Development
39
53
 
40
54
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,60 +1,42 @@
1
1
  module LoggedRequest
2
- PATTERN = 'rest_client.request'.freeze
3
- DEFAULT_CONTENT_TYPE = 'application/json'.freeze
4
-
5
2
  def logged_request(opts = {}, &block)
6
3
  # We intend on using the following variables in this method's
7
4
  # ensure block. This means that we must take care to ensure
8
5
  # that we check for nil against these variables whenever they
9
6
  # are accessed.
10
- response, exception = nil, nil
11
7
  started = Time.now
8
+ log_request(opts, started)
9
+ response, exception = nil, nil
12
10
  response = execute(opts, &block)
13
11
  rescue StandardError => ex
14
12
  exception = ex.class.to_s
15
- response = ex.respond_to?(:response) && ex.response
13
+ response = ex.respond_to?(:response) ? ex.response : nil
16
14
  raise ex # Re-raise the exception, we just wanted to capture it
17
15
  ensure
18
- time = (Time.now - started).round(2)
19
- content_type = content_type_from_headers(opts[:headers])
20
- payload = filter(content_type).new(data: opts[:payload]).filter
21
- opts[:headers].reject! { |k, _| k.to_s.casecmp('authorization').zero? } if opts[:headers]
22
- params = opts.except(:user, :password, :payload).merge(payload: payload)
23
- ActiveSupport::Notifications.instrument PATTERN,
24
- log_data(params, response, exception, time)
16
+ logged_response = opts.merge(exception: exception, response: response)
17
+ ActiveSupport::Notifications.instrument(
18
+ RestClient::Jogger.response_pattern,
19
+ log_payload(logged_response, started)
20
+ )
25
21
  end
26
22
 
27
23
  private
28
24
 
29
- def log_data(params, response, exception, time)
30
- request_data(params).merge(
31
- response: response_data(response),
32
- exception: exception,
33
- time_elapsed: time
25
+ def log_payload(params, started)
26
+ params.merge(
27
+ headers: filtered_headers(params),
28
+ start_time: started
34
29
  )
35
30
  end
36
31
 
37
- def response_data(response = nil)
38
- if response
39
- {
40
- code: response.code,
41
- headers: response.headers.reject { |k, _| k.to_s.casecmp('authorization').zero? },
42
- body: response.body.to_s.force_encoding('UTF-8')
43
- }
44
- end
32
+ def filtered_headers(opts)
33
+ opts.fetch(:headers, {}).reject { |k, _| k.to_s.casecmp('authorization').zero? }
45
34
  end
46
35
 
47
- def request_data(params)
48
- {
49
- request: params
50
- }
51
- end
52
-
53
- def filter(content_type)
54
- RestClient::Jogger::Filters::Base.filter_class(content_type)
55
- end
56
-
57
- def content_type_from_headers(headers)
58
- (headers && headers[:content_type]) || DEFAULT_CONTENT_TYPE
36
+ def log_request(opts, started)
37
+ ActiveSupport::Notifications.instrument(
38
+ RestClient::Jogger.request_pattern,
39
+ log_payload(opts, started)
40
+ )
59
41
  end
60
42
  end
@@ -0,0 +1,59 @@
1
+ module RestClient
2
+ module Jogger
3
+ class Action
4
+ include ActiveModel::Model
5
+ attr_accessor :logger, :notifier
6
+
7
+ def initialize(args = {})
8
+ self.logger = args.fetch :logger
9
+ super
10
+ end
11
+
12
+ def notifier
13
+ @notifier ||= ::Rollbar
14
+ end
15
+
16
+ def call(name, start, finish, id, payload)
17
+ start_time = payload.fetch(:start_time)
18
+ render_params = {
19
+ args: payload,
20
+ payload: filter(payload),
21
+ verify_ssl: payload[:verify_ssl],
22
+ read_timeout: payload.fetch(:timeout) { payload[:read_timeout] },
23
+ open_timeout: payload.fetch(:timeout) { payload[:open_timeout] },
24
+ event_id: id,
25
+ timestamp: start,
26
+ time_elapsed: (finish - start_time).round(10),
27
+ ip_address: ip_address
28
+ }
29
+ json = template.render nil, render_params
30
+ name =~ /error/ ? logger.error(json) : logger.debug(json)
31
+ rescue StandardError => e
32
+ notifier.error e, payload: payload
33
+ end
34
+
35
+ def template
36
+ raise NotImplementedError, 'define a #template method in a subclass'
37
+ end
38
+
39
+ private
40
+
41
+ def filter(opts = {})
42
+ filter_class(opts[:headers] || {}).new(data: opts[:payload].to_s).filter
43
+ end
44
+
45
+ def filter_class(headers = {})
46
+ content_type = headers.fetch(:content_type) { 'application/json' }
47
+ RestClient::Jogger::Filters::Base.filter_class(content_type)
48
+ end
49
+
50
+ def root
51
+ Pathname.new(ROOT_PATH).freeze
52
+ end
53
+
54
+ def ip_address
55
+ Socket.ip_address_list.select(&:ipv4_private?).first.try(:ip_address)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ module RestClient
2
+ module Jogger
3
+ class Configuration
4
+ include ActiveModel::Model
5
+
6
+ REQUIRED_ATTRIBUTES = %i().freeze
7
+ OPTIONAL_ATTRIBUTES = %i(
8
+ request_pattern
9
+ response_pattern
10
+ default_content_type
11
+ default_filter_replacement
12
+ ).freeze
13
+ ATTRIBUTES = (REQUIRED_ATTRIBUTES | OPTIONAL_ATTRIBUTES).freeze
14
+
15
+ attr_accessor *ATTRIBUTES
16
+
17
+ def request_pattern
18
+ @request_pattern || 'rest_client.request'
19
+ end
20
+
21
+ def response_pattern
22
+ @response_pattern || 'rest_client.response'
23
+ end
24
+
25
+ def default_content_type
26
+ @default_content_type || 'application/json'
27
+ end
28
+
29
+ def default_filter_replacement
30
+ @default_filter_replacement || '[FILTERED]'
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,14 +7,18 @@ module RestClient
7
7
  @logger ||= ActiveSupport::Logger.new('log/rest_client.log').tap { |l| l.level = Logger::DEBUG }
8
8
  end
9
9
 
10
- def pattern
11
- LoggedRequest::PATTERN
10
+ def request_pattern
11
+ RestClient::Jogger.request_pattern
12
12
  end
13
13
 
14
- def subscribe
15
- ActiveSupport::Notifications.subscribe pattern, RequestComplete.new(logger: logger)
14
+ def response_pattern
15
+ RestClient::Jogger.response_pattern
16
16
  end
17
17
 
18
+ def subscribe
19
+ ActiveSupport::Notifications.subscribe request_pattern, Request.new(logger: logger)
20
+ ActiveSupport::Notifications.subscribe response_pattern, Response.new(logger: logger)
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -2,8 +2,6 @@ module RestClient
2
2
  module Jogger
3
3
  module Filters
4
4
  class Base
5
- DEFAULT_REPLACEMENT = '[FILTERED]'.freeze
6
-
7
5
  include ActiveModel::Model
8
6
 
9
7
  attr_accessor :data, :content_type, :filters, :filter_replacement
@@ -17,6 +15,11 @@ module RestClient
17
15
  end
18
16
  end
19
17
 
18
+ def initialize(opts = {})
19
+ super
20
+ self.data = data.dup
21
+ end
22
+
20
23
  def filter
21
24
  filters.each do |filter|
22
25
  filter_data filter
@@ -29,7 +32,7 @@ module RestClient
29
32
  end
30
33
 
31
34
  def filter_replacement
32
- @filter_replacement ||= DEFAULT_REPLACEMENT
35
+ @filter_replacement ||= RestClient::Jogger.default_filter_replacement
33
36
  end
34
37
 
35
38
  def filters
@@ -37,7 +40,7 @@ module RestClient
37
40
  end
38
41
 
39
42
  def content_type
40
- @content_type ||= 'application/json'
43
+ @content_type ||= RestClient::Jogger.default_content_type
41
44
  end
42
45
 
43
46
  private
@@ -0,0 +1,9 @@
1
+ module RestClient
2
+ module Jogger
3
+ class Request < Action
4
+ def template
5
+ Tilt::JbuilderTemplate.new root.join('templates', 'request_logging_template.json.jbuilder')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module RestClient
2
+ module Jogger
3
+ class Response < Action
4
+ def template
5
+ Tilt::JbuilderTemplate.new root.join('templates', 'response_logging_template.json.jbuilder')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  module RestClient
2
2
  module Jogger
3
- VERSION = '0.3.5'.freeze
3
+ VERSION = '1.0.0'.freeze
4
4
  end
5
5
  end
@@ -1,19 +1,42 @@
1
- require "json"
2
- require "mime/types"
3
- require "active_model"
4
- require "rollbar"
5
- require "rest_client/jogger/version"
6
- require "rest_client/jogger/event_subscriber"
7
- require "rest_client/jogger/request_complete"
8
- require "rest_client/jogger/filters/base"
9
- require "rest_client/jogger/filters/json"
10
- require "rest_client/jogger/filters/xml"
11
- require "rest_client/core_ext/logged_request"
1
+ require 'json'
2
+ require 'mime/types'
3
+ require 'active_model'
4
+ require 'active_support/all'
5
+ require 'rollbar'
6
+ require 'tilt/jbuilder'
7
+ require 'rest_client/jogger/version'
8
+ require 'rest_client/jogger/configuration'
9
+ require 'rest_client/jogger/event_subscriber'
10
+ require 'rest_client/jogger/action'
11
+ require 'rest_client/jogger/request'
12
+ require 'rest_client/jogger/response'
13
+ require 'rest_client/jogger/filters/base'
14
+ require 'rest_client/jogger/filters/json'
15
+ require 'rest_client/jogger/filters/xml'
16
+ require 'rest_client/core_ext/logged_request'
12
17
 
13
18
  module RestClient
14
19
  class Request
15
20
  extend LoggedRequest
16
21
  end
22
+
17
23
  module Jogger
24
+ ROOT_PATH = File.expand_path(File.dirname(__FILE__)).freeze
25
+
26
+ class << self
27
+ Configuration::ATTRIBUTES.each do |attribute|
28
+ delegate attribute, to: :configuration
29
+ end
30
+
31
+ attr_writer :configuration
32
+
33
+ def configuration
34
+ @configuration ||= Configuration.new
35
+ end
36
+
37
+ def configure
38
+ yield(configuration)
39
+ end
40
+ end
18
41
  end
19
42
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ json.ignore_nil!
3
+ json.url args[:url]
4
+ json.method args[:method]
5
+ json.verifySsl verify_ssl
6
+ json.requestHeaders args.fetch(:headers, {})
7
+ json.requestBody payload
8
+ json.sourceIp ip_address
9
+ json.eventName RestClient::Jogger.request_pattern
10
+ json.eventId event_id
11
+ json.timeElapsed time_elapsed
12
+ json.openTimeout open_timeout
13
+ json.readTimeout read_timeout
14
+ json.timestamp timestamp.iso8601
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ json.ignore_nil!
3
+ json.exception args[:exception]
4
+ json.url args[:url]
5
+ json.method args[:method]
6
+ json.verifySsl verify_ssl
7
+ json.requestHeaders args.fetch(:headers, {})
8
+ json.responseHeaders args[:response].try(:headers)
9
+ json.requestBody payload
10
+ json.responseBody args[:response].try(:body).to_s.force_encoding('UTF-8')
11
+ json.sourceIp ip_address
12
+ json.eventName RestClient::Jogger.response_pattern
13
+ json.eventId event_id
14
+ json.timeElapsed time_elapsed
15
+ json.openTimeout open_timeout
16
+ json.readTimeout read_timeout
17
+ json.code args[:response].try(:code)
18
+ json.timestamp timestamp.iso8601
Binary file
@@ -30,6 +30,9 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  spec.add_dependency "mime-types"
32
32
  spec.add_dependency "rollbar"
33
+ spec.add_dependency "jbuilder"
34
+ spec.add_dependency 'tilt'
35
+ spec.add_dependency 'tilt-jbuilder'
33
36
 
34
37
  spec.add_development_dependency "bundler", "~> 1.12"
35
38
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-client-jogger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Babe
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2018-04-30 00:00:00.000000000 Z
13
+ date: 2018-10-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -68,6 +68,48 @@ dependencies:
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: jbuilder
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: tilt
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ - !ruby/object:Gem::Dependency
100
+ name: tilt-jbuilder
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ type: :runtime
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
71
113
  - !ruby/object:Gem::Dependency
72
114
  name: bundler
73
115
  requirement: !ruby/object:Gem::Requirement
@@ -217,12 +259,18 @@ files:
217
259
  - bin/setup
218
260
  - lib/rest_client/core_ext/logged_request.rb
219
261
  - lib/rest_client/jogger.rb
262
+ - lib/rest_client/jogger/action.rb
263
+ - lib/rest_client/jogger/configuration.rb
220
264
  - lib/rest_client/jogger/event_subscriber.rb
221
265
  - lib/rest_client/jogger/filters/base.rb
222
266
  - lib/rest_client/jogger/filters/json.rb
223
267
  - lib/rest_client/jogger/filters/xml.rb
224
- - lib/rest_client/jogger/request_complete.rb
268
+ - lib/rest_client/jogger/request.rb
269
+ - lib/rest_client/jogger/response.rb
225
270
  - lib/rest_client/jogger/version.rb
271
+ - lib/rest_client/templates/request_logging_template.json.jbuilder
272
+ - lib/rest_client/templates/response_logging_template.json.jbuilder
273
+ - rest-client-jogger-0.3.4.gem
226
274
  - rest-client-jogger.gemspec
227
275
  homepage: https://github.com/amaabca/rest-client-jogger
228
276
  licenses:
@@ -244,7 +292,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
244
292
  version: '0'
245
293
  requirements: []
246
294
  rubyforge_project:
247
- rubygems_version: 2.5.1
295
+ rubygems_version: 2.5.2.3
248
296
  signing_key:
249
297
  specification_version: 4
250
298
  summary: Logs RestClient requests in a JSON format
@@ -1,25 +0,0 @@
1
- module RestClient
2
- module Jogger
3
- class RequestComplete
4
- include ::ActiveModel::Model
5
- attr_accessor :logger, :notifier
6
-
7
- def initialize(args = {})
8
- self.logger = args.fetch :logger
9
- super
10
- end
11
-
12
- def notifier
13
- @notifier ||= ::Rollbar
14
- end
15
-
16
- def call(name, start, finish, id, payload)
17
- message = ::JSON.dump(payload.merge(event_name: name, event_id: id, timestamp: start))
18
- name =~ /error/ ? logger.error(message) : logger.debug(message)
19
- rescue StandardError => e
20
- notifier.error e, payload: payload
21
- end
22
-
23
- end
24
- end
25
- end