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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.semaphore/semaphore.yml +132 -2
  4. data/.standard.yml +2 -0
  5. data/Appraisals +31 -0
  6. data/CHANGELOG.md +62 -3
  7. data/README.md +90 -53
  8. data/Rakefile +7 -2
  9. data/app/middlewares/rails_api_logger/middleware.rb +80 -0
  10. data/app/models/rails_api_logger/inbound_request_log.rb +5 -0
  11. data/app/models/rails_api_logger/loggable.rb +27 -0
  12. data/app/models/rails_api_logger/logger.rb +22 -0
  13. data/app/models/rails_api_logger/outbound_request_log.rb +5 -0
  14. data/app/models/rails_api_logger/request_log.rb +85 -0
  15. data/bin/rails +16 -0
  16. data/gemfiles/rails_6.1.gemfile +10 -0
  17. data/gemfiles/rails_6.1.gemfile.lock +240 -0
  18. data/gemfiles/rails_7.0.gemfile +10 -0
  19. data/gemfiles/rails_7.0.gemfile.lock +239 -0
  20. data/gemfiles/rails_7.1.gemfile +9 -0
  21. data/gemfiles/rails_7.1.gemfile.lock +272 -0
  22. data/gemfiles/rails_7.2.gemfile +9 -0
  23. data/gemfiles/rails_7.2.gemfile.lock +272 -0
  24. data/gemfiles/rails_8.0.gemfile +9 -0
  25. data/lib/generators/rails_api_logger/install_generator.rb +1 -1
  26. data/lib/rails_api_logger/engine.rb +25 -0
  27. data/lib/rails_api_logger/version.rb +5 -0
  28. data/lib/rails_api_logger.rb +9 -27
  29. data/rails_api_logger.gemspec +10 -6
  30. metadata +58 -29
  31. data/CODE_OF_CONDUCT.md +0 -74
  32. data/lib/rails_api_logger/inbound_request_log.rb +0 -2
  33. data/lib/rails_api_logger/inbound_requests_logger_middleware.rb +0 -71
  34. data/lib/rails_api_logger/outbound_request_log.rb +0 -2
  35. data/lib/rails_api_logger/request_log.rb +0 -76
  36. /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.9.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: 2024-09-12 00:00:00.000000000 Z
11
+ date: 2025-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: railties
14
+ name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.1.0
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: 4.1.0
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activerecord
28
+ name: activejob
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 4.1.0
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: 4.1.0
40
+ version: '6.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: actionpack
42
+ name: railties
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 4.1.0
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: 4.1.0
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.4.0
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.4.0
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: standard
112
+ name: mysql2
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.31'
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: '1.31'
124
+ version: 0.5.6
125
125
  - !ruby/object:Gem::Dependency
126
- name: rake
126
+ name: standard
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '12.0'
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: '12.0'
138
+ version: '1.31'
139
139
  - !ruby/object:Gem::Dependency
140
- name: rspec
140
+ name: rake
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '3.0'
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: '3.0'
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/inbound_request_log.rb
191
- - lib/rails_api_logger/inbound_requests_logger.rb
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.5.17
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,2 +0,0 @@
1
- class InboundRequestLog < RequestLog
2
- end
@@ -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,2 +0,0 @@
1
- class OutboundRequestLog < RequestLog
2
- 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