grape_logging 1.3.0 → 1.4.0

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: fe992e3b160e737c3ad0d38a636252db026dbf97
4
- data.tar.gz: fbbcd347c5846b25d4a737a964fb2600c4e8ac98
3
+ metadata.gz: fb1521644b8ec276a0cd7eeb3cadcc75c98d88f5
4
+ data.tar.gz: 815eaa0bf94e7f282ac99be2f0746ba31abdb4e2
5
5
  SHA512:
6
- metadata.gz: 35efe1809d92fa3a12d260f71306b8c2aa8f08254607ea2c46c9d3c2dcc38e5a8a009af0b4044f26660feae420b12ef5c0f4d17059d086227253cc2cc9a16000
7
- data.tar.gz: a2021c9a92c8b4c4d96cf494b3ef27da4c17bb05c839d7c8e3c35660fbfbae9ba279380f66c173c7e863d110de7c959207367f180292258c3f218f1a72c6272e
6
+ metadata.gz: 66614c057b039c188ed42a0058d178ffc128e2f3a04fa03e2df2c98558063f5161236f348251ca2aa7b03cabbc35a5894fcde074e2a8257121cbaf627bc92831
7
+ data.tar.gz: 4af96b697baed8d4cb03d958133a18ad9ed66e7e601397330cd80960a19871c1c295b64de3c4d90b115ca6a23c6b4b3cc4bf7982ee6aa79812ee14a9fdf3f702
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .rspec
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ cache: bundler
5
+ script:
6
+ - bundle exec rspec
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # grape_logging
2
2
 
3
3
  [![Code Climate](https://codeclimate.com/github/aserafin/grape_logging/badges/gpa.svg)](https://codeclimate.com/github/aserafin/grape_logging)
4
+ [![Build Status](https://travis-ci.org/aserafin/grape_logging.svg?branch=master)](https://travis-ci.org/aserafin/grape_logging)
4
5
 
5
6
  ## Installation
6
7
 
@@ -20,9 +21,11 @@ Or install it yourself as:
20
21
 
21
22
  In your api file (somewhere on the top)
22
23
 
23
- require 'grape_logging'
24
- logger.formatter = GrapeLogging::Formatters::Default.new
25
- use GrapeLogging::Middleware::RequestLogger, { logger: logger }
24
+ ```ruby
25
+ require 'grape_logging'
26
+ logger.formatter = GrapeLogging::Formatters::Default.new
27
+ use GrapeLogging::Middleware::RequestLogger, { logger: logger }
28
+ ```
26
29
 
27
30
  **ProTip:** If your logger doesn't support setting formatter you can remove this line - it's optional
28
31
 
@@ -37,23 +40,25 @@ With the default configuration you will get nice log message
37
40
  If you prefer some other format I strongly encourage you to do pull request with new formatter class ;)
38
41
 
39
42
  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
43
+ ```ruby
44
+ class MyAPI < Grape::API
45
+ use GrapeLogging::Middleware::RequestLogger, logger: logger, formatter: MyFormatter.new
46
+ end
47
+ ```
44
48
 
45
49
  ### Customising What Is Logged
46
50
 
47
51
  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
- GrapeLogging::Loggers::ClientEnv.new,
55
- GrapeLogging::Loggers::RequestHeaders.new ]
56
- end
52
+ ```ruby
53
+ class MyAPI < Grape::API
54
+ use GrapeLogging::Middleware::RequestLogger,
55
+ logger: logger,
56
+ include: [ GrapeLogging::Loggers::Response.new,
57
+ GrapeLogging::Loggers::FilterParameters.new,
58
+ GrapeLogging::Loggers::ClientEnv.new,
59
+ GrapeLogging::Loggers::RequestHeaders.new ]
60
+ end
61
+ ```
57
62
 
58
63
  #### FilterParameters
59
64
  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.
@@ -67,45 +72,48 @@ The `RequestHeaders` logger will add `request headers` in your log.
67
72
  ### Logging to file and STDOUT
68
73
 
69
74
  You can log to file and STDOUT at the same time, you just need to assign new logger
70
-
71
- log_file = File.open('path/to/your/logfile.log', 'a')
72
- log_file.sync = true
73
- logger Logger.new GrapeLogging::MultiIO.new(STDOUT, log_file)
75
+ ```ruby
76
+ log_file = File.open('path/to/your/logfile.log', 'a')
77
+ log_file.sync = true
78
+ logger Logger.new GrapeLogging::MultiIO.new(STDOUT, log_file)
79
+ ```
74
80
 
75
81
  ### Logging via Rails instrumentation
76
82
 
77
83
  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.
78
84
  First, config ```grape_logging```, like that:
79
-
80
- class MyAPI < Grape::API
81
- use GrapeLogging::Middleware::RequestLogger,
82
- instrumentation_key: 'grape_key',
83
- include: [ GrapeLogging::Loggers::Response.new,
84
- GrapeLogging::Loggers::FilterParameters.new ]
85
- end
85
+ ```ruby
86
+ class MyAPI < Grape::API
87
+ use GrapeLogging::Middleware::RequestLogger,
88
+ instrumentation_key: 'grape_key',
89
+ include: [ GrapeLogging::Loggers::Response.new,
90
+ GrapeLogging::Loggers::FilterParameters.new ]
91
+ end
92
+ ```
86
93
 
87
94
  and then add an initializer in your Rails project:
95
+ ```ruby
96
+ # config/initializers/instrumentation.rb
88
97
 
89
- # config/initializers/instrumentation.rb
90
-
91
- # Subscribe to grape request and log with Rails.logger
92
- ActiveSupport::Notifications.subscribe('grape_key') do |name, starts, ends, notification_id, payload|
93
- Rails.logger.info payload
94
- end
98
+ # Subscribe to grape request and log with Rails.logger
99
+ ActiveSupport::Notifications.subscribe('grape_key') do |name, starts, ends, notification_id, payload|
100
+ Rails.logger.info payload
101
+ end
102
+ ```
95
103
 
96
104
  The idea come from here: https://gist.github.com/teamon/e8ae16ffb0cb447e5b49
97
105
 
98
106
  ### Logging exceptions
99
107
 
100
108
  If you want to log exceptions you can do it like this
101
-
102
- class MyAPI < Grape::API
103
- rescue_from :all do |e|
104
- MyAPI.logger.error e
105
- #do here whatever you originally planned to do :)
106
- end
107
- end
108
-
109
+ ```ruby
110
+ class MyAPI < Grape::API
111
+ rescue_from :all do |e|
112
+ MyAPI.logger.error e
113
+ #do here whatever you originally planned to do :)
114
+ end
115
+ end
116
+ ```
109
117
  ## Development
110
118
 
111
119
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -23,4 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency 'bundler', '~> 1.8'
25
25
  spec.add_development_dependency 'rake', '~> 10.0'
26
- end
26
+ spec.add_development_dependency 'rspec', '~> 3.5'
27
+ spec.add_development_dependency 'pry-byebug', '~> 3.4.2'
28
+ end
@@ -2,6 +2,7 @@ require 'grape_logging/multi_io'
2
2
  require 'grape_logging/version'
3
3
  require 'grape_logging/formatters/default'
4
4
  require 'grape_logging/formatters/json'
5
+ require 'grape_logging/formatters/logstash'
5
6
  require 'grape_logging/loggers/base'
6
7
  require 'grape_logging/loggers/response'
7
8
  require 'grape_logging/loggers/filter_parameters'
@@ -11,3 +12,4 @@ require 'grape_logging/reporters/active_support_reporter'
11
12
  require 'grape_logging/reporters/logger_reporter'
12
13
  require 'grape_logging/timings'
13
14
  require 'grape_logging/middleware/request_logger'
15
+ require 'grape_logging/util/parameter_filter'
@@ -0,0 +1,35 @@
1
+ module GrapeLogging
2
+ module Formatters
3
+ class Logstash
4
+ def call(severity, datetime, _, data)
5
+ {
6
+ :'@timestamp' => datetime.iso8601,
7
+ :'@version' => '1',
8
+ :severity => severity
9
+ }.merge!(format(data)).to_json
10
+ end
11
+
12
+ private
13
+
14
+ def format(data)
15
+ if data.is_a?(Hash)
16
+ data
17
+ elsif data.is_a?(String)
18
+ { message: data }
19
+ elsif data.is_a?(Exception)
20
+ format_exception(data)
21
+ else
22
+ { message: data.inspect }
23
+ end
24
+ end
25
+
26
+ def format_exception(exception)
27
+ {
28
+ exception: {
29
+ message: exception.message
30
+ }
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,23 +1,35 @@
1
1
  module GrapeLogging
2
2
  module Loggers
3
3
  class FilterParameters < GrapeLogging::Loggers::Base
4
- def initialize(filter_parameters = nil, replacement = '[FILTERED]')
4
+ AD_PARAMS = 'action_dispatch.request.parameters'.freeze
5
+
6
+ def initialize(filter_parameters = nil, replacement = nil, exceptions = %w(controller action format))
5
7
  @filter_parameters = filter_parameters || (defined?(Rails.application) ? Rails.application.config.filter_parameters : [])
6
- @replacement = replacement
8
+ @replacement = replacement || '[FILTERED]'
9
+ @exceptions = exceptions
7
10
  end
8
11
 
9
12
  def parameters(request, _)
10
- { params: replace_parameters(request.params.clone) }
13
+ { params: safe_parameters(request) }
11
14
  end
12
15
 
13
16
  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
17
+
18
+ def parameter_filter
19
+ @parameter_filter ||= ParameterFilter.new(@replacement, @filter_parameters)
20
+ end
21
+
22
+ def safe_parameters(request)
23
+ # Now this logger can work also over Rails requests
24
+ if request.params.empty?
25
+ clean_parameters(request.env[AD_PARAMS] || {})
26
+ else
27
+ clean_parameters(request.params)
19
28
  end
20
- parameters
29
+ end
30
+
31
+ def clean_parameters(parameters)
32
+ parameter_filter.filter(parameters).reject{ |key, _value| @exceptions.include?(key) }
21
33
  end
22
34
  end
23
35
  end
@@ -58,7 +58,8 @@ module GrapeLogging
58
58
  },
59
59
  method: request.request_method,
60
60
  path: request.path,
61
- params: request.params
61
+ params: request.params,
62
+ host: request.host
62
63
  }
63
64
  end
64
65
 
@@ -2,7 +2,9 @@ module Reporters
2
2
  class LoggerReporter
3
3
  def initialize(logger, formatter)
4
4
  @logger = logger || Logger.new(STDOUT)
5
- @logger.formatter = formatter || GrapeLogging::Formatters::Default.new if @logger.respond_to?(:formatter=)
5
+ if @logger.respond_to?(:formatter=)
6
+ @logger.formatter = formatter || @logger.formatter || GrapeLogging::Formatters::Default.new
7
+ end
6
8
  end
7
9
 
8
10
  def perform(params)
@@ -0,0 +1,90 @@
1
+ if defined?(Rails.application)
2
+ class ParameterFilter < ActionDispatch::Http::ParameterFilter
3
+ def initialize(_replacement, filter_parameters)
4
+ super(filter_parameters)
5
+ end
6
+ end
7
+ else
8
+ #
9
+ # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameter_filter.rb
10
+ # we could depend on Rails specifically, but that would us way to hefty!
11
+ #
12
+ class ParameterFilter
13
+ def initialize(replacement, filters = [])
14
+ @replacement = replacement
15
+ @filters = filters
16
+ end
17
+
18
+ def filter(params)
19
+ compiled_filter.call(params)
20
+ end
21
+
22
+ private
23
+
24
+ def compiled_filter
25
+ @compiled_filter ||= CompiledFilter.compile(@replacement, @filters)
26
+ end
27
+
28
+ class CompiledFilter # :nodoc:
29
+ def self.compile(replacement, filters)
30
+ return lambda { |params| params.dup } if filters.empty?
31
+
32
+ strings, regexps, blocks = [], [], []
33
+
34
+ filters.each do |item|
35
+ case item
36
+ when Proc
37
+ blocks << item
38
+ when Regexp
39
+ regexps << item
40
+ else
41
+ strings << Regexp.escape(item.to_s)
42
+ end
43
+ end
44
+
45
+ deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
46
+ deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
47
+
48
+ regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
49
+ deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
50
+
51
+ new replacement, regexps, deep_regexps, blocks
52
+ end
53
+
54
+ attr_reader :regexps, :deep_regexps, :blocks
55
+
56
+ def initialize(replacement, regexps, deep_regexps, blocks)
57
+ @replacement = replacement
58
+ @regexps = regexps
59
+ @deep_regexps = deep_regexps.any? ? deep_regexps : nil
60
+ @blocks = blocks
61
+ end
62
+
63
+ def call(original_params, parents = [])
64
+ filtered_params = {}
65
+
66
+ original_params.each do |key, value|
67
+ parents.push(key) if deep_regexps
68
+ if regexps.any? { |r| key =~ r }
69
+ value = @replacement
70
+ elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
71
+ value = @replacement
72
+ elsif value.is_a?(Hash)
73
+ value = call(value, parents)
74
+ elsif value.is_a?(Array)
75
+ value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
76
+ elsif blocks.any?
77
+ key = key.dup if key.duplicable?
78
+ value = value.dup if value.duplicable?
79
+ blocks.each { |b| b.call(key, value) }
80
+ end
81
+ parents.pop if deep_regexps
82
+
83
+ filtered_params[key] = value
84
+ end
85
+
86
+ filtered_params
87
+ end
88
+ end
89
+ end
90
+ end
@@ -1,3 +1,3 @@
1
1
  module GrapeLogging
2
- VERSION = '1.3.0'
2
+ VERSION = '1.4.0'
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.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aserafin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-18 00:00:00.000000000 Z
11
+ date: 2017-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grape
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.4.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.4.2
55
83
  description: This gem provides simple request logging for Grape with just few lines
56
84
  of code you have to put in your project! In return you will get response codes,
57
85
  paths, parameters and more!
@@ -62,6 +90,7 @@ extensions: []
62
90
  extra_rdoc_files: []
63
91
  files:
64
92
  - ".gitignore"
93
+ - ".travis.yml"
65
94
  - Gemfile
66
95
  - LICENSE.txt
67
96
  - README.md
@@ -72,6 +101,7 @@ files:
72
101
  - lib/grape_logging.rb
73
102
  - lib/grape_logging/formatters/default.rb
74
103
  - lib/grape_logging/formatters/json.rb
104
+ - lib/grape_logging/formatters/logstash.rb
75
105
  - lib/grape_logging/loggers/base.rb
76
106
  - lib/grape_logging/loggers/client_env.rb
77
107
  - lib/grape_logging/loggers/filter_parameters.rb
@@ -82,6 +112,7 @@ files:
82
112
  - lib/grape_logging/reporters/active_support_reporter.rb
83
113
  - lib/grape_logging/reporters/logger_reporter.rb
84
114
  - lib/grape_logging/timings.rb
115
+ - lib/grape_logging/util/parameter_filter.rb
85
116
  - lib/grape_logging/version.rb
86
117
  homepage: http://github.com/aserafin/grape_logging
87
118
  licenses:
@@ -103,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
134
  version: '0'
104
135
  requirements: []
105
136
  rubyforge_project:
106
- rubygems_version: 2.4.6
137
+ rubygems_version: 2.5.1
107
138
  signing_key:
108
139
  specification_version: 4
109
140
  summary: Out of the box request logging for Grape!