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 +4 -4
- data/README.md +50 -4
- data/lib/grape_logging.rb +8 -1
- data/lib/grape_logging/formatters/default.rb +2 -2
- data/lib/grape_logging/formatters/json.rb +33 -0
- data/lib/grape_logging/loggers/base.rb +9 -0
- data/lib/grape_logging/loggers/filter_parameters.rb +24 -0
- data/lib/grape_logging/loggers/response.rb +21 -0
- data/lib/grape_logging/middleware/request_logger.rb +67 -18
- data/lib/grape_logging/reporters/active_support_reporter.rb +11 -0
- data/lib/grape_logging/reporters/logger_reporter.rb +12 -0
- data/lib/grape_logging/timings.rb +21 -0
- data/lib/grape_logging/version.rb +1 -1
- metadata +9 -3
- data/grape_logging-1.1.1.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59face7f1f95aa107acdf703dbc1f3b7cd7a7089
|
4
|
+
data.tar.gz: ddbc3faa4075116e49201ed0e42a8a484fe6f0bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
|
data/lib/grape_logging.rb
CHANGED
@@ -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/
|
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)} --
|
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,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
|
-
|
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
|
-
|
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
|
-
|
32
|
-
|
33
|
-
method: request.request_method,
|
53
|
+
status: response.nil? ? 'fail' : response.status,
|
54
|
+
time: {
|
34
55
|
total: total_runtime,
|
35
|
-
db:
|
36
|
-
|
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,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
|
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
|
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:
|
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:
|
data/grape_logging-1.1.1.gem
DELETED
Binary file
|