rails_api_logger 0.6.3 → 0.7.0
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 +4 -4
- data/.ruby-version +1 -1
- data/.semaphore/semaphore.yml +1 -0
- data/CHANGELOG.md +5 -0
- data/README.md +41 -8
- data/lib/rails_api_logger/inbound_requests_logger.rb +1 -0
- data/lib/rails_api_logger/inbound_requests_logger_middleware.rb +16 -6
- data/lib/rails_api_logger/request_log.rb +4 -3
- data/rails_api_logger.gemspec +3 -2
- metadata +22 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b99069d517d5cd82e5e073121ebb94306335c052644115cc56765a0a3c166447
|
4
|
+
data.tar.gz: bfac0a6e391ff5c1e29e481e313c47419a6b6f4835871e9f12624638b38d497e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b97315feb5e4792465a85819c829d33733a854fe77a9af907935058eb468c44829f524a29fb6c969cef6efe342903bcd6384989720bd54180f274fbde2bb0c7
|
7
|
+
data.tar.gz: 7139532155a71e2f9d068438164425acebb9f5bb6825f6fbdac0a5f0d0b0f58204dd824b7dcfd474776133b2c4e616a6b7834bd40a94f6500d845c885d45f326
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
3.2.1
|
data/.semaphore/semaphore.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 0.7.0
|
2
|
+
* Fix an issue in the middleware where the request body was not read correctly if there were encoding issues.
|
3
|
+
* Improved documentation about outboud request logging.
|
4
|
+
* Add option skip_body_regexp to skip logging the body of requests matching a regexp.
|
5
|
+
|
1
6
|
# 0.6.3
|
2
7
|
* Fix the CHANGELOG path in gemspec.
|
3
8
|
|
data/README.md
CHANGED
@@ -71,34 +71,67 @@ log.save!
|
|
71
71
|
You can also use the provided logger class to do that in a simpler and safer manner:
|
72
72
|
|
73
73
|
```ruby
|
74
|
-
uri = URI('
|
75
|
-
|
76
|
-
request =
|
77
|
-
|
74
|
+
uri = URI('https://example.com/some_path')
|
75
|
+
request = Net::HTTP::Post.new(uri)
|
76
|
+
request.body = { answer: 42 }.to_json
|
77
|
+
request.content_type = 'application/json'
|
78
|
+
|
79
|
+
response = RailsApiLogger.new.call(nil, request) do
|
80
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
|
81
|
+
end
|
78
82
|
```
|
79
83
|
|
80
84
|
This will guarantee that the log is always persisted, even in case of errors.
|
81
85
|
|
86
|
+
### Database Transactions Caveats
|
87
|
+
|
88
|
+
If you log your outbound requests inside of parent app transactions, your logs will not be persisted if
|
89
|
+
the transaction is rolled-back. You can circumvent that by opening another database connection
|
90
|
+
to the same (or another database if you're into that stuff) when logging.
|
91
|
+
|
92
|
+
```
|
93
|
+
# config/initializers/outbound_request_log_patch.rb
|
94
|
+
|
95
|
+
module OutboundRequestLogTransactionPatch
|
96
|
+
extend ActiveSupport::Concern
|
97
|
+
|
98
|
+
included do
|
99
|
+
connects_to database: { writing: :primary, reading: :primary }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
OutboundRequestLog.include(OutboundRequestLogTransactionPatch)
|
104
|
+
```
|
105
|
+
|
106
|
+
another way to do the same is to start a new thread to log the request.
|
107
|
+
See the [linked test for an example](https://github.com/renuo/rails_api_logger/blob/main/spec/outbound_request_log_spec.rb:15)
|
108
|
+
|
82
109
|
## Log Inbound Requests
|
83
110
|
|
84
111
|
If you are exposing some API you might be interested in logging the requests you receive.
|
85
112
|
You can do so by adding this middleware in `config/application.rb`
|
86
113
|
|
87
114
|
```ruby
|
88
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
115
|
+
config.middleware.insert_before Rails::Rack::Logger, InboundRequestsLoggerMiddleware
|
89
116
|
```
|
90
117
|
|
91
118
|
this will by default only log requests that have an impact in your system (POST, PUT, and PATCH calls).
|
92
119
|
If you want to log all requests (also GET ones) use
|
93
120
|
|
94
121
|
```ruby
|
95
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
122
|
+
config.middleware.insert_before Rails::Rack::Logger, InboundRequestsLoggerMiddleware, only_state_change: false
|
96
123
|
```
|
97
124
|
|
98
125
|
If you want to log only requests on a certain path, you can pass a regular expression:
|
99
126
|
|
100
127
|
```ruby
|
101
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
128
|
+
config.middleware.insert_before Rails::Rack::Logger, InboundRequestsLoggerMiddleware, path_regexp: /api/
|
129
|
+
```
|
130
|
+
|
131
|
+
If you want to skip logging the body of certain requests, you can pass a regular expression:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
config.middleware.insert_before Rails::Rack::Logger, InboundRequestsLoggerMiddleware, skip_body_regexp: /api/letters/
|
102
135
|
```
|
103
136
|
|
104
137
|
|
@@ -106,7 +139,6 @@ In the implementation of your API, you can call any time `attach_inbound_request
|
|
106
139
|
to attach an already persisted model to the log record.
|
107
140
|
|
108
141
|
|
109
|
-
|
110
142
|
For example:
|
111
143
|
```ruby
|
112
144
|
|
@@ -170,6 +202,7 @@ This configuration will give you some nice views, and searches to work with the
|
|
170
202
|
end
|
171
203
|
```
|
172
204
|
|
205
|
+
|
173
206
|
## Development
|
174
207
|
|
175
208
|
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,10 +1,11 @@
|
|
1
1
|
class InboundRequestsLoggerMiddleware
|
2
|
-
attr_accessor :only_state_change, :path_regexp
|
2
|
+
attr_accessor :only_state_change, :path_regexp, :skip_body_regexp
|
3
3
|
|
4
|
-
def initialize(app, only_state_change: true, path_regexp:
|
4
|
+
def initialize(app, only_state_change: true, path_regexp: /.*/, skip_body_regexp: nil)
|
5
5
|
@app = app
|
6
6
|
self.only_state_change = only_state_change
|
7
7
|
self.path_regexp = path_regexp
|
8
|
+
self.skip_body_regexp = skip_body_regexp
|
8
9
|
end
|
9
10
|
|
10
11
|
def call(env)
|
@@ -16,15 +17,24 @@ class InboundRequestsLoggerMiddleware
|
|
16
17
|
end
|
17
18
|
status, headers, body = @app.call(env)
|
18
19
|
if logging
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
updates = {response_code: status, ended_at: Time.current}
|
21
|
+
updates[:response_body] = parsed_body(body) if log_response_body?(env)
|
22
|
+
# this usually works. let's be optimistic.
|
23
|
+
begin
|
24
|
+
env["INBOUND_REQUEST_LOG"].update_columns(updates)
|
25
|
+
rescue JSON::GeneratorError => _e # this can be raised by activerecord if the string is not UTF-8.
|
26
|
+
env["INBOUND_REQUEST_LOG"].update_columns(updates.except(:response_body))
|
27
|
+
end
|
22
28
|
end
|
23
29
|
[status, headers, body]
|
24
30
|
end
|
25
31
|
|
26
32
|
private
|
27
33
|
|
34
|
+
def log_response_body?(env)
|
35
|
+
skip_body_regexp.nil? || env["PATH_INFO"] !~ skip_body_regexp
|
36
|
+
end
|
37
|
+
|
28
38
|
def log?(env, request)
|
29
39
|
env["PATH_INFO"] =~ path_regexp && (!only_state_change || request_with_state_change?(request))
|
30
40
|
end
|
@@ -39,7 +49,7 @@ class InboundRequestsLoggerMiddleware
|
|
39
49
|
else
|
40
50
|
body
|
41
51
|
end
|
42
|
-
rescue JSON::ParserError
|
52
|
+
rescue JSON::ParserError, ArgumentError
|
43
53
|
body
|
44
54
|
end
|
45
55
|
|
@@ -6,14 +6,14 @@ class RequestLog < ActiveRecord::Base
|
|
6
6
|
|
7
7
|
belongs_to :loggable, optional: true, polymorphic: true
|
8
8
|
|
9
|
-
scope :failed, -> { where.not(response_code:
|
9
|
+
scope :failed, -> { where(response_code: 400..599).or(where.not(ended_at: nil).where(response_code: nil)) }
|
10
10
|
|
11
11
|
validates :method, presence: true
|
12
12
|
validates :path, presence: true
|
13
13
|
|
14
14
|
def self.from_request(request, loggable: nil)
|
15
15
|
request_body = (request.body.respond_to?(:read) ? request.body.read : request.body)
|
16
|
-
body = request_body
|
16
|
+
body = request_body&.dup&.force_encoding("UTF-8")
|
17
17
|
begin
|
18
18
|
body = JSON.parse(body) if body.present?
|
19
19
|
rescue JSON::ParserError
|
@@ -24,13 +24,14 @@ class RequestLog < ActiveRecord::Base
|
|
24
24
|
|
25
25
|
def from_response(response)
|
26
26
|
self.response_code = response.code
|
27
|
-
body = response.body
|
27
|
+
body = response.body&.dup&.force_encoding("UTF-8")
|
28
28
|
begin
|
29
29
|
body = JSON.parse(body) if body.present?
|
30
30
|
rescue JSON::ParserError
|
31
31
|
body
|
32
32
|
end
|
33
33
|
self.response_body = body
|
34
|
+
self
|
34
35
|
end
|
35
36
|
|
36
37
|
def formatted_request_body
|
data/rails_api_logger.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "rails_api_logger"
|
3
|
-
spec.version = "0.
|
3
|
+
spec.version = "0.7.0"
|
4
4
|
spec.authors = ["Alessandro Rodi"]
|
5
5
|
spec.email = ["alessandro.rodi@renuo.ch"]
|
6
6
|
|
@@ -30,7 +30,8 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency "zeitwerk", ">= 2.0.0"
|
31
31
|
|
32
32
|
spec.add_development_dependency "sqlite3", "~> 1.4.0"
|
33
|
-
spec.add_development_dependency "
|
33
|
+
spec.add_development_dependency "pg", "~> 1.5.4"
|
34
|
+
spec.add_development_dependency "standard", "~> 1.31"
|
34
35
|
spec.add_development_dependency "rake", "~> 12.0"
|
35
36
|
spec.add_development_dependency "rspec", "~> 3.0"
|
36
37
|
spec.add_development_dependency "rack"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_api_logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Rodi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -94,20 +94,34 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 1.4.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pg
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.5.4
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.5.4
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: standard
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
117
|
+
version: '1.31'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
124
|
+
version: '1.31'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rake
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,7 +200,7 @@ metadata:
|
|
186
200
|
homepage_uri: https://github.com/renuo/rails_api_logger
|
187
201
|
source_code_uri: https://github.com/renuo/rails_api_logger
|
188
202
|
changelog_uri: https://github.com/renuo/rails_api_logger/blob/main/CHANGELOG.md
|
189
|
-
post_install_message:
|
203
|
+
post_install_message:
|
190
204
|
rdoc_options: []
|
191
205
|
require_paths:
|
192
206
|
- lib
|
@@ -201,8 +215,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
215
|
- !ruby/object:Gem::Version
|
202
216
|
version: '0'
|
203
217
|
requirements: []
|
204
|
-
rubygems_version: 3.
|
205
|
-
signing_key:
|
218
|
+
rubygems_version: 3.4.21
|
219
|
+
signing_key:
|
206
220
|
specification_version: 4
|
207
221
|
summary: "Log API requests like a king \U0001F451"
|
208
222
|
test_files: []
|