├── .gemtest ├── .github └── workflows │ ├── ci.yml │ └── linter.yml ├── .gitignore ├── .mdlrc ├── .rspec ├── .rubocop.yml ├── .yardopts ├── CHANGELOG.md ├── Gemfile ├── LICENSE.md ├── README.md ├── Rakefile ├── lib ├── silencer.rb └── silencer │ ├── hush.rb │ ├── methods.rb │ ├── rack │ └── logger.rb │ ├── rails │ ├── environment.rb │ └── logger.rb │ ├── util.rb │ └── version.rb ├── lint └── markdown.rb ├── silencer.gemspec └── spec ├── log └── test.log ├── silencer ├── rack │ └── logger_spec.rb └── rails │ └── logger_spec.rb └── spec_helper.rb /.gemtest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stve/silencer/234b67673afc5d880c0be7df7cdc3750fde8ba23/.gemtest -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ '**' ] 6 | 7 | jobs: 8 | # Set the job key. The key is displayed as the job name 9 | # when a job name is not provided 10 | tests: 11 | strategy: 12 | matrix: 13 | ruby: [ '2.6', '2.7', '3.0' ] 14 | 15 | name: Tests - Ruby ${{ matrix.ruby }} 16 | # Set the type of machine to run on 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | # Checks out a copy of your repository on the ubuntu-latest machine 21 | - name: Checkout code 22 | uses: actions/checkout@v2 23 | 24 | - uses: actions/cache@v2 25 | with: 26 | path: vendor/bundle 27 | key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} 28 | restore-keys: | 29 | ${{ runner.os }}-gems- 30 | 31 | - name: Set up Ruby 32 | uses: ruby/setup-ruby@v1 33 | with: 34 | ruby-version: ${{ matrix.ruby }} 35 | bundler-cache: true 36 | 37 | - name: Bundle install 38 | run: | 39 | bundle config path vendor/bundle 40 | bundle install --jobs 4 --retry 3 --without development 41 | 42 | - name: Run tests 43 | run: | 44 | bundle exec rake test 45 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################# 3 | ################################# 4 | ## Super Linter GitHub Actions ## 5 | ################################# 6 | ################################# 7 | name: Lint Code Base 8 | 9 | # 10 | # Documentation: 11 | # https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions 12 | # 13 | 14 | ############################# 15 | # Start the job on all push # 16 | ############################# 17 | on: 18 | push: 19 | branches-ignore: [main] 20 | # Remove the line above to run when pushing to master 21 | pull_request: 22 | branches: [ '**' ] 23 | 24 | ############### 25 | # Set the Job # 26 | ############### 27 | jobs: 28 | build: 29 | # Name the Job 30 | name: Lint Code Base 31 | # Set the agent to run on 32 | runs-on: ubuntu-latest 33 | 34 | ################## 35 | # Load all steps # 36 | ################## 37 | steps: 38 | ########################## 39 | # Checkout the code base # 40 | ########################## 41 | - name: Checkout Code 42 | uses: actions/checkout@v3 43 | with: 44 | # Full git history is needed to get a proper list of changed files within `super-linter` 45 | fetch-depth: 0 46 | 47 | ################################ 48 | # Run Linter against code base # 49 | ################################ 50 | - name: Lint Code Base 51 | uses: github/super-linter@v4 52 | env: 53 | VALIDATE_ALL_CODEBASE: false 54 | DEFAULT_BRANCH: main 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | LINTER_RULES_PATH: . 57 | RUBY_CONFIG_FILE: .rubocop.yml 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp/*.log 18 | -------------------------------------------------------------------------------- /.mdlrc: -------------------------------------------------------------------------------- 1 | style 'lint/markdown.rb' 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format=documentation 3 | --backtrace 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.6 3 | Include: 4 | - "./Rakefile" 5 | - "instapaper.gemspec" 6 | - "lib/**/*.rb" 7 | - "spec/**/*.rb" 8 | DisplayCopNames: true 9 | SuggestExtensions: false 10 | NewCops: enable 11 | 12 | Layout/LineLength: 13 | AllowURI: true 14 | Enabled: false 15 | 16 | Layout/SpaceInsideHashLiteralBraces: 17 | EnforcedStyle: no_space 18 | 19 | Metrics/BlockNesting: 20 | Max: 2 21 | 22 | Metrics/MethodLength: 23 | CountComments: false 24 | Max: 10 25 | 26 | Metrics/ParameterLists: 27 | Max: 4 28 | CountKeywordArgs: true 29 | 30 | Metrics/BlockLength: 31 | Enabled: false 32 | 33 | Style/CollectionMethods: 34 | PreferredMethods: 35 | map: "collect" 36 | reduce: "inject" 37 | find: "detect" 38 | find_all: "select" 39 | 40 | Style/Documentation: 41 | Enabled: false 42 | 43 | Style/DoubleNegation: 44 | Enabled: false 45 | 46 | Style/MutableConstant: 47 | Enabled: false 48 | 49 | Style/TrailingCommaInArguments: 50 | EnforcedStyleForMultiline: "comma" 51 | 52 | Style/TrailingCommaInArrayLiteral: 53 | EnforcedStyleForMultiline: "comma" 54 | 55 | Style/TrailingCommaInHashLiteral: 56 | EnforcedStyleForMultiline: "comma" 57 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2.0.0 2 | ------ 3 | 4 | * Breaking Change: [Remove implicit logger definition](https://github.com/stve/silencer/pull/35) 5 | 6 | 7 | 1.1.0 - yanked 8 | ------ 9 | 10 | * [Check if Rails Logger Present for environment](https://github.com/stve/silencer/commit/56a16bec3ee6fb1b1b68865453caee660af76716) 11 | * [Make X-SILENCE-LOGGER header optional](https://github.com/stve/silencer/commit/df3aa725bd07f731358bf1a347893bb9856444de) 12 | 13 | 14 | 1.0.1 15 | ------ 16 | 17 | * [avoid conflicts with Kernel.silence](https://github.com/stve/silencer/commit/69294f0529ee9cb6070453217a0938bf142cd84b) 18 | 19 | 1.0.0 20 | ------ 21 | 22 | * [add threadsafe support in Rails 4.2+](https://github.com/stve/silencer/commit/3d9b6f529d4a8819023535bda4932c5d3aa0f819) 23 | * [add support for silencing specific request methods](https://github.com/stve/silencer/commit/85cb9a5173d2ee11b6b12e38b2cab76bc20912ff) 24 | * [remove railties as a dependency](https://github.com/stve/silencer/commit/e3226947084a26a6dc61b9c20f891cbf66c22648) 25 | 26 | 0.6.0 27 | ------ 28 | 29 | * [fix HTTP header based silencer](https://github.com/stve/silencer/commit/31d54a7c718de8729eb9bd7fa982d4b4892a9a2a) 30 | 31 | 0.5.0 32 | ------ 33 | 34 | * [add taggers support](https://github.com/stve/silencer/commit/938dd72841728b939e9d60636425d1a10c551a83) 35 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'yard' 5 | 6 | gem 'rack' 7 | gem 'rails', (ENV['RAILS_VERSION'] || '5.2.2') 8 | 9 | group :development do 10 | gem 'kramdown' 11 | end 12 | 13 | group :test do 14 | gem 'rspec', '3.5' 15 | gem 'rubocop' 16 | gem 'simplecov', require: false 17 | end 18 | 19 | group :test, :development do 20 | gem 'syslogger' 21 | end 22 | 23 | gemspec 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Steve Agalloco 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Silencer 2 | 3 | [![Gem Version](http://img.shields.io/gem/v/silencer.svg)][gem] 4 | ![Tests](https://github.com/stve/silencer/actions/workflows/ci.yml/badge.svg) 5 | 6 | [gem]: https://rubygems.org/gems/silencer 7 | 8 | Silencer is a simple rack-middleware for Rails that can selectively disable logging on per-action basis. It's based on a [blog post](http://dennisreimann.de/blog/silencing-the-rails-log-on-a-per-action-basis/) by Dennis Reimann. 9 | 10 | __Note__: Silencer is only threadsafe in Rails version 4.2.6 and later. 11 | 12 | ## Installation 13 | 14 | Just add silencer to your Gemfile: 15 | 16 | ```ruby 17 | gem 'silencer', require: false 18 | ``` 19 | 20 | ### Upgrading to version 2.0 21 | 22 | __Note:__ 1.x versions of silencer detected the presence of Rails when it was required. This made it easy to use silencer for most applications, but made assumptions on usage. 23 | 24 | In version 2.0, you'll need to require the correct logger within your application. See the Usage documentation for more details. 25 | 26 | ## Usage 27 | 28 | ### Rails 29 | 30 | Create an initializer (like `config/initializers/silencer.rb`) with the contents: 31 | 32 | ```ruby 33 | require 'silencer/rails/logger' 34 | 35 | Rails.application.configure do 36 | config.middleware.swap( 37 | Rails::Rack::Logger, 38 | Silencer::Logger, 39 | config.log_tags, 40 | silence: ["/noisy/action.json"] 41 | ) 42 | end 43 | ``` 44 | 45 | ### Rack 46 | 47 | ```ruby 48 | require 'silencer/rack/logger' 49 | 50 | use Silencer::Logger, silence: ["/noisy/action.json"] 51 | ``` 52 | 53 | ## Configuration 54 | 55 | Or if you'd prefer, you can pass it regular expressions: 56 | 57 | ```ruby 58 | config.middleware.swap( 59 | Rails::Rack::Logger, 60 | Silencer::Logger, 61 | config.log_tags, 62 | silence: [%r{^/assets/}] 63 | ) 64 | ``` 65 | 66 | Or you can silence specific request methods only: 67 | 68 | ```ruby 69 | config.middleware.swap( 70 | Rails::Rack::Logger, 71 | Silencer::Logger, 72 | config.log_tags, 73 | get: [%r{^/assets/}], 74 | post: [%r{^/some_path}] 75 | ) 76 | ``` 77 | 78 | Silencer's logger will serve as a drop-in replacement for Rails' default logger. It will not suppress any logging by default, simply pass it an array of URLs via the options hash. You can also send an `X-SILENCE-LOGGER` header (with any value) with your request and that will also produce the same behavior. 79 | 80 | ### All options 81 | 82 | Silencer supports the following configuration options. 83 | 84 | | Configuration | Description | Default | 85 | |---------------|-------------|---------| 86 | | `silence` | Silences matching requests regardless of request method | None | 87 | | `get` | Silences matching GET requests | None | 88 | | `head` | Silences matching HEAD requests | None | 89 | | `post` | Silences matching POST requests | None | 90 | | `put` | Silences matching PUT requests | None | 91 | | `delete` | Silences matching DELETE requests | None | 92 | | `patch` | Silences matching PATCH requests | None | 93 | | `trace` | Silences matching TRACE requests | None | 94 | | `connect` | Silences matching CONNECT requests | None | 95 | | `options` | Silences matching OPTIONS requests | None | 96 | | `enable_header` | Enable/disable X-SILENCE-LOGGER header support | `true` | 97 | 98 | ## Note on Patches/Pull Requests 99 | 100 | * Fork the project. 101 | * Make your feature addition or bugfix. 102 | * Add tests for it. This is important so I don't break it in a 103 | future version unintentionally. 104 | * Commit, do not mess with rakefile, version, or history. 105 | (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) 106 | * Send me a pull request. Bonus points for topic branches. 107 | 108 | ## Copyright 109 | 110 | Copyright (c) 2012 Steve Agalloco. See [LICENSE](https://github.com/stve/silencer/blob/main/LICENSE.md) for details. 111 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | 4 | require 'rspec/core/rake_task' 5 | RSpec::Core::RakeTask.new(:spec) 6 | 7 | task :default => :spec 8 | task test: :spec 9 | 10 | require 'rubocop/rake_task' 11 | RuboCop::RakeTask.new 12 | 13 | require 'yard' 14 | YARD::Rake::YardocTask.new 15 | 16 | task default: [:spec, :rubocop] 17 | -------------------------------------------------------------------------------- /lib/silencer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | -------------------------------------------------------------------------------- /lib/silencer/hush.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | module Hush 5 | private 6 | 7 | def silence_request?(env, enable_header: true) 8 | ((enable_header && silent_header?(env)) || silent_path?(env)) 9 | end 10 | 11 | def silent_header?(env) 12 | env['HTTP_X_SILENCE_LOGGER'] 13 | end 14 | 15 | def silent_path?(env) 16 | (@routes[env['REQUEST_METHOD']] || @silence).any? do |rule| 17 | case rule 18 | when String, Integer 19 | rule.to_s == env['PATH_INFO'] 20 | when Regexp 21 | rule =~ env['PATH_INFO'] 22 | else 23 | false 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/silencer/methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | module Methods 5 | METHODS = %i[options get head post put delete trace connect patch] 6 | 7 | def define_routes(silence_paths, opts) 8 | METHODS.each_with_object({}) do |method, routes| 9 | routes[method.to_s.upcase] = wrap(opts.delete(method)) + silence_paths 10 | routes 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/silencer/rack/logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/logger' 4 | require 'silencer/hush' 5 | require 'silencer/methods' 6 | require 'silencer/util' 7 | 8 | module Silencer 9 | module Rack 10 | class Logger < ::Rack::Logger 11 | include Silencer::Hush 12 | include Silencer::Methods 13 | include Silencer::Util 14 | 15 | def initialize(app, *args) 16 | opts = extract_options!(args) 17 | @silence = wrap(opts.delete(:silence)) 18 | @routes = define_routes(@silence, opts) 19 | 20 | @enable_header = opts.delete(:enable_header) { true } 21 | 22 | super(app, *args) 23 | end 24 | 25 | def call(env) 26 | if silence_request?(env, enable_header: @enable_header) 27 | quiet(env) do 28 | super 29 | end 30 | else 31 | super 32 | end 33 | end 34 | 35 | private 36 | 37 | def quiet(env) 38 | old_logger = env['rack.logger'] 39 | logger = ::Logger.new(env['rack.errors']) 40 | logger.level = ::Logger::ERROR 41 | 42 | env['rack.logger'] = logger 43 | yield 44 | ensure 45 | env['rack.logger'] = old_logger 46 | end 47 | end 48 | end 49 | 50 | Logger = Silencer::Rack::Logger 51 | end 52 | -------------------------------------------------------------------------------- /lib/silencer/rails/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | module Environment 5 | RAILS_4 = /^4/ 6 | RAILS_5 = /^5/ 7 | 8 | module_function 9 | 10 | def rails? 11 | defined?(::Rails) 12 | end 13 | 14 | def rails_version 15 | return unless rails? 16 | 17 | ::Rails::VERSION::STRING 18 | end 19 | 20 | def rails4? 21 | rails_version =~ RAILS_4 22 | end 23 | 24 | def rails5? 25 | rails_version =~ RAILS_5 26 | end 27 | 28 | def tagged_logger? 29 | rails4? || rails5? 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/silencer/rails/logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails/rack/logger' 4 | require 'silencer/hush' 5 | require 'silencer/methods' 6 | require 'silencer/util' 7 | require 'silencer/rails/environment' 8 | 9 | module Silencer 10 | module Rails 11 | class Logger < ::Rails::Rack::Logger 12 | include Silencer::Hush 13 | include Silencer::Methods 14 | include Silencer::Util 15 | 16 | def initialize(app, *args) 17 | opts = extract_options!(args) 18 | @silence = wrap(opts.delete(:silence)) 19 | @routes = define_routes(@silence, opts) 20 | 21 | @enable_header = opts.delete(:enable_header) { true } 22 | 23 | normalized_args = normalize(args) 24 | if normalized_args 25 | super(app, normalized_args) 26 | else 27 | super(app) 28 | end 29 | end 30 | 31 | def call(env) 32 | if silence_request?(env, enable_header: @enable_header) 33 | quiet do 34 | super 35 | end 36 | else 37 | super 38 | end 39 | end 40 | 41 | private 42 | 43 | def quiet(&block) 44 | if ::Rails.logger.respond_to?(:silence) && ::Rails.logger.method(:silence).owner != ::Kernel 45 | quiet_with_silence(&block) 46 | else 47 | quiet_with_log_level(&block) 48 | end 49 | end 50 | 51 | # This is threadsafe in Rails 4.2.6+ 52 | def quiet_with_silence(&block) 53 | ::Rails.logger.silence(&block) 54 | end 55 | 56 | # This is not threadsafe 57 | def quiet_with_log_level 58 | old_logger_level = ::Rails.logger.level 59 | ::Rails.logger.level = ::Logger::ERROR 60 | 61 | yield 62 | ensure 63 | # Return back to previous logging level 64 | ::Rails.logger.level = old_logger_level 65 | end 66 | 67 | def normalize(args) 68 | case args.size 69 | when 0 then nil 70 | when 1 then args.shift 71 | else args 72 | end 73 | end 74 | end 75 | end 76 | 77 | Logger = Silencer::Rails::Logger 78 | end 79 | -------------------------------------------------------------------------------- /lib/silencer/util.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | module Util 5 | def wrap(object) 6 | if object.nil? 7 | [] 8 | elsif object.respond_to?(:to_ary) 9 | object.to_ary || [object] 10 | else 11 | [object] 12 | end 13 | end 14 | 15 | def extract_options!(args) 16 | if args.last.is_a?(Hash) 17 | args.pop 18 | else 19 | {} 20 | end 21 | end 22 | 23 | module_function :wrap, :extract_options! 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/silencer/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | VERSION = '2.0.0' 5 | end 6 | -------------------------------------------------------------------------------- /lint/markdown.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | all 4 | rule "MD046", style: "fenced" 5 | -------------------------------------------------------------------------------- /silencer.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'silencer/version' 5 | 6 | Gem::Specification.new do |gem| 7 | gem.name = "silencer" 8 | gem.version = Silencer::VERSION 9 | gem.authors = ["Steve Agalloco"] 10 | gem.email = ["steve.agalloco@gmail.com"] 11 | gem.homepage = "https://github.com/stve/silencer" 12 | gem.description = 'Selectively quiet your Rails/Rack logger on a per-route basis' 13 | gem.summary = gem.description 14 | 15 | gem.files = %w(.yardopts LICENSE.md README.md Rakefile silencer.gemspec) 16 | gem.files += Dir.glob("lib/**/*.rb") 17 | 18 | gem.test_files = Dir.glob("spec/**/*") 19 | 20 | gem.require_paths = ["lib"] 21 | end 22 | -------------------------------------------------------------------------------- /spec/log/test.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stve/silencer/234b67673afc5d880c0be7df7cdc3750fde8ba23/spec/log/test.log -------------------------------------------------------------------------------- /spec/silencer/rack/logger_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'silencer/rack/logger' 5 | 6 | describe Silencer::Rack::Logger do 7 | let(:app) do 8 | lambda { |env| 9 | log = env['rack.logger'] 10 | log.info('ohai') 11 | 12 | [200, {'Content-Type' => 'text/plain'}, ['Hello, World!']] 13 | } 14 | end 15 | 16 | let(:errors) do 17 | StringIO.new 18 | end 19 | 20 | it 'quiets the log when configured with a silenced path' do 21 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app, silence: ['/'])) 22 | Rack::MockRequest.new(a).get('/', 'rack.errors' => errors) 23 | expect(errors).not_to match('ohai') 24 | end 25 | 26 | it 'quiets the log when configured with a regex' do 27 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app, silence: [/assets/])) 28 | Rack::MockRequest.new(a).get('/assets/application.css', 'rack.errors' => errors) 29 | expect(errors).not_to match('ohai') 30 | end 31 | 32 | %w[OPTIONS GET POST PUT DELETE PATCH].each do |method| 33 | it "quiets the log when configured with a silenced path for #{method} requests" do 34 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app, method.downcase.to_sym => ['/'])) 35 | Rack::MockRequest.new(a).send(method.downcase.to_sym, '/', 'rack.errors' => errors) 36 | expect(errors).not_to match('ohai') 37 | end 38 | 39 | it "quiets the log when configured with a regex for #{method} requests" do 40 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app, method.downcase.to_sym => [/assets/])) 41 | Rack::MockRequest.new(a).send(method.downcase.to_sym, '/assets/application.css', 'rack.errors' => errors) 42 | expect(errors).not_to match('ohai') 43 | end 44 | end 45 | 46 | it 'quiets the log when configured with a regex for non-standard requests' do 47 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app, silence: [/assets/])) 48 | Rack::MockRequest.new(a).get('/', 'rack.errors' => errors) 49 | expect(errors).not_to match('ohai') 50 | end 51 | 52 | it 'quiets the log when passed a custom header "X-SILENCE-LOGGER"' do 53 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app)) 54 | Rack::MockRequest.new(a).get('/', 'rack.errors' => errors, 'HTTP_X_SILENCE_LOGGER' => 'true') 55 | expect(errors).not_to match('ohai') 56 | end 57 | 58 | it 'does not tamper with the response' do 59 | a = Rack::Lint.new(Silencer::Rack::Logger.new(app)) 60 | response = Rack::MockRequest.new(a).get('/', 'rack.errors' => errors, 'HTTP_X_SILENCE_LOGGER' => 'true') 61 | expect(response.status).to eq(200) 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/silencer/rails/logger_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'syslogger' 5 | require 'silencer/rails/logger' 6 | 7 | describe Silencer::Rails::Logger do 8 | let(:app) { ->(_env) { [200, {}, ''] } } 9 | let(:log_tags) { %i[uuid queue] } 10 | 11 | context 'quieted' do 12 | before do 13 | expect_any_instance_of(Silencer::Rails::Logger).to receive(:quiet).at_least(:once).and_call_original 14 | end 15 | 16 | it 'quiets the log when configured with a silenced path' do 17 | Silencer::Rails::Logger.new(app, silence: ['/']) 18 | .call(Rack::MockRequest.env_for('/')) 19 | end 20 | 21 | it 'quiets the log when configured with a regex' do 22 | Silencer::Rails::Logger.new(app, silence: [/assets/]) 23 | .call(Rack::MockRequest.env_for('/assets/application.css')) 24 | end 25 | 26 | %w[OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT PATCH].each do |method| 27 | it "quiets the log when configured with a silenced path for #{method} requests" do 28 | Silencer::Rails::Logger.new(app, method.downcase.to_sym => ['/']) 29 | .call(Rack::MockRequest.env_for('/', method: method)) 30 | end 31 | 32 | it "quiets the log when configured with a regex for #{method} requests" do 33 | Silencer::Rails::Logger.new(app, method.downcase.to_sym => [/assets/]) 34 | .call(Rack::MockRequest.env_for('/assets/application.css', method: method)) 35 | end 36 | end 37 | 38 | it 'quiets the log when configured with a silenced path for non-standard requests' do 39 | Silencer::Rails::Logger.new(app, silence: ['/']) 40 | .call(Rack::MockRequest.env_for('/', method: 'UPDATE')) 41 | end 42 | 43 | it 'quiets the log when configured with a regex for non-standard requests' do 44 | Silencer::Rails::Logger.new(app, silence: [/assets/]) 45 | .call(Rack::MockRequest.env_for('/assets/application.css', method: 'UPDATE')) 46 | end 47 | 48 | it 'quiets the log when passed a custom header "X-SILENCE-LOGGER"' do 49 | Silencer::Rails::Logger.new(app) 50 | .call(Rack::MockRequest.env_for('/', 'HTTP_X_SILENCE_LOGGER' => 'true')) 51 | end 52 | 53 | it 'does not tamper with the response' do 54 | response = Silencer::Rails::Logger.new(app) 55 | .call(Rack::MockRequest.env_for('/', 'HTTP_X_SILENCE_LOGGER' => 'true')) 56 | 57 | expect(response[0]).to eq(200) 58 | end 59 | 60 | if Silencer::Environment.tagged_logger? 61 | it 'instantiates with an optional taggers array' do 62 | Silencer::Rails::Logger.new(app, log_tags, silence: ['/']) 63 | .call(Rack::MockRequest.env_for('/')) 64 | end 65 | 66 | it 'instantiates with an optional taggers array passed as args' do 67 | Silencer::Rails::Logger.new(app, :uuid, :queue, silence: ['/']) 68 | .call(Rack::MockRequest.env_for('/')) 69 | end 70 | end 71 | end 72 | 73 | describe 'enable_header option' do 74 | it 'does not quiet the log when passed a custom header "X-SILENCE-LOGGER" when enable_header option is false' do 75 | expect_any_instance_of(Silencer::Rails::Logger).to_not receive(:quiet) 76 | 77 | Silencer::Rails::Logger.new(app, enable_header: false) 78 | .call(Rack::MockRequest.env_for('/', 'HTTP_X_SILENCE_LOGGER' => 'true')) 79 | end 80 | 81 | it 'quiets the log when passed a custom header "X-SILENCE-LOGGER" when enable_header option is true' do 82 | expect_any_instance_of(Silencer::Rails::Logger).to receive(:quiet).once.and_call_original 83 | 84 | Silencer::Rails::Logger.new(app, enable_header: true) 85 | .call(Rack::MockRequest.env_for('/', 'HTTP_X_SILENCE_LOGGER' => 'true')) 86 | end 87 | end 88 | 89 | it 'silences' do 90 | logger = Silencer::Rails::Logger.new(app, silence: ['/']) 91 | 92 | if ::Rails.logger.respond_to?(:silence) 93 | expect(::Rails.logger).to receive(:silence).at_least(:once) 94 | else 95 | expect(::Rails.logger).to receive(:level=) 96 | .with(::Logger::ERROR).at_least(:once) 97 | end 98 | 99 | logger.call(Rack::MockRequest.env_for('/')) 100 | end 101 | 102 | context 'when logger is Syslogger' do 103 | it 'does not throw error' do 104 | mock_rails_logger = Syslogger.new 105 | allow(::Rails).to receive(:logger) { mock_rails_logger } 106 | 107 | logger = Silencer::Rails::Logger.new(app, silence: ['/']) 108 | expect { logger.call(Rack::MockRequest.env_for('/')) }.not_to raise_error 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | unless ENV['CI'] 4 | require 'simplecov' 5 | SimpleCov.start do 6 | add_group 'Silencer', 'lib/silencer' 7 | add_group 'Specs', 'spec' 8 | end 9 | end 10 | 11 | require 'rack' 12 | require 'rack/lint' 13 | require 'rspec' 14 | 15 | require 'logger' 16 | require 'stringio' 17 | 18 | io = StringIO.new 19 | 20 | begin 21 | require 'rails' 22 | ::Rails.logger = if Rails::VERSION::MAJOR >= 4 23 | ::ActiveSupport::Logger.new(io) 24 | else 25 | ::Logger.new(io) 26 | end 27 | rescue LoadError 28 | require 'activesupport' 29 | RAILS_ENV = 'test' 30 | RAILS_ROOT = File.dirname(__FILE__) 31 | RAILS_DEFAULT_LOGGER = ::Logger.new(io) 32 | require 'initializer' 33 | end 34 | 35 | require 'silencer' 36 | 37 | RSpec.configure do |config| 38 | config.expect_with :rspec do |c| 39 | c.syntax = :expect 40 | end 41 | 42 | config.before(:each) do 43 | allow(::Rails.logger).to receive(:level=).with(anything) 44 | end 45 | end 46 | --------------------------------------------------------------------------------