├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── concise_logging.gemspec ├── img └── screenshot.png ├── lib ├── concise_logging.rb └── concise_logging │ ├── log_middleware.rb │ ├── log_subscriber.rb │ ├── railtie.rb │ └── version.rb └── test └── loader_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 1.1.0 / Nov 14, 2016 4 | 5 | * Reduce dependency footprint. 6 | 7 | ## 1.0.1 / Jun 1, 2016 8 | 9 | * Allow usage by Rails 5 10 | 11 | ## 1.0.0 / Feb 10, 2015 12 | 13 | * Add IP option for X-REAL-IP (@konsti) 14 | 15 | ## 0.1.1 / Oct 15, 2014 16 | 17 | * Do not enable concise_logging in development 18 | 19 | ## 0.1.0 / Oct 15, 2014 20 | 21 | * Move initialization code to Railtie (@zohrehj) 22 | 23 | ## 0.0.1 / Oct 11, 2014 24 | 25 | * Initial release 26 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in concise_logging.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Gerry Shaw 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ConciseLogging 2 | 3 | Concise request logging for Rails production 4 | 5 | ![screenshot](https://github.com/gshaw/concise_logging/raw/master/img/screenshot.png) 6 | 7 | Logs a concise single line for each request at `:warn` level. This allows 8 | logging requests without all the extra logging that `:info` level outputs. 9 | 10 | Not suitable for development but ideal for production settings where each 11 | request and associated parameters is logged. 12 | 13 | Inspired by a [blog post on RubyJunky.com][1]. 14 | 15 | Special thanks to [Zohreh Jabbari](https://github.com/zohrehj) for doing the 16 | initial coding and proof of concept. 17 | 18 | [1]: http://rubyjunky.com/cleaning-up-rails-4-production-logging.html 19 | 20 | ## Installation 21 | 22 | Add this line to your application's Gemfile: 23 | 24 | ```ruby 25 | gem 'concise_logging' 26 | ``` 27 | 28 | And then execute: 29 | 30 | $ bundle 31 | 32 | Or install it yourself as: 33 | 34 | $ gem install concise_logging 35 | 36 | ## Usage 37 | 38 | Add this to your `config/production.rb`. Configure tagging as per your desires. 39 | We use tagging to indicate application with a 2 letter code and environment with 40 | a single letter (e.g., p = production, s = staging). 41 | 42 | ```ruby 43 | # Configure logger to log warn and above 44 | config.log_level = :warn 45 | config.log_tags = ["cv-#{Rails.env[0]}"] 46 | config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(File.join(Rails.root, "log", "#{Rails.env}.log"))) 47 | ``` 48 | 49 | If you want to try the logger in development than you have to manually add the 50 | middleware and attach the log subscriber by adding these lines in your 51 | `config/development.rb` file. These lines are not needed for production. 52 | 53 | ```ruby 54 | Rails.application.middleware.use ConciseLogging::LogMiddleware 55 | ConciseLogging::LogSubscriber.attach_to :action_controller 56 | ``` 57 | 58 | ## Contributing 59 | 60 | 1. Fork it ( https://github.com/[my-github-username]/concise_logging/fork ) 61 | 2. Create your feature branch (`git checkout -b my-new-feature`) 62 | 3. Commit your changes (`git commit -am 'Add some feature'`) 63 | 4. Push to the branch (`git push origin my-new-feature`) 64 | 5. Create a new Pull Request 65 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | task default: :test 4 | task :test do 5 | Dir.glob("./test/*_test.rb").each { |file| require file } 6 | end 7 | -------------------------------------------------------------------------------- /concise_logging.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'concise_logging/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "concise_logging" 8 | spec.version = ConciseLogging::VERSION 9 | spec.authors = ["Gerry Shaw"] 10 | spec.email = ["gerry_shaw@yahoo.com"] 11 | spec.summary = %q{Alternate logging for Rails production servers} 12 | spec.homepage = "https://github.com/gshaw/concise_logging" 13 | spec.license = "MIT" 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ["lib"] 19 | 20 | spec.add_runtime_dependency "railties", ">= 4.2" 21 | spec.add_runtime_dependency "activesupport", ">= 4.2" 22 | 23 | spec.add_development_dependency "bundler", "~> 1.7" 24 | spec.add_development_dependency "rake", "~> 10.0" 25 | spec.add_development_dependency "minitest", "~> 5.9" 26 | end 27 | -------------------------------------------------------------------------------- /img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gshaw/concise_logging/bac45faae3862c6bdc7232fde4785a2648cccffd/img/screenshot.png -------------------------------------------------------------------------------- /lib/concise_logging.rb: -------------------------------------------------------------------------------- 1 | require "concise_logging/version" 2 | require "concise_logging/log_middleware" 3 | require "concise_logging/log_subscriber" 4 | require "concise_logging/railtie" if defined? Rails 5 | -------------------------------------------------------------------------------- /lib/concise_logging/log_middleware.rb: -------------------------------------------------------------------------------- 1 | module ConciseLogging 2 | class LogMiddleware 3 | def initialize(app) 4 | @app = app 5 | end 6 | 7 | def call(env) 8 | request = ActionDispatch::Request.new(env) 9 | Thread.current[:logged_ip] = request.env['HTTP_X_REAL_IP'] || request.ip 10 | @app.call(env) 11 | ensure 12 | Thread.current[:logged_ip] = nil 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/concise_logging/log_subscriber.rb: -------------------------------------------------------------------------------- 1 | require "active_support" 2 | 3 | module ConciseLogging 4 | class LogSubscriber < ActiveSupport::LogSubscriber 5 | INTERNAL_PARAMS = %w(controller action format _method only_path) 6 | 7 | def redirect_to(event) 8 | Thread.current[:logged_location] = event.payload[:location] 9 | end 10 | 11 | def process_action(event) 12 | payload = event.payload 13 | param_method = payload[:params]["_method"] 14 | method = param_method ? param_method.upcase : payload[:method] 15 | status, exception_details = compute_status(payload) 16 | path = payload[:path].to_s.gsub(/\?.*/, "") 17 | params = payload[:params].except(*INTERNAL_PARAMS) 18 | 19 | ip = Thread.current[:logged_ip] 20 | location = Thread.current[:logged_location] 21 | Thread.current[:logged_location] = nil 22 | 23 | app = payload[:view_runtime].to_i 24 | db = payload[:db_runtime].to_i 25 | 26 | message = format( 27 | "%{method} %{status} %{ip} %{path}", 28 | ip: format("%-15s", ip), 29 | method: format_method(format("%-6s", method)), 30 | status: format_status(status), 31 | path: path 32 | ) 33 | message << " redirect_to=#{location}" if location.present? 34 | message << " parameters=#{params}" if params.present? 35 | message << " #{color(exception_details, RED)}" if exception_details.present? 36 | message << " (app:#{app}ms db:#{db}ms)" 37 | 38 | logger.warn message 39 | end 40 | 41 | def compute_status(payload) 42 | details = nil 43 | status = payload[:status] 44 | if status.nil? && payload[:exception].present? 45 | exception_class_name = payload[:exception].first 46 | status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name) 47 | 48 | if payload[:exception].respond_to?(:uniq) 49 | details = payload[:exception].uniq.join(" ") 50 | end 51 | end 52 | [status, details] 53 | end 54 | 55 | def format_method(method) 56 | if method.strip == "GET" 57 | method 58 | else 59 | color(method, CYAN) 60 | end 61 | end 62 | 63 | def format_status(status) 64 | status = status.to_i 65 | if status >= 400 66 | color(status, RED) 67 | elsif status >= 300 68 | color(status, YELLOW) 69 | else 70 | color(status, GREEN) 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/concise_logging/railtie.rb: -------------------------------------------------------------------------------- 1 | module ConciseLogging 2 | class Railtie < Rails::Railtie 3 | unless Rails.env.development? 4 | initializer "railtie.concise_logging" do |app| 5 | app.middleware.use ConciseLogging::LogMiddleware 6 | end 7 | 8 | ConciseLogging::LogSubscriber.attach_to :action_controller 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/concise_logging/version.rb: -------------------------------------------------------------------------------- 1 | module ConciseLogging 2 | VERSION = "1.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /test/loader_test.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require "concise_logging/log_subscriber" 3 | 4 | class LoaderTest < Minitest::Test 5 | def test_attach_to_log_subscriber 6 | log_subscriber = ConciseLogging::LogSubscriber.new 7 | ActiveSupport::LogSubscriber.attach_to(:my_log_subscriber, log_subscriber) 8 | assert true 9 | end 10 | end 11 | --------------------------------------------------------------------------------