lograge-with-time 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac5cfd309efdd6412c63cc4295d0ba9117eb9c65
4
+ data.tar.gz: a80420cf987a1d75c1e8fcb4a070bfc6873bd9eb
5
+ SHA512:
6
+ metadata.gz: 4936ec0831533e52689c7d0ede3e586da8da4da5cb9d3dd4fc38fd5e952aae8685cf379e0423a091084e05ed1cf0157a1b74dbd9a493a773f107798a67156721
7
+ data.tar.gz: 2b52005718728e6d3f6ac9c5fbe9bd304342f033f80ea359d725eb401bcc978c97358da74e8b044efddba5939d4df6978f9eed6da58ea4b6cab4e7ef2fdbe4bb
@@ -0,0 +1,149 @@
1
+ require 'lograge/version'
2
+ require 'lograge/formatters/cee'
3
+ require 'lograge/formatters/json'
4
+ require 'lograge/formatters/graylog2'
5
+ require 'lograge/formatters/key_value'
6
+ require 'lograge/formatters/l2met'
7
+ require 'lograge/formatters/lines'
8
+ require 'lograge/formatters/logstash'
9
+ require 'lograge/formatters/raw'
10
+ require 'lograge/log_subscriber'
11
+ require 'active_support/core_ext/module/attribute_accessors'
12
+ require 'active_support/core_ext/string/inflections'
13
+ require 'active_support/ordered_options'
14
+
15
+ module Lograge
16
+ module_function
17
+
18
+ mattr_accessor :logger, :application, :ignore_tests
19
+
20
+ # Custom options that will be appended to log line
21
+ #
22
+ # Currently supported formats are:
23
+ # - Hash
24
+ # - Any object that responds to call and returns a hash
25
+ #
26
+ mattr_writer :custom_options
27
+ self.custom_options = nil
28
+
29
+ def self.custom_options(event)
30
+ if @@custom_options.respond_to?(:call)
31
+ @@custom_options.call(event)
32
+ else
33
+ @@custom_options
34
+ end
35
+ end
36
+
37
+ # Before format allows you to change the structure of the output.
38
+ # You've to pass in something callable
39
+ #
40
+ mattr_writer :before_format
41
+ self.before_format = nil
42
+
43
+ def self.before_format(data, payload)
44
+ result = nil
45
+ result = @@before_format.call(data, payload) if @@before_format
46
+ result || data
47
+ end
48
+
49
+ # Set conditions for events that should be ignored
50
+ #
51
+ # Currently supported formats are:
52
+ # - A single string representing a controller action, e.g. 'users#sign_in'
53
+ # - An array of strings representing controller actions
54
+ # - An object that responds to call with an event argument and returns
55
+ # true iff the event should be ignored.
56
+ #
57
+ # The action ignores are given to 'ignore_actions'. The callable ignores
58
+ # are given to 'ignore'. Both methods can be called multiple times, which
59
+ # just adds more ignore conditions to a list that is checked before logging.
60
+
61
+ def self.ignore_actions(actions)
62
+ ignore(lambda do |event|
63
+ params = event.payload[:params]
64
+ Array(actions).include?("#{params['controller']}##{params['action']}")
65
+ end)
66
+ end
67
+
68
+ def ignore_tests
69
+ @ignore_tests ||= []
70
+ end
71
+
72
+ def self.ignore(test)
73
+ ignore_tests.push(test) if test
74
+ end
75
+
76
+ def ignore_nothing
77
+ @ignore_tests = []
78
+ end
79
+
80
+ def self.ignore?(event)
81
+ ignore_tests.any? { |ignore_test| ignore_test.call(event) }
82
+ end
83
+
84
+ # Loglines are emitted with this log level
85
+ mattr_accessor :log_level
86
+ self.log_level = :info
87
+
88
+ # The emitted log format
89
+ #
90
+ # Currently supported formats are>
91
+ # - :lograge - The custom tense lograge format
92
+ # - :logstash - JSON formatted as a Logstash Event.
93
+ mattr_accessor :formatter
94
+
95
+ def self.remove_existing_log_subscriptions
96
+ ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
97
+ case subscriber
98
+ when ActionView::LogSubscriber
99
+ unsubscribe(:action_view, subscriber)
100
+ when ActionController::LogSubscriber
101
+ unsubscribe(:action_controller, subscriber)
102
+ end
103
+ end
104
+ end
105
+
106
+ def self.unsubscribe(component, subscriber)
107
+ events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
108
+ events.each do |event|
109
+ ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
110
+ if listener.instance_variable_get('@delegate') == subscriber
111
+ ActiveSupport::Notifications.unsubscribe listener
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def self.setup(app)
118
+ self.application = app
119
+ app.config.action_dispatch.rack_cache[:verbose] = false if app.config.action_dispatch.rack_cache
120
+ require 'lograge/rails_ext/rack/logger'
121
+ Lograge.remove_existing_log_subscriptions
122
+ Lograge::RequestLogSubscriber.attach_to :action_controller
123
+ Lograge.custom_options = lograge_config.custom_options
124
+ Lograge.before_format = lograge_config.before_format
125
+ Lograge.log_level = lograge_config.log_level || :info
126
+ support_deprecated_config # TODO: Remove with version 1.0
127
+ Lograge.formatter = lograge_config.formatter || Lograge::Formatters::KeyValue.new
128
+ Lograge.ignore_actions(lograge_config.ignore_actions)
129
+ Lograge.ignore(lograge_config.ignore_custom)
130
+ end
131
+
132
+ # TODO: Remove with version 1.0
133
+
134
+ def support_deprecated_config
135
+ return unless lograge_config.log_format
136
+
137
+ legacy_log_format = lograge_config.log_format
138
+ warning = 'config.lograge.log_format is deprecated. Use config.lograge.formatter instead.'
139
+ ActiveSupport::Deprecation.warn(warning, caller)
140
+ legacy_log_format = :key_value if legacy_log_format == :lograge
141
+ lograge_config.formatter = "Lograge::Formatters::#{legacy_log_format.to_s.classify}".constantize.new
142
+ end
143
+
144
+ def lograge_config
145
+ application.config.lograge
146
+ end
147
+ end
148
+
149
+ require 'lograge/railtie' if defined?(Rails)
@@ -0,0 +1,9 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Cee
4
+ def call(data)
5
+ "@cee: #{JSON.dump(data)}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Graylog2
4
+ def call(data)
5
+ # Cloning because we don't want to mess with the original when mutating keys.
6
+ data_clone = data.clone
7
+
8
+ base = {
9
+ short_message: short_message(data_clone)
10
+ }
11
+
12
+ # Add underscore to every key to follow GELF additional field syntax.
13
+ data_clone.keys.each do |key|
14
+ data_clone[underscore_prefix(key)] = data_clone[key]
15
+ data_clone.delete(key)
16
+ end
17
+
18
+ data_clone.merge(base)
19
+ end
20
+
21
+ def underscore_prefix(key)
22
+ "_#{key}".to_sym
23
+ end
24
+
25
+ def short_message(data)
26
+ "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ require 'json'
2
+ module Lograge
3
+ module Formatters
4
+ class Json
5
+ def call(data)
6
+ ::JSON.dump(data)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,38 @@
1
+ module Lograge
2
+ module Formatters
3
+ class KeyValue
4
+ LOGRAGE_FIELDS = [
5
+ :time, :method, :path, :format, :controller, :action, :status, :error,
6
+ :duration, :view, :db, :location
7
+ ]
8
+
9
+ def call(data)
10
+ fields = fields_to_display(data)
11
+
12
+ event = fields.reduce([]) do |message, key|
13
+ next message unless data.key?(key)
14
+
15
+ message << format(key, data[key])
16
+ message
17
+ end
18
+ event.join(' ')
19
+ end
20
+
21
+ def fields_to_display(data)
22
+ LOGRAGE_FIELDS + (data.keys - LOGRAGE_FIELDS)
23
+ end
24
+
25
+ def format(key, value)
26
+ # Exactly preserve the previous output
27
+ # Parsing this can be ambigious if the error messages contains
28
+ # a single quote
29
+ value = "'#{value}'" if key == :error
30
+
31
+ # Ensure that we always have exactly two decimals
32
+ value = Kernel.format('%.2f', value) if value.is_a? Float
33
+
34
+ "#{key}=#{value}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ require 'lograge/formatters/key_value'
2
+
3
+ module Lograge
4
+ module Formatters
5
+ class L2met < KeyValue
6
+ L2MET_FIELDS = [
7
+ :method, :path, :format, :source, :status, :error,
8
+ :duration, :view, :db, :location
9
+ ]
10
+
11
+ def call(data)
12
+ super(modify_payload(data))
13
+ end
14
+
15
+ def format(key, value)
16
+ key = "measure#page.#{key}" if value.is_a?(Float)
17
+
18
+ super(key, value)
19
+ end
20
+
21
+ def fields_to_display(data)
22
+ L2MET_FIELDS + (data.keys - L2MET_FIELDS) - [:controller, :action]
23
+ end
24
+
25
+ def modify_payload(data)
26
+ data[:source] = source_field(data) if data[:controller] && data[:action]
27
+
28
+ data
29
+ end
30
+
31
+ def source_field(data)
32
+ "#{data[:controller].to_s.gsub('/', '-')}:#{data[:action]}"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Lines
4
+ def call(data)
5
+ load_dependencies
6
+
7
+ ::Lines.dump(data)
8
+ end
9
+
10
+ def load_dependencies
11
+ require 'lines'
12
+ rescue LoadError
13
+ puts 'You need to install the lines gem to use this output.'
14
+ raise
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Logstash
4
+ def call(data)
5
+ load_dependencies
6
+ event = LogStash::Event.new(data)
7
+
8
+ event.message = "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})"
9
+ event.to_json
10
+ end
11
+
12
+ def load_dependencies
13
+ require 'logstash-event'
14
+ rescue LoadError
15
+ puts 'You need to install the logstash-event gem to use the logstash output.'
16
+ raise
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Raw
4
+ def call(data)
5
+ data
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,104 @@
1
+ require 'json'
2
+
3
+ require 'active_support/core_ext/class/attribute'
4
+ require 'active_support/log_subscriber'
5
+
6
+ module Lograge
7
+ class RequestLogSubscriber < ActiveSupport::LogSubscriber
8
+ def process_action(event)
9
+ return if Lograge.ignore?(event)
10
+
11
+ payload = event.payload
12
+
13
+ data = extract_time(event)
14
+ data.merge! extract_request(payload)
15
+ data.merge! extract_status(payload)
16
+ data.merge! runtimes(event)
17
+ data.merge! location(event)
18
+ data.merge! custom_options(event)
19
+
20
+ data = before_format(data, payload)
21
+ formatted_message = Lograge.formatter.call(data)
22
+ logger.send(Lograge.log_level, formatted_message)
23
+ end
24
+
25
+ def redirect_to(event)
26
+ Thread.current[:lograge_location] = event.payload[:location]
27
+ end
28
+
29
+ def logger
30
+ Lograge.logger.presence || super
31
+ end
32
+
33
+ private
34
+
35
+ def extract_time(event)
36
+ {
37
+ time: event.time
38
+ }
39
+ end
40
+
41
+ def extract_request(payload)
42
+ {
43
+ method: payload[:method],
44
+ path: extract_path(payload),
45
+ format: extract_format(payload),
46
+ controller: payload[:params]['controller'],
47
+ action: payload[:params]['action']
48
+ }
49
+ end
50
+
51
+ def extract_path(payload)
52
+ payload[:path].split('?').first
53
+ end
54
+
55
+ def extract_format(payload)
56
+ if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR == 0
57
+ payload[:formats].first
58
+ else
59
+ payload[:format]
60
+ end
61
+ end
62
+
63
+ def extract_status(payload)
64
+ if payload[:status]
65
+ { status: payload[:status].to_i }
66
+ elsif payload[:exception]
67
+ exception, message = payload[:exception]
68
+ { status: 500, error: "#{exception}:#{message}" }
69
+ else
70
+ { status: 0 }
71
+ end
72
+ end
73
+
74
+ def custom_options(event)
75
+ Lograge.custom_options(event) || {}
76
+ end
77
+
78
+ def before_format(data, payload)
79
+ Lograge.before_format(data, payload)
80
+ end
81
+
82
+ def runtimes(event)
83
+ {
84
+ duration: event.duration,
85
+ view: event.payload[:view_runtime],
86
+ db: event.payload[:db_runtime]
87
+ }.reduce({}) do |runtimes, (name, runtime)|
88
+ runtimes[name] = runtime.to_f.round(2) if runtime
89
+ runtimes
90
+ end
91
+ end
92
+
93
+ def location(_event)
94
+ location = Thread.current[:lograge_location]
95
+
96
+ if location
97
+ Thread.current[:lograge_location] = nil
98
+ { location: location }
99
+ else
100
+ {}
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+ require 'rails/rack/logger'
3
+
4
+ module Rails
5
+ module Rack
6
+ # Overwrites defaults of Rails::Rack::Logger that cause
7
+ # unnecessary logging.
8
+ # This effectively removes the log lines from the log
9
+ # that say:
10
+ # Started GET / for 192.168.2.1...
11
+ class Logger
12
+ # Overwrites Rails 3.2 code that logs new requests
13
+ def call_app(*args)
14
+ env = args.last
15
+ @app.call(env)
16
+ ensure
17
+ ActiveSupport::LogSubscriber.flush_all!
18
+ end
19
+
20
+ # Overwrites Rails 3.0/3.1 code that logs new requests
21
+ def before_dispatch(_env)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/railtie'
2
+ require 'action_view/log_subscriber'
3
+ require 'action_controller/log_subscriber'
4
+
5
+ module Lograge
6
+ class Railtie < Rails::Railtie
7
+ config.lograge = ActiveSupport::OrderedOptions.new
8
+ config.lograge.enabled = false
9
+
10
+ initializer :lograge do |app|
11
+ Lograge.setup(app) if app.config.lograge.enabled
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Lograge
2
+ VERSION = '0.4.0'
3
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lograge-with-time
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Mathias Meyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: guard-rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: actionpack
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: railties
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '3'
83
+ description: Tame Rails' multi-line logging into a single line per request
84
+ email:
85
+ - meyer@paperplanes.de
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/lograge.rb
91
+ - lib/lograge/formatters/cee.rb
92
+ - lib/lograge/formatters/graylog2.rb
93
+ - lib/lograge/formatters/json.rb
94
+ - lib/lograge/formatters/key_value.rb
95
+ - lib/lograge/formatters/l2met.rb
96
+ - lib/lograge/formatters/lines.rb
97
+ - lib/lograge/formatters/logstash.rb
98
+ - lib/lograge/formatters/raw.rb
99
+ - lib/lograge/log_subscriber.rb
100
+ - lib/lograge/rails_ext/rack/logger.rb
101
+ - lib/lograge/railtie.rb
102
+ - lib/lograge/version.rb
103
+ homepage: https://github.com/roidrage/lograge
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.2.0
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Tame Rails' multi-line logging into a single line per request
127
+ test_files: []