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
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
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.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Rodi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '6.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '6.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: activejob
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '6.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '6.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: railties
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '6.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: '6.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: nokogiri
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.
|
89
|
+
version: 2.1.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.
|
96
|
+
version: 2.1.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: pg
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,47 +109,47 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 1.5.4
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: mysql2
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
117
|
+
version: 0.5.6
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
124
|
+
version: 0.5.6
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: standard
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
131
|
+
version: '1.31'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
138
|
+
version: '1.31'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rake
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '12.0'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '12.0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: rack
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: appraisal
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '2.5'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '2.5'
|
167
181
|
description: Log inbound and outbound API requests in your Rails application
|
168
182
|
email:
|
169
183
|
- alessandro.rodi@renuo.ch
|
@@ -176,22 +190,37 @@ files:
|
|
176
190
|
- ".ruby-version"
|
177
191
|
- ".semaphore/main-deploy.yml"
|
178
192
|
- ".semaphore/semaphore.yml"
|
193
|
+
- ".standard.yml"
|
194
|
+
- Appraisals
|
179
195
|
- CHANGELOG.md
|
180
|
-
- CODE_OF_CONDUCT.md
|
181
196
|
- Gemfile
|
182
197
|
- LICENSE.txt
|
183
198
|
- README.md
|
184
199
|
- Rakefile
|
200
|
+
- app/controllers/inbound_requests_logger.rb
|
201
|
+
- app/middlewares/rails_api_logger/middleware.rb
|
202
|
+
- app/models/rails_api_logger/inbound_request_log.rb
|
203
|
+
- app/models/rails_api_logger/loggable.rb
|
204
|
+
- app/models/rails_api_logger/logger.rb
|
205
|
+
- app/models/rails_api_logger/outbound_request_log.rb
|
206
|
+
- app/models/rails_api_logger/request_log.rb
|
185
207
|
- bin/console
|
208
|
+
- bin/rails
|
186
209
|
- bin/setup
|
210
|
+
- gemfiles/rails_6.1.gemfile
|
211
|
+
- gemfiles/rails_6.1.gemfile.lock
|
212
|
+
- gemfiles/rails_7.0.gemfile
|
213
|
+
- gemfiles/rails_7.0.gemfile.lock
|
214
|
+
- gemfiles/rails_7.1.gemfile
|
215
|
+
- gemfiles/rails_7.1.gemfile.lock
|
216
|
+
- gemfiles/rails_7.2.gemfile
|
217
|
+
- gemfiles/rails_7.2.gemfile.lock
|
218
|
+
- gemfiles/rails_8.0.gemfile
|
187
219
|
- lib/generators/rails_api_logger/install_generator.rb
|
188
220
|
- lib/generators/templates/create_rails_api_logger_table.rb.tt
|
189
221
|
- lib/rails_api_logger.rb
|
190
|
-
- lib/rails_api_logger/
|
191
|
-
- lib/rails_api_logger/
|
192
|
-
- lib/rails_api_logger/inbound_requests_logger_middleware.rb
|
193
|
-
- lib/rails_api_logger/outbound_request_log.rb
|
194
|
-
- lib/rails_api_logger/request_log.rb
|
222
|
+
- lib/rails_api_logger/engine.rb
|
223
|
+
- lib/rails_api_logger/version.rb
|
195
224
|
- rails_api_logger.gemspec
|
196
225
|
homepage: https://github.com/renuo/rails_api_logger
|
197
226
|
licenses:
|
@@ -215,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
244
|
- !ruby/object:Gem::Version
|
216
245
|
version: '0'
|
217
246
|
requirements: []
|
218
|
-
rubygems_version: 3.
|
247
|
+
rubygems_version: 3.3.27
|
219
248
|
signing_key:
|
220
249
|
specification_version: 4
|
221
250
|
summary: "Log API requests like a king \U0001F451"
|
data/CODE_OF_CONDUCT.md
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
2
|
-
|
3
|
-
## Our Pledge
|
4
|
-
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
-
orientation.
|
11
|
-
|
12
|
-
## Our Standards
|
13
|
-
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
15
|
-
include:
|
16
|
-
|
17
|
-
* Using welcoming and inclusive language
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
19
|
-
* Gracefully accepting constructive criticism
|
20
|
-
* Focusing on what is best for the community
|
21
|
-
* Showing empathy towards other community members
|
22
|
-
|
23
|
-
Examples of unacceptable behavior by participants include:
|
24
|
-
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
-
advances
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
-
* Public or private harassment
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
30
|
-
address, without explicit permission
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
-
professional setting
|
33
|
-
|
34
|
-
## Our Responsibilities
|
35
|
-
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
38
|
-
response to any instances of unacceptable behavior.
|
39
|
-
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
-
threatening, offensive, or harmful.
|
45
|
-
|
46
|
-
## Scope
|
47
|
-
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
-
when an individual is representing the project or its community. Examples of
|
50
|
-
representing a project or community include using an official project e-mail
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
53
|
-
further defined and clarified by project maintainers.
|
54
|
-
|
55
|
-
## Enforcement
|
56
|
-
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
-
reported by contacting the project team at alessandro.rodi@renuo.ch. All
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
63
|
-
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
66
|
-
members of the project's leadership.
|
67
|
-
|
68
|
-
## Attribution
|
69
|
-
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
-
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
-
|
73
|
-
[homepage]: https://contributor-covenant.org
|
74
|
-
[version]: https://contributor-covenant.org/version/1/4/
|
@@ -1,71 +0,0 @@
|
|
1
|
-
class InboundRequestsLoggerMiddleware
|
2
|
-
attr_accessor :only_state_change, :path_regexp, :skip_request_body_regexp, :skip_response_body_regexp
|
3
|
-
|
4
|
-
def initialize(app, only_state_change: true,
|
5
|
-
path_regexp: /.*/,
|
6
|
-
skip_request_body_regexp: nil,
|
7
|
-
skip_response_body_regexp: nil)
|
8
|
-
@app = app
|
9
|
-
self.only_state_change = only_state_change
|
10
|
-
self.path_regexp = path_regexp
|
11
|
-
self.skip_request_body_regexp = skip_request_body_regexp
|
12
|
-
self.skip_response_body_regexp = skip_response_body_regexp
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
request = ActionDispatch::Request.new(env)
|
17
|
-
logging = log?(env, request)
|
18
|
-
if logging
|
19
|
-
env["INBOUND_REQUEST_LOG"] = InboundRequestLog.from_request(request, skip_request_body: skip_request_body?(env))
|
20
|
-
request.body.rewind
|
21
|
-
end
|
22
|
-
status, headers, body = @app.call(env)
|
23
|
-
if logging
|
24
|
-
updates = {response_code: status, ended_at: Time.current}
|
25
|
-
updates[:response_body] = if skip_response_body?(env)
|
26
|
-
"[Skipped]"
|
27
|
-
else
|
28
|
-
parsed_body(body)
|
29
|
-
end
|
30
|
-
# this usually works. let's be optimistic.
|
31
|
-
begin
|
32
|
-
env["INBOUND_REQUEST_LOG"].update_columns(updates)
|
33
|
-
rescue JSON::GeneratorError => _e # this can be raised by activerecord if the string is not UTF-8.
|
34
|
-
env["INBOUND_REQUEST_LOG"].update_columns(updates.except(:response_body))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
[status, headers, body]
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def skip_request_body?(env)
|
43
|
-
skip_request_body_regexp && env["PATH_INFO"] =~ skip_request_body_regexp
|
44
|
-
end
|
45
|
-
|
46
|
-
def skip_response_body?(env)
|
47
|
-
skip_response_body_regexp && env["PATH_INFO"] =~ skip_response_body_regexp
|
48
|
-
end
|
49
|
-
|
50
|
-
def log?(env, request)
|
51
|
-
env["PATH_INFO"] =~ path_regexp && (!only_state_change || request_with_state_change?(request))
|
52
|
-
end
|
53
|
-
|
54
|
-
def parsed_body(body)
|
55
|
-
return unless body.present?
|
56
|
-
|
57
|
-
if body.respond_to?(:to_ary)
|
58
|
-
JSON.parse(body.to_ary[0])
|
59
|
-
elsif body.respond_to?(:body)
|
60
|
-
JSON.parse(body.body)
|
61
|
-
else
|
62
|
-
body
|
63
|
-
end
|
64
|
-
rescue JSON::ParserError, ArgumentError
|
65
|
-
body
|
66
|
-
end
|
67
|
-
|
68
|
-
def request_with_state_change?(request)
|
69
|
-
request.post? || request.put? || request.patch? || request.delete?
|
70
|
-
end
|
71
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
class RequestLog < ActiveRecord::Base
|
2
|
-
self.abstract_class = true
|
3
|
-
|
4
|
-
serialize :request_body, coder: JSON
|
5
|
-
serialize :response_body, coder: JSON
|
6
|
-
|
7
|
-
belongs_to :loggable, optional: true, polymorphic: true
|
8
|
-
|
9
|
-
scope :failed, -> { where(response_code: 400..599).or(where.not(ended_at: nil).where(response_code: nil)) }
|
10
|
-
|
11
|
-
validates :method, presence: true
|
12
|
-
validates :path, presence: true
|
13
|
-
|
14
|
-
def self.from_request(request, loggable: nil, skip_request_body: false)
|
15
|
-
if skip_request_body
|
16
|
-
body = "[Skipped]"
|
17
|
-
else
|
18
|
-
request_body = (request.body.respond_to?(:read) ? request.body.read : request.body)
|
19
|
-
body = request_body&.dup&.force_encoding("UTF-8")
|
20
|
-
begin
|
21
|
-
body = JSON.parse(body) if body.present?
|
22
|
-
rescue JSON::ParserError
|
23
|
-
body
|
24
|
-
end
|
25
|
-
end
|
26
|
-
create(path: request.path, request_body: body, method: request.method, started_at: Time.current, loggable: loggable)
|
27
|
-
end
|
28
|
-
|
29
|
-
def from_response(response, skip_response_body: false)
|
30
|
-
self.response_code = response.code
|
31
|
-
self.response_body = skip_response_body ? "[Skipped]" : manipulate_body(response.body)
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def formatted_request_body
|
36
|
-
formatted_body(request_body)
|
37
|
-
end
|
38
|
-
|
39
|
-
def formatted_response_body
|
40
|
-
formatted_body(response_body)
|
41
|
-
end
|
42
|
-
|
43
|
-
def formatted_body(body)
|
44
|
-
if body.is_a?(String) && body.blank?
|
45
|
-
""
|
46
|
-
elsif body.is_a?(Hash)
|
47
|
-
JSON.pretty_generate(body)
|
48
|
-
else
|
49
|
-
xml = Nokogiri::XML(body)
|
50
|
-
if xml.errors.any?
|
51
|
-
body
|
52
|
-
else
|
53
|
-
xml.to_xml(indent: 2)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
rescue
|
57
|
-
body
|
58
|
-
end
|
59
|
-
|
60
|
-
def duration
|
61
|
-
return if started_at.nil? || ended_at.nil?
|
62
|
-
ended_at - started_at
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def manipulate_body(body)
|
68
|
-
body_duplicate = body&.dup&.force_encoding("UTF-8")
|
69
|
-
begin
|
70
|
-
body_duplicate = JSON.parse(body_duplicate) if body_duplicate.present?
|
71
|
-
rescue JSON::ParserError
|
72
|
-
body_duplicate
|
73
|
-
end
|
74
|
-
body_duplicate
|
75
|
-
end
|
76
|
-
end
|
File without changes
|