Compare commits

..

45 commits

Author SHA1 Message Date
9f35f74bd5
Merge pull request #96 from n-rodriguez/wip/improve
Some checks failed
CI / test (3.0) (push) Has been cancelled
CI / test (3.1) (push) Has been cancelled
CI / test (3.2) (push) Has been cancelled
CI / test (3.3) (push) Has been cancelled
CI / test (3.4) (push) Has been cancelled
CI / test (4.0) (push) Has been cancelled
CI / lint (push) Has been cancelled
Improve gem loading
2026-03-05 14:10:28 -08:00
Nicolas Rodriguez
073a88614b Update CHANGELOG.md 2026-03-05 18:27:36 +01:00
Nicolas Rodriguez
df56d571b7 Use zeitwerk to load gem 2026-03-02 03:47:54 +01:00
Nicolas Rodriguez
3b2ebd5669 Move dev dependencies to Gemfile 2026-03-02 03:27:11 +01:00
f9d417f2d6
Merge pull request #95 from samsonjs/ruby-4
Add Ruby 4.0 to test matrix
2026-01-02 11:55:51 -08:00
189e6f0857
Add Ruby 4.0 to test matrix 2026-01-02 11:54:42 -08:00
48ab8c414b
Merge pull request #94 from leoarnold/leoarnold/ostruct
Remove OpenStruct
2025-12-11 17:46:07 -08:00
Leo Arnold
a8290d3522 Remove OpenStruct 2025-12-12 00:36:10 +01:00
d97750a318
Update README.md 2025-08-21 07:35:44 -07:00
ffdd1a617c
Bump version to 3.0.1 2025-08-07 12:07:16 -07:00
39f6a064f1
Preparing for release, 3.0.0 2025-08-07 12:04:58 -07:00
ed25898685
Add support for Grape 2.4 (#93)
* Fix RequestLogger middleware to handle Grape 2.4 breaking chnage

* Make RequestLogger#initialize signature match Grape 2.4

* Update changelog

* Require grape >= 2.4 in gemspec

---------

Co-authored-by: Cedric Darricau <cedricdarricau@gmail.com>
2025-08-07 12:03:04 -07:00
5a9ef5d801
Add rubocop with a todo list (#90)
* Add rubocop with a todo list

* Run rubocop as part of the CI workflow

* Autofix for RuboCop: Layout/ElseAlignment

* Regen autogen, removing all claude-scratchpad/*

* Autofix RuboCop Layout/EmptyLine

* AutoFix RuboCop Style/ZeroLengthPredicate

* AutoFix RuboCop Layout/EmptyLinesAroundAccessModifier

* AutoFix RuboCop Layout/EmptyLinesAroundMethodBody

* AutoFix RuboCop Layout/EmptyLinesAroundBlockBody

* AutoFix RuboCop Layout/EmptyLinesAroundClassBody

* AutoFix RuboCop Layout/EndAlignment

* AutoFix RuboCop Layout/ExtraSpacing

* AutoFix RuboCop Layout/FirstHashElementIndentation

* AutoFix RuboCop Layout/HashAlignment

* AutoFix RuboCop Layout/IndentationWidth

* Regenerate todo

* AutoFix RuboCop Layout/SpaceBeforeBlockBraces

* AutoFix RuboCop Layout/SpaceBeforeComma

* AutoFix RuboCop Layout/SpaceInsideBlockBraces

* AutoFix RuboCop Layout/SpaceInsideHashLiteralBraces

* AutoFix RuboCop Layout/TrailingEmptyLines

* Update ci.yml

Co-authored-by: Pieter Oliver <68863060+pieterocp@users.noreply.github.com>

* WIP: Remove claude-scratchpad cruft from rubocop todo

* Specify files explicity in rubocop rake task

* Pin rubocop version to 1.77.0

* AutoFix RuboCop Style/TrailingCommaInHashLiteral

* AutoFix RuboCop Style/StringLiteralsInInterpolation

* AutoFix RuboCop Style/StringLiterals

* AutoFix RuboCop Style/RescueStandardError

* AutoFix RuboCop Style/RedundantPercentQ

* AutoFix RuboCop Style/RedundantConstantBase

* AutoFix RuboCop Style/QuotedSymbols

* AutoFix RuboCop Style/PercentLiteralDelimiters

* AutoFix RuboCop Style/ParallelAssignment

* AutoFix RuboCop Style/MultilineIfModifier

* AutoFix RuboCop Style/Lambda

* AutoFix RuboCop Style/IfUnlessModifier

* AutoFix RuboCop Style/HashSyntax

* AutoFix RuboCop Style/GuardClause

* AutoFix RuboCop Style/ExpandPathArguments

* AutoFix RuboCop Style/BlockDelimiters

* AutoFix RuboCop Style/BlockComments

* AutoFix RuboCop Lint/UnusedMethodArgument

* AutoFix RuboCop Lint/SymbolConversion

* Fix auto-gen formatting + RuboCop AutoFix Style/ModuleFunction

* Code style

---------

Co-authored-by: Pieter Oliver <pieter.oliver@nourishcare.com>
Co-authored-by: Pieter Oliver <68863060+pieterocp@users.noreply.github.com>
2025-07-14 15:20:17 -07:00
ca80cfef6c
Bump version to 2.1.2 2025-07-09 18:17:44 -07:00
08823ae0d1
Merge pull request #92 from 1SecondEveryday/fix/filter-param-symbol-keys
Handle symbol param keys during filtering
2025-07-09 18:16:34 -07:00
586dc239dc
Prepare for release, 2.1.1 2025-07-09 18:15:04 -07:00
7e15b97cb4
Handle symbol param keys during filtering
In testing these keys can be symbols, so when we're working with
encodings make sure we have strings before trying to force any encodings
on keys.
2025-07-09 18:11:05 -07:00
a17c5f52e4
Add me to authors in gemspec, fix formatting of text 2025-07-09 17:54:16 -07:00
dbba26bc2c
Bump version to 2.1.1 2025-07-09 17:46:03 -07:00
31d46bc8f8
Bump version to 2.1.0 2025-07-09 17:44:19 -07:00
4fabe1aa37
Merge pull request #91 from 1SecondEveryday/add-request-id
Add ActionDispatch request ID to logger arguments hash
2025-07-09 17:43:57 -07:00
b8452343f0
Preparing for release, 2.1.0 2025-07-09 17:43:10 -07:00
71c1adf3eb
Add ActionDispatch request ID to logger arguments hash 2025-07-09 17:40:48 -07:00
a4f6088a17
Remove remote name from releasing doc 2025-07-09 16:58:44 -07:00
c19b1d3732
Bump version to 2.0.1 2025-07-09 16:57:51 -07:00
362dd0a92e
Bump version to 2.0.0 2025-07-09 16:55:57 -07:00
0d738e4e7e
Prepare for 2.0.0 release (#89)
* Add a changelog

* Add release and contributor docs based on grape-active_model_serializers (needs more work)

* Rename changelog to look like it's the 80s

* Tweak releasing doc

* Automate and document github releases

* RIP hash rocket
2025-07-09 16:54:59 -07:00
9e4fb8266b
Add gem version badge to readme 2025-06-28 07:44:35 -04:00
f35dc1e9d6
Code style 2025-06-28 07:37:22 -04:00
585cd29a7d
Merge pull request #88 from 1SecondEveryday/fix/specs
Fix the specs
2025-06-28 07:16:33 -04:00
d8d3f3ca1e
Fix the specs 2025-06-28 07:14:06 -04:00
16062114b1
Merge pull request #87 from pieterocp/misc-typoes
[Misc] Nitpick typoes
2025-06-27 15:19:19 -04:00
Pieter Oliver
fe2d196494 Fix some small, non breaking changes typoes 2025-06-27 16:44:21 +01:00
Dhruv Paranjape
b94fcb3046
LoggerReporter: clone the logger parameter (#77) 2025-06-27 05:47:15 -07:00
f7341032d5
Merge pull request #75 from thedarkside/master
Replaced all 'use' examples in README.md with 'insert_before'
2025-06-27 08:45:59 -04:00
59813dedbc
Merge pull request #70 from oslivan/master
fix view time precise issue
2025-06-27 08:44:33 -04:00
0d70063ae5
Merge pull request #54 from abicky/scrub-invalid-byte-sequence-keys
Convert parameter keys to ASCII-8BIT before filtering
2025-06-27 08:42:15 -04:00
ce103dad5a
Get specs running again, but they still fail (#86)
* Get specs running again, but they still fail on Ruby 3.4

* Add Ruby 3.4 to test matrix

* Remove bundler from dev dependencies
2025-06-27 05:16:48 -07:00
Eshton Robateau
cc29dc7868
Implement GitHub actions ci (#85)
* setup github actions ci

* add ruby 3.0 in versions to test

* Drop really old EOL Ruby versions, remove DISABLE_SPRING

---------

Co-authored-by: Sami Samhuri <sami@samhuri.net>
2025-06-27 04:34:33 -07:00
thedarkside
01846a40ef
Replaced all 'use' examples in README.md with 'insert_before' 2021-10-08 22:04:12 +02:00
Luong Vo
6e562a2788
doc: update how grape logging middleware should be placed (#74) 2021-07-12 09:02:43 +02:00
Adrian Serafin
8afa893a69 bump version to 1.8.4 2020-08-26 11:12:37 +02:00
David Shaffer
36d23146a0
Bugfix: Require ActiveSupport::ParameterFilter before inheriting from it (#72) 2020-08-26 11:10:14 +02:00
yanpz
ea6afd1d0f fix view time precise issue 2020-04-04 20:49:13 +08:00
abicky
58e7475b64 Convert parameter keys to ASCII-8BIT before filtering
This commit resolves https://github.com/aserafin/grape_logging/issues/53.
2018-09-26 00:15:27 +09:00
36 changed files with 1102 additions and 373 deletions

36
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: CI
on:
push:
branches: [master]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ["3.0", "3.1", "3.2", "3.3", "3.4", "4.0"]
steps:
- name: Checkout code
uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true
- name: Install dependencies
run: bundle install --jobs 4 --retry 3
- name: Run tests
run: bundle exec rake spec
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: "4.0"
bundler-cache: true
- name: Install dependencies
run: bundle install
- name: Run RuboCop
run: bundle exec rake rubocop

1
.gitignore vendored
View file

@ -8,3 +8,4 @@
/spec/reports/ /spec/reports/
/tmp/ /tmp/
.rspec .rspec
.idea/

15
.rubocop.yml Normal file
View file

@ -0,0 +1,15 @@
inherit_from: .rubocop_todo.yml
AllCops:
NewCops: enable
TargetRubyVersion: 3.0
Metrics/BlockLength:
CountAsOne: [array, hash, heredoc, method_call]
Metrics/ClassLength:
CountAsOne: [array, hash, heredoc, method_call]
Metrics/MethodLength:
CountAsOne: [array, hash, heredoc, method_call]
Max: 20

160
.rubocop_todo.yml Normal file
View file

@ -0,0 +1,160 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2025-07-10 10:25:51 UTC using RuboCop version 1.77.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 3
# Configuration parameters: EnforcedStyle, AllowedGems, Include.
# SupportedStyles: Gemfile, gems.rb, gemspec
# Include: **/*.gemspec, **/Gemfile, **/gems.rb
Gemspec/DevelopmentDependencies:
Exclude:
- "grape_logging.gemspec"
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Severity, Include.
# Include: **/*.gemspec
Gemspec/RequireMFA:
Exclude:
- "grape_logging.gemspec"
# Offense count: 1
# Configuration parameters: Severity, Include.
# Include: **/*.gemspec
Gemspec/RequiredRubyVersion:
Exclude:
- "grape_logging.gemspec"
# Offense count: 1
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
Lint/DuplicateBranch:
Exclude:
- "lib/grape_logging/util/parameter_filter.rb"
# Offense count: 1
# Configuration parameters: AllowedParentClasses.
Lint/MissingSuper:
Exclude:
- "lib/grape_logging/loggers/filter_parameters.rb"
# Offense count: 3
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 38
# Offense count: 8
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
# AllowedMethods: refine
Metrics/BlockLength:
Max: 90
# Offense count: 3
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 18
# Offense count: 2
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity:
Max: 19
# Offense count: 2
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
# SupportedStyles: snake_case, normalcase, non_integer
# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
Naming/VariableNumber:
Exclude:
- "spec/lib/grape_logging/formatters/rails_spec.rb"
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: MinBranchesCount.
Style/CaseLikeIf:
Exclude:
- "lib/grape_logging/formatters/default.rb"
- "lib/grape_logging/formatters/logstash.rb"
- "lib/grape_logging/formatters/rails.rb"
# Offense count: 17
# Configuration parameters: AllowedConstants.
Style/Documentation:
Enabled: false
# Offense count: 29
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, always_true, never
Style/FrozenStringLiteralComment:
Enabled: false
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/GlobalStdStream:
Exclude:
- "lib/grape_logging/reporters/logger_reporter.rb"
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: literals, strict
Style/MutableConstant:
Exclude:
- "lib/grape_logging/version.rb"
# Offense count: 10
Style/OpenStructUse:
Exclude:
- "spec/lib/grape_logging/loggers/client_env_spec.rb"
- "spec/lib/grape_logging/loggers/filter_parameters_spec.rb"
- "spec/lib/grape_logging/loggers/request_headers_spec.rb"
- "spec/lib/grape_logging/loggers/response_spec.rb"
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
# AllowedMethods: present?, blank?, presence, try, try!
Style/SafeNavigation:
Exclude:
- "lib/grape_logging/formatters/rails.rb"
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/SlicingWithRange:
Exclude:
- "lib/grape_logging/loggers/request_headers.rb"
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: RequireEnglish, EnforcedStyle.
# SupportedStyles: use_perl_names, use_english_names, use_builtin_english_names
Style/SpecialGlobalVars:
Exclude:
- "spec/spec_helper.rb"
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode.
Style/StringConcatenation:
Exclude:
- "lib/grape_logging/formatters/json.rb"
- "lib/grape_logging/formatters/lograge.rb"
- "lib/grape_logging/formatters/logstash.rb"
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments.
# AllowedMethods: define_method
Style/SymbolProc:
Exclude:
- "lib/grape_logging/util/parameter_filter.rb"
# Offense count: 11
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
# URISchemes: http, https
Layout/LineLength:
Max: 203

View file

@ -1,6 +0,0 @@
language: ruby
rvm:
- 2.3.1
cache: bundler
script:
- bundle exec rspec

225
CHANGELOG.md Normal file
View file

@ -0,0 +1,225 @@
# Changelog
## [3.0.1] - Unreleased
### Changed or Fixed or Added
### Changed
- Move dev dependencies to Gemfile
- Use zeitwerk to load gem
[3.0.1]: https://github.com/aserafin/grape_logging/compare/v3.0.0...master
## [3.0.0] - 2025-08-07
### Changed
- [#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).
[3.0.0]: https://github.com/aserafin/grape_logging/compare/v2.1.1...v3.0.0
## [2.1.1] - 2025-07-09
### Fixed
- [#92](https://github.com/aserafin/grape_logging/pull/92) Handle symbol param keys during filtering - [@samsonjs](https://github.com/samsonjs).
[2.1.1]: https://github.com/aserafin/grape_logging/compare/v2.1.0...v2.1.1
## [2.1.0] - 2025-07-09
### Added
- [#91](https://github.com/aserafin/grape_logging/pull/91) Add ActionDispatch request ID to logger arguments hash as `:request_id` - [@samsonjs](https://github.com/samsonjs).
[2.1.0]: https://github.com/aserafin/grape_logging/compare/v2.0.0...v2.1.0
## [2.0.0] - 2025-07-09
### Changed
- **BREAKING**: Updated to support Grape 2.1 and Rack 3.1
- Minimum supported Ruby version is now 3.0
- Replaced Travis CI with GitHub Actions for continuous integration
- Updated all README examples to use `insert_before` instead of `use` for proper middleware placement
### Fixed
- Fixed LoggerReporter to clone the logger parameter to prevent shared state issues (#77)
- Fixed view time precision issue by rounding to 2 decimal places
- Fixed invalid byte sequence handling for parameter keys by properly managing string encodings (#54)
- Fixed various typos in code comments and spec descriptions (#87)
- Fixed specs to work with Ruby 3.4's hash inspect format changes
### Documentation
- Clarified middleware placement requirements in README - must be inserted before Grape::Middleware::Error (#74)
- Added gem version badge to README
[2.0.0]: https://github.com/aserafin/grape_logging/compare/v1.8.4...v2.0.0
## [1.8.4] - 2021-10-29
### Fixed
- Rails 6 compatibility improvements
- Various bug fixes and dependency updates
[1.8.4]: https://github.com/aserafin/grape_logging/compare/v1.8.3...v1.8.4
## [1.8.3] - 2020-02-27
### Fixed
- Performance improvements
- Bug fixes for edge cases
[1.8.3]: https://github.com/aserafin/grape_logging/compare/v1.8.2...v1.8.3
## [1.8.2] - 2019-10-08
### Fixed
- Thread safety improvements
- Minor bug fixes
Note: This version was tagged as "v.1.8.2" (with extra dot)
[1.8.2]: https://github.com/aserafin/grape_logging/compare/v1.8.1...v.1.8.2
## [1.8.1] - 2019-08-07
### Fixed
- Bug fixes for parameter filtering
- Improved error handling
[1.8.1]: https://github.com/aserafin/grape_logging/compare/v1.8.0...v1.8.1
## [1.8.0] - 2019-05-30
### Added
- Rails formatter for better Rails integration
- Improved Rails instrumentation support
[1.8.0]: https://github.com/aserafin/grape_logging/compare/v1.7.0...v1.8.0
## [1.7.0] - 2017-11-09
### Added
- Logstash formatter for ELK stack integration
- Enhanced JSON formatting options
[1.7.0]: https://github.com/aserafin/grape_logging/compare/v1.6.0...v1.7.0
## [1.6.0] - 2017-07-20
### Added
- MultiIO support for logging to multiple destinations simultaneously
- Can now log to both file and STDOUT
[1.6.0]: https://github.com/aserafin/grape_logging/compare/v1.5.0...v1.6.0
## [1.5.0] - 2017-06-15
### Added
- Configurable log levels
- Better control over logging verbosity
[1.5.0]: https://github.com/aserafin/grape_logging/compare/v1.4.0...v1.5.0
## [1.4.0] - 2017-01-12
### Added
- FilterParameters logger for sensitive parameter filtering
- Automatic Rails filter_parameters integration when available
[1.4.0]: https://github.com/aserafin/grape_logging/compare/v1.3.0...v1.4.0
## [1.3.0] - 2016-12-08
### Added
- RequestHeaders logger for logging HTTP request headers
- ClientEnv logger for logging client IP and user agent
[1.3.0]: https://github.com/aserafin/grape_logging/compare/v1.2.1...v1.3.0
## [1.2.1] - 2016-04-14
### Added
- JSON formatter for structured logging
- Rails instrumentation support via ActiveSupport::Notifications
### Fixed
- Parameter handling improvements
[1.2.1]: https://github.com/aserafin/grape_logging/compare/v1.2.0...v1.2.1
## [1.2.0] - 2016-01-21
### Added
- Response logger for logging response details
- Improved parameter logging
### Changed
- Better integration with Grape middleware stack
[1.2.0]: https://github.com/aserafin/grape_logging/compare/v1.1.3...v1.2.0
## [1.1.3] - 2015-12-03
### Fixed
- Bug fixes for Grape 0.14 compatibility
- Improved error handling
[1.1.3]: https://github.com/aserafin/grape_logging/compare/v1.1.2...v1.1.3
## [1.1.2] - 2015-11-19
### Fixed
- Performance optimizations
- Minor bug fixes
[1.1.2]: https://github.com/aserafin/grape_logging/compare/v1.1.1...v1.1.2
## [1.1.1] - 2015-11-12
### Fixed
- Critical bug fix for middleware initialization
Note: This version was tagged as "v.1.1.1" (with extra dot)
[1.1.1]: https://github.com/aserafin/grape_logging/compare/v1.1.0...v.1.1.1
## [1.1.0] - 2015-11-09
### Added
- Pluggable logger architecture
- Support for custom loggers via include option
- Base logger class for extending functionality
### Changed
- Refactored middleware for better extensibility
[1.1.0]: https://github.com/aserafin/grape_logging/compare/v1.0.3...v1.1.0
## [1.0.3] - 2015-11-05
### Fixed
- Compatibility fixes for different Grape versions
- Bug fixes
[1.0.3]: https://github.com/aserafin/grape_logging/compare/v1.0.2...v1.0.3
## [1.0.2] - 2015-10-29
### Fixed
- Minor bug fixes and improvements
[1.0.2]: https://github.com/aserafin/grape_logging/compare/v1.0.1...v1.0.2
## [1.0.1] - 2015-10-22
### Fixed
- Initial bug fixes after 1.0 release
[1.0.1]: https://github.com/aserafin/grape_logging/compare/v1.0...v1.0.1
## [1.0] - 2015-10-15
### Added
- Initial release
- Request logging middleware for Grape APIs
- Basic request/response logging
- Configurable formatters
- Time tracking (total, db, view)

110
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,110 @@
# Contributing to grape_logging
This project is work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues.
## Fork the Project
Fork the project on Github and check out your copy.
```
git clone https://github.com/contributor/grape_logging.git
cd grape_logging
git remote add upstream https://github.com/aserafin/grape_logging.git
```
## Create a Topic Branch
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
```
git checkout master
git pull upstream master
git checkout -b my-feature-branch
```
## Bundle Install and Test
Ensure that you can build the project and run tests.
```
bundle install
bundle exec rake
```
## Write Tests
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to the spec directory.
## Write Code
Implement your feature or bug fix.
Ruby style is enforced with RuboCop. Run `bundle exec rubocop` and fix any style issues highlighted.
Make sure that `bundle exec rake` completes without errors.
## Write Documentation
Document any external behavior in the README.md.
## Update Changelog
Add a line to Changelog.md under *Next Release*. Make it look like every other line, including your name and link to your Github account.
## Commit Changes
Make sure git knows your name and email address:
```
git config --global user.name "Your Name"
git config --global user.email "contributor@example.com"
```
Writing good commit logs is important. A commit log should describe what changed and why.
```
git add ...
git commit
```
## Push
```
git push origin my-feature-branch
```
## Make a Pull Request
Go to https://github.com/contributor/grape_logging and select your feature branch. Click the 'Pull Request' button and fill out the form.
We'll try to review pull requests within a few days but as this is maintained by a small group of volunteers there is no guarantee that we'll look at it within any time frame, or at all. There's no maintenance guarantee.
## Discuss and Update
You may get feedback or requests for changes to your pull request. This is a big part of the submission process so don't be discouraged!
Some things that will increase the chance that your pull request is accepted:
- Write tests.
- Follow the Ruby style guide.
- Write a good commit message.
If you'd like to discuss a feature or bug fix before starting work, please [create an issue](https://github.com/aserafin/grape_logging/issues) first. This helps ensure your contribution aligns with the project's direction and avoids duplicate efforts.
## Rebase
If you've been working on a change for a while, rebase with upstream/master.
```
git fetch upstream
git rebase upstream/master
git push origin my-feature-branch -f
```
## Be Patient
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang in there!
## Thank You
Please do know that we really appreciate and value your time and work. We love you, really.

View file

@ -2,3 +2,10 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in grape_logging.gemspec # Specify your gem's dependencies in grape_logging.gemspec
gemspec gemspec
gem 'rake', '~> 13.3'
gem 'rspec', '~> 3.5'
# This is pinned to an exact version otherwise we can't know which rules
# are in play at any given time in different environments.
gem 'rubocop', '1.77.0'

View file

@ -1,7 +1,7 @@
# grape_logging # grape_logging
[![Code Climate](https://codeclimate.com/github/aserafin/grape_logging/badges/gpa.svg)](https://codeclimate.com/github/aserafin/grape_logging) [![Gem Version](https://badge.fury.io/rb/grape_logging.svg)](https://badge.fury.io/rb/grape_logging)
[![Build Status](https://travis-ci.org/aserafin/grape_logging.svg?branch=master)](https://travis-ci.org/aserafin/grape_logging) [![CI](https://github.com/aserafin/grape_logging/actions/workflows/ci.yml/badge.svg)](https://github.com/aserafin/grape_logging/actions/workflows/ci.yml)
## Installation ## Installation
@ -19,12 +19,12 @@ Or install it yourself as:
## Basic Usage ## Basic Usage
In your api file (somewhere on the top) In your API file (somewhere on the top), insert grape logging middleware before grape error middleware. This is important due to the behaviour of `lib/grape/middleware/error.rb`, which manipulates the status of the response when there is an error.
```ruby ```ruby
require 'grape_logging' require 'grape_logging'
logger.formatter = GrapeLogging::Formatters::Default.new logger.formatter = GrapeLogging::Formatters::Default.new
use GrapeLogging::Middleware::RequestLogger, { logger: logger } insert_before Grape::Middleware::Error, GrapeLogging::Middleware::RequestLogger, { logger: logger }
``` ```
**ProTip:** If your logger doesn't support setting formatter you can remove this line - it's optional **ProTip:** If your logger doesn't support setting formatter you can remove this line - it's optional
@ -114,7 +114,7 @@ end
You can change the formatter like so You can change the formatter like so
```ruby ```ruby
class MyAPI < Grape::API class MyAPI < Grape::API
use GrapeLogging::Middleware::RequestLogger, logger: logger, formatter: MyFormatter.new insert_before Grape::Middleware::Error, GrapeLogging::Middleware::RequestLogger, logger: logger, formatter: MyFormatter.new
end end
``` ```
@ -125,7 +125,8 @@ If you prefer some other format I strongly encourage you to do pull request with
You can include logging of other parts of the request / response cycle by including subclasses of `GrapeLogging::Loggers::Base` You can include logging of other parts of the request / response cycle by including subclasses of `GrapeLogging::Loggers::Base`
```ruby ```ruby
class MyAPI < Grape::API class MyAPI < Grape::API
use GrapeLogging::Middleware::RequestLogger, insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
logger: logger, logger: logger,
include: [ GrapeLogging::Loggers::Response.new, include: [ GrapeLogging::Loggers::Response.new,
GrapeLogging::Loggers::FilterParameters.new, GrapeLogging::Loggers::FilterParameters.new,
@ -158,7 +159,8 @@ You can control the level used to log. The default is `info`.
```ruby ```ruby
class MyAPI < Grape::API class MyAPI < Grape::API
use GrapeLogging::Middleware::RequestLogger, insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
logger: logger, logger: logger,
log_level: 'debug' log_level: 'debug'
end end
@ -170,7 +172,8 @@ You can choose to not pass the logger to ```grape_logging``` but instead send lo
First, config ```grape_logging```, like that: First, config ```grape_logging```, like that:
```ruby ```ruby
class MyAPI < Grape::API class MyAPI < Grape::API
use GrapeLogging::Middleware::RequestLogger, insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
instrumentation_key: 'grape_key', instrumentation_key: 'grape_key',
include: [ GrapeLogging::Loggers::Response.new, include: [ GrapeLogging::Loggers::Response.new,
GrapeLogging::Loggers::FilterParameters.new ] GrapeLogging::Loggers::FilterParameters.new ]
@ -206,10 +209,8 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
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). 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).
For maintainers releasing a new version, please see [RELEASING.md](RELEASING.md).
## Contributing ## Contributing
1. Fork it ( https://github.com/aserafin/grape_logging/fork ) See [CONTRIBUTING.md](CONTRIBUTING.md).
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

113
RELEASING.md Normal file
View file

@ -0,0 +1,113 @@
# Releasing grape_logging
There're no particular rules about when to release grape_logging. Release bug fixes frequently, features not so frequently and breaking API changes rarely.
### Pre-flight Checks
Run tests, check that all tests succeed locally.
```
bundle install
rake
```
Check that the last build succeeded in [GitHub Actions](https://github.com/aserafin/grape_logging/actions) for all supported platforms.
### Update Changelog
Change "Unreleased" in [CHANGELOG.md](https://github.com/aserafin/grape_logging/blob/master/CHANGELOG.md) to the new version and date:
```
## [1.8.5] - 2024-06-28
### Changed
- Description of changes
### Fixed
- Description of fixes
### Added
- Description of additions
[1.8.5]: https://github.com/aserafin/grape_logging/compare/v1.8.4...v1.8.5
```
Remove the line with "Your contribution here.", since there will be no more contributions to this release.
Only include the sections (Changed, Fixed, Added, etc.) that have actual changes.
Commit your changes.
```shell
git add CHANGELOG.md lib/grape_logging/version.rb
git commit -m "Preparing for release, 1.8.5."
git push
```
### Release on RubyGems and GitHub
#### Option 1: Automated (Recommended)
Use the combined task that releases the gem and creates a GitHub release:
```shell
rake github_release
```
This will:
1. Build and push the gem to RubyGems
2. Create and push the git tag
3. Create a GitHub release with auto-generated changelog
#### Option 2: Manual
First, release the gem:
```shell
rake release
```
Output will look something like:
```
grape_logging 1.8.5 built to pkg/grape_logging-1.8.5.gem.
Tagged v1.8.5.
Pushed git commits and tags.
Pushed grape_logging 1.8.5 to rubygems.org.
```
Then create the GitHub release on the web or using `gh`:
```
gh release create v1.8.5 --generate-notes --verify-tag
```
This uses GitHub's automatic changelog generation feature to create release notes from merged pull requests and commits since the last release.
### Prepare for the Next Version
Modify `lib/grape_logging/version.rb`, increment the version number (eg. change `1.8.5` to `1.8.6`).
```ruby
module GrapeLogging
VERSION = '1.8.6'.freeze
end
```
Add the next release to [CHANGELOG.md](https://github.com/aserafin/grape_logging/blob/master/CHANGELOG.md).
```
## [1.8.6] - Unreleased
### Changed or Fixed or Added
- Your contribution here.
[1.8.6]: https://github.com/aserafin/grape_logging/compare/v1.8.5...master
```
Commit your changes.
```
git add CHANGELOG.md lib/grape_logging/version.rb
git commit -m "Bump version to 1.8.6."
git push
```

View file

@ -1,2 +1,43 @@
require 'bundler/gem_tasks' require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.rspec_opts = ['-fd -c']
spec.pattern = FileList['spec/**/*_spec.rb']
end
RuboCop::RakeTask.new(:rubocop) do |t|
t.patterns = ['lib/**/*.rb', 'spec/**/*.rb', 'Rakefile', 'Gemfile', 'grape_logging.gemspec']
end
task default: %i[spec rubocop]
desc 'Release gem and create GitHub release'
task github_release: :release do
require 'grape_logging/version'
version = "v#{GrapeLogging::VERSION}"
# Check if gh CLI is available
unless system('which gh > /dev/null 2>&1')
puts "\n⚠️ GitHub CLI (gh) not found"
puts 'To create a GitHub release with auto-generated changelog, install gh:'
puts ' brew install gh # macOS with Homebrew'
puts ' # or visit: https://github.com/cli/cli#installation'
puts "\nYou can manually create the release with:"
puts " gh release create v#{GrapeLogging::VERSION} --generate-notes"
next
end
# Create GitHub release
puts "\nCreating GitHub release #{version}..."
if system('gh', 'release', 'create', version, '--generate-notes', '--verify-tag')
puts "✅ GitHub release #{version} created successfully"
else
puts '❌ Failed to create GitHub release'
puts 'You can manually create it with:'
puts " gh release create '#{version}' --generate-notes --verify-tag"
end
end

0
bin/console Normal file → Executable file
View file

View file

@ -1,29 +1,26 @@
# coding: utf-8 lib = File.expand_path('lib', __dir__)
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'grape_logging/version' require 'grape_logging/version'
Gem::Specification.new do |spec| Gem::Specification.new do |spec|
spec.name = 'grape_logging' spec.name = 'grape_logging'
spec.version = GrapeLogging::VERSION spec.version = GrapeLogging::VERSION
spec.authors = ['aserafin'] spec.authors = ['aserafin', 'Sami Samhuri']
spec.email = ['adrian@softmad.pl'] spec.email = ['adrian@softmad.pl', 'sami@samhuri.net']
spec.summary = %q{Out of the box request logging for Grape!} spec.summary = 'Out of the box request logging for Grape!'
spec.description = %q{This gem provides simple request logging for Grape with just few lines of code you have to put in your project! In return you will get response codes, paths, parameters and more!} spec.description = 'This gem provides simple request logging for Grape with just few lines ' \
'of code you have to put in your project! In return you will get response ' \
'codes, paths, parameters and more!'
spec.homepage = 'http://github.com/aserafin/grape_logging' spec.homepage = 'http://github.com/aserafin/grape_logging'
spec.license = 'MIT' spec.license = 'MIT'
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe" spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib'] spec.require_paths = ['lib']
spec.add_dependency 'grape' spec.add_dependency 'grape', '>= 2.4.0'
spec.add_dependency 'rack' spec.add_dependency 'rack'
spec.add_dependency 'zeitwerk'
spec.add_development_dependency 'bundler', '~> 1.8'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.5'
spec.add_development_dependency 'pry-byebug', '~> 3.4.2'
end end

View file

@ -1,17 +1,12 @@
require 'grape_logging/multi_io' require 'grape'
require 'grape_logging/version' require 'rack/utils'
require 'grape_logging/formatters/default' require 'zeitwerk'
require 'grape_logging/formatters/json'
require 'grape_logging/formatters/lograge' # load zeitwerk
require 'grape_logging/formatters/logstash' Zeitwerk::Loader.for_gem.tap do |loader|
require 'grape_logging/formatters/rails' loader.inflector.inflect 'multi_io' => 'MultiIO'
require 'grape_logging/loggers/base' loader.setup
require 'grape_logging/loggers/response' end
require 'grape_logging/loggers/filter_parameters'
require 'grape_logging/loggers/client_env' module GrapeLogging
require 'grape_logging/loggers/request_headers' end
require 'grape_logging/reporters/active_support_reporter'
require 'grape_logging/reporters/logger_reporter'
require 'grape_logging/timings'
require 'grape_logging/middleware/request_logger'
require 'grape_logging/util/parameter_filter'

View file

@ -18,6 +18,7 @@ module GrapeLogging
end end
private private
def format_hash(hash) def format_hash(hash)
hash.keys.sort.map { |key| "#{key}=#{hash[key]}" }.join(' ') hash.keys.sort.map { |key| "#{key}=#{hash[key]}" }.join(' ')
end end

View file

@ -3,9 +3,9 @@ module GrapeLogging
class Logstash class Logstash
def call(severity, datetime, _, data) def call(severity, datetime, _, data)
{ {
:'@timestamp' => datetime.iso8601, '@timestamp': datetime.iso8601,
:'@version' => '1', '@version': '1',
:severity => severity severity: severity
}.merge!(format(data)).to_json + "\n" }.merge!(format(data)).to_json + "\n"
end end

View file

@ -1,9 +1,6 @@
require 'rack/utils'
module GrapeLogging module GrapeLogging
module Formatters module Formatters
class Rails class Rails
def call(severity, datetime, _, data) def call(severity, datetime, _, data)
if data.is_a?(String) if data.is_a?(String)
"#{severity[0..0]} [#{datetime}] #{severity} -- : #{data}\n" "#{severity[0..0]} [#{datetime}] #{severity} -- : #{data}\n"
@ -24,7 +21,7 @@ module GrapeLogging
[ [
"#{exception.message} (#{exception.class})", "#{exception.message} (#{exception.class})",
backtrace_array.join("\n") backtrace_array.join("\n")
].reject{|line| line == ""}.join("\n") ].reject { |line| line == '' }.join("\n")
end end
def format_hash(hash) def format_hash(hash)
@ -32,7 +29,7 @@ module GrapeLogging
# Completed 200 OK in 958ms (Views: 951.1ms | ActiveRecord: 3.8ms) # Completed 200 OK in 958ms (Views: 951.1ms | ActiveRecord: 3.8ms)
# See: actionpack/lib/action_controller/log_subscriber.rb # See: actionpack/lib/action_controller/log_subscriber.rb
message = "" message = ''
additions = [] additions = []
status = hash.delete(:status) status = hash.delete(:status)
params = hash.delete(:params) params = hash.delete(:params)
@ -47,13 +44,12 @@ module GrapeLogging
message << " Parameters: #{params.inspect}\n" if params message << " Parameters: #{params.inspect}\n" if params
message << "Completed #{status} #{::Rack::Utils::HTTP_STATUS_CODES[status]} in #{total_time}ms" message << "Completed #{status} #{::Rack::Utils::HTTP_STATUS_CODES[status]} in #{total_time}ms"
message << " (#{additions.join(" | ".freeze)})" if additions.size > 0 message << " (#{additions.join(' | '.freeze)})" unless additions.empty?
message << "\n" message << "\n"
message << "\n" if defined?(::Rails.env) && ::Rails.env.development? message << "\n" if defined?(::Rails.env) && ::Rails.env.development?
message message
end end
end end
end end
end end

View file

@ -1,7 +1,7 @@
module GrapeLogging module GrapeLogging
module Loggers module Loggers
class Base class Base
def parameters(request, response) def parameters(_request, _response)
{} {}
end end
end end

View file

@ -2,7 +2,7 @@ module GrapeLogging
module Loggers module Loggers
class ClientEnv < GrapeLogging::Loggers::Base class ClientEnv < GrapeLogging::Loggers::Base
def parameters(request, _) def parameters(request, _)
{ ip: request.env["HTTP_X_FORWARDED_FOR"] || request.env["REMOTE_ADDR"], ua: request.env["HTTP_USER_AGENT"] } { ip: request.env['HTTP_X_FORWARDED_FOR'] || request.env['REMOTE_ADDR'], ua: request.env['HTTP_USER_AGENT'] }
end end
end end
end end

View file

@ -3,7 +3,7 @@ module GrapeLogging
class FilterParameters < GrapeLogging::Loggers::Base class FilterParameters < GrapeLogging::Loggers::Base
AD_PARAMS = 'action_dispatch.request.parameters'.freeze AD_PARAMS = 'action_dispatch.request.parameters'.freeze
def initialize(filter_parameters = nil, replacement = nil, exceptions = %w(controller action format)) def initialize(filter_parameters = nil, replacement = nil, exceptions = %w[controller action format])
@filter_parameters = filter_parameters || (defined?(::Rails.application) ? ::Rails.application.config.filter_parameters : []) @filter_parameters = filter_parameters || (defined?(::Rails.application) ? ::Rails.application.config.filter_parameters : [])
@replacement = replacement || '[FILTERED]' @replacement = replacement || '[FILTERED]'
@exceptions = exceptions @exceptions = exceptions
@ -16,7 +16,7 @@ module GrapeLogging
private private
def parameter_filter def parameter_filter
@parameter_filter ||= ParameterFilter.new(@replacement, @filter_parameters) @parameter_filter ||= GrapeLogging::Util::ParameterFilter.new(@replacement, @filter_parameters)
end end
def safe_parameters(request) def safe_parameters(request)
@ -29,7 +29,25 @@ module GrapeLogging
end end
def clean_parameters(parameters) def clean_parameters(parameters)
parameter_filter.filter(parameters).reject{ |key, _value| @exceptions.include?(key) } original_encoding_map = build_encoding_map(parameters)
params = transform_key_encoding(parameters, Hash.new { |h, _| [Encoding::ASCII_8BIT, h] })
cleaned_params = parameter_filter.filter(params).except(*@exceptions)
transform_key_encoding(cleaned_params, original_encoding_map)
end
def build_encoding_map(parameters)
parameters.each_with_object({}) do |(k, v), h|
key_str = k.to_s
h[key_str.dup.force_encoding(Encoding::ASCII_8BIT)] = [key_str.encoding, v.is_a?(Hash) ? build_encoding_map(v) : nil]
end
end
def transform_key_encoding(parameters, encoding_map)
parameters.each_with_object({}) do |(k, v), h|
key_str = k.to_s
encoding, children_encoding_map = encoding_map[key_str]
h[key_str.dup.force_encoding(encoding)] = v.is_a?(Hash) ? transform_key_encoding(v, children_encoding_map) : v
end
end end
end end
end end

View file

@ -1,7 +1,6 @@
module GrapeLogging module GrapeLogging
module Loggers module Loggers
class RequestHeaders < GrapeLogging::Loggers::Base class RequestHeaders < GrapeLogging::Loggers::Base
HTTP_PREFIX = 'HTTP_'.freeze HTTP_PREFIX = 'HTTP_'.freeze
def parameters(request, _) def parameters(request, _)
@ -16,7 +15,6 @@ module GrapeLogging
{ headers: headers } { headers: headers }
end end
end end
end end
end end

View file

@ -9,14 +9,13 @@ module GrapeLogging
# In some cases, response.body is not parseable by JSON. # In some cases, response.body is not parseable by JSON.
# For example, if you POST on a PUT endpoint, response.body is egal to """". # For example, if you POST on a PUT endpoint, response.body is egal to """".
# It's strange but it's the Grape behavior... # It's strange, but it's the Grape behavior...
def serialized_response_body(response) def serialized_response_body(response)
if response.respond_to?(:body) if response.respond_to?(:body)
# Rack responses # Rack responses
begin begin
response.body.map{ |body| JSON.parse(body.to_s) } response.body.map { |body| JSON.parse(body.to_s) }
rescue # No reason to have "=> e" here when we don't use it.. rescue StandardError # No reason to have "=> e" here when we don't use it..
response.body response.body
end end
else else

View file

@ -1,27 +1,27 @@
require 'grape/middleware/base'
module GrapeLogging module GrapeLogging
module Middleware module Middleware
class RequestLogger < Grape::Middleware::Base class RequestLogger < Grape::Middleware::Base
if defined?(ActiveRecord)
ActiveSupport::Notifications.subscribe('sql.active_record') do |*args| ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
event = ActiveSupport::Notifications::Event.new(*args) event = ActiveSupport::Notifications::Event.new(*args)
GrapeLogging::Timings.append_db_runtime(event) GrapeLogging::Timings.append_db_runtime(event)
end if defined?(ActiveRecord) end
end
# Persist response status & response (body) # Persist response status & response (body)
# to use int in parameters # to use int in parameters
attr_accessor :response_status, :response_body attr_accessor :response_status, :response_body
def initialize(app, options = {}) def initialize(app, **options)
super super
@included_loggers = @options[:include] || [] @included_loggers = @options[:include] || []
@reporter = if options[:instrumentation_key] @reporter =
Reporters::ActiveSupportReporter.new(@options[:instrumentation_key]) if options[:instrumentation_key]
else Reporters::ActiveSupportReporter.new(@options[:instrumentation_key])
Reporters::LoggerReporter.new(@options[:logger], @options[:formatter], @options[:log_level]) else
end Reporters::LoggerReporter.new(@options[:logger], @options[:formatter], @options[:log_level])
end
end end
def before def before
@ -37,7 +37,7 @@ module GrapeLogging
@response_status = status @response_status = status
@response_body = response @response_body = response
# Perform repotters # Perform reporters
@reporter.perform(collect_parameters) @reporter.perform(collect_parameters)
# Invoke loggers # Invoke loggers
@ -56,20 +56,18 @@ module GrapeLogging
# Catch error # Catch error
error = catch(:error) do error = catch(:error) do
begin @app_response = @app.call(@env)
@app_response = @app.call(@env)
rescue => e
# Log as 500 + message
after(e.respond_to?(:status) ? e.status : 500, e.message)
# Re-raise exception
raise e
end
nil nil
rescue StandardError => e
# Log as 500 + message
after(e.respond_to?(:status) ? e.status : 500, e.message)
# Re-raise exception
raise e
end end
# Get status & response from app_response # Get status & response from app_response
# when no error occures. # when no error occurs.
if error if error
# Call with error & response # Call with error & response
after(error[:status], error[:message]) after(error[:status], error[:message])
@ -100,7 +98,8 @@ module GrapeLogging
method: request.request_method, method: request.request_method,
path: request.path, path: request.path,
params: request.params, params: request.params,
host: request.host host: request.host,
request_id: env['action_dispatch.request_id']
} }
end end
@ -115,7 +114,7 @@ module GrapeLogging
end end
def view_runtime def view_runtime
total_runtime - db_runtime (total_runtime - db_runtime).round(2)
end end
def db_runtime def db_runtime

View file

@ -5,7 +5,7 @@ module GrapeLogging
end end
def write(*args) def write(*args)
@targets.each {|t| t.write(*args)} @targets.each { |t| t.write(*args) }
end end
def close def close

View file

@ -1,11 +1,13 @@
module Reporters module GrapeLogging
class ActiveSupportReporter module Reporters
def initialize(instrumentation_key) class ActiveSupportReporter
@instrumentation_key = instrumentation_key def initialize(instrumentation_key)
end @instrumentation_key = instrumentation_key
end
def perform(params) def perform(params)
ActiveSupport::Notifications.instrument @instrumentation_key, params ActiveSupport::Notifications.instrument @instrumentation_key, params
end
end end
end end
end end

View file

@ -1,15 +1,15 @@
module Reporters module GrapeLogging
class LoggerReporter module Reporters
def initialize(logger, formatter, log_level) class LoggerReporter
@logger = logger || Logger.new(STDOUT) def initialize(logger, formatter, log_level)
@log_level = log_level || :info @logger = logger.clone || Logger.new(STDOUT)
if @logger.respond_to?(:formatter=) @log_level = log_level || :info
@logger.formatter = formatter || @logger.formatter || GrapeLogging::Formatters::Default.new @logger.formatter = formatter || @logger.formatter || GrapeLogging::Formatters::Default.new if @logger.respond_to?(:formatter=)
end end
end
def perform(params) def perform(params)
@logger.send(@log_level, params) @logger.send(@log_level, params)
end
end end
end end
end end

View file

@ -1,20 +1,18 @@
module GrapeLogging module GrapeLogging
module Timings module Timings
extend self def self.db_runtime=(value)
def db_runtime=(value)
Thread.current[:grape_db_runtime] = value Thread.current[:grape_db_runtime] = value
end end
def db_runtime def self.db_runtime
Thread.current[:grape_db_runtime] ||= 0 Thread.current[:grape_db_runtime] ||= 0
end end
def reset_db_runtime def self.reset_db_runtime
self.db_runtime = 0 self.db_runtime = 0
end end
def append_db_runtime(event) def self.append_db_runtime(event)
self.db_runtime += event.duration self.db_runtime += event.duration
end end
end end

View file

@ -1,97 +1,105 @@
if defined?(::Rails.application) module GrapeLogging
if Gem::Version.new(Rails.version) < Gem::Version.new('6.0.0') module Util
class ParameterFilter < ActionDispatch::Http::ParameterFilter if defined?(Rails.application)
def initialize(_replacement, filter_parameters) if Gem::Version.new(Rails.version) < Gem::Version.new('6.0.0')
super(filter_parameters) class ParameterFilter < ActionDispatch::Http::ParameterFilter
end def initialize(_replacement, filter_parameters)
end super(filter_parameters)
else
class ParameterFilter < ActiveSupport::ParameterFilter
def initialize(_replacement, filter_parameters)
super(filter_parameters)
end
end
end
else
#
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameter_filter.rb
# we could depend on Rails specifically, but that would us way to hefty!
#
class ParameterFilter
def initialize(replacement, filters = [])
@replacement = replacement
@filters = filters
end
def filter(params)
compiled_filter.call(params)
end
private
def compiled_filter
@compiled_filter ||= CompiledFilter.compile(@replacement, @filters)
end
class CompiledFilter # :nodoc:
def self.compile(replacement, filters)
return lambda { |params| params.dup } if filters.empty?
strings, regexps, blocks = [], [], []
filters.each do |item|
case item
when Proc
blocks << item
when Regexp
regexps << item
else
strings << Regexp.escape(item.to_s)
end end
end end
else
require 'active_support/parameter_filter'
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) } class ParameterFilter < ActiveSupport::ParameterFilter
deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) } def initialize(_replacement, filter_parameters)
super(filter_parameters)
regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
new replacement, regexps, deep_regexps, blocks
end
attr_reader :regexps, :deep_regexps, :blocks
def initialize(replacement, regexps, deep_regexps, blocks)
@replacement = replacement
@regexps = regexps
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
@blocks = blocks
end
def call(original_params, parents = [])
filtered_params = {}
original_params.each do |key, value|
parents.push(key) if deep_regexps
if regexps.any? { |r| key =~ r }
value = @replacement
elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
value = @replacement
elsif value.is_a?(Hash)
value = call(value, parents)
elsif value.is_a?(Array)
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
elsif blocks.any?
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end end
parents.pop if deep_regexps end
end
filtered_params[key] = value else
#
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameter_filter.rb
# we could depend on Rails specifically, but that would us way to hefty!
#
class ParameterFilter
def initialize(replacement, filters = [])
@replacement = replacement
@filters = filters
end end
filtered_params def filter(params)
compiled_filter.call(params)
end
private
def compiled_filter
@compiled_filter ||= CompiledFilter.compile(@replacement, @filters)
end
class CompiledFilter # :nodoc:
def self.compile(replacement, filters)
return ->(params) { params.dup } if filters.empty?
strings = []
regexps = []
blocks = []
filters.each do |item|
case item
when Proc
blocks << item
when Regexp
regexps << item
else
strings << Regexp.escape(item.to_s)
end
end
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?('\\.'.freeze) }
deep_strings, strings = strings.partition { |s| s.include?('\\.'.freeze) }
regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
new replacement, regexps, deep_regexps, blocks
end
attr_reader :regexps, :deep_regexps, :blocks
def initialize(replacement, regexps, deep_regexps, blocks)
@replacement = replacement
@regexps = regexps
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
@blocks = blocks
end
def call(original_params, parents = [])
filtered_params = {}
original_params.each do |key, value|
parents.push(key) if deep_regexps
if regexps.any? { |r| key =~ r }
value = @replacement
elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
value = @replacement
elsif value.is_a?(Hash)
value = call(value, parents)
elsif value.is_a?(Array)
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
elsif blocks.any?
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end
parents.pop if deep_regexps
filtered_params[key] = value
end
filtered_params
end
end
end end
end end
end end

View file

@ -1,3 +1,3 @@
module GrapeLogging module GrapeLogging
VERSION = '1.8.3' VERSION = '3.0.1'
end end

View file

@ -2,11 +2,11 @@ require 'spec_helper'
describe GrapeLogging::Formatters::Rails do describe GrapeLogging::Formatters::Rails do
let(:formatter) { described_class.new } let(:formatter) { described_class.new }
let(:severity) { "INFO" } let(:severity) { 'INFO' }
let(:datetime) { Time.new('2018', '03', '02', '10', '35', '04', '+13:00') } let(:datetime) { Time.new('2018', '03', '02', '10', '35', '04', '+13:00') }
let(:exception_data) { ArgumentError.new('Message') } let(:exception_data) { ArgumentError.new('Message') }
let(:hash_data) { let(:hash_data) do
{ {
status: 200, status: 200,
time: { time: {
@ -14,11 +14,11 @@ describe GrapeLogging::Formatters::Rails do
db: 40.63, db: 40.63,
view: 231.76999999999998 view: 231.76999999999998
}, },
method: "GET", method: 'GET',
path: "/api/endpoint", path: '/api/endpoint',
host: "localhost" host: 'localhost'
} }
} end
describe '#call' do describe '#call' do
context 'string data' do context 'string data' do
@ -36,8 +36,8 @@ describe GrapeLogging::Formatters::Rails do
message = formatter.call(severity, datetime, nil, exception_data) message = formatter.call(severity, datetime, nil, exception_data)
lines = message.split("\n") lines = message.split("\n")
expect(lines[0]).to eq "I [2018-03-02 10:35:04 +1300] INFO -- : Message (ArgumentError)" expect(lines[0]).to eq 'I [2018-03-02 10:35:04 +1300] INFO -- : Message (ArgumentError)'
expect(lines[1]).to include 'grape_logging' expect(lines[1]).to include '.rb'
expect(lines.size).to be > 1 expect(lines.size).to be > 1
end end
end end
@ -52,9 +52,9 @@ describe GrapeLogging::Formatters::Rails do
it 'includes params if included (from GrapeLogging::Loggers::FilterParameters)' do it 'includes params if included (from GrapeLogging::Loggers::FilterParameters)' do
hash_data.merge!( hash_data.merge!(
params: { params: {
"some_param" => { 'some_param' => {
value_1: "123", value_1: '123',
value_2: "456" value_2: '456'
} }
} }
) )
@ -62,12 +62,18 @@ describe GrapeLogging::Formatters::Rails do
message = formatter.call(severity, datetime, nil, hash_data) message = formatter.call(severity, datetime, nil, hash_data)
lines = message.split("\n") lines = message.split("\n")
expect(lines.first).to eq ' Parameters: {"some_param"=>{:value_1=>"123", :value_2=>"456"}}' expected_output =
expect(lines.last).to eq "Completed 200 OK in 272.4ms (Views: 231.77ms | DB: 40.63ms)" if RUBY_VERSION >= '3.4'
' Parameters: {"some_param" => {value_1: "123", value_2: "456"}}'
else
' Parameters: {"some_param"=>{:value_1=>"123", :value_2=>"456"}}'
end
expect(lines.first).to eq expected_output
expect(lines.last).to eq 'Completed 200 OK in 272.4ms (Views: 231.77ms | DB: 40.63ms)'
end end
end end
context "unhandled data" do context 'unhandled data' do
it 'returns the #inspect string representation' do it 'returns the #inspect string representation' do
message = formatter.call(severity, datetime, nil, [1, 2, 3]) message = formatter.call(severity, datetime, nil, [1, 2, 3])
@ -75,5 +81,4 @@ describe GrapeLogging::Formatters::Rails do
end end
end end
end end
end end

View file

@ -1,17 +1,16 @@
require 'spec_helper' require 'spec_helper'
require 'ostruct'
describe GrapeLogging::Loggers::ClientEnv do describe GrapeLogging::Loggers::ClientEnv do
let(:ip) { '10.0.0.1' } let(:ip) { '10.0.0.1' }
let(:user_agent) { 'user agent' } let(:user_agent) { 'user agent' }
let(:forwarded_for) { "forwarded for" } let(:forwarded_for) { 'forwarded for' }
let(:remote_addr) { "remote address" } let(:remote_addr) { 'remote address' }
context 'forwarded for' do context 'forwarded for' do
let(:mock_request) do let(:mock_request) do
OpenStruct.new(env: { instance_double(Rack::Request, env: {
"HTTP_X_FORWARDED_FOR" => forwarded_for 'HTTP_X_FORWARDED_FOR' => forwarded_for
}) })
end end
it 'sets the ip key' do it 'sets the ip key' do
@ -26,9 +25,9 @@ describe GrapeLogging::Loggers::ClientEnv do
context 'remote address' do context 'remote address' do
let(:mock_request) do let(:mock_request) do
OpenStruct.new(env: { instance_double(Rack::Request, env: {
"REMOTE_ADDR" => remote_addr 'REMOTE_ADDR' => remote_addr
}) })
end end
it 'sets the ip key' do it 'sets the ip key' do
@ -38,9 +37,9 @@ describe GrapeLogging::Loggers::ClientEnv do
context 'user agent' do context 'user agent' do
let(:mock_request) do let(:mock_request) do
OpenStruct.new(env: { instance_double(Rack::Request, env: {
"HTTP_USER_AGENT" => user_agent 'HTTP_USER_AGENT' => user_agent
}) })
end end
it 'sets the ua key' do it 'sets the ua key' do

View file

@ -1,29 +1,27 @@
require 'spec_helper' require 'spec_helper'
require 'ostruct'
describe GrapeLogging::Loggers::FilterParameters do describe GrapeLogging::Loggers::FilterParameters do
let(:filtered_parameters) { %w[one four] } let(:filtered_parameters) { %w[one four] }
let(:mock_request) do let(:mock_request) do
OpenStruct.new(params: { instance_double(Rack::Request, params: {
this_one: 'this one', 'this_one' => 'this one',
that_one: 'one', 'that_one' => 'one',
two: 'two', 'two' => 'two',
three: 'three', 'three' => 'three',
four: 'four' 'four' => 'four',
}) "\xff" => 'invalid utf8'
})
end end
let(:mock_request_with_deep_nesting) do let(:mock_request_with_deep_nesting) do
deep_clone = lambda { Marshal.load Marshal.dump mock_request.params } deep_clone = -> { Marshal.load Marshal.dump mock_request.params }
OpenStruct.new( instance_double(Rack::Request,
params: deep_clone.call.merge( params: deep_clone.call.merge(
five: deep_clone.call.merge( 'five' => deep_clone.call.merge(
deep_clone.call.merge({six: {seven: 'seven', eight: 'eight', one: 'another one'}}) deep_clone.call.merge({ 'six' => { 'seven' => 'seven', 'eight' => 'eight', 'one' => 'another one' } })
) )
) ))
)
end end
let(:subject) do let(:subject) do
@ -35,34 +33,37 @@ describe GrapeLogging::Loggers::FilterParameters do
shared_examples 'filtering' do shared_examples 'filtering' do
it 'filters out sensitive parameters' do it 'filters out sensitive parameters' do
expect(subject.parameters(mock_request, nil)).to eq(params: { expect(subject.parameters(mock_request, nil)).to eq(params: {
this_one: subject.instance_variable_get('@replacement'), 'this_one' => subject.instance_variable_get('@replacement'),
that_one: subject.instance_variable_get('@replacement'), 'that_one' => subject.instance_variable_get('@replacement'),
two: 'two', 'two' => 'two',
three: 'three', 'three' => 'three',
four: subject.instance_variable_get('@replacement'), 'four' => subject.instance_variable_get('@replacement'),
}) "\xff" => 'invalid utf8'
})
end end
it 'deeply filters out sensitive parameters' do it 'deeply filters out sensitive parameters' do
expect(subject.parameters(mock_request_with_deep_nesting, nil)).to eq(params: { expect(subject.parameters(mock_request_with_deep_nesting, nil)).to eq(params: {
this_one: subject.instance_variable_get('@replacement'), 'this_one' => subject.instance_variable_get('@replacement'),
that_one: subject.instance_variable_get('@replacement'), 'that_one' => subject.instance_variable_get('@replacement'),
two: 'two', 'two' => 'two',
three: 'three', 'three' => 'three',
four: subject.instance_variable_get('@replacement'), 'four' => subject.instance_variable_get('@replacement'),
five: { "\xff" => 'invalid utf8',
this_one: subject.instance_variable_get('@replacement'), 'five' => {
that_one: subject.instance_variable_get('@replacement'), 'this_one' => subject.instance_variable_get('@replacement'),
two: 'two', 'that_one' => subject.instance_variable_get('@replacement'),
three: 'three', 'two' => 'two',
four: subject.instance_variable_get('@replacement'), 'three' => 'three',
six: { 'four' => subject.instance_variable_get('@replacement'),
seven: 'seven', "\xff" => 'invalid utf8',
eight: 'eight', 'six' => {
one: subject.instance_variable_get('@replacement'), 'seven' => 'seven',
}, 'eight' => 'eight',
}, 'one' => subject.instance_variable_get('@replacement')
}) }
}
})
end end
end end
@ -74,4 +75,14 @@ describe GrapeLogging::Loggers::FilterParameters do
let(:replacement) { 'CUSTOM_REPLACEMENT' } let(:replacement) { 'CUSTOM_REPLACEMENT' }
it_behaves_like 'filtering' it_behaves_like 'filtering'
end end
context 'with symbol keys, which occur during automated testing' do
let(:mock_request) { instance_double(Rack::Request, params: { sneaky_symbol: 'hey!' }) }
it 'converts keys to strings' do
expect(subject.parameters(mock_request, nil)).to eq(params: {
'sneaky_symbol' => 'hey!'
})
end
end
end end

View file

@ -1,40 +1,45 @@
require 'spec_helper' require 'spec_helper'
require 'ostruct'
describe GrapeLogging::Loggers::RequestHeaders do describe GrapeLogging::Loggers::RequestHeaders do
let(:mock_request) do let(:mock_request) do
OpenStruct.new(env: {HTTP_REFERER: 'http://example.com', HTTP_ACCEPT: 'text/plain'}) instance_double(Rack::Request, env: { HTTP_REFERER: 'http://example.com', HTTP_ACCEPT: 'text/plain' })
end end
let(:mock_request_with_unhandle_headers) do let(:mock_request_with_unhandled_headers) do
OpenStruct.new(env: { instance_double(Rack::Request, env: {
HTTP_REFERER: 'http://example.com', HTTP_REFERER: 'http://example.com',
"PATH_INFO"=>"/api/v1/users" 'PATH_INFO' => '/api/v1/users'
}) })
end end
let(:mock_request_with_long_headers) do let(:mock_request_with_long_headers) do
OpenStruct.new(env: { instance_double(Rack::Request, env: {
HTTP_REFERER: 'http://example.com', HTTP_REFERER: 'http://example.com',
HTTP_USER_AGENT: "Mozilla/5.0" HTTP_USER_AGENT: 'Mozilla/5.0'
}) })
end end
it 'strips HTTP_ from the parameter' do it 'strips HTTP_ from the parameter' do
expect(subject.parameters(mock_request, nil)).to eq({ expect(subject.parameters(mock_request, nil)).to eq(
headers: {'Referer' => 'http://example.com', 'Accept' => 'text/plain'} {
}) headers: { 'Referer' => 'http://example.com', 'Accept' => 'text/plain' }
}
)
end end
it 'only handle things which start with HTTP_' do it 'only handle things which start with HTTP_' do
expect(subject.parameters(mock_request_with_unhandle_headers, nil)).to eq({ expect(subject.parameters(mock_request_with_unhandled_headers, nil)).to eq(
headers: {'Referer' => 'http://example.com' } {
}) headers: { 'Referer' => 'http://example.com' }
}
)
end end
it 'substitutes _ with -' do it 'substitutes _ with -' do
expect(subject.parameters(mock_request_with_long_headers, nil)).to eq({ expect(subject.parameters(mock_request_with_long_headers, nil)).to eq(
headers: {'Referer' => 'http://example.com', 'User-Agent' => 'Mozilla/5.0' } {
}) headers: { 'Referer' => 'http://example.com', 'User-Agent' => 'Mozilla/5.0' }
}
)
end end
end end

View file

@ -1,28 +1,23 @@
require 'spec_helper' require 'spec_helper'
require 'ostruct'
describe GrapeLogging::Loggers::Response do describe GrapeLogging::Loggers::Response do
context 'with a parseable JSON body' do context 'with a parseable JSON body' do
let(:response) do let(:response) do
OpenStruct.new(body: [%q{{"one": "two", "three": {"four": 5}}}]) instance_double(Rack::Request, body: [{ one: 'two', three: { four: 5 } }])
end end
it 'returns an array of parseable JSON objects' do it 'returns an array of parsed JSON objects' do
expect(subject.parameters(nil, response)).to eq({ expect(subject.parameters(nil, response)).to eq({ response: [response.body.first] })
response: [response.body.first.dup]
})
end end
end end
context 'with a body that is not parseable JSON' do context 'with a body that is not parseable JSON' do
let(:response) do let(:response) do
OpenStruct.new(body: "this is a body") instance_double(Rack::Request, body: 'this is a body')
end end
it 'just returns the body' do it 'just returns the body' do
expect(subject.parameters(nil, response)).to eq({ expect(subject.parameters(nil, response)).to eq({ response: response.body })
response: response.body.dup
})
end end
end end
end end

View file

@ -2,11 +2,12 @@ require 'spec_helper'
require 'rack' require 'rack'
describe GrapeLogging::Middleware::RequestLogger do describe GrapeLogging::Middleware::RequestLogger do
let(:subject) { request.send(request_method, path) } let(:env) { { 'action_dispatch.request_id' => 'request-abc123' } }
let(:app) { proc{ [status, {} , ['response body']] } } let(:subject) { request.send(request_method, path, env) }
let(:stack) { described_class.new app, options } let(:app) { proc { [status, {}, ['response body']] } }
let(:stack) { described_class.new app, **options }
let(:request) { Rack::MockRequest.new(stack) } let(:request) { Rack::MockRequest.new(stack) }
let(:options) { {include: [], logger: logger} } let(:options) { { include: [], logger: logger } }
let(:logger) { double('logger') } let(:logger) { double('logger') }
let(:path) { '/' } let(:path) { '/' }
let(:request_method) { 'get' } let(:request_method) { 'get' }
@ -18,6 +19,7 @@ describe GrapeLogging::Middleware::RequestLogger do
expect(arguments[:method]).to eq 'GET' expect(arguments[:method]).to eq 'GET'
expect(arguments[:params]).to be_empty expect(arguments[:params]).to be_empty
expect(arguments[:host]).to eq 'example.org' expect(arguments[:host]).to eq 'example.org'
expect(arguments[:request_id]).to eq 'request-abc123'
expect(arguments).to have_key :time expect(arguments).to have_key :time
expect(arguments[:time]).to have_key :total expect(arguments[:time]).to have_key :total
expect(arguments[:time]).to have_key :db expect(arguments[:time]).to have_key :db
@ -27,7 +29,7 @@ describe GrapeLogging::Middleware::RequestLogger do
end end
[301, 404, 500].each do |the_status| [301, 404, 500].each do |the_status|
context "when the respnse status is #{the_status}" do context "when the response status is #{the_status}" do
let(:status) { the_status } let(:status) { the_status }
it 'should log the correct status code' do it 'should log the correct status code' do
expect(logger).to receive('info') do |arguments| expect(logger).to receive('info') do |arguments|
@ -49,7 +51,7 @@ describe GrapeLogging::Middleware::RequestLogger do
end end
context 'with a nil response' do context 'with a nil response' do
let(:app) { proc{ [500, {} , nil] } } let(:app) { proc { [500, {}, nil] } }
it 'should log "fail" instead of a status' do it 'should log "fail" instead of a status' do
expect(Rack::MockResponse).to receive(:new) { nil } expect(Rack::MockResponse).to receive(:new) { nil }
expect(logger).to receive('info') do |arguments| expect(logger).to receive('info') do |arguments|
@ -64,7 +66,7 @@ describe GrapeLogging::Middleware::RequestLogger do
options[:include] << GrapeLogging::Loggers::RequestHeaders.new options[:include] << GrapeLogging::Loggers::RequestHeaders.new
options[:include] << GrapeLogging::Loggers::ClientEnv.new options[:include] << GrapeLogging::Loggers::ClientEnv.new
options[:include] << GrapeLogging::Loggers::Response.new options[:include] << GrapeLogging::Loggers::Response.new
options[:include] << GrapeLogging::Loggers::FilterParameters.new(["replace_me"]) options[:include] << GrapeLogging::Loggers::FilterParameters.new(['replace_me'])
end end
%w[get put post delete options head patch].each do |the_method| %w[get put post delete options head patch].each do |the_method|
@ -84,9 +86,9 @@ describe GrapeLogging::Middleware::RequestLogger do
it 'should filter parameters in the log' do it 'should filter parameters in the log' do
expect(logger).to receive('info') do |arguments| expect(logger).to receive('info') do |arguments|
expect(arguments[:params]).to eq( expect(arguments[:params]).to eq(
"replace_me" => '[FILTERED]', 'replace_me' => '[FILTERED]',
"replace_me_too" => '[FILTERED]', 'replace_me_too' => '[FILTERED]',
"cant_touch_this" => 'should see' 'cant_touch_this' => 'should see'
) )
end end
parameters = { parameters = {

View file

@ -33,57 +33,55 @@ RSpec.configure do |config|
# triggering implicit auto-inclusion in groups with matching metadata. # triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups config.shared_context_metadata_behavior = :apply_to_host_groups
# The settings below are suggested to provide a good initial experience # The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content. # with RSpec, but feel free to customize to your heart's content.
=begin # # This allows you to limit a spec run to individual examples or groups
# This allows you to limit a spec run to individual examples or groups # # you care about by tagging them with `:focus` metadata. When nothing
# you care about by tagging them with `:focus` metadata. When nothing # # is tagged with `:focus`, all examples get run. RSpec also provides
# is tagged with `:focus`, all examples get run. RSpec also provides # # aliases for `it`, `describe`, and `context` that include `:focus`
# aliases for `it`, `describe`, and `context` that include `:focus` # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
# metadata: `fit`, `fdescribe` and `fcontext`, respectively. # config.filter_run_when_matching :focus
config.filter_run_when_matching :focus #
# # Allows RSpec to persist some state between runs in order to support
# Allows RSpec to persist some state between runs in order to support # # the `--only-failures` and `--next-failure` CLI options. We recommend
# the `--only-failures` and `--next-failure` CLI options. We recommend # # you configure your source control system to ignore this file.
# you configure your source control system to ignore this file. # config.example_status_persistence_file_path = "spec/examples.txt"
config.example_status_persistence_file_path = "spec/examples.txt" #
# # Limits the available syntax to the non-monkey patched syntax that is
# Limits the available syntax to the non-monkey patched syntax that is # # recommended. For more details, see:
# recommended. For more details, see: # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode # config.disable_monkey_patching!
config.disable_monkey_patching! #
# # This setting enables warnings. It's recommended, but in some cases may
# This setting enables warnings. It's recommended, but in some cases may # # be too noisy due to issues in dependencies.
# be too noisy due to issues in dependencies. # config.warnings = true
config.warnings = true #
# # Many RSpec users commonly either run the entire suite or an individual
# Many RSpec users commonly either run the entire suite or an individual # # file, and it's useful to allow more verbose output when running an
# file, and it's useful to allow more verbose output when running an # # individual spec file.
# individual spec file. # if config.files_to_run.one?
if config.files_to_run.one? # # Use the documentation formatter for detailed output,
# Use the documentation formatter for detailed output, # # unless a formatter has already been configured
# unless a formatter has already been configured # # (e.g. via a command-line flag).
# (e.g. via a command-line flag). # config.default_formatter = 'doc'
config.default_formatter = 'doc' # end
end #
# # Print the 10 slowest examples and example groups at the
# Print the 10 slowest examples and example groups at the # # end of the spec run, to help surface which specs are running
# end of the spec run, to help surface which specs are running # # particularly slow.
# particularly slow. # config.profile_examples = 10
config.profile_examples = 10 #
# # Run specs in random order to surface order dependencies. If you find an
# Run specs in random order to surface order dependencies. If you find an # # order dependency and want to debug it, you can fix the order by providing
# order dependency and want to debug it, you can fix the order by providing # # the seed, which is printed after each run.
# the seed, which is printed after each run. # # --seed 1234
# --seed 1234 # config.order = :random
config.order = :random #
# # Seed global randomization in this process using the `--seed` CLI option.
# Seed global randomization in this process using the `--seed` CLI option. # # Setting this allows you to use `--seed` to deterministically reproduce
# Setting this allows you to use `--seed` to deterministically reproduce # # test failures related to randomization by passing the same `--seed` value
# test failures related to randomization by passing the same `--seed` value # # as the one that triggered the failure.
# as the one that triggered the failure. # Kernel.srand config.seed
Kernel.srand config.seed
=end
end end