grape_logging 1.1.2 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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