rails_api_logger 0.9.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.semaphore/semaphore.yml +132 -2
- data/.standard.yml +2 -0
- data/Appraisals +31 -0
- data/CHANGELOG.md +62 -3
- data/README.md +90 -53
- data/Rakefile +7 -2
- data/app/middlewares/rails_api_logger/middleware.rb +80 -0
- data/app/models/rails_api_logger/inbound_request_log.rb +5 -0
- data/app/models/rails_api_logger/loggable.rb +27 -0
- data/app/models/rails_api_logger/logger.rb +22 -0
- data/app/models/rails_api_logger/outbound_request_log.rb +5 -0
- data/app/models/rails_api_logger/request_log.rb +85 -0
- data/bin/rails +16 -0
- data/gemfiles/rails_6.1.gemfile +10 -0
- data/gemfiles/rails_6.1.gemfile.lock +240 -0
- data/gemfiles/rails_7.0.gemfile +10 -0
- data/gemfiles/rails_7.0.gemfile.lock +239 -0
- data/gemfiles/rails_7.1.gemfile +9 -0
- data/gemfiles/rails_7.1.gemfile.lock +272 -0
- data/gemfiles/rails_7.2.gemfile +9 -0
- data/gemfiles/rails_7.2.gemfile.lock +272 -0
- data/gemfiles/rails_8.0.gemfile +9 -0
- data/lib/generators/rails_api_logger/install_generator.rb +1 -1
- data/lib/rails_api_logger/engine.rb +25 -0
- data/lib/rails_api_logger/version.rb +5 -0
- data/lib/rails_api_logger.rb +9 -27
- data/rails_api_logger.gemspec +10 -6
- metadata +58 -29
- data/CODE_OF_CONDUCT.md +0 -74
- data/lib/rails_api_logger/inbound_request_log.rb +0 -2
- data/lib/rails_api_logger/inbound_requests_logger_middleware.rb +0 -71
- data/lib/rails_api_logger/outbound_request_log.rb +0 -2
- data/lib/rails_api_logger/request_log.rb +0 -76
- /data/{lib/rails_api_logger → app/controllers}/inbound_requests_logger.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4959094cde8a80515bac5d15b4bd4f475e7c723b94803a2ecdc00de59aba1995
|
4
|
+
data.tar.gz: 283881fcb6952b5ffab21a816558f8c6ef9c705252d25f183a261e614317db3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d727ed904aff3668f16d2bdfdedee5576b30c53819911303f7df0723608344fbe9c30eb7e313cde7c2ca6d33e832c9ac4073baa065331f2cb9e11276975e3f8
|
7
|
+
data.tar.gz: e76f28822d9646a1973f4fb75612c52a0ed0d18d089ae27e9eccc5ac5f1313ee58e5236564b086246a17d6f158d4616a29ebc1419e25484a7a6cb73021529629
|
data/.gitignore
CHANGED
data/.semaphore/semaphore.yml
CHANGED
@@ -21,12 +21,142 @@ blocks:
|
|
21
21
|
- cache restore
|
22
22
|
- bundle config set path 'vendor/bundle'
|
23
23
|
- bundle install -j 4
|
24
|
-
|
24
|
+
|
25
25
|
- cache store
|
26
|
+
env_vars:
|
27
|
+
- name: BUNDLE_GEMFILE
|
28
|
+
value: /home/semaphore/rails_api_logger/gemfiles/rails_8.0.gemfile
|
26
29
|
jobs:
|
27
|
-
- name:
|
30
|
+
- name: linter
|
28
31
|
commands:
|
29
32
|
- bundle exec standardrb
|
33
|
+
- name: tests postgres separate db and separate target
|
34
|
+
env_vars:
|
35
|
+
- name: SAME_DB
|
36
|
+
value: "false"
|
37
|
+
- name: SAME_TARGET
|
38
|
+
value: "false"
|
39
|
+
- name: TARGET_DB
|
40
|
+
value: postgres
|
41
|
+
- name: RAILS_ENV
|
42
|
+
value: test
|
43
|
+
commands:
|
44
|
+
- sem-service start postgres 14
|
45
|
+
- bin/rails db:create db:migrate
|
46
|
+
- bundle exec rspec
|
47
|
+
- name: tests postgres separate db and same target
|
48
|
+
env_vars:
|
49
|
+
- name: SAME_DB
|
50
|
+
value: "false"
|
51
|
+
- name: SAME_TARGET
|
52
|
+
value: "true"
|
53
|
+
- name: TARGET_DB
|
54
|
+
value: postgres
|
55
|
+
- name: RAILS_ENV
|
56
|
+
value: test
|
57
|
+
commands:
|
58
|
+
- sem-service start postgres 14
|
59
|
+
- bin/rails db:create db:migrate
|
60
|
+
- bundle exec rspec
|
61
|
+
- name: tests postgres same db and separate target
|
62
|
+
env_vars:
|
63
|
+
- name: SAME_DB
|
64
|
+
value: "true"
|
65
|
+
- name: TARGET_DB
|
66
|
+
value: postgres
|
67
|
+
- name: RAILS_ENV
|
68
|
+
value: test
|
69
|
+
commands:
|
70
|
+
- sem-service start postgres 14
|
71
|
+
- bin/rails db:create db:migrate
|
72
|
+
- bundle exec rspec
|
73
|
+
- name: tests postgres separate db and separate target | rails 6.1
|
74
|
+
env_vars:
|
75
|
+
- name: SAME_DB
|
76
|
+
value: "false"
|
77
|
+
- name: SAME_TARGET
|
78
|
+
value: "false"
|
79
|
+
- name: TARGET_DB
|
80
|
+
value: postgres
|
81
|
+
- name: RAILS_ENV
|
82
|
+
value: test
|
83
|
+
- name: BUNDLE_GEMFILE
|
84
|
+
value: /home/semaphore/rails_api_logger/gemfiles/rails_6.1.gemfile
|
85
|
+
commands:
|
86
|
+
- sem-service start postgres 14
|
87
|
+
- bin/rails db:create db:migrate
|
88
|
+
- bundle exec rspec
|
89
|
+
- name: tests postgres separate db and separate target | rails 7.0
|
90
|
+
env_vars:
|
91
|
+
- name: SAME_DB
|
92
|
+
value: "false"
|
93
|
+
- name: SAME_TARGET
|
94
|
+
value: "false"
|
95
|
+
- name: TARGET_DB
|
96
|
+
value: postgres
|
97
|
+
- name: RAILS_ENV
|
98
|
+
value: test
|
99
|
+
- name: BUNDLE_GEMFILE
|
100
|
+
value: /home/semaphore/rails_api_logger/gemfiles/rails_7.0.gemfile
|
101
|
+
commands:
|
102
|
+
- sem-service start postgres 14
|
103
|
+
- bin/rails db:create db:migrate
|
104
|
+
- bundle exec rspec
|
105
|
+
- name: tests postgres separate db and separate target | rails 7.1
|
106
|
+
env_vars:
|
107
|
+
- name: SAME_DB
|
108
|
+
value: "false"
|
109
|
+
- name: SAME_TARGET
|
110
|
+
value: "false"
|
111
|
+
- name: TARGET_DB
|
112
|
+
value: postgres
|
113
|
+
- name: RAILS_ENV
|
114
|
+
value: test
|
115
|
+
- name: BUNDLE_GEMFILE
|
116
|
+
value: /home/semaphore/rails_api_logger/gemfiles/rails_7.1.gemfile
|
117
|
+
commands:
|
118
|
+
- sem-service start postgres 14
|
119
|
+
- bin/rails db:create db:migrate
|
120
|
+
- bundle exec rspec
|
121
|
+
- name: tests postgres separate db and separate target | rails 7.2
|
122
|
+
env_vars:
|
123
|
+
- name: SAME_DB
|
124
|
+
value: "false"
|
125
|
+
- name: SAME_TARGET
|
126
|
+
value: "false"
|
127
|
+
- name: TARGET_DB
|
128
|
+
value: postgres
|
129
|
+
- name: RAILS_ENV
|
130
|
+
value: test
|
131
|
+
- name: BUNDLE_GEMFILE
|
132
|
+
value: /home/semaphore/rails_api_logger/gemfiles/rails_7.2.gemfile
|
133
|
+
commands:
|
134
|
+
- sem-service start postgres 14
|
135
|
+
- bin/rails db:create db:migrate
|
136
|
+
- bundle exec rspec
|
137
|
+
- name: tests sqlite separate db and separate target
|
138
|
+
env_vars:
|
139
|
+
- name: SAME_DB
|
140
|
+
value: "false"
|
141
|
+
- name: SAME_TARGET
|
142
|
+
value: "false"
|
143
|
+
- name: TARGET_DB
|
144
|
+
value: sqlite
|
145
|
+
- name: RAILS_ENV
|
146
|
+
value: test
|
147
|
+
commands:
|
148
|
+
- bin/rails db:create db:migrate
|
149
|
+
- bundle exec rspec
|
150
|
+
- name: tests sqlite same db
|
151
|
+
env_vars:
|
152
|
+
- name: SAME_DB
|
153
|
+
value: "true"
|
154
|
+
- name: TARGET_DB
|
155
|
+
value: sqlite
|
156
|
+
- name: RAILS_ENV
|
157
|
+
value: test
|
158
|
+
commands:
|
159
|
+
- bin/rails db:create db:migrate
|
30
160
|
- bundle exec rspec
|
31
161
|
promotions:
|
32
162
|
- name: main
|
data/.standard.yml
ADDED
data/Appraisals
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
appraise "rails-6.1" do
|
2
|
+
gem "concurrent-ruby", "1.3.4"
|
3
|
+
gem "rails", "~> 6.1.0"
|
4
|
+
gem "rspec-rails", "~> 6.1.0"
|
5
|
+
gem "sqlite3", "~> 1.7.3"
|
6
|
+
end
|
7
|
+
|
8
|
+
appraise "rails-7.0" do
|
9
|
+
gem "concurrent-ruby", "1.3.4"
|
10
|
+
gem "rails", "~> 7.0.0"
|
11
|
+
gem "rspec-rails", "~> 7.1.0"
|
12
|
+
gem "sqlite3", "~> 1.7.3"
|
13
|
+
end
|
14
|
+
|
15
|
+
appraise "rails-7.1" do
|
16
|
+
gem "rails", "~> 7.1.0"
|
17
|
+
gem "rspec-rails", "~> 7.1.0"
|
18
|
+
gem "sqlite3", "~> 1.7.3"
|
19
|
+
end
|
20
|
+
|
21
|
+
appraise "rails-7.2" do
|
22
|
+
gem "rails", "~> 7.2.0"
|
23
|
+
gem "rspec-rails", "~> 7.1.0"
|
24
|
+
gem "sqlite3", "~> 1.7.3"
|
25
|
+
end
|
26
|
+
|
27
|
+
appraise "rails-8.0" do
|
28
|
+
gem "rails", "~> 8.0.0"
|
29
|
+
gem "rspec-rails", "~> 7.1.0"
|
30
|
+
gem "sqlite3", "~> 2.1.0"
|
31
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,41 +1,98 @@
|
|
1
|
+
# 0.10.1
|
2
|
+
|
3
|
+
* Fix a bug introduced in 0.8.1 where we fixed Rails 7.1 warnings. This broke the serialization in Rails < 7.1.
|
4
|
+
We now configure the serializer differently if you are running Rails 7.0 or lower.
|
5
|
+
If you used the gem version 0.8.1 or above in combination with Rails 7.0 or lower this caused the serialization of
|
6
|
+
the request and response body into YML format instead of JSON. This is now fixed and tests run on different rails
|
7
|
+
versions as well.
|
8
|
+
|
9
|
+
# 0.10.0
|
10
|
+
|
11
|
+
**BREAKING CHANGES**
|
12
|
+
|
13
|
+
This version contains many breaking changes. Consider this when upgrading:
|
14
|
+
|
15
|
+
* Replace calls to `RailsApiLogger.new` with `RailsApiLogger::Logger.new`. More in general the logger has been renamed.
|
16
|
+
* `InboundRequestLog` has been renamed to `RailsApiLogger::InboundRequestLog`. Table name did not change.
|
17
|
+
* `OutboundRequestLog` has been renamed to `RailsApiLogger::OutboundRequestLog`. Table name did not change.
|
18
|
+
* If you had `has_many :inbound_request_logs` or `has_many :outbound_request_logs` defined, this will break. There's
|
19
|
+
now [three methods](app/models/rails_api_logger/loggable.rb) you can use on your model.
|
20
|
+
* `InboundRequestsLoggerMiddleware` has been renamed to `RailsApiLogger::Middleware`
|
21
|
+
|
22
|
+
> Do the changes above and then continue with the following steps if you want to connect rails_api_logger to a different
|
23
|
+
> database:
|
24
|
+
|
25
|
+
* Specify a database called `api_logger`. [Check here](spec/dummy/config/database.yml) for an example.
|
26
|
+
* Check that everything still works (also in production!) with the new configuration.
|
27
|
+
* Add the migrations in the right folder to create again the necessary tables. Run the migrations that will generate a
|
28
|
+
new schema file.
|
29
|
+
* Release and do the same in production. Adapt your build/release steps if you need.
|
30
|
+
|
31
|
+
* Add the following line into `production.rb`:
|
32
|
+
`config.rails_api_logger.connects_to = { database: { writing: :api_logger } }` if you want to point to a new database.
|
33
|
+
|
34
|
+
> If you are not on SQLite you can point also `api_logger` database to the current database you have, so you benefit
|
35
|
+
> from isolated transactions but don't need to create a new database or migrate data.
|
36
|
+
|
37
|
+
### List of changes in this version:
|
38
|
+
|
39
|
+
* Namespace correctly. Renamed all classes
|
40
|
+
* Added tests with a dummy app
|
41
|
+
* Use a separate database connection configuration to isolate transactions
|
42
|
+
* I acknowledge that there might be issues on mysql. I don't use it so I won't fix them, but PR are welcome.
|
43
|
+
* Added `host_regexp` option to the middleware.
|
44
|
+
|
1
45
|
# 0.9.0
|
2
|
-
|
46
|
+
|
47
|
+
* Add option skip_request_body to skip the request body. Use this option when you don't want to persist the request
|
48
|
+
body. `[Skipped]` will be persisted instead.
|
3
49
|
* Add option skip_request_body_regexp to skip logging the body of requests matching a regexp.
|
4
50
|
* Renamed the option skip_body into skip_response_body. This is a breaking change!
|
5
51
|
* Renamed the option skip_body_regexp into skip_response_body_regexp. This is a breaking change!
|
6
52
|
|
7
53
|
# 0.8.1
|
54
|
+
|
8
55
|
* Fix Rails 7.1 warnings.
|
9
56
|
|
10
57
|
# 0.8.0
|
11
|
-
|
58
|
+
|
59
|
+
* Add option skip_body to skip the body for request responses. Use this option when you don't want to persist the
|
60
|
+
response body. `[Skipped]` will be persisted instead. This is not a breaking change.
|
12
61
|
|
13
62
|
# 0.7.0
|
63
|
+
|
14
64
|
* Fix an issue in the middleware where the request body was not read correctly if there were encoding issues.
|
15
65
|
* Improved documentation about outboud request logging.
|
16
66
|
* Add option skip_body_regexp to skip logging the body of requests matching a regexp.
|
17
67
|
|
18
68
|
# 0.6.3
|
69
|
+
|
19
70
|
* Fix the CHANGELOG path in gemspec.
|
20
71
|
|
21
72
|
# 0.6.2
|
73
|
+
|
22
74
|
* Fixes Zeitwerk warning.
|
23
75
|
|
24
76
|
# 0.6.1
|
77
|
+
|
25
78
|
* Fixes the loading of concern into controllers.
|
26
79
|
|
27
80
|
# 0.6.0
|
81
|
+
|
28
82
|
* Fixes an important concurrency issue by removing instance variables in the rack middleware.
|
29
83
|
|
30
84
|
# 0.5.0
|
85
|
+
|
31
86
|
* Started using Zeitwerk.
|
32
87
|
* Removed RailsAdmin specific code.
|
33
88
|
* Improved RailsApiLogger class.
|
34
89
|
|
35
90
|
# 0.4.1
|
91
|
+
|
36
92
|
* Fixed the `.failed` scope.
|
37
93
|
|
38
94
|
# 0.4.0
|
95
|
+
|
39
96
|
* Added `started_at`, `ended_at` and `duration` methods.
|
40
97
|
|
41
98
|
Migrate your tables with:
|
@@ -47,12 +104,14 @@ add_column :outbound_request_logs, :started_at, :timestamp
|
|
47
104
|
add_column :outbound_request_logs, :ended_at, :timestamp
|
48
105
|
```
|
49
106
|
|
50
|
-
|
51
107
|
# 0.3.0
|
108
|
+
|
52
109
|
* Added `formatted_request_body` and `formatted_response_body` methods.
|
53
110
|
|
54
111
|
# 0.2.0
|
112
|
+
|
55
113
|
* Switch to a middleware solution.
|
56
114
|
|
57
115
|
# 0.1.0
|
116
|
+
|
58
117
|
* Initial release.
|
data/README.md
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# Rails API Logger
|
2
2
|
|
3
|
-
The simplest way to log API requests
|
3
|
+
The simplest way to log API requests in your database.
|
4
4
|
|
5
5
|
The Rails API logger gem introduces a set of tools to log and debug API requests.
|
6
|
+
|
6
7
|
It works on two sides:
|
7
8
|
|
8
9
|
* **Inbound requests**: API exposed by your application
|
9
|
-
* **Outbound requests**: API invoked by your application
|
10
|
+
* **Outbound requests**: API invoked by your application
|
10
11
|
|
11
|
-
This gem has been extracted from various Renuo projects
|
12
|
-
technique multiple times successfully.
|
12
|
+
This gem has been extracted from various [Renuo](https://www.renuo.ch) projects.
|
13
13
|
|
14
14
|
This gem creates two database tables to log the following information:
|
15
15
|
|
16
16
|
* **path** the path/url invoked
|
17
17
|
* **method** the method used to invoke the API (get, post, put, etc...)
|
18
18
|
* **request_body** what was included in the request body
|
19
|
-
* **response_body** what was included in the response body
|
20
|
-
* **response_code** the HTTP response code of the request
|
19
|
+
* **response_body** what was included in the response body
|
20
|
+
* **response_code** the HTTP response code of the request
|
21
21
|
* **started_at** when the request started
|
22
22
|
* **ended_at** when the request finished
|
23
23
|
|
@@ -33,14 +33,34 @@ And then execute:
|
|
33
33
|
|
34
34
|
```bash
|
35
35
|
bundle install
|
36
|
-
|
37
|
-
|
38
|
-
bundle exec rails db:migrate
|
36
|
+
bin/rails g rails_api_logger:install
|
37
|
+
bin/rails db:migrate
|
39
38
|
```
|
40
39
|
|
41
40
|
This will generate two tables `inbound_request_logs` and `outbound_request_logs`.
|
42
41
|
These tables will contain the logs.
|
43
42
|
|
43
|
+
## Ensure logging of data
|
44
|
+
|
45
|
+
RailsApiLogger can use a separate database, to ensure that the logs are written in the database even if a
|
46
|
+
surrounding database transaction is rolled back.
|
47
|
+
|
48
|
+
Make sure to add the following in your `config/environments/production.rb`:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
config.rails_api_logger.connects_to = { database: { writing: :api_logger } }
|
52
|
+
```
|
53
|
+
|
54
|
+
and [configure a new database](spec/dummy/config/database.yml) accordingly.
|
55
|
+
|
56
|
+
> ⚠️ If you skip this step, rails_api_logger will use your primary database but a rollback will also rollback the
|
57
|
+
> writing of logs
|
58
|
+
> If you are not on SQLite you can point also `api_logger` to the same database! By doing so you can use a single
|
59
|
+
> database but still guarantee the writing of logs in an isolated transaction:
|
60
|
+
> ```
|
61
|
+
> config.rails_api_logger.connects_to = { database: { writing: :primary } }
|
62
|
+
> ```
|
63
|
+
|
44
64
|
## Log Outbound Requests
|
45
65
|
|
46
66
|
Given an outbound request in the following format:
|
@@ -59,7 +79,7 @@ uri = URI('http://example.com/some_path?query=string')
|
|
59
79
|
http = Net::HTTP.start(uri.host, uri.port)
|
60
80
|
request = Net::HTTP::Get.new(uri)
|
61
81
|
|
62
|
-
log = OutboundRequestLog.from_request(request)
|
82
|
+
log = RailsApiLogger::OutboundRequestLog.from_request(request)
|
63
83
|
|
64
84
|
response = http.request(request)
|
65
85
|
|
@@ -76,7 +96,7 @@ request = Net::HTTP::Post.new(uri)
|
|
76
96
|
request.body = { answer: 42 }.to_json
|
77
97
|
request.content_type = 'application/json'
|
78
98
|
|
79
|
-
response = RailsApiLogger.new.call(nil, request) do
|
99
|
+
response = RailsApiLogger::Logger.new.call(nil, request) do
|
80
100
|
Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
|
81
101
|
end
|
82
102
|
```
|
@@ -86,25 +106,7 @@ This will guarantee that the log is always persisted, even in case of errors.
|
|
86
106
|
### Database Transactions Caveats
|
87
107
|
|
88
108
|
If you log your outbound requests inside of parent app transactions, your logs will not be persisted if
|
89
|
-
the transaction is rolled-back.
|
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
|
-
You can also log the request in a separate thread to provoke the checkout of a separate database connection.
|
107
|
-
Have a look at [this example here](https://github.com/renuo/rails_api_logger/blob/28d4ced88fea5a5f4fd72f5a1db42ad4734eb547/spec/outbound_request_log_spec.rb#L28-L30).
|
109
|
+
the transaction is rolled-back. Use a separate database to prevent this.
|
108
110
|
|
109
111
|
## Log Inbound Requests
|
110
112
|
|
@@ -112,36 +114,41 @@ If you are exposing some API you might be interested in logging the requests you
|
|
112
114
|
You can do so by adding this middleware in `config/application.rb`
|
113
115
|
|
114
116
|
```ruby
|
115
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
117
|
+
config.middleware.insert_before Rails::Rack::Logger, RailsApiLogger::Middleware
|
116
118
|
```
|
117
119
|
|
118
120
|
this will by default only log requests that have an impact in your system (POST, PUT, and PATCH calls).
|
119
121
|
If you want to log all requests (also GET ones) use
|
120
122
|
|
121
123
|
```ruby
|
122
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
124
|
+
config.middleware.insert_before Rails::Rack::Logger, RailsApiLogger::Middleware, only_state_change: false
|
123
125
|
```
|
124
126
|
|
125
127
|
If you want to log only requests on a certain path, you can pass a regular expression:
|
126
128
|
|
127
129
|
```ruby
|
128
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
130
|
+
config.middleware.insert_before Rails::Rack::Logger, RailsApiLogger::Middleware, path_regexp: /api/
|
129
131
|
```
|
130
132
|
|
131
|
-
If you want to
|
133
|
+
If you want to log only requests on a certain host, you can also use a regular expression:
|
132
134
|
|
133
135
|
```ruby
|
134
|
-
config.middleware.insert_before Rails::Rack::Logger,
|
135
|
-
skip_request_body_regexp: /api/books/,
|
136
|
-
skip_response_body_regexp: /api/letters/
|
136
|
+
config.middleware.insert_before Rails::Rack::Logger, RailsApiLogger::Middleware, host_regexp: /api.example.com/
|
137
137
|
```
|
138
138
|
|
139
|
+
If you want to skip logging the response or request body of certain requests, you can pass a regular expression:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
config.middleware.insert_before Rails::Rack::Logger, RailsApiLogger::Middleware,
|
143
|
+
skip_request_body_regexp: /api\/books/,
|
144
|
+
skip_response_body_regexp: /api\/letters/
|
145
|
+
```
|
139
146
|
|
140
147
|
In the implementation of your API, you can call any time `attach_inbound_request_loggable(model)`
|
141
148
|
to attach an already persisted model to the log record.
|
142
149
|
|
143
|
-
|
144
150
|
For example:
|
151
|
+
|
145
152
|
```ruby
|
146
153
|
|
147
154
|
def create
|
@@ -158,18 +165,21 @@ end
|
|
158
165
|
in the User model you can define:
|
159
166
|
|
160
167
|
```ruby
|
161
|
-
|
168
|
+
has_many_inbound_request_logs
|
162
169
|
```
|
163
170
|
|
164
|
-
to be able to access the logs attached to the model.
|
171
|
+
to be able to access the inbound logs attached to the model.
|
172
|
+
|
173
|
+
You also have `has_many_outbound_request_logs` and `has_many_request_logs` that includes both.
|
165
174
|
|
166
175
|
## RailsAdmin integration
|
167
176
|
|
168
177
|
We provide here some code samples to integrate the models in [RailsAdmin](https://github.com/sferik/rails_admin).
|
169
178
|
|
170
|
-
This configuration will give you some nice views, and searches to work with the logs efficiently.
|
179
|
+
This configuration will give you some nice views, and searches to work with the logs efficiently.
|
180
|
+
|
171
181
|
```ruby
|
172
|
-
%w[InboundRequestLog OutboundRequestLog].each do |logging_model|
|
182
|
+
%w[RailsApiLogger::InboundRequestLog RailsApiLogger::OutboundRequestLog].each do |logging_model|
|
173
183
|
config.model logging_model do
|
174
184
|
list do
|
175
185
|
filters %i[method path response_code request_body response_body created_at]
|
@@ -204,24 +214,51 @@ This configuration will give you some nice views, and searches to work with the
|
|
204
214
|
end
|
205
215
|
```
|
206
216
|
|
207
|
-
|
208
217
|
## Development
|
209
218
|
|
210
|
-
|
219
|
+
We use Appraisals to un on different Rails versions. This is a run example:
|
211
220
|
|
212
|
-
|
221
|
+
```bash
|
222
|
+
export SAME_TARGET=false
|
223
|
+
export SAME_DB=false
|
224
|
+
export TARGET_DB=postgres
|
225
|
+
export BUNDLE_GEMFILE=/Users/alessandrorodi/RenuoWorkspace/rails_api_logger/gemfiles/rails_6.1.gemfile
|
226
|
+
bundle exec rails db:create db:migrate
|
227
|
+
bundle exec rspec
|
228
|
+
```
|
229
|
+
|
230
|
+
These are the possible ENV variables:
|
231
|
+
|
232
|
+
* `SAME_TARGET` if true, the api_logger database is the same as the primary one. It will still use two separate
|
233
|
+
connection pools, but they'll point to the same database. This cannot be set to true if TARGET_DB is sqlite because
|
234
|
+
sqlite does not support multiple connection pools to the same database.
|
235
|
+
* `SAME_DB` if true, the api_logger uses the primary database. In this case SAME_TARGET is ignored.
|
236
|
+
* `TARGET_DB` the database to use. Can be `postgres`, `mysql`, or `sqlite`.
|
237
|
+
* `BUNDLE_GEMFILE` the gemfile to use. This is used to run the tests on different Rails versions.
|
238
|
+
|
239
|
+
Possible combinations:
|
240
|
+
|
241
|
+
| SAME_DB | SAME_TARGET | TARGET_DB | Description |
|
242
|
+
|---------|-------------|-----------|----------------------------------------------------------------------|
|
243
|
+
| false | false | postgres | Separate database, separate connection pool. |
|
244
|
+
| false | true | postgres | Same database, separate connection pool. |
|
245
|
+
| true | - | postgres | Same connection pool so the separate target is ignored. |
|
246
|
+
| false | false | sqlite | Separate database, separate connection pool. |
|
247
|
+
| false | true | sqlite | Not allowed. sqlite cannot have two connection pools to the same db. |
|
248
|
+
| true | - | sqlite | Same connection pool so the separate target is ignored. |
|
249
|
+
|
250
|
+
|
251
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
252
|
+
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
253
|
+
push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
213
254
|
|
214
255
|
## Contributing
|
215
256
|
|
216
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/renuo/rails_api_logger.
|
217
|
-
This project is intended to be a safe, welcoming space for collaboration
|
218
|
-
|
257
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/renuo/rails_api_logger.
|
258
|
+
This project is intended to be a safe, welcoming space for collaboration.
|
259
|
+
|
260
|
+
Try to be a decent human being while interacting with other people.
|
219
261
|
|
220
262
|
## License
|
221
263
|
|
222
264
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
223
|
-
|
224
|
-
## Code of Conduct
|
225
|
-
|
226
|
-
Everyone interacting in the RailsApiLogger project's codebases, issue trackers, chat rooms and mailing lists is
|
227
|
-
expected to follow the [code of conduct](https://github.com/renuo/rails_api_logger/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
1
4
|
require "bundler/gem_tasks"
|
2
|
-
require "
|
5
|
+
require "rake/testtask"
|
3
6
|
|
4
|
-
|
7
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
8
|
+
load "rails/tasks/engine.rake"
|
9
|
+
load "rails/tasks/statistics.rake"
|
5
10
|
|
6
11
|
task default: :spec
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module RailsApiLogger
|
2
|
+
class Middleware
|
3
|
+
attr_accessor :only_state_change, :host_regexp, :path_regexp, :skip_request_body_regexp, :skip_response_body_regexp
|
4
|
+
|
5
|
+
def initialize(app, only_state_change: true,
|
6
|
+
host_regexp: /.*/,
|
7
|
+
path_regexp: /.*/,
|
8
|
+
skip_request_body_regexp: nil,
|
9
|
+
skip_response_body_regexp: nil)
|
10
|
+
@app = app
|
11
|
+
self.only_state_change = only_state_change
|
12
|
+
self.host_regexp = host_regexp
|
13
|
+
self.path_regexp = path_regexp
|
14
|
+
self.skip_request_body_regexp = skip_request_body_regexp
|
15
|
+
self.skip_response_body_regexp = skip_response_body_regexp
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
request = ActionDispatch::Request.new(env)
|
20
|
+
logging = log?(env, request)
|
21
|
+
if logging
|
22
|
+
env["INBOUND_REQUEST_LOG"] = InboundRequestLog.from_request(request, skip_request_body: skip_request_body?(env))
|
23
|
+
request.body.rewind if request.body.respond_to?(:read)
|
24
|
+
end
|
25
|
+
status, headers, body = @app.call(env)
|
26
|
+
if logging
|
27
|
+
updates = {response_code: status, ended_at: Time.current}
|
28
|
+
updates[:response_body] = if skip_response_body?(env)
|
29
|
+
"[Skipped]"
|
30
|
+
else
|
31
|
+
parsed_body(body)
|
32
|
+
end
|
33
|
+
# this usually works. let's be optimistic.
|
34
|
+
begin
|
35
|
+
env["INBOUND_REQUEST_LOG"].update_columns(updates)
|
36
|
+
rescue JSON::GeneratorError => _e # this can be raised by activerecord if the string is not UTF-8.
|
37
|
+
env["INBOUND_REQUEST_LOG"].update_columns(updates.except(:response_body))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
[status, headers, body]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def skip_request_body?(env)
|
46
|
+
skip_request_body_regexp && env["PATH_INFO"] =~ skip_request_body_regexp
|
47
|
+
end
|
48
|
+
|
49
|
+
def skip_response_body?(env)
|
50
|
+
skip_response_body_regexp && env["PATH_INFO"] =~ skip_response_body_regexp
|
51
|
+
end
|
52
|
+
|
53
|
+
def log?(env, request)
|
54
|
+
# The HTTP_HOST header is preferred to the SERVER_NAME header per the Rack spec: https://github.com/rack/rack/blob/main/SPEC.rdoc#label-The+Environment
|
55
|
+
host = env["HTTP_HOST"] || env["SERVER_NAME"]
|
56
|
+
path = env["PATH_INFO"]
|
57
|
+
(host =~ host_regexp) &&
|
58
|
+
(path =~ path_regexp) &&
|
59
|
+
(!only_state_change || request_with_state_change?(request))
|
60
|
+
end
|
61
|
+
|
62
|
+
def parsed_body(body)
|
63
|
+
return unless body.present?
|
64
|
+
|
65
|
+
if body.respond_to?(:to_ary)
|
66
|
+
JSON.parse(body.to_ary[0])
|
67
|
+
elsif body.respond_to?(:body)
|
68
|
+
JSON.parse(body.body)
|
69
|
+
else
|
70
|
+
body
|
71
|
+
end
|
72
|
+
rescue JSON::ParserError, ArgumentError
|
73
|
+
body
|
74
|
+
end
|
75
|
+
|
76
|
+
def request_with_state_change?(request)
|
77
|
+
request.post? || request.put? || request.patch? || request.delete?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|