api_valve 0.0.1.beta.1 → 0.0.1.beta.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0db44e3a1e246e94e9c31ad856fef01d7b76626cfe665bd18dfa769223c385bc
4
- data.tar.gz: 7a05b9b44d9606bb831da1709bacc50135115311d4517f87bdad59e17ea3340d
3
+ metadata.gz: 88db069feae42e9dc2fe3397891acfc31567a36b057a78c57d0a8ed2be567be7
4
+ data.tar.gz: 29aba6e067ae80f88effcde5d03d048eff6137c34b11376ae0dfba9a0b47669b
5
5
  SHA512:
6
- metadata.gz: d86f709762d7cd80fe4d1d01184310ae422e38dac84c9244a968ce52cae0ede75365975d8bd86b3fc9bdc5e9dd16d34ac1e94bf3f6129d97d662cabb13ac72d8
7
- data.tar.gz: a733954d49421ad1735f12c27b3361026c8a3f4d5378837090d5373dcfb75e8409adca6566b6d437cfb64d0512a8531b8de551a14cd65ed1c60771df4514e039
6
+ metadata.gz: 9c7d05c3e3788a426844ea4628c2fc8fa83def60bfba39e85f0138407c820ba81b942e947e3576e85d1fb27c62206698b6b60b517fdb08478cbeb202f541ab6f
7
+ data.tar.gz: 3c57ae3efe82c65ff552084300bc7b0aa494789490ed132689f0c48c91a4b0920c937767dd41564ad7e782578bdb92c567ae71e4a231de296dde1756261a7f75
@@ -39,7 +39,7 @@ module ApiValve
39
39
 
40
40
  def json_meta
41
41
  (@error.try(:to_hash).presence || {}).merge(
42
- backtrace: ApiValve.expose_backtraces ? json_backtrace : nil
42
+ backtrace: ApiValve.expose_backtraces ? @error.backtrace : nil
43
43
  ).compact.presence
44
44
  end
45
45
  end
@@ -18,6 +18,7 @@ module ApiValve
18
18
  X-Forwarded-Host
19
19
  X-Forwarded-Port
20
20
  X-Forwarded-Proto
21
+ X-Real-IP
21
22
  ).freeze
22
23
  NOT_PREFIXED_HEADERS = %w(
23
24
  Content-Length
@@ -0,0 +1,21 @@
1
+ require 'active_support/tagged_logging'
2
+ require 'logger'
3
+
4
+ module ApiValve
5
+ class Logger < ::Logger
6
+ include ActiveSupport::TaggedLogging
7
+
8
+ class Formatter < ActiveSupport::Logger::SimpleFormatter
9
+ include ActiveSupport::TaggedLogging::Formatter
10
+ end
11
+
12
+ def initialize(target = STDOUT)
13
+ super(target)
14
+ self.formatter = Formatter.new
15
+ end
16
+
17
+ # some rack apps have weird ways to write to rack.logger
18
+ alias puts error
19
+ alias write info
20
+ end
21
+ end
@@ -0,0 +1,127 @@
1
+ module ApiValve::Middleware
2
+ class Logging
3
+ include ActiveSupport::Configurable
4
+
5
+ class Log
6
+ INCOMING = %(Started %s "%s" for %s at %s).freeze
7
+ COMPLETE = %(Completed %s %s in %dms\n).freeze
8
+ URL_PARAMS = %(URL params %s).freeze
9
+ REQUEST_PAYLOAD = %(Request payload\n%s).freeze
10
+ REQUEST_HEADERS = %(Request HTTP Headers %s).freeze
11
+ RESPONSE_HEADERS = %(Response HTTP headers %s).freeze
12
+ RESPONSE_PAYLOAD = %(Response payload\n%s).freeze
13
+ NON_STANDARD_REQUEST_HEADERS = %w(CONTENT_LENGTH CONTENT_TYPE).freeze
14
+
15
+ attr_accessor :began_at, :env, :status, :response_headers, :response_payload
16
+
17
+ def initialize(options = {})
18
+ assign options
19
+ end
20
+
21
+ def assign(options = {})
22
+ options.each do |k, v|
23
+ public_send "#{k}=", v
24
+ end
25
+ end
26
+
27
+ def before_request
28
+ log_request
29
+ log_url_params
30
+ log_request_headers if Logging.log_request_headers
31
+ log_request_payload if Logging.log_request_payload
32
+ end
33
+
34
+ def after_request
35
+ log_response_headers if Logging.log_response_headers
36
+ log_response_payload if Logging.log_response_payload
37
+ log_response
38
+ end
39
+
40
+ private
41
+
42
+ delegate :logger, to: ApiValve
43
+
44
+ def log_request
45
+ logger.info INCOMING % [
46
+ env['REQUEST_METHOD'],
47
+ [env['PATH_INFO'], env['QUERY_STRING'].presence].compact.join('?'),
48
+ (env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_ADDR']),
49
+ began_at.strftime('%Y-%m-%d %H:%M:%S %z')
50
+ ]
51
+ end
52
+
53
+ def log_url_params
54
+ return unless env['QUERY_STRING'].present?
55
+ logger.info URL_PARAMS % Rack::Utils.parse_nested_query(env['QUERY_STRING']).inspect
56
+ end
57
+
58
+ def log_request_headers
59
+ headers = {}
60
+ env.each_pair do |k, v|
61
+ next unless k =~ /^HTTP_/ && v.present?
62
+ next if v.blank? || (!k.start_with?('HTTP_') && !NON_STANDARD_REQUEST_HEADERS.include?(k))
63
+ headers[k] = v
64
+ end
65
+ return if headers.empty?
66
+ logger.debug REQUEST_HEADERS % headers
67
+ end
68
+
69
+ def log_request_payload
70
+ return unless %w(PATCH POST PUT).include? env['REQUEST_METHOD']
71
+ logger.debug REQUEST_PAYLOAD % env['rack.input'].read(1000)
72
+ env['rack.input'].rewind
73
+ end
74
+
75
+ def log_response_headers
76
+ return if response_headers&.empty?
77
+ logger.debug RESPONSE_HEADERS % response_headers.inspect
78
+ end
79
+
80
+ def log_response_payload
81
+ return if response_payload&.empty?
82
+ logger.debug RESPONSE_PAYLOAD % response_payload.first(config_log_body_size)
83
+ end
84
+
85
+ def log_response
86
+ logger.info COMPLETE % [
87
+ status,
88
+ Rack::Utils::HTTP_STATUS_CODES[status],
89
+ (Time.now - began_at) * 1000
90
+ ]
91
+ end
92
+ end
93
+
94
+ config_accessor :log_request_headers do
95
+ false
96
+ end
97
+
98
+ config_accessor :log_request_payload do
99
+ false
100
+ end
101
+
102
+ config_accessor :log_response_headers do
103
+ false
104
+ end
105
+
106
+ config_accessor :log_response_payload do
107
+ false
108
+ end
109
+
110
+ def initialize(app)
111
+ @app = app
112
+ end
113
+
114
+ def call(env)
115
+ env['rack.logger'] = ApiValve.logger
116
+ env['rack.errors'] = ApiValve.logger
117
+ ApiValve.logger.tagged(Thread.current[:request_id]) do
118
+ log = Log.new(began_at: Time.now, env: env)
119
+ log.before_request
120
+ status, headers, body = @app.call(env)
121
+ log.assign status: status, response_headers: headers, response_payload: body
122
+ log.after_request
123
+ [status, headers, body]
124
+ end
125
+ end
126
+ end
127
+ end
@@ -9,8 +9,8 @@ module ApiValve
9
9
  define_callbacks :call
10
10
 
11
11
  class << self
12
- def from_yaml(file_path)
13
- from_hash YAML.load_file(file_path)
12
+ def from_yaml(string)
13
+ from_hash YAML.load(string) # rubocop:disable Security/YAMLLoad
14
14
  end
15
15
 
16
16
  def from_hash(config)
data/lib/api_valve.rb CHANGED
@@ -16,6 +16,7 @@ module ApiValve
16
16
  autoload :Error, 'api_valve/error'
17
17
  autoload :ErrorResponder, 'api_valve/error_responder'
18
18
  autoload :Forwarder, 'api_valve/forwarder'
19
+ autoload :Logger, 'api_valve/logger'
19
20
  autoload :Proxy, 'api_valve/proxy'
20
21
  autoload :Router, 'api_valve/router'
21
22
 
@@ -23,6 +24,7 @@ module ApiValve
23
24
 
24
25
  module Middleware
25
26
  autoload :ErrorHandling, 'api_valve/middleware/error_handling'
27
+ autoload :Logging, 'api_valve/middleware/logging'
26
28
  end
27
29
 
28
30
  config_accessor :logger do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_valve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta.1
4
+ version: 0.0.1.beta.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - mkon
@@ -48,16 +48,16 @@ dependencies:
48
48
  name: multi_json
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '1.13'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0'
60
+ version: '1.13'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rack
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -186,7 +186,9 @@ files:
186
186
  - lib/api_valve/forwarder/permission_handler.rb
187
187
  - lib/api_valve/forwarder/request.rb
188
188
  - lib/api_valve/forwarder/response.rb
189
+ - lib/api_valve/logger.rb
189
190
  - lib/api_valve/middleware/error_handling.rb
191
+ - lib/api_valve/middleware/logging.rb
190
192
  - lib/api_valve/proxy.rb
191
193
  - lib/api_valve/router.rb
192
194
  homepage: https://github.com/mkon/api_valve