grape_logging 1.1.2 → 1.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b3bf40b45307865cbd2c98fe98ca4a8a3a4d159
4
- data.tar.gz: 116be8f340bab2a4d7b7b66bc1aba888a35db947
3
+ metadata.gz: 59face7f1f95aa107acdf703dbc1f3b7cd7a7089
4
+ data.tar.gz: ddbc3faa4075116e49201ed0e42a8a484fe6f0bb
5
5
  SHA512:
6
- metadata.gz: 29a8feba5650aa2034a30263bae9dab1e1810053e0df49d7a4e7224d569645c9002434f35aea875753d50c46d8cd869cded6aadaffdddd63fc06178f24474a28
7
- data.tar.gz: 5cc8354ea7119b4e11b1619bb6795931e7f7f88f59392cd61bcd4ee76d3e4a825302ebef975a3908a267e0e8210ad62457a5477e9441cfb68b5bdd05a32ca3b7
6
+ metadata.gz: 80f4eea80aa5b7cdee7e6e2f45ec1a52c35c41839f67988fa89a70290b6706547cc4a664cce4a0dea136fd5d56b6bc266e8d592176b732e94527c8731c038219
7
+ data.tar.gz: 6effcdf54c98000c0b8417ea2f02c6a707054ade7e66c035cc55e68ee721d5d25cf9d81c34683545f1a31c88d8bc6a433219600164369078294c3b48fc92b8ed
data/README.md CHANGED
@@ -10,7 +10,7 @@ Add this line to your application's Gemfile:
10
10
 
11
11
  And then execute:
12
12
 
13
- $ bundle
13
+ $ bundle install
14
14
 
15
15
  Or install it yourself as:
16
16
 
@@ -19,10 +19,12 @@ Or install it yourself as:
19
19
  ## Basic Usage
20
20
 
21
21
  In your api file (somewhere on the top)
22
-
22
+
23
+ require 'grape_logging'
23
24
  logger.formatter = GrapeLogging::Formatters::Default.new
24
25
  use GrapeLogging::Middleware::RequestLogger, { logger: logger }
25
26
 
27
+ **ProTip:** If your logger doesn't support setting formatter you can remove this line - it's optional
26
28
 
27
29
  ## Features
28
30
 
@@ -34,11 +36,55 @@ With the default configuration you will get nice log message
34
36
 
35
37
  If you prefer some other format I strongly encourage you to do pull request with new formatter class ;)
36
38
 
39
+ You can change the formatter like so
40
+
41
+ class MyAPI < Grape::API
42
+ use GrapeLogging::Middleware::RequestLogger, logger: logger, format: MyFormatter.new
43
+ end
44
+
45
+ ### Customising What Is Logged
46
+
47
+ You can include logging of other parts of the request / response cycle by including subclasses of `GrapeLogging::Loggers::Base`
48
+
49
+ class MyAPI < Grape::API
50
+ use GrapeLogging::Middleware::RequestLogger,
51
+ logger: logger,
52
+ include: [ GrapeLogging::Loggers::Response.new,
53
+ GrapeLogging::Loggers::FilterParameters.new ]
54
+ end
55
+
56
+ The `FilterParameters` logger will filter out sensitive parameters from your logs. If mounted inside rails, will use the `Rails.application.config.filter_parameters` by default. Otherwise, you must specify a list of keys to filter out.
57
+
37
58
  ### Logging to file and STDOUT
38
59
 
39
- You can to file and STDOUT at the same time, you just need to assign new logger
60
+ You can log to file and STDOUT at the same time, you just need to assign new logger
61
+
62
+ log_file = File.open('path/to/your/logfile.log', 'a')
63
+ log_file.sync = true
64
+ logger Logger.new GrapeLogging::MultiIO.new(STDOUT, log_file)
65
+
66
+ ### Logging via Rails instrumentation
67
+
68
+ You can choose to not pass the logger to ```grape_logging``` but instead send logs to Rails instrumentation in order to let Rails and its configured Logger do the log job, for example.
69
+ First, config ```grape_logging```, like that:
40
70
 
41
- logger Logger.new GrapeLogging::MultiIO.new(STDOUT, File.open('path/to/your/logfile.log', 'a'))
71
+ class MyAPI < Grape::API
72
+ use GrapeLogging::Middleware::RequestLogger,
73
+ instrumentation_key: 'grape_key',
74
+ include: [ GrapeLogging::Loggers::Response.new,
75
+ GrapeLogging::Loggers::FilterParameters.new ]
76
+ end
77
+
78
+ and then add an initializer in your Rails project:
79
+
80
+ # config/initializers/instrumentation.rb
81
+
82
+ # Subscribe to grape request and log with Rails.logger
83
+ ActiveSupport::Notifications.subscribe('grape_key') do |name, starts, ends, notification_id, payload|
84
+ Rails.logger.info payload
85
+ end
86
+
87
+ The idea come from here: https://gist.github.com/teamon/e8ae16ffb0cb447e5b49
42
88
 
43
89
  ### Logging exceptions
44
90
 
@@ -1,4 +1,11 @@
1
1
  require 'grape_logging/multi_io'
2
2
  require 'grape_logging/version'
3
3
  require 'grape_logging/formatters/default'
4
- require 'grape_logging/middleware/request_logger'
4
+ require 'grape_logging/formatters/json'
5
+ require 'grape_logging/loggers/base'
6
+ require 'grape_logging/loggers/response'
7
+ require 'grape_logging/loggers/filter_parameters'
8
+ require 'grape_logging/reporters/active_support_reporter'
9
+ require 'grape_logging/reporters/logger_reporter'
10
+ require 'grape_logging/timings'
11
+ require 'grape_logging/middleware/request_logger'
@@ -11,7 +11,7 @@ module GrapeLogging
11
11
  elsif data.is_a?(Exception)
12
12
  format_exception(data)
13
13
  elsif data.is_a?(Hash)
14
- "#{data.delete(:status)} -- total=#{data.delete(:total)} db=#{data.delete(:db)} -- #{data.delete(:method)} #{data.delete(:path)} #{format_hash(data)}"
14
+ "#{data.delete(:status)} -- #{format_hash(data.delete(:time))} -- #{data.delete(:method)} #{data.delete(:path)} #{format_hash(data)}"
15
15
  else
16
16
  data.inspect
17
17
  end
@@ -28,4 +28,4 @@ module GrapeLogging
28
28
  end
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -0,0 +1,33 @@
1
+ module GrapeLogging
2
+ module Formatters
3
+ class Json
4
+ def call(severity, datetime, _, data)
5
+ {
6
+ date: datetime,
7
+ severity: severity,
8
+ data: format(data)
9
+ }.to_json
10
+ end
11
+
12
+ private
13
+
14
+ def format(data)
15
+ if data.is_a?(String) || data.is_a?(Hash)
16
+ data
17
+ elsif data.is_a?(Exception)
18
+ format_exception(data)
19
+ else
20
+ data.inspect
21
+ end
22
+ end
23
+
24
+ def format_exception(exception)
25
+ {
26
+ exception: {
27
+ message: exception.message
28
+ }
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module GrapeLogging
2
+ module Loggers
3
+ class Base
4
+ def parameters(request, response)
5
+ {}
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ module GrapeLogging
2
+ module Loggers
3
+ class FilterParameters < GrapeLogging::Loggers::Base
4
+ def initialize(filter_parameters = nil, replacement = '[FILTERED]')
5
+ @filter_parameters = filter_parameters || (defined?(Rails.application) ? Rails.application.config.filter_parameters : [])
6
+ @replacement = replacement
7
+ end
8
+
9
+ def parameters(request, _)
10
+ { params: replace_parameters(request.params.clone) }
11
+ end
12
+
13
+ private
14
+ def replace_parameters(parameters)
15
+ @filter_parameters.each do |parameter_name|
16
+ if parameters.key?(parameter_name.to_s)
17
+ parameters[parameter_name.to_s] = @replacement
18
+ end
19
+ end
20
+ parameters
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module GrapeLogging
2
+ module Loggers
3
+ class Response < GrapeLogging::Loggers::Base
4
+ def parameters(_, response)
5
+ response ? { response: serialized_response_body(response) } : {}
6
+ end
7
+
8
+ private
9
+ # In some cases, response.body is not parseable by JSON.
10
+ # For example, if you POST on a PUT endpoint, response.body is egal to """".
11
+ # It's strange but it's the Grape behavior...
12
+ def serialized_response_body(response)
13
+ begin
14
+ response.body.map{ |body| JSON.parse(body.to_s) }
15
+ rescue => e
16
+ response.body
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,45 +3,66 @@ require 'grape/middleware/base'
3
3
  module GrapeLogging
4
4
  module Middleware
5
5
  class RequestLogger < Grape::Middleware::Base
6
+
7
+ ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
8
+ event = ActiveSupport::Notifications::Event.new(*args)
9
+ GrapeLogging::Timings.append_db_runtime(event)
10
+ end if defined?(ActiveRecord)
11
+
12
+ def initialize(app, options = {})
13
+ super
14
+
15
+ @included_loggers = @options[:include] || []
16
+ @reporter = if options[:instrumentation_key]
17
+ Reporters::ActiveSupportReporter.new(@options[:instrumentation_key])
18
+ else
19
+ Reporters::LoggerReporter.new(@options[:logger], @options[:formatter])
20
+ end
21
+ end
22
+
6
23
  def before
24
+ reset_db_runtime
7
25
  start_time
8
26
 
9
- @db_duration = 0
10
- @subscription = ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
11
- event = ActiveSupport::Notifications::Event.new(*args)
12
- @db_duration += event.duration
13
- end if defined?(ActiveRecord)
27
+ invoke_included_loggers(:before)
14
28
  end
15
29
 
16
30
  def after
17
31
  stop_time
18
- logger.info parameters
32
+ @reporter.perform(collect_parameters)
33
+ invoke_included_loggers(:after)
19
34
  nil
20
35
  end
21
36
 
22
37
  def call!(env)
23
38
  super
24
- ensure
25
- ActiveSupport::Notifications.unsubscribe(@subscription) if @subscription
26
39
  end
27
40
 
28
41
  protected
42
+
43
+ def response
44
+ begin
45
+ super
46
+ rescue
47
+ nil
48
+ end
49
+ end
50
+
29
51
  def parameters
30
52
  {
31
- path: request.path,
32
- params: request.params.to_hash,
33
- method: request.request_method,
53
+ status: response.nil? ? 'fail' : response.status,
54
+ time: {
34
55
  total: total_runtime,
35
- db: @db_duration.round(2),
36
- status: response.status
56
+ db: db_runtime,
57
+ view: view_runtime
58
+ },
59
+ method: request.request_method,
60
+ path: request.path,
61
+ params: request.params
37
62
  }
38
63
  end
39
64
 
40
65
  private
41
- def logger
42
- @logger ||= @options[:logger] || Logger.new(STDOUT)
43
- end
44
-
45
66
  def request
46
67
  @request ||= ::Rack::Request.new(env)
47
68
  end
@@ -50,6 +71,18 @@ module GrapeLogging
50
71
  ((stop_time - start_time) * 1000).round(2)
51
72
  end
52
73
 
74
+ def view_runtime
75
+ total_runtime - db_runtime
76
+ end
77
+
78
+ def db_runtime
79
+ GrapeLogging::Timings.db_runtime.round(2)
80
+ end
81
+
82
+ def reset_db_runtime
83
+ GrapeLogging::Timings.reset_db_runtime
84
+ end
85
+
53
86
  def start_time
54
87
  @start_time ||= Time.now
55
88
  end
@@ -57,6 +90,22 @@ module GrapeLogging
57
90
  def stop_time
58
91
  @stop_time ||= Time.now
59
92
  end
93
+
94
+ def collect_parameters
95
+ parameters.tap do |params|
96
+ @included_loggers.each do |logger|
97
+ params.merge! logger.parameters(request, response) do |_, oldval, newval|
98
+ oldval.respond_to?(:merge) ? oldval.merge(newval) : newval
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def invoke_included_loggers(method_name)
105
+ @included_loggers.each do |logger|
106
+ logger.send(method_name) if logger.respond_to?(method_name)
107
+ end
108
+ end
60
109
  end
61
110
  end
62
- end
111
+ end
@@ -0,0 +1,11 @@
1
+ module Reporters
2
+ class ActiveSupportReporter
3
+ def initialize(instrumentation_key)
4
+ @instrumentation_key = instrumentation_key
5
+ end
6
+
7
+ def perform(params)
8
+ ActiveSupport::Notifications.instrument @instrumentation_key, params
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Reporters
2
+ class LoggerReporter
3
+ def initialize(logger, formatter)
4
+ @logger = logger || Logger.new(STDOUT)
5
+ @logger.formatter = formatter || GrapeLogging::Formatters::Default.new if @logger.respond_to?(:formatter=)
6
+ end
7
+
8
+ def perform(params)
9
+ @logger.info params
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module GrapeLogging
2
+ module Timings
3
+ extend self
4
+
5
+ def db_runtime=(value)
6
+ Thread.current[:grape_db_runtime] = value
7
+ end
8
+
9
+ def db_runtime
10
+ Thread.current[:grape_db_runtime] ||= 0
11
+ end
12
+
13
+ def reset_db_runtime
14
+ self.db_runtime = 0
15
+ end
16
+
17
+ def append_db_runtime(event)
18
+ self.db_runtime += event.duration
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module GrapeLogging
2
- VERSION = '1.1.2'
2
+ VERSION = '1.2.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape_logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - aserafin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-06-29 00:00:00.000000000 Z
11
+ date: 2016-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grape
@@ -68,12 +68,18 @@ files:
68
68
  - Rakefile
69
69
  - bin/console
70
70
  - bin/setup
71
- - grape_logging-1.1.1.gem
72
71
  - grape_logging.gemspec
73
72
  - lib/grape_logging.rb
74
73
  - lib/grape_logging/formatters/default.rb
74
+ - lib/grape_logging/formatters/json.rb
75
+ - lib/grape_logging/loggers/base.rb
76
+ - lib/grape_logging/loggers/filter_parameters.rb
77
+ - lib/grape_logging/loggers/response.rb
75
78
  - lib/grape_logging/middleware/request_logger.rb
76
79
  - lib/grape_logging/multi_io.rb
80
+ - lib/grape_logging/reporters/active_support_reporter.rb
81
+ - lib/grape_logging/reporters/logger_reporter.rb
82
+ - lib/grape_logging/timings.rb
77
83
  - lib/grape_logging/version.rb
78
84
  homepage: http://github.com/aserafin/grape_logging
79
85
  licenses:
Binary file