grape_logging 2.1.1 → 3.0.1
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/.github/workflows/ci.yml +17 -4
- data/.rubocop.yml +17 -0
- data/.rubocop_todo.yml +160 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +7 -0
- data/README.md +2 -2
- data/Rakefile +15 -7
- data/grape_logging.gemspec +4 -6
- data/lib/grape_logging/formatters/default.rb +1 -0
- data/lib/grape_logging/formatters/logstash.rb +3 -3
- data/lib/grape_logging/formatters/rails.rb +3 -7
- data/lib/grape_logging/loggers/base.rb +1 -1
- data/lib/grape_logging/loggers/client_env.rb +1 -1
- data/lib/grape_logging/loggers/filter_parameters.rb +4 -4
- data/lib/grape_logging/loggers/request_headers.rb +0 -2
- data/lib/grape_logging/loggers/response.rb +2 -3
- data/lib/grape_logging/middleware/request_logger.rb +28 -15
- data/lib/grape_logging/multi_io.rb +2 -2
- data/lib/grape_logging/reporters/active_support_reporter.rb +10 -8
- data/lib/grape_logging/reporters/logger_reporter.rb +10 -10
- data/lib/grape_logging/timings.rb +5 -7
- data/lib/grape_logging/util/parameter_filter.rb +86 -80
- data/lib/grape_logging/version.rb +1 -1
- data/lib/grape_logging.rb +12 -17
- metadata +12 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 812a02e3c1b1f55003d060c5d31887be91cd73115cdb366c36c4e29c8e5507a0
|
|
4
|
+
data.tar.gz: 929dec60825b2aa8ec50c349506f383cd58a01d987bc8eb8b02990c225279e34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3043a583d5b227f2fb474a1e036ad0f27589dafa1a11d428b0e93c3441e6cc6204001bfe26dbd6f925ea2fe2a6a681ff3e6c2853979e458f19c43ece1696e0ec
|
|
7
|
+
data.tar.gz: 9ea303723891185798f23494e53c542c73ceee318f4fa72c073277e263e72e1f1dac885729126eda13c3aee89893488d88b4173eff877b2ff30998d77c944435
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -9,15 +9,28 @@ jobs:
|
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
strategy:
|
|
11
11
|
matrix:
|
|
12
|
-
ruby-version: ["3.0", "3.1", "3.2", "3.3", "3.4"]
|
|
12
|
+
ruby-version: ["3.0", "3.1", "3.2", "3.3", "3.4", "4.0"]
|
|
13
13
|
steps:
|
|
14
14
|
- name: Checkout code
|
|
15
|
-
uses: actions/checkout@
|
|
15
|
+
uses: actions/checkout@v6
|
|
16
16
|
- uses: ruby/setup-ruby@v1
|
|
17
17
|
with:
|
|
18
18
|
ruby-version: ${{ matrix.ruby-version }}
|
|
19
19
|
bundler-cache: true
|
|
20
20
|
- name: Install dependencies
|
|
21
|
-
run: bundle install
|
|
21
|
+
run: bundle install --jobs 4 --retry 3
|
|
22
22
|
- name: Run tests
|
|
23
|
-
run: bundle exec
|
|
23
|
+
run: bundle exec rake spec
|
|
24
|
+
lint:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout code
|
|
28
|
+
uses: actions/checkout@v6
|
|
29
|
+
- uses: ruby/setup-ruby@v1
|
|
30
|
+
with:
|
|
31
|
+
ruby-version: "4.0"
|
|
32
|
+
bundler-cache: true
|
|
33
|
+
- name: Install dependencies
|
|
34
|
+
run: bundle install
|
|
35
|
+
- name: Run RuboCop
|
|
36
|
+
run: bundle exec rake rubocop
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
AllCops:
|
|
4
|
+
NewCops: enable
|
|
5
|
+
TargetRubyVersion: 3.0
|
|
6
|
+
|
|
7
|
+
Metrics/BlockLength:
|
|
8
|
+
CountAsOne: [array, hash, heredoc, method_call]
|
|
9
|
+
Exclude:
|
|
10
|
+
- 'spec/**/*'
|
|
11
|
+
|
|
12
|
+
Metrics/ClassLength:
|
|
13
|
+
CountAsOne: [array, hash, heredoc, method_call]
|
|
14
|
+
|
|
15
|
+
Metrics/MethodLength:
|
|
16
|
+
CountAsOne: [array, hash, heredoc, method_call]
|
|
17
|
+
Max: 20
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2025-07-10 10:25:51 UTC using RuboCop version 1.77.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 3
|
|
10
|
+
# Configuration parameters: EnforcedStyle, AllowedGems, Include.
|
|
11
|
+
# SupportedStyles: Gemfile, gems.rb, gemspec
|
|
12
|
+
# Include: **/*.gemspec, **/Gemfile, **/gems.rb
|
|
13
|
+
Gemspec/DevelopmentDependencies:
|
|
14
|
+
Exclude:
|
|
15
|
+
- "grape_logging.gemspec"
|
|
16
|
+
|
|
17
|
+
# Offense count: 1
|
|
18
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
19
|
+
# Configuration parameters: Severity, Include.
|
|
20
|
+
# Include: **/*.gemspec
|
|
21
|
+
Gemspec/RequireMFA:
|
|
22
|
+
Exclude:
|
|
23
|
+
- "grape_logging.gemspec"
|
|
24
|
+
|
|
25
|
+
# Offense count: 1
|
|
26
|
+
# Configuration parameters: Severity, Include.
|
|
27
|
+
# Include: **/*.gemspec
|
|
28
|
+
Gemspec/RequiredRubyVersion:
|
|
29
|
+
Exclude:
|
|
30
|
+
- "grape_logging.gemspec"
|
|
31
|
+
|
|
32
|
+
# Offense count: 1
|
|
33
|
+
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
|
34
|
+
Lint/DuplicateBranch:
|
|
35
|
+
Exclude:
|
|
36
|
+
- "lib/grape_logging/util/parameter_filter.rb"
|
|
37
|
+
|
|
38
|
+
# Offense count: 1
|
|
39
|
+
# Configuration parameters: AllowedParentClasses.
|
|
40
|
+
Lint/MissingSuper:
|
|
41
|
+
Exclude:
|
|
42
|
+
- "lib/grape_logging/loggers/filter_parameters.rb"
|
|
43
|
+
|
|
44
|
+
# Offense count: 3
|
|
45
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
46
|
+
Metrics/AbcSize:
|
|
47
|
+
Max: 38
|
|
48
|
+
|
|
49
|
+
# Offense count: 8
|
|
50
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
51
|
+
# AllowedMethods: refine
|
|
52
|
+
Metrics/BlockLength:
|
|
53
|
+
Max: 90
|
|
54
|
+
|
|
55
|
+
# Offense count: 3
|
|
56
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
57
|
+
Metrics/CyclomaticComplexity:
|
|
58
|
+
Max: 18
|
|
59
|
+
|
|
60
|
+
# Offense count: 2
|
|
61
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
62
|
+
Metrics/PerceivedComplexity:
|
|
63
|
+
Max: 19
|
|
64
|
+
|
|
65
|
+
# Offense count: 2
|
|
66
|
+
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
|
|
67
|
+
# SupportedStyles: snake_case, normalcase, non_integer
|
|
68
|
+
# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
|
|
69
|
+
Naming/VariableNumber:
|
|
70
|
+
Exclude:
|
|
71
|
+
- "spec/lib/grape_logging/formatters/rails_spec.rb"
|
|
72
|
+
|
|
73
|
+
# Offense count: 3
|
|
74
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
75
|
+
# Configuration parameters: MinBranchesCount.
|
|
76
|
+
Style/CaseLikeIf:
|
|
77
|
+
Exclude:
|
|
78
|
+
- "lib/grape_logging/formatters/default.rb"
|
|
79
|
+
- "lib/grape_logging/formatters/logstash.rb"
|
|
80
|
+
- "lib/grape_logging/formatters/rails.rb"
|
|
81
|
+
|
|
82
|
+
# Offense count: 17
|
|
83
|
+
# Configuration parameters: AllowedConstants.
|
|
84
|
+
Style/Documentation:
|
|
85
|
+
Enabled: false
|
|
86
|
+
|
|
87
|
+
# Offense count: 29
|
|
88
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
89
|
+
# Configuration parameters: EnforcedStyle.
|
|
90
|
+
# SupportedStyles: always, always_true, never
|
|
91
|
+
Style/FrozenStringLiteralComment:
|
|
92
|
+
Enabled: false
|
|
93
|
+
|
|
94
|
+
# Offense count: 1
|
|
95
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
96
|
+
Style/GlobalStdStream:
|
|
97
|
+
Exclude:
|
|
98
|
+
- "lib/grape_logging/reporters/logger_reporter.rb"
|
|
99
|
+
|
|
100
|
+
# Offense count: 1
|
|
101
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
102
|
+
# Configuration parameters: EnforcedStyle.
|
|
103
|
+
# SupportedStyles: literals, strict
|
|
104
|
+
Style/MutableConstant:
|
|
105
|
+
Exclude:
|
|
106
|
+
- "lib/grape_logging/version.rb"
|
|
107
|
+
|
|
108
|
+
# Offense count: 10
|
|
109
|
+
Style/OpenStructUse:
|
|
110
|
+
Exclude:
|
|
111
|
+
- "spec/lib/grape_logging/loggers/client_env_spec.rb"
|
|
112
|
+
- "spec/lib/grape_logging/loggers/filter_parameters_spec.rb"
|
|
113
|
+
- "spec/lib/grape_logging/loggers/request_headers_spec.rb"
|
|
114
|
+
- "spec/lib/grape_logging/loggers/response_spec.rb"
|
|
115
|
+
|
|
116
|
+
# Offense count: 3
|
|
117
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
118
|
+
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
|
|
119
|
+
# AllowedMethods: present?, blank?, presence, try, try!
|
|
120
|
+
Style/SafeNavigation:
|
|
121
|
+
Exclude:
|
|
122
|
+
- "lib/grape_logging/formatters/rails.rb"
|
|
123
|
+
|
|
124
|
+
# Offense count: 1
|
|
125
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
126
|
+
Style/SlicingWithRange:
|
|
127
|
+
Exclude:
|
|
128
|
+
- "lib/grape_logging/loggers/request_headers.rb"
|
|
129
|
+
|
|
130
|
+
# Offense count: 1
|
|
131
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
132
|
+
# Configuration parameters: RequireEnglish, EnforcedStyle.
|
|
133
|
+
# SupportedStyles: use_perl_names, use_english_names, use_builtin_english_names
|
|
134
|
+
Style/SpecialGlobalVars:
|
|
135
|
+
Exclude:
|
|
136
|
+
- "spec/spec_helper.rb"
|
|
137
|
+
|
|
138
|
+
# Offense count: 3
|
|
139
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
140
|
+
# Configuration parameters: Mode.
|
|
141
|
+
Style/StringConcatenation:
|
|
142
|
+
Exclude:
|
|
143
|
+
- "lib/grape_logging/formatters/json.rb"
|
|
144
|
+
- "lib/grape_logging/formatters/lograge.rb"
|
|
145
|
+
- "lib/grape_logging/formatters/logstash.rb"
|
|
146
|
+
|
|
147
|
+
# Offense count: 1
|
|
148
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
149
|
+
# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments.
|
|
150
|
+
# AllowedMethods: define_method
|
|
151
|
+
Style/SymbolProc:
|
|
152
|
+
Exclude:
|
|
153
|
+
- "lib/grape_logging/util/parameter_filter.rb"
|
|
154
|
+
|
|
155
|
+
# Offense count: 11
|
|
156
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
157
|
+
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
|
158
|
+
# URISchemes: http, https
|
|
159
|
+
Layout/LineLength:
|
|
160
|
+
Max: 203
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.0.1] - 2026-09-11
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- [#98](https://github.com/aserafin/grape_logging/pull/98) Adapt to new Grape::Exceptions::ErrorResponse throwable for Grape 3.3.0 support - [@leoarnold](https://github.com/leoarnold).
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- [#96](https://github.com/aserafin/grape_logging/pull/96) Move dev dependencies to Gemfile and use zeitwerk to load files - [@n-rodriguez](https://github.com/n-rodriguez).
|
|
10
|
+
|
|
11
|
+
[3.0.1]: https://github.com/aserafin/grape_logging/compare/v3.0.0...v3.0.1
|
|
12
|
+
|
|
13
|
+
## [3.0.0] - 2025-08-07
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- [#93](https://github.com/aserafin/grape_logging/pull/93) RequestLogger middleware to handle Grape 2.4 breaking change - [@devsigner](https://github.com/devsigner) and [@samsonjs](https://github.com/samsonjs).
|
|
17
|
+
|
|
18
|
+
[3.0.0]: https://github.com/aserafin/grape_logging/compare/v2.1.1...v3.0.0
|
|
19
|
+
|
|
3
20
|
## [2.1.1] - 2025-07-09
|
|
4
21
|
|
|
5
22
|
### Fixed
|
data/Gemfile
CHANGED
|
@@ -2,3 +2,10 @@ source 'https://rubygems.org'
|
|
|
2
2
|
|
|
3
3
|
# Specify your gem's dependencies in grape_logging.gemspec
|
|
4
4
|
gemspec
|
|
5
|
+
|
|
6
|
+
gem 'rake', '~> 13.3'
|
|
7
|
+
gem 'rspec', '~> 3.5'
|
|
8
|
+
|
|
9
|
+
# This is pinned to an exact version otherwise we can't know which rules
|
|
10
|
+
# are in play at any given time in different environments.
|
|
11
|
+
gem 'rubocop', '1.77.0'
|
data/README.md
CHANGED
|
@@ -209,8 +209,8 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
|
209
209
|
|
|
210
210
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
211
211
|
|
|
212
|
-
For maintainers releasing a new version, please see [
|
|
212
|
+
For maintainers releasing a new version, please see [RELEASING.md](RELEASING.md).
|
|
213
213
|
|
|
214
214
|
## Contributing
|
|
215
215
|
|
|
216
|
-
See [
|
|
216
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
data/Rakefile
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
require 'bundler/gem_tasks'
|
|
2
2
|
require 'rspec/core/rake_task'
|
|
3
|
+
require 'rubocop/rake_task'
|
|
3
4
|
|
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
6
|
+
spec.rspec_opts = ['-fd -c']
|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
|
11
|
+
t.patterns = ['lib/**/*.rb', 'spec/**/*.rb', 'Rakefile', 'Gemfile', 'grape_logging.gemspec']
|
|
12
|
+
end
|
|
5
13
|
|
|
6
|
-
task default:
|
|
14
|
+
task default: %i[spec rubocop]
|
|
7
15
|
|
|
8
16
|
desc 'Release gem and create GitHub release'
|
|
9
17
|
task github_release: :release do
|
|
@@ -14,9 +22,9 @@ task github_release: :release do
|
|
|
14
22
|
# Check if gh CLI is available
|
|
15
23
|
unless system('which gh > /dev/null 2>&1')
|
|
16
24
|
puts "\n⚠️ GitHub CLI (gh) not found"
|
|
17
|
-
puts
|
|
18
|
-
puts
|
|
19
|
-
puts
|
|
25
|
+
puts 'To create a GitHub release with auto-generated changelog, install gh:'
|
|
26
|
+
puts ' brew install gh # macOS with Homebrew'
|
|
27
|
+
puts ' # or visit: https://github.com/cli/cli#installation'
|
|
20
28
|
puts "\nYou can manually create the release with:"
|
|
21
29
|
puts " gh release create v#{GrapeLogging::VERSION} --generate-notes"
|
|
22
30
|
next
|
|
@@ -28,8 +36,8 @@ task github_release: :release do
|
|
|
28
36
|
if system('gh', 'release', 'create', version, '--generate-notes', '--verify-tag')
|
|
29
37
|
puts "✅ GitHub release #{version} created successfully"
|
|
30
38
|
else
|
|
31
|
-
puts
|
|
32
|
-
puts
|
|
39
|
+
puts '❌ Failed to create GitHub release'
|
|
40
|
+
puts 'You can manually create it with:'
|
|
33
41
|
puts " gh release create '#{version}' --generate-notes --verify-tag"
|
|
34
42
|
end
|
|
35
43
|
end
|
data/grape_logging.gemspec
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
lib = File.expand_path('
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
require 'grape_logging/version'
|
|
4
4
|
|
|
@@ -16,13 +16,11 @@ Gem::Specification.new do |spec|
|
|
|
16
16
|
spec.license = 'MIT'
|
|
17
17
|
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
-
spec.bindir =
|
|
19
|
+
spec.bindir = 'exe'
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
21
|
spec.require_paths = ['lib']
|
|
22
22
|
|
|
23
|
-
spec.add_dependency 'grape', '
|
|
23
|
+
spec.add_dependency 'grape', '>= 2.4.0'
|
|
24
24
|
spec.add_dependency 'rack'
|
|
25
|
-
|
|
26
|
-
spec.add_development_dependency 'rake', '~> 13.3'
|
|
27
|
-
spec.add_development_dependency 'rspec', '~> 3.5'
|
|
25
|
+
spec.add_dependency 'zeitwerk'
|
|
28
26
|
end
|
|
@@ -3,9 +3,9 @@ module GrapeLogging
|
|
|
3
3
|
class Logstash
|
|
4
4
|
def call(severity, datetime, _, data)
|
|
5
5
|
{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:
|
|
6
|
+
'@timestamp': datetime.iso8601,
|
|
7
|
+
'@version': '1',
|
|
8
|
+
severity: severity
|
|
9
9
|
}.merge!(format(data)).to_json + "\n"
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
require 'rack/utils'
|
|
2
|
-
|
|
3
1
|
module GrapeLogging
|
|
4
2
|
module Formatters
|
|
5
3
|
class Rails
|
|
6
|
-
|
|
7
4
|
def call(severity, datetime, _, data)
|
|
8
5
|
if data.is_a?(String)
|
|
9
6
|
"#{severity[0..0]} [#{datetime}] #{severity} -- : #{data}\n"
|
|
@@ -24,7 +21,7 @@ module GrapeLogging
|
|
|
24
21
|
[
|
|
25
22
|
"#{exception.message} (#{exception.class})",
|
|
26
23
|
backtrace_array.join("\n")
|
|
27
|
-
].reject{|line| line ==
|
|
24
|
+
].reject { |line| line == '' }.join("\n")
|
|
28
25
|
end
|
|
29
26
|
|
|
30
27
|
def format_hash(hash)
|
|
@@ -32,7 +29,7 @@ module GrapeLogging
|
|
|
32
29
|
# Completed 200 OK in 958ms (Views: 951.1ms | ActiveRecord: 3.8ms)
|
|
33
30
|
# See: actionpack/lib/action_controller/log_subscriber.rb
|
|
34
31
|
|
|
35
|
-
message =
|
|
32
|
+
message = ''
|
|
36
33
|
additions = []
|
|
37
34
|
status = hash.delete(:status)
|
|
38
35
|
params = hash.delete(:params)
|
|
@@ -47,13 +44,12 @@ module GrapeLogging
|
|
|
47
44
|
message << " Parameters: #{params.inspect}\n" if params
|
|
48
45
|
|
|
49
46
|
message << "Completed #{status} #{::Rack::Utils::HTTP_STATUS_CODES[status]} in #{total_time}ms"
|
|
50
|
-
message << " (#{additions.join(
|
|
47
|
+
message << " (#{additions.join(' | '.freeze)})" unless additions.empty?
|
|
51
48
|
message << "\n"
|
|
52
49
|
message << "\n" if defined?(::Rails.env) && ::Rails.env.development?
|
|
53
50
|
|
|
54
51
|
message
|
|
55
52
|
end
|
|
56
|
-
|
|
57
53
|
end
|
|
58
54
|
end
|
|
59
55
|
end
|
|
@@ -2,7 +2,7 @@ module GrapeLogging
|
|
|
2
2
|
module Loggers
|
|
3
3
|
class ClientEnv < GrapeLogging::Loggers::Base
|
|
4
4
|
def parameters(request, _)
|
|
5
|
-
{ ip: request.env[
|
|
5
|
+
{ ip: request.env['HTTP_X_FORWARDED_FOR'] || request.env['REMOTE_ADDR'], ua: request.env['HTTP_USER_AGENT'] }
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
8
|
end
|
|
@@ -3,7 +3,7 @@ module GrapeLogging
|
|
|
3
3
|
class FilterParameters < GrapeLogging::Loggers::Base
|
|
4
4
|
AD_PARAMS = 'action_dispatch.request.parameters'.freeze
|
|
5
5
|
|
|
6
|
-
def initialize(filter_parameters = nil, replacement = nil, exceptions = %w
|
|
6
|
+
def initialize(filter_parameters = nil, replacement = nil, exceptions = %w[controller action format])
|
|
7
7
|
@filter_parameters = filter_parameters || (defined?(::Rails.application) ? ::Rails.application.config.filter_parameters : [])
|
|
8
8
|
@replacement = replacement || '[FILTERED]'
|
|
9
9
|
@exceptions = exceptions
|
|
@@ -16,7 +16,7 @@ module GrapeLogging
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def parameter_filter
|
|
19
|
-
@parameter_filter ||= ParameterFilter.new(@replacement, @filter_parameters)
|
|
19
|
+
@parameter_filter ||= GrapeLogging::Util::ParameterFilter.new(@replacement, @filter_parameters)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def safe_parameters(request)
|
|
@@ -30,8 +30,8 @@ module GrapeLogging
|
|
|
30
30
|
|
|
31
31
|
def clean_parameters(parameters)
|
|
32
32
|
original_encoding_map = build_encoding_map(parameters)
|
|
33
|
-
params = transform_key_encoding(parameters, Hash.new{ |h, _| [Encoding::ASCII_8BIT, h] })
|
|
34
|
-
cleaned_params = parameter_filter.filter(params).
|
|
33
|
+
params = transform_key_encoding(parameters, Hash.new { |h, _| [Encoding::ASCII_8BIT, h] })
|
|
34
|
+
cleaned_params = parameter_filter.filter(params).except(*@exceptions)
|
|
35
35
|
transform_key_encoding(cleaned_params, original_encoding_map)
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
module GrapeLogging
|
|
2
2
|
module Loggers
|
|
3
3
|
class RequestHeaders < GrapeLogging::Loggers::Base
|
|
4
|
-
|
|
5
4
|
HTTP_PREFIX = 'HTTP_'.freeze
|
|
6
5
|
|
|
7
6
|
def parameters(request, _)
|
|
@@ -16,7 +15,6 @@ module GrapeLogging
|
|
|
16
15
|
|
|
17
16
|
{ headers: headers }
|
|
18
17
|
end
|
|
19
|
-
|
|
20
18
|
end
|
|
21
19
|
end
|
|
22
20
|
end
|
|
@@ -11,12 +11,11 @@ module GrapeLogging
|
|
|
11
11
|
# For example, if you POST on a PUT endpoint, response.body is egal to """".
|
|
12
12
|
# It's strange, but it's the Grape behavior...
|
|
13
13
|
def serialized_response_body(response)
|
|
14
|
-
|
|
15
14
|
if response.respond_to?(:body)
|
|
16
15
|
# Rack responses
|
|
17
16
|
begin
|
|
18
|
-
response.body.map{ |body| JSON.parse(body.to_s) }
|
|
19
|
-
rescue # No reason to have "=> e" here when we don't use it..
|
|
17
|
+
response.body.map { |body| JSON.parse(body.to_s) }
|
|
18
|
+
rescue StandardError # No reason to have "=> e" here when we don't use it..
|
|
20
19
|
response.body
|
|
21
20
|
end
|
|
22
21
|
else
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
require 'grape'
|
|
2
|
-
|
|
3
1
|
module GrapeLogging
|
|
4
2
|
module Middleware
|
|
5
3
|
class RequestLogger < Grape::Middleware::Base
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
if defined?(ActiveRecord)
|
|
5
|
+
ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
|
|
6
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
7
|
+
GrapeLogging::Timings.append_db_runtime(event)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
11
10
|
|
|
12
11
|
# Persist response status & response (body)
|
|
13
12
|
# to use int in parameters
|
|
14
13
|
attr_accessor :response_status, :response_body
|
|
15
14
|
|
|
16
|
-
def initialize(app, options
|
|
15
|
+
def initialize(app, **options)
|
|
17
16
|
super
|
|
18
17
|
|
|
19
18
|
@included_loggers = @options[:include] || []
|
|
20
|
-
@reporter =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
@reporter =
|
|
20
|
+
if options[:instrumentation_key]
|
|
21
|
+
Reporters::ActiveSupportReporter.new(@options[:instrumentation_key])
|
|
22
|
+
else
|
|
23
|
+
Reporters::LoggerReporter.new(@options[:logger], @options[:formatter], @options[:log_level])
|
|
24
|
+
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def before
|
|
@@ -70,7 +70,9 @@ module GrapeLogging
|
|
|
70
70
|
# when no error occurs.
|
|
71
71
|
if error
|
|
72
72
|
# Call with error & response
|
|
73
|
-
|
|
73
|
+
status, message = status_and_message(error)
|
|
74
|
+
|
|
75
|
+
after(status, message)
|
|
74
76
|
|
|
75
77
|
# Throw again
|
|
76
78
|
throw(:error, error)
|
|
@@ -99,7 +101,7 @@ module GrapeLogging
|
|
|
99
101
|
path: request.path,
|
|
100
102
|
params: request.params,
|
|
101
103
|
host: request.host,
|
|
102
|
-
request_id: env['action_dispatch.request_id']
|
|
104
|
+
request_id: env['action_dispatch.request_id']
|
|
103
105
|
}
|
|
104
106
|
end
|
|
105
107
|
|
|
@@ -148,6 +150,17 @@ module GrapeLogging
|
|
|
148
150
|
logger.send(method_name) if logger.respond_to?(method_name)
|
|
149
151
|
end
|
|
150
152
|
end
|
|
153
|
+
|
|
154
|
+
def status_and_message(error)
|
|
155
|
+
case Gem::Version.new(Grape::VERSION)
|
|
156
|
+
when Gem::Requirement.new('>= 3.3.0')
|
|
157
|
+
# `error` is a `Grape::Exceptions::ErrorResponse`
|
|
158
|
+
[error.status, error.message]
|
|
159
|
+
else
|
|
160
|
+
# `error` is a `Hash`
|
|
161
|
+
[error[:status], error[:message]]
|
|
162
|
+
end
|
|
163
|
+
end
|
|
151
164
|
end
|
|
152
165
|
end
|
|
153
166
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
module GrapeLogging
|
|
2
|
+
module Reporters
|
|
3
|
+
class ActiveSupportReporter
|
|
4
|
+
def initialize(instrumentation_key)
|
|
5
|
+
@instrumentation_key = instrumentation_key
|
|
6
|
+
end
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
def perform(params)
|
|
9
|
+
ActiveSupport::Notifications.instrument @instrumentation_key, params
|
|
10
|
+
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
11
|
-
end
|
|
13
|
+
end
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@logger.formatter = formatter || @logger.formatter || GrapeLogging::Formatters::Default.new
|
|
1
|
+
module GrapeLogging
|
|
2
|
+
module Reporters
|
|
3
|
+
class LoggerReporter
|
|
4
|
+
def initialize(logger, formatter, log_level)
|
|
5
|
+
@logger = logger.clone || Logger.new(STDOUT)
|
|
6
|
+
@log_level = log_level || :info
|
|
7
|
+
@logger.formatter = formatter || @logger.formatter || GrapeLogging::Formatters::Default.new if @logger.respond_to?(:formatter=)
|
|
8
8
|
end
|
|
9
|
-
end
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
def perform(params)
|
|
11
|
+
@logger.send(@log_level, params)
|
|
12
|
+
end
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
module GrapeLogging
|
|
2
2
|
module Timings
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def db_runtime=(value)
|
|
3
|
+
def self.db_runtime=(value)
|
|
6
4
|
Thread.current[:grape_db_runtime] = value
|
|
7
5
|
end
|
|
8
6
|
|
|
9
|
-
def db_runtime
|
|
7
|
+
def self.db_runtime
|
|
10
8
|
Thread.current[:grape_db_runtime] ||= 0
|
|
11
9
|
end
|
|
12
10
|
|
|
13
|
-
def reset_db_runtime
|
|
11
|
+
def self.reset_db_runtime
|
|
14
12
|
self.db_runtime = 0
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
def append_db_runtime(event)
|
|
15
|
+
def self.append_db_runtime(event)
|
|
18
16
|
self.db_runtime += event.duration
|
|
19
17
|
end
|
|
20
18
|
end
|
|
21
|
-
end
|
|
19
|
+
end
|
|
@@ -1,99 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
module GrapeLogging
|
|
2
|
+
module Util
|
|
3
|
+
if defined?(Rails.application)
|
|
4
|
+
if Gem::Version.new(Rails.version) < Gem::Version.new('6.0.0')
|
|
5
|
+
class ParameterFilter < ActionDispatch::Http::ParameterFilter
|
|
6
|
+
def initialize(_replacement, filter_parameters)
|
|
7
|
+
super(filter_parameters)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
else
|
|
11
|
+
require 'active_support/parameter_filter'
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
class ParameterFilter < ActiveSupport::ParameterFilter
|
|
14
|
+
def initialize(_replacement, filter_parameters)
|
|
15
|
+
super(filter_parameters)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
14
18
|
end
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@filters = filters
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def filter(params)
|
|
29
|
-
compiled_filter.call(params)
|
|
30
|
-
end
|
|
19
|
+
else
|
|
20
|
+
#
|
|
21
|
+
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameter_filter.rb
|
|
22
|
+
# we could depend on Rails specifically, but that would us way to hefty!
|
|
23
|
+
#
|
|
24
|
+
class ParameterFilter
|
|
25
|
+
def initialize(replacement, filters = [])
|
|
26
|
+
@replacement = replacement
|
|
27
|
+
@filters = filters
|
|
28
|
+
end
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
def filter(params)
|
|
31
|
+
compiled_filter.call(params)
|
|
32
|
+
end
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
@compiled_filter ||= CompiledFilter.compile(@replacement, @filters)
|
|
36
|
-
end
|
|
34
|
+
private
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
def compiled_filter
|
|
37
|
+
@compiled_filter ||= CompiledFilter.compile(@replacement, @filters)
|
|
38
|
+
end
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
class CompiledFilter # :nodoc:
|
|
41
|
+
def self.compile(replacement, filters)
|
|
42
|
+
return ->(params) { params.dup } if filters.empty?
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
blocks << item
|
|
48
|
-
when Regexp
|
|
49
|
-
regexps << item
|
|
50
|
-
else
|
|
51
|
-
strings << Regexp.escape(item.to_s)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
44
|
+
strings = []
|
|
45
|
+
regexps = []
|
|
46
|
+
blocks = []
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
filters.each do |item|
|
|
49
|
+
case item
|
|
50
|
+
when Proc
|
|
51
|
+
blocks << item
|
|
52
|
+
when Regexp
|
|
53
|
+
regexps << item
|
|
54
|
+
else
|
|
55
|
+
strings << Regexp.escape(item.to_s)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?('\\.'.freeze) }
|
|
60
|
+
deep_strings, strings = strings.partition { |s| s.include?('\\.'.freeze) }
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
|
|
63
|
+
deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
new replacement, regexps, deep_regexps, blocks
|
|
66
|
+
end
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
@replacement = replacement
|
|
68
|
-
@regexps = regexps
|
|
69
|
-
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
|
70
|
-
@blocks = blocks
|
|
71
|
-
end
|
|
68
|
+
attr_reader :regexps, :deep_regexps, :blocks
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if regexps.any? { |r| key =~ r }
|
|
79
|
-
value = @replacement
|
|
80
|
-
elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
|
|
81
|
-
value = @replacement
|
|
82
|
-
elsif value.is_a?(Hash)
|
|
83
|
-
value = call(value, parents)
|
|
84
|
-
elsif value.is_a?(Array)
|
|
85
|
-
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
|
|
86
|
-
elsif blocks.any?
|
|
87
|
-
key = key.dup if key.duplicable?
|
|
88
|
-
value = value.dup if value.duplicable?
|
|
89
|
-
blocks.each { |b| b.call(key, value) }
|
|
70
|
+
def initialize(replacement, regexps, deep_regexps, blocks)
|
|
71
|
+
@replacement = replacement
|
|
72
|
+
@regexps = regexps
|
|
73
|
+
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
|
74
|
+
@blocks = blocks
|
|
90
75
|
end
|
|
91
|
-
parents.pop if deep_regexps
|
|
92
76
|
|
|
93
|
-
|
|
77
|
+
def call(original_params, parents = [])
|
|
78
|
+
filtered_params = {}
|
|
79
|
+
|
|
80
|
+
original_params.each do |key, value|
|
|
81
|
+
parents.push(key) if deep_regexps
|
|
82
|
+
if regexps.any? { |r| key =~ r }
|
|
83
|
+
value = @replacement
|
|
84
|
+
elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
|
|
85
|
+
value = @replacement
|
|
86
|
+
elsif value.is_a?(Hash)
|
|
87
|
+
value = call(value, parents)
|
|
88
|
+
elsif value.is_a?(Array)
|
|
89
|
+
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
|
|
90
|
+
elsif blocks.any?
|
|
91
|
+
key = key.dup if key.duplicable?
|
|
92
|
+
value = value.dup if value.duplicable?
|
|
93
|
+
blocks.each { |b| b.call(key, value) }
|
|
94
|
+
end
|
|
95
|
+
parents.pop if deep_regexps
|
|
96
|
+
|
|
97
|
+
filtered_params[key] = value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
filtered_params
|
|
101
|
+
end
|
|
94
102
|
end
|
|
95
|
-
|
|
96
|
-
filtered_params
|
|
97
103
|
end
|
|
98
104
|
end
|
|
99
105
|
end
|
data/lib/grape_logging.rb
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require '
|
|
3
|
-
require '
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
require 'grape_logging/reporters/active_support_reporter'
|
|
14
|
-
require 'grape_logging/reporters/logger_reporter'
|
|
15
|
-
require 'grape_logging/timings'
|
|
16
|
-
require 'grape_logging/middleware/request_logger'
|
|
17
|
-
require 'grape_logging/util/parameter_filter'
|
|
1
|
+
require 'grape'
|
|
2
|
+
require 'rack/utils'
|
|
3
|
+
require 'zeitwerk'
|
|
4
|
+
|
|
5
|
+
# load zeitwerk
|
|
6
|
+
Zeitwerk::Loader.for_gem.tap do |loader|
|
|
7
|
+
loader.inflector.inflect 'multi_io' => 'MultiIO'
|
|
8
|
+
loader.setup
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module GrapeLogging
|
|
12
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grape_logging
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- aserafin
|
|
@@ -14,14 +14,14 @@ dependencies:
|
|
|
14
14
|
name: grape
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: 2.4.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
26
|
version: 2.4.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
@@ -39,33 +39,19 @@ dependencies:
|
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: zeitwerk
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '13.3'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - "~>"
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '13.3'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rspec
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
45
|
+
- - ">="
|
|
60
46
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
62
|
-
type: :
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
63
49
|
prerelease: false
|
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
51
|
requirements:
|
|
66
|
-
- - "
|
|
52
|
+
- - ">="
|
|
67
53
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
54
|
+
version: '0'
|
|
69
55
|
description: This gem provides simple request logging for Grape with just few lines
|
|
70
56
|
of code you have to put in your project! In return you will get response codes,
|
|
71
57
|
paths, parameters and more!
|
|
@@ -78,6 +64,8 @@ extra_rdoc_files: []
|
|
|
78
64
|
files:
|
|
79
65
|
- ".github/workflows/ci.yml"
|
|
80
66
|
- ".gitignore"
|
|
67
|
+
- ".rubocop.yml"
|
|
68
|
+
- ".rubocop_todo.yml"
|
|
81
69
|
- CHANGELOG.md
|
|
82
70
|
- CONTRIBUTING.md
|
|
83
71
|
- Gemfile
|
|
@@ -124,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
124
112
|
- !ruby/object:Gem::Version
|
|
125
113
|
version: '0'
|
|
126
114
|
requirements: []
|
|
127
|
-
rubygems_version: 3.6.
|
|
115
|
+
rubygems_version: 3.6.9
|
|
128
116
|
specification_version: 4
|
|
129
117
|
summary: Out of the box request logging for Grape!
|
|
130
118
|
test_files: []
|