loga 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/.rspec +2 -0
- data/.rubocop.yml +19 -0
- data/.rubocop_todo.yml +33 -0
- data/Appraisals +14 -0
- data/Gemfile +8 -0
- data/README.md +147 -0
- data/Rakefile +9 -0
- data/circle.yml +23 -0
- data/gemfiles/rails32.gemfile +11 -0
- data/gemfiles/rails40.gemfile +11 -0
- data/gemfiles/sinatra14.gemfile +11 -0
- data/gemfiles/unit.gemfile +9 -0
- data/lib/loga.rb +33 -0
- data/lib/loga/configuration.rb +96 -0
- data/lib/loga/event.rb +21 -0
- data/lib/loga/ext/rails/rack/logger3.rb +21 -0
- data/lib/loga/ext/rails/rack/logger4.rb +13 -0
- data/lib/loga/formatter.rb +104 -0
- data/lib/loga/parameter_filter.rb +65 -0
- data/lib/loga/rack/logger.rb +102 -0
- data/lib/loga/rack/request.rb +77 -0
- data/lib/loga/rack/request_id.rb +44 -0
- data/lib/loga/railtie.rb +139 -0
- data/lib/loga/tagged_logging.rb +76 -0
- data/lib/loga/utilities.rb +7 -0
- data/lib/loga/version.rb +3 -0
- data/loga.gemspec +31 -0
- data/spec/fixtures/README.md +8 -0
- data/spec/fixtures/rails32/Rakefile +7 -0
- data/spec/fixtures/rails32/app/controllers/application_controller.rb +28 -0
- data/spec/fixtures/rails32/app/helpers/application_helper.rb +2 -0
- data/spec/fixtures/rails32/app/views/layouts/application.html.erb +14 -0
- data/spec/fixtures/rails32/app/views/user.html.erb +1 -0
- data/spec/fixtures/rails32/config.ru +4 -0
- data/spec/fixtures/rails32/config/application.rb +71 -0
- data/spec/fixtures/rails32/config/boot.rb +6 -0
- data/spec/fixtures/rails32/config/environment.rb +5 -0
- data/spec/fixtures/rails32/config/environments/development.rb +26 -0
- data/spec/fixtures/rails32/config/environments/production.rb +50 -0
- data/spec/fixtures/rails32/config/environments/test.rb +35 -0
- data/spec/fixtures/rails32/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/fixtures/rails32/config/initializers/inflections.rb +15 -0
- data/spec/fixtures/rails32/config/initializers/mime_types.rb +5 -0
- data/spec/fixtures/rails32/config/initializers/secret_token.rb +7 -0
- data/spec/fixtures/rails32/config/initializers/session_store.rb +8 -0
- data/spec/fixtures/rails32/config/initializers/wrap_parameters.rb +10 -0
- data/spec/fixtures/rails32/config/locales/en.yml +5 -0
- data/spec/fixtures/rails32/config/routes.rb +64 -0
- data/spec/fixtures/rails32/public/404.html +26 -0
- data/spec/fixtures/rails32/public/422.html +26 -0
- data/spec/fixtures/rails32/public/500.html +25 -0
- data/spec/fixtures/rails32/public/favicon.ico +0 -0
- data/spec/fixtures/rails32/public/index.html +241 -0
- data/spec/fixtures/rails32/public/robots.txt +5 -0
- data/spec/fixtures/rails32/script/rails +6 -0
- data/spec/fixtures/rails40/Rakefile +6 -0
- data/spec/fixtures/rails40/app/controllers/application_controller.rb +30 -0
- data/spec/fixtures/rails40/app/helpers/application_helper.rb +2 -0
- data/spec/fixtures/rails40/app/views/layouts/application.html.erb +14 -0
- data/spec/fixtures/rails40/app/views/user.html.erb +1 -0
- data/spec/fixtures/rails40/bin/bundle +3 -0
- data/spec/fixtures/rails40/bin/rails +4 -0
- data/spec/fixtures/rails40/bin/rake +4 -0
- data/spec/fixtures/rails40/config.ru +4 -0
- data/spec/fixtures/rails40/config/application.rb +37 -0
- data/spec/fixtures/rails40/config/boot.rb +4 -0
- data/spec/fixtures/rails40/config/environment.rb +5 -0
- data/spec/fixtures/rails40/config/environments/development.rb +24 -0
- data/spec/fixtures/rails40/config/environments/production.rb +65 -0
- data/spec/fixtures/rails40/config/environments/test.rb +39 -0
- data/spec/fixtures/rails40/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/fixtures/rails40/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/fixtures/rails40/config/initializers/inflections.rb +16 -0
- data/spec/fixtures/rails40/config/initializers/mime_types.rb +5 -0
- data/spec/fixtures/rails40/config/initializers/secret_token.rb +12 -0
- data/spec/fixtures/rails40/config/initializers/session_store.rb +3 -0
- data/spec/fixtures/rails40/config/initializers/wrap_parameters.rb +9 -0
- data/spec/fixtures/rails40/config/locales/en.yml +23 -0
- data/spec/fixtures/rails40/config/routes.rb +62 -0
- data/spec/fixtures/rails40/public/404.html +58 -0
- data/spec/fixtures/rails40/public/422.html +58 -0
- data/spec/fixtures/rails40/public/500.html +57 -0
- data/spec/fixtures/rails40/public/favicon.ico +0 -0
- data/spec/fixtures/rails40/public/robots.txt +5 -0
- data/spec/integration/rails/railtie_spec.rb +64 -0
- data/spec/integration/rails/request_spec.rb +42 -0
- data/spec/integration/sinatra_spec.rb +54 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/helpers.rb +16 -0
- data/spec/support/request_spec.rb +183 -0
- data/spec/support/timecop_shared.rb +7 -0
- data/spec/unit/loga/configuration_spec.rb +123 -0
- data/spec/unit/loga/event_spec.rb +20 -0
- data/spec/unit/loga/formatter_spec.rb +186 -0
- data/spec/unit/loga/parameter_filter_spec.rb +76 -0
- data/spec/unit/loga/rack/logger_spec.rb +114 -0
- data/spec/unit/loga/rack/request_spec.rb +70 -0
- data/spec/unit/loga/utilities_spec.rb +16 -0
- data/spec/unit/loga_spec.rb +41 -0
- metadata +357 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/422.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>The change you wanted was rejected.</h1>
|
54
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
55
|
+
</div>
|
56
|
+
<p>If you are the application owner check the logs for more information.</p>
|
57
|
+
</body>
|
58
|
+
</html>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/500.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>We're sorry, but something went wrong.</h1>
|
54
|
+
</div>
|
55
|
+
<p>If you are the application owner check the logs for more information.</p>
|
56
|
+
</body>
|
57
|
+
</html>
|
File without changes
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
RSpec.describe Loga::Railtie do
|
4
|
+
let(:app) { Rails.application }
|
5
|
+
let(:middlewares) { app.middleware.middlewares }
|
6
|
+
let(:initializers) { described_class.initializers }
|
7
|
+
|
8
|
+
describe 'loga_initialize_logger' do
|
9
|
+
let(:initializer) { initializers.find { |i| i.name == :loga_initialize_logger } }
|
10
|
+
|
11
|
+
let(:app) { OpenStruct.new(config: config) }
|
12
|
+
let(:config) { OpenStruct.new(loga: loga, log_level: :info) }
|
13
|
+
|
14
|
+
before { initializer.run(app) }
|
15
|
+
|
16
|
+
context 'when loga is disabled' do
|
17
|
+
let(:loga) { Loga::Configuration.new.tap { |c| c.enabled = false } }
|
18
|
+
|
19
|
+
it 'is not initialized' do
|
20
|
+
expect(config.logger).to be_nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when loga is enabled' do
|
25
|
+
let(:loga) { Loga::Configuration.new }
|
26
|
+
|
27
|
+
it 'initializes the logger' do
|
28
|
+
expect(config.logger).to be_a(Logger)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'inserts Loga::Rack::Logger middleware after Rails::Rack::Logger' do
|
34
|
+
expect(middlewares.index(Loga::Rack::Logger))
|
35
|
+
.to eq(middlewares.index(Rails::Rack::Logger) + 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'disables colorized logging' do
|
39
|
+
expect(app.config.colorize_logging).to eq(false)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'instrumentation' do
|
43
|
+
let(:listeners) do
|
44
|
+
ActiveSupport::Notifications.notifier.listeners_for(notification)
|
45
|
+
end
|
46
|
+
let(:subscribers) do
|
47
|
+
listeners.map { |l| l.instance_variable_get(:@delegate).class }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'ActionView' do
|
51
|
+
[
|
52
|
+
'render_collection.action_view',
|
53
|
+
'render_partial.action_view',
|
54
|
+
'render_template.action_view',
|
55
|
+
].each do |notification|
|
56
|
+
let(:notification) { notification }
|
57
|
+
|
58
|
+
it 'removes ActionView::LogSubscriber' do
|
59
|
+
expect(subscribers).to_not include(ActionView::LogSubscriber)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Integration with Rails', timecop: true do
|
4
|
+
let(:app) { Rails.application }
|
5
|
+
|
6
|
+
let(:json_entries) do
|
7
|
+
[].tap do |entries|
|
8
|
+
STREAM.tap do |s|
|
9
|
+
s.rewind
|
10
|
+
s.read.split("\n").each do |line|
|
11
|
+
entries << JSON.parse(line)
|
12
|
+
end
|
13
|
+
s.close
|
14
|
+
s.reopen
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:json) { json_entries.last }
|
20
|
+
let(:json_response) { JSON.parse(last_response.body) }
|
21
|
+
|
22
|
+
include_examples 'request logger'
|
23
|
+
|
24
|
+
it 'preserves rails parameters' do
|
25
|
+
get '/show'
|
26
|
+
expect(json_response).to eq('action' => 'show', 'controller' => 'application')
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when a template is rendered' do
|
30
|
+
let(:action_view_notifications) do
|
31
|
+
json_entries.select { |e| e.to_json =~ /Rendered/ }
|
32
|
+
end
|
33
|
+
|
34
|
+
before { put '/users/5' }
|
35
|
+
|
36
|
+
specify { expect(last_response.status).to eq(200) }
|
37
|
+
|
38
|
+
it 'silences ActionView::LogSubscriber' do
|
39
|
+
expect(action_view_notifications).to be_empty
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Rack request logger with Sinatra', timecop: true do
|
4
|
+
let(:io) { StringIO.new }
|
5
|
+
before do
|
6
|
+
Loga.reset
|
7
|
+
Loga.configure do |config|
|
8
|
+
config.service_name = 'hello_world_app'
|
9
|
+
config.service_version = '1.0'
|
10
|
+
config.filter_parameters = [:password]
|
11
|
+
config.device = io
|
12
|
+
end
|
13
|
+
Loga.initialize!
|
14
|
+
end
|
15
|
+
let(:json) do
|
16
|
+
io.rewind
|
17
|
+
JSON.parse(io.read)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:app) do
|
21
|
+
Class.new(Sinatra::Base) do
|
22
|
+
# Disable show_exceptions and rely on user defined exception handlers
|
23
|
+
# (e.i. the error blocks)
|
24
|
+
set :show_exceptions, false
|
25
|
+
|
26
|
+
use Loga::Rack::RequestId
|
27
|
+
use Loga::Rack::Logger, Loga.logger, [:uuid]
|
28
|
+
|
29
|
+
error do
|
30
|
+
status 500
|
31
|
+
body 'Ooops'
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/ok' do
|
35
|
+
'Hello Sinatra'
|
36
|
+
end
|
37
|
+
|
38
|
+
get '/error' do
|
39
|
+
nil.name
|
40
|
+
end
|
41
|
+
|
42
|
+
post '/users' do
|
43
|
+
content_type :json
|
44
|
+
params.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/new' do
|
48
|
+
redirect '/ok'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
include_examples 'request logger'
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
require 'pry'
|
3
|
+
require 'support/helpers'
|
4
|
+
require 'support/timecop_shared'
|
5
|
+
require 'support/request_spec'
|
6
|
+
require 'rack/test'
|
7
|
+
|
8
|
+
CodeClimate::TestReporter.start if ENV.fetch('CODECLIMATE_REPO_TOKEN', nil)
|
9
|
+
|
10
|
+
class Socket
|
11
|
+
def self.gethostname
|
12
|
+
'bird.example.com'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
case ENV['BUNDLE_GEMFILE']
|
17
|
+
when /rails/
|
18
|
+
rspec_pattern = 'integration/rails/**/*_spec.rb'
|
19
|
+
/(?<appraisal>rails\d{2})\.gemfile/ =~ ENV['BUNDLE_GEMFILE']
|
20
|
+
require 'rails'
|
21
|
+
require File.expand_path("../fixtures/#{appraisal}/config/environment.rb", __FILE__)
|
22
|
+
when /sinatra/
|
23
|
+
rspec_pattern = 'integration/sinatra_spec.rb'
|
24
|
+
require 'json'
|
25
|
+
require 'sinatra'
|
26
|
+
require 'loga'
|
27
|
+
when /unit/
|
28
|
+
rspec_pattern = 'unit/**/*_spec.rb'
|
29
|
+
require 'loga'
|
30
|
+
else
|
31
|
+
fail 'BUNDLE_GEMFILE is unknown. Ensure the appraisal is present in Appraisals'
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec.configure do |config|
|
35
|
+
config.include Helpers
|
36
|
+
config.include Rack::Test::Methods
|
37
|
+
|
38
|
+
config.pattern = rspec_pattern
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
module Helpers
|
4
|
+
# Time used when testing timestamp
|
5
|
+
def time_anchor
|
6
|
+
Time.new(2015, 12, 15, 9, 30, 5.123, '+06:00')
|
7
|
+
end
|
8
|
+
|
9
|
+
def time_anchor_unix
|
10
|
+
BigDecimal.new('1450150205.123')
|
11
|
+
end
|
12
|
+
|
13
|
+
def hostname_anchor
|
14
|
+
'bird.example.com'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
RSpec.shared_examples 'request logger' do
|
2
|
+
context 'get request' do
|
3
|
+
it 'logs the request' do
|
4
|
+
get '/ok',
|
5
|
+
{ username: 'yoshi' },
|
6
|
+
'HTTP_USER_AGENT' => 'Chrome', 'HTTP_X_REQUEST_ID' => '471a34dc'
|
7
|
+
|
8
|
+
expect(json).to match(
|
9
|
+
'version' => '1.1',
|
10
|
+
'host' => 'bird.example.com',
|
11
|
+
'short_message' => 'GET /ok?username=yoshi 200 in 0ms',
|
12
|
+
'timestamp' => 1_450_150_205.123,
|
13
|
+
'level' => 6,
|
14
|
+
'_type' => 'request',
|
15
|
+
'_service.name' => 'hello_world_app',
|
16
|
+
'_service.version' => '1.0',
|
17
|
+
'_request.method' => 'GET',
|
18
|
+
'_request.path' => '/ok',
|
19
|
+
'_request.params' => { 'username' => 'yoshi' },
|
20
|
+
'_request.request_ip' => '127.0.0.1',
|
21
|
+
'_request.user_agent' => 'Chrome',
|
22
|
+
'_request.status' => 200,
|
23
|
+
'_request.request_id' => '471a34dc',
|
24
|
+
'_request.duration' => 0,
|
25
|
+
'_tags' => ['471a34dc'],
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'post request' do
|
31
|
+
let(:json_response) { JSON.parse(last_response.body) }
|
32
|
+
|
33
|
+
it 'logs the request' do
|
34
|
+
post '/users?username=yoshi',
|
35
|
+
{ email: 'hello@world.com' },
|
36
|
+
'HTTP_USER_AGENT' => 'Chrome', 'HTTP_X_REQUEST_ID' => '471a34dc'
|
37
|
+
|
38
|
+
expect(json).to match(
|
39
|
+
'version' => '1.1',
|
40
|
+
'host' => 'bird.example.com',
|
41
|
+
'short_message' => 'POST /users?username=yoshi 200 in 0ms',
|
42
|
+
'timestamp' => 1_450_150_205.123,
|
43
|
+
'level' => 6,
|
44
|
+
'_type' => 'request',
|
45
|
+
'_service.name' => 'hello_world_app',
|
46
|
+
'_service.version' => '1.0',
|
47
|
+
'_request.method' => 'POST',
|
48
|
+
'_request.path' => '/users',
|
49
|
+
'_request.params' => { 'username' => 'yoshi', 'email' => 'hello@world.com' },
|
50
|
+
'_request.request_ip' => '127.0.0.1',
|
51
|
+
'_request.user_agent' => 'Chrome',
|
52
|
+
'_request.status' => 200,
|
53
|
+
'_request.request_id' => '471a34dc',
|
54
|
+
'_request.duration' => 0,
|
55
|
+
'_tags' => ['471a34dc'],
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'preseves request parameters' do
|
60
|
+
post '/users?username=yoshi', email: 'hello@world.com'
|
61
|
+
expect(json_response).to include('email' => 'hello@world.com', 'username' => 'yoshi')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'request with redirect' do
|
66
|
+
it 'specifies the original path' do
|
67
|
+
get '/new', {}, 'HTTP_USER_AGENT' => 'Chrome', 'HTTP_X_REQUEST_ID' => '471a34dc'
|
68
|
+
|
69
|
+
expect(json).to match(
|
70
|
+
'version' => '1.1',
|
71
|
+
'host' => 'bird.example.com',
|
72
|
+
'short_message' => 'GET /new 302 in 0ms',
|
73
|
+
'timestamp' => 1_450_150_205.123,
|
74
|
+
'level' => 6,
|
75
|
+
'_type' => 'request',
|
76
|
+
'_service.name' => 'hello_world_app',
|
77
|
+
'_service.version' => '1.0',
|
78
|
+
'_request.method' => 'GET',
|
79
|
+
'_request.path' => '/new',
|
80
|
+
'_request.params' => {},
|
81
|
+
'_request.request_ip' => '127.0.0.1',
|
82
|
+
'_request.user_agent' => 'Chrome',
|
83
|
+
'_request.status' => 302,
|
84
|
+
'_request.request_id' => '471a34dc',
|
85
|
+
'_request.duration' => 0,
|
86
|
+
'_tags' => ['471a34dc'],
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when the request raises an exception' do
|
92
|
+
it 'logs the request with the exception' do
|
93
|
+
get '/error',
|
94
|
+
{ username: 'yoshi' },
|
95
|
+
'HTTP_USER_AGENT' => 'Chrome', 'HTTP_X_REQUEST_ID' => '471a34dc'
|
96
|
+
|
97
|
+
expect(json).to match(
|
98
|
+
'version' => '1.1',
|
99
|
+
'host' => 'bird.example.com',
|
100
|
+
'short_message' => 'GET /error?username=yoshi 500 in 0ms',
|
101
|
+
'timestamp' => 1_450_150_205.123,
|
102
|
+
'level' => 3,
|
103
|
+
'_type' => 'request',
|
104
|
+
'_service.name' => 'hello_world_app',
|
105
|
+
'_service.version' => '1.0',
|
106
|
+
'_request.method' => 'GET',
|
107
|
+
'_request.path' => '/error',
|
108
|
+
'_request.params' => { 'username' => 'yoshi' },
|
109
|
+
'_request.request_ip' => '127.0.0.1',
|
110
|
+
'_request.user_agent' => 'Chrome',
|
111
|
+
'_request.status' => 500,
|
112
|
+
'_request.request_id' => '471a34dc',
|
113
|
+
'_request.duration' => 0,
|
114
|
+
'_exception.klass' => 'NoMethodError',
|
115
|
+
'_exception.message' => "undefined method `name' for nil:NilClass",
|
116
|
+
'_exception.backtrace' => be_a(String),
|
117
|
+
'_tags' => ['471a34dc'],
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'when request causes 404' do
|
123
|
+
it 'does not log the framework exception' do
|
124
|
+
get '/not_found', {}, 'HTTP_X_REQUEST_ID' => '471a34dc'
|
125
|
+
|
126
|
+
expect(json).to match(
|
127
|
+
'version' => '1.1',
|
128
|
+
'host' => 'bird.example.com',
|
129
|
+
'short_message' => 'GET /not_found 404 in 0ms',
|
130
|
+
'timestamp' => 1_450_150_205.123,
|
131
|
+
'level' => 6,
|
132
|
+
'_type' => 'request',
|
133
|
+
'_service.name' => 'hello_world_app',
|
134
|
+
'_service.version' => '1.0',
|
135
|
+
'_request.method' => 'GET',
|
136
|
+
'_request.path' => '/not_found',
|
137
|
+
'_request.params' => {},
|
138
|
+
'_request.request_ip' => '127.0.0.1',
|
139
|
+
'_request.user_agent' => nil,
|
140
|
+
'_request.status' => 404,
|
141
|
+
'_request.request_id' => '471a34dc',
|
142
|
+
'_request.duration' => 0,
|
143
|
+
'_tags' => ['471a34dc'],
|
144
|
+
)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'when the request includes a filtered parameter' do
|
149
|
+
before { get '/ok', params }
|
150
|
+
|
151
|
+
context 'when params is shallow' do
|
152
|
+
let(:params) { { password: 'password123' } }
|
153
|
+
|
154
|
+
it 'filters the parameter from the params hash' do
|
155
|
+
expect(json).to include(
|
156
|
+
'_request.params' => { 'password' => '[FILTERED]' },
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'filters the parameter from the message' do
|
161
|
+
expect(json).to include(
|
162
|
+
'short_message' => 'GET /ok?password=[FILTERED] 200 in 0ms',
|
163
|
+
)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when params is nested' do
|
168
|
+
let(:params) { { users: [password: 'password123'] } }
|
169
|
+
|
170
|
+
it 'filters the parameter from the params hash' do
|
171
|
+
expect(json).to include(
|
172
|
+
'_request.params' => { 'users' => ['password' => '[FILTERED]'] },
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'filters the parameter from the message' do
|
177
|
+
expect(json).to include(
|
178
|
+
'short_message' => 'GET /ok?users[][password]=[FILTERED] 200 in 0ms',
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|