lograge-0.5.0/0000755000175000017500000000000013150054645012163 5ustar pravipravilograge-0.5.0/lograge.gemspec0000644000175000017500000000515013150054645015151 0ustar pravipravi######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: lograge 0.5.0 ruby lib Gem::Specification.new do |s| s.name = "lograge".freeze s.version = "0.5.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Mathias Meyer".freeze, "Ben Lovell".freeze] s.date = "2017-04-28" s.description = "Tame Rails' multi-line logging into a single line per request".freeze s.email = ["meyer@paperplanes.de".freeze, "benjamin.lovell@gmail.com".freeze] s.files = ["lib/lograge.rb".freeze, "lib/lograge/formatters/cee.rb".freeze, "lib/lograge/formatters/graylog2.rb".freeze, "lib/lograge/formatters/json.rb".freeze, "lib/lograge/formatters/key_value.rb".freeze, "lib/lograge/formatters/l2met.rb".freeze, "lib/lograge/formatters/lines.rb".freeze, "lib/lograge/formatters/logstash.rb".freeze, "lib/lograge/formatters/ltsv.rb".freeze, "lib/lograge/formatters/raw.rb".freeze, "lib/lograge/log_subscriber.rb".freeze, "lib/lograge/rails_ext/rack/logger.rb".freeze, "lib/lograge/railtie.rb".freeze, "lib/lograge/version.rb".freeze] s.homepage = "https://github.com/roidrage/lograge".freeze s.licenses = ["MIT".freeze] s.rubygems_version = "2.5.2".freeze s.summary = "Tame Rails' multi-line logging into a single line per request".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_runtime_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_runtime_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["= 0.46.0"]) else s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["= 0.46.0"]) end else s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, ["<= 5.1.0", ">= 4"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["= 0.46.0"]) end end lograge-0.5.0/lib/0000755000175000017500000000000013150054645012731 5ustar pravipravilograge-0.5.0/lib/lograge.rb0000644000175000017500000001252213150054645014700 0ustar pravipravirequire 'lograge/version' require 'lograge/formatters/cee' require 'lograge/formatters/json' require 'lograge/formatters/graylog2' require 'lograge/formatters/key_value' require 'lograge/formatters/l2met' require 'lograge/formatters/lines' require 'lograge/formatters/logstash' require 'lograge/formatters/ltsv' require 'lograge/formatters/raw' require 'lograge/log_subscriber' require 'active_support/core_ext/module/attribute_accessors' require 'active_support/core_ext/string/inflections' require 'active_support/ordered_options' # rubocop:disable ModuleLength module Lograge module_function mattr_accessor :logger, :application, :ignore_tests # Custom options that will be appended to log line # # Currently supported formats are: # - Hash # - Any object that responds to call and returns a hash # mattr_writer :custom_options self.custom_options = nil def custom_options(event) if @@custom_options.respond_to?(:call) @@custom_options.call(event) else @@custom_options end end # Before format allows you to change the structure of the output. # You've to pass in something callable # mattr_writer :before_format self.before_format = nil def before_format(data, payload) result = nil result = @@before_format.call(data, payload) if @@before_format result || data end # Set conditions for events that should be ignored # # Currently supported formats are: # - A single string representing a controller action, e.g. 'UsersController#sign_in' # - An array of strings representing controller actions # - An object that responds to call with an event argument and returns # true iff the event should be ignored. # # The action ignores are given to 'ignore_actions'. The callable ignores # are given to 'ignore'. Both methods can be called multiple times, which # just adds more ignore conditions to a list that is checked before logging. def ignore_actions(actions) ignore(lambda do |event| params = event.payload Array(actions).include?("#{params[:controller]}##{params[:action]}") end) end def ignore_tests @ignore_tests ||= [] end def ignore(test) ignore_tests.push(test) if test end def ignore_nothing @ignore_tests = [] end def ignore?(event) ignore_tests.any? { |ignore_test| ignore_test.call(event) } end # Loglines are emitted with this log level mattr_accessor :log_level self.log_level = :info # The emitted log format # # Currently supported formats are> # - :lograge - The custom tense lograge format # - :logstash - JSON formatted as a Logstash Event. mattr_accessor :formatter def remove_existing_log_subscriptions ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber| case subscriber when ActionView::LogSubscriber unsubscribe(:action_view, subscriber) when ActionController::LogSubscriber unsubscribe(:action_controller, subscriber) end end end def unsubscribe(component, subscriber) events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' } events.each do |event| ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener| if listener.instance_variable_get('@delegate') == subscriber ActiveSupport::Notifications.unsubscribe listener end end end end def setup(app) self.application = app disable_rack_cache_verbose_output keep_original_rails_log attach_to_action_controller set_lograge_log_options support_deprecated_config # TODO: Remove with version 1.0 set_formatter set_ignores end def set_ignores Lograge.ignore_actions(lograge_config.ignore_actions) Lograge.ignore(lograge_config.ignore_custom) end def set_formatter Lograge.formatter = lograge_config.formatter || Lograge::Formatters::KeyValue.new end def attach_to_action_controller Lograge::RequestLogSubscriber.attach_to :action_controller end def set_lograge_log_options Lograge.logger = lograge_config.logger Lograge.custom_options = lograge_config.custom_options Lograge.before_format = lograge_config.before_format Lograge.log_level = lograge_config.log_level || :info end def disable_rack_cache_verbose_output application.config.action_dispatch.rack_cache[:verbose] = false if rack_cache_hashlike?(application) end def keep_original_rails_log return if lograge_config.keep_original_rails_log require 'lograge/rails_ext/rack/logger' Lograge.remove_existing_log_subscriptions end def rack_cache_hashlike?(app) app.config.action_dispatch.rack_cache && app.config.action_dispatch.rack_cache.respond_to?(:[]=) end private_class_method :rack_cache_hashlike? # TODO: Remove with version 1.0 def support_deprecated_config return unless lograge_config.log_format legacy_log_format = lograge_config.log_format warning = 'config.lograge.log_format is deprecated. Use config.lograge.formatter instead.' ActiveSupport::Deprecation.warn(warning, caller) legacy_log_format = :key_value if legacy_log_format == :lograge lograge_config.formatter = "Lograge::Formatters::#{legacy_log_format.to_s.classify}".constantize.new end def lograge_config application.config.lograge end end require 'lograge/railtie' if defined?(Rails) lograge-0.5.0/lib/lograge/0000755000175000017500000000000013150054645014351 5ustar pravipravilograge-0.5.0/lib/lograge/log_subscriber.rb0000644000175000017500000000623113150054645017704 0ustar pravipravirequire 'json' require 'action_pack' require 'active_support/core_ext/class/attribute' require 'active_support/log_subscriber' module Lograge class RequestLogSubscriber < ActiveSupport::LogSubscriber def process_action(event) return if Lograge.ignore?(event) payload = event.payload data = extract_request(event, payload) data = before_format(data, payload) formatted_message = Lograge.formatter.call(data) logger.send(Lograge.log_level, formatted_message) end def redirect_to(event) Thread.current[:lograge_location] = event.payload[:location] end def unpermitted_parameters(event) Thread.current[:lograge_unpermitted_params] ||= [] Thread.current[:lograge_unpermitted_params].concat(event.payload[:keys]) end def logger Lograge.logger.presence || super end private def extract_request(event, payload) payload = event.payload data = initial_data(payload) data.merge!(extract_status(payload)) data.merge!(extract_runtimes(event, payload)) data.merge!(extract_location) data.merge!(extract_unpermitted_params) data.merge!(custom_options(event)) end def initial_data(payload) { method: payload[:method], path: extract_path(payload), format: extract_format(payload), controller: payload[:controller], action: payload[:action] } end def extract_path(payload) path = payload[:path] index = path.index('?') index ? path[0, index] : path end if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR.zero? def extract_format(payload) payload[:formats].first end else def extract_format(payload) payload[:format] end end def extract_status(payload) if (status = payload[:status]) { status: status.to_i } elsif (error = payload[:exception]) exception, message = error { status: get_error_status_code(exception), error: "#{exception}: #{message}" } else { status: 0 } end end def get_error_status_code(exception) status = ActionDispatch::ExceptionWrapper.rescue_responses[exception] Rack::Utils.status_code(status) end def custom_options(event) Lograge.custom_options(event) || {} end def before_format(data, payload) Lograge.before_format(data, payload) end def extract_runtimes(event, payload) data = { duration: event.duration.to_f.round(2) } data[:view] = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime) data[:db] = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime) data end def extract_location location = Thread.current[:lograge_location] return {} unless location Thread.current[:lograge_location] = nil { location: location } end def extract_unpermitted_params unpermitted_params = Thread.current[:lograge_unpermitted_params] return {} unless unpermitted_params Thread.current[:lograge_unpermitted_params] = nil { unpermitted_params: unpermitted_params } end end end lograge-0.5.0/lib/lograge/railtie.rb0000644000175000017500000000054213150054645016330 0ustar pravipravirequire 'rails/railtie' require 'action_view/log_subscriber' require 'action_controller/log_subscriber' module Lograge class Railtie < Rails::Railtie config.lograge = ActiveSupport::OrderedOptions.new config.lograge.enabled = false config.after_initialize do |app| Lograge.setup(app) if app.config.lograge.enabled end end end lograge-0.5.0/lib/lograge/formatters/0000755000175000017500000000000013150054645016537 5ustar pravipravilograge-0.5.0/lib/lograge/formatters/raw.rb0000644000175000017500000000015713150054645017660 0ustar pravipravimodule Lograge module Formatters class Raw def call(data) data end end end end lograge-0.5.0/lib/lograge/formatters/key_value.rb0000644000175000017500000000121713150054645021051 0ustar pravipravimodule Lograge module Formatters class KeyValue def call(data) fields = fields_to_display(data) event = fields.map { |key| format(key, data[key]) } event.join(' ') end def fields_to_display(data) data.keys end def format(key, value) if key == :error # Exactly preserve the previous output # Parsing this can be ambigious if the error messages contains # a single quote value = "'#{value}'" elsif value.is_a? Float value = Kernel.format('%.2f', value) end "#{key}=#{value}" end end end end lograge-0.5.0/lib/lograge/formatters/logstash.rb0000644000175000017500000000077513150054645020721 0ustar pravipravimodule Lograge module Formatters class Logstash def call(data) load_dependencies event = LogStash::Event.new(data) event['message'] = "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})" event.to_json end def load_dependencies require 'logstash-event' rescue LoadError puts 'You need to install the logstash-event gem to use the logstash output.' raise end end end end lograge-0.5.0/lib/lograge/formatters/lines.rb0000644000175000017500000000050313150054645020174 0ustar pravipravimodule Lograge module Formatters class Lines def call(data) load_dependencies ::Lines.dump(data) end def load_dependencies require 'lines' rescue LoadError puts 'You need to install the lines gem to use this output.' raise end end end end lograge-0.5.0/lib/lograge/formatters/json.rb0000644000175000017500000000021413150054645020032 0ustar pravipravirequire 'json' module Lograge module Formatters class Json def call(data) ::JSON.dump(data) end end end end lograge-0.5.0/lib/lograge/formatters/ltsv.rb0000644000175000017500000000163313150054645020057 0ustar pravipravimodule Lograge module Formatters class LTSV def call(data) fields = fields_to_display(data) event = fields.map { |key| format(key, data[key]) } event.join("\t") end def fields_to_display(data) data.keys end def format(key, value) if key == :error # Exactly preserve the previous output # Parsing this can be ambigious if the error messages contains # a single quote value = "'#{escape value}'" elsif value.is_a? Float value = Kernel.format('%.2f', value) end "#{key}:#{value}" end private def escape(string) value = string.is_a?(String) ? string.dup : string.to_s value.gsub!('\\', '\\\\') value.gsub!('\n', '\\n') value.gsub!('\r', '\\r') value.gsub!('\t', '\\t') value end end end end lograge-0.5.0/lib/lograge/formatters/cee.rb0000644000175000017500000000020513150054645017615 0ustar pravipravimodule Lograge module Formatters class Cee def call(data) "@cee: #{JSON.dump(data)}" end end end end lograge-0.5.0/lib/lograge/formatters/graylog2.rb0000644000175000017500000000140013150054645020605 0ustar pravipravimodule Lograge module Formatters class Graylog2 def call(data) # Cloning because we don't want to mess with the original when mutating keys. data_clone = data.clone base = { short_message: short_message(data_clone) } # Add underscore to every key to follow GELF additional field syntax. data_clone.keys.each do |key| data_clone[underscore_prefix(key)] = data_clone[key] data_clone.delete(key) end data_clone.merge(base) end def underscore_prefix(key) "_#{key}".to_sym end def short_message(data) "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})" end end end end lograge-0.5.0/lib/lograge/formatters/l2met.rb0000644000175000017500000000155613150054645020116 0ustar pravipravirequire 'lograge/formatters/key_value' module Lograge module Formatters class L2met < KeyValue L2MET_FIELDS = [ :method, :path, :format, :source, :status, :error, :duration, :view, :db, :location ].freeze def call(data) super(modify_payload(data)) end def format(key, value) key = "measure#page.#{key}" if value.is_a?(Float) super(key, value) end def fields_to_display(data) L2MET_FIELDS + (data.keys - L2MET_FIELDS) - [:controller, :action] end def modify_payload(data) data[:source] = source_field(data) if data[:controller] && data[:action] data end def source_field(data) "#{data[:controller].to_s.tr('/', '-')}:#{data[:action]}" end end end end lograge-0.5.0/lib/lograge/rails_ext/0000755000175000017500000000000013150054645016343 5ustar pravipravilograge-0.5.0/lib/lograge/rails_ext/rack/0000755000175000017500000000000013150054645017263 5ustar pravipravilograge-0.5.0/lib/lograge/rails_ext/rack/logger.rb0000644000175000017500000000116513150054645021072 0ustar pravipravirequire 'active_support/concern' require 'rails/rack/logger' module Rails module Rack # Overwrites defaults of Rails::Rack::Logger that cause # unnecessary logging. # This effectively removes the log lines from the log # that say: # Started GET / for 192.168.2.1... class Logger # Overwrites Rails 3.2 code that logs new requests def call_app(*args) env = args.last @app.call(env) ensure ActiveSupport::LogSubscriber.flush_all! end # Overwrites Rails 3.0/3.1 code that logs new requests def before_dispatch(_env) end end end end lograge-0.5.0/lib/lograge/version.rb0000644000175000017500000000005613150054645016364 0ustar pravipravimodule Lograge VERSION = '0.5.0'.freeze end