timber 1.1.14 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -2
  3. data/.travis.yml +47 -0
  4. data/Gemfile +1 -28
  5. data/README.md +83 -298
  6. data/bin/timber +13 -0
  7. data/gemfiles/rails-3.0.gemfile +5 -0
  8. data/gemfiles/rails-3.1.gemfile +5 -0
  9. data/gemfiles/rails-3.2.gemfile +5 -0
  10. data/gemfiles/rails-4.0.gemfile +9 -0
  11. data/gemfiles/rails-4.1.gemfile +9 -0
  12. data/gemfiles/rails-4.2.gemfile +9 -0
  13. data/gemfiles/rails-5.0.gemfile +9 -0
  14. data/gemfiles/rails-edge.gemfile +7 -0
  15. data/lib/timber.rb +7 -7
  16. data/lib/timber/cli.rb +72 -0
  17. data/lib/timber/cli/api.rb +104 -0
  18. data/lib/timber/cli/application.rb +28 -0
  19. data/lib/timber/cli/install.rb +186 -0
  20. data/lib/timber/cli/io_helper.rb +58 -0
  21. data/lib/timber/cli/messages.rb +170 -0
  22. data/lib/timber/config.rb +47 -6
  23. data/lib/timber/contexts/http.rb +2 -2
  24. data/lib/timber/current_context.rb +1 -1
  25. data/lib/timber/event.rb +8 -0
  26. data/lib/timber/events.rb +2 -0
  27. data/lib/timber/events/controller_call.rb +12 -3
  28. data/lib/timber/events/exception.rb +4 -3
  29. data/lib/timber/events/http_client_request.rb +61 -0
  30. data/lib/timber/events/http_client_response.rb +47 -0
  31. data/lib/timber/events/http_server_request.rb +15 -23
  32. data/lib/timber/events/http_server_response.rb +9 -9
  33. data/lib/timber/events/sql_query.rb +2 -2
  34. data/lib/timber/events/template_render.rb +2 -2
  35. data/lib/timber/frameworks/rails.rb +31 -6
  36. data/lib/timber/integrations.rb +22 -0
  37. data/lib/timber/integrations/action_controller/log_subscriber.rb +25 -0
  38. data/lib/timber/integrations/action_controller/log_subscriber/timber_log_subscriber.rb +40 -0
  39. data/lib/timber/integrations/action_dispatch/debug_exceptions.rb +51 -0
  40. data/lib/timber/integrations/action_view/log_subscriber.rb +25 -0
  41. data/lib/timber/integrations/action_view/log_subscriber/timber_log_subscriber.rb +73 -0
  42. data/lib/timber/integrations/active_record/log_subscriber.rb +25 -0
  43. data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +39 -0
  44. data/lib/timber/integrations/active_support/tagged_logging.rb +71 -0
  45. data/lib/timber/integrations/rack.rb +16 -0
  46. data/lib/timber/integrations/rack/exception_event.rb +28 -0
  47. data/lib/timber/integrations/rack/http_context.rb +25 -0
  48. data/lib/timber/integrations/rack/http_events.rb +46 -0
  49. data/lib/timber/integrations/rack/user_context.rb +59 -0
  50. data/lib/timber/integrations/rails/rack_logger.rb +49 -0
  51. data/lib/timber/integrator.rb +24 -0
  52. data/lib/timber/log_devices/http.rb +14 -21
  53. data/lib/timber/log_entry.rb +1 -1
  54. data/lib/timber/logger.rb +38 -12
  55. data/lib/timber/overrides.rb +9 -0
  56. data/lib/timber/overrides/lograge.rb +14 -0
  57. data/lib/timber/overrides/rails_server.rb +10 -0
  58. data/lib/timber/util.rb +2 -0
  59. data/lib/timber/util/active_support_log_subscriber.rb +13 -9
  60. data/lib/timber/util/http_event.rb +54 -0
  61. data/lib/timber/util/request.rb +44 -0
  62. data/lib/timber/version.rb +1 -1
  63. data/spec/README.md +5 -9
  64. data/spec/spec_helper.rb +1 -4
  65. data/spec/support/action_controller.rb +7 -3
  66. data/spec/support/active_record.rb +23 -19
  67. data/spec/support/rails.rb +56 -32
  68. data/spec/support/timber.rb +2 -3
  69. data/spec/support/webmock.rb +1 -0
  70. data/spec/timber/integrations/action_controller/log_subscriber_spec.rb +55 -0
  71. data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +53 -0
  72. data/spec/timber/integrations/action_view/log_subscriber_spec.rb +115 -0
  73. data/spec/timber/integrations/active_record/log_subscriber_spec.rb +46 -0
  74. data/spec/timber/integrations/rack/http_context_spec.rb +60 -0
  75. data/spec/timber/integrations/rails/rack_logger_spec.rb +58 -0
  76. data/spec/timber/logger_spec.rb +45 -9
  77. data/timber.gemspec +29 -3
  78. metadata +143 -46
  79. data/Appraisals +0 -41
  80. data/circle.yml +0 -33
  81. data/lib/timber/overrides/logger_add.rb +0 -38
  82. data/lib/timber/probe.rb +0 -23
  83. data/lib/timber/probes.rb +0 -23
  84. data/lib/timber/probes/action_controller_log_subscriber.rb +0 -20
  85. data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +0 -64
  86. data/lib/timber/probes/action_controller_user_context.rb +0 -52
  87. data/lib/timber/probes/action_dispatch_debug_exceptions.rb +0 -80
  88. data/lib/timber/probes/action_view_log_subscriber.rb +0 -20
  89. data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +0 -69
  90. data/lib/timber/probes/active_record_log_subscriber.rb +0 -20
  91. data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +0 -31
  92. data/lib/timber/probes/active_support_tagged_logging.rb +0 -63
  93. data/lib/timber/probes/rails_rack_logger.rb +0 -77
  94. data/lib/timber/rack_middlewares.rb +0 -12
  95. data/lib/timber/rack_middlewares/http_context.rb +0 -30
  96. data/spec/support/action_view.rb +0 -4
  97. data/spec/support/coveralls.rb +0 -2
  98. data/spec/support/simplecov.rb +0 -9
  99. data/spec/timber/overrides/logger_add_spec.rb +0 -26
  100. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +0 -65
  101. data/spec/timber/probes/action_controller_user_context_spec.rb +0 -53
  102. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +0 -48
  103. data/spec/timber/probes/action_view_log_subscriber_spec.rb +0 -107
  104. data/spec/timber/probes/active_record_log_subscriber_spec.rb +0 -47
  105. data/spec/timber/probes/rails_rack_logger_spec.rb +0 -46
  106. data/spec/timber/rack_middlewares/http_context_spec.rb +0 -47
@@ -1,77 +0,0 @@
1
- module Timber
2
- module Probes
3
- # Responsible for automatically tracking the http request events for applications
4
- # that use `Rack`.
5
- class RailsRackLogger < Probe
6
- module InstanceMethods
7
- def self.included(klass)
8
- klass.class_eval do
9
- protected
10
- if klass.private_instance_methods.include?(:started_request_message) || klass.method_defined?(:started_request_message)
11
- def started_request_message(request)
12
- http_request_event(request)
13
- end
14
- elsif klass.method_defined?(:before_dispatch)
15
- def before_dispatch(env)
16
- request = ActionDispatch::Request.new(env)
17
- info do
18
- http_request_event(request)
19
- end
20
- end
21
- end
22
-
23
- def http_request_event(request)
24
- # No idea why rails 3.X returns a "/" :/
25
- referrer = request.referer == "/" ? nil : request.referer
26
- Events::HTTPServerRequest.new(
27
- content_type: request.content_type,
28
- host: request.host,
29
- method: request.request_method,
30
- path: request.filtered_path,
31
- port: request.port,
32
- query_string: request.query_string,
33
- remote_addr: request.ip,
34
- referrer: referrer,
35
- request_id: request_id(request.env),
36
- scheme: request.scheme,
37
- user_agent: request.user_agent
38
- )
39
- end
40
-
41
- def request_id(env)
42
- env["X-Request-ID"] ||
43
- env["X-Request-Id"] ||
44
- env["action_dispatch.request_id"]
45
- end
46
- end
47
- end
48
- end
49
-
50
- module BeforeDispatchInstanceMethods
51
- def self.included(klass)
52
- klass.class_eval do
53
- protected
54
- def before_dispatch(env)
55
- request = ActionDispatch::Request.new(env)
56
- path = request.filtered_path
57
-
58
- info "\n\nStarted #{request.request_method} \"#{path}\" " \
59
- "for #{request.ip} at #{Time.now.to_default_s}"
60
- end
61
- end
62
- end
63
- end
64
-
65
- def initialize
66
- require "rails/rack/logger"
67
- rescue LoadError => e
68
- raise RequirementNotMetError.new(e.message)
69
- end
70
-
71
- def insert!
72
- return true if ::Rails::Rack::Logger.include?(InstanceMethods)
73
- ::Rails::Rack::Logger.send(:include, InstanceMethods)
74
- end
75
- end
76
- end
77
- end
@@ -1,12 +0,0 @@
1
- require "timber/rack_middlewares/http_context"
2
-
3
- module Timber
4
- # Namespace for all Rack middlewares.
5
- module RackMiddlewares
6
- # A list containing *all* `Timber::RackMiddlewares::*` sub classes. This makes it easy to
7
- # achieve forward compatibility as middlewares are modified.
8
- def self.middlewares
9
- @middlewares ||= [HTTPContext]
10
- end
11
- end
12
- end
@@ -1,30 +0,0 @@
1
- module Timber
2
- module RackMiddlewares
3
- # Reponsible for adding the HTTP context for applications that use `Rack`.
4
- class HTTPContext
5
- def initialize(app)
6
- @app = app
7
- end
8
-
9
- def call(env)
10
- request = ::Rack::Request.new(env)
11
- context = Contexts::HTTP.new(
12
- method: request.request_method,
13
- path: request.path,
14
- remote_addr: request.ip,
15
- request_id: request_id(env)
16
- )
17
- CurrentContext.with(context) do
18
- @app.call(env)
19
- end
20
- end
21
-
22
- private
23
- def request_id(env)
24
- env["X-Request-ID"] ||
25
- env["X-Request-Id"] ||
26
- env["action_dispatch.request_id"]
27
- end
28
- end
29
- end
30
- end
@@ -1,4 +0,0 @@
1
- require "action_view"
2
-
3
- # Needed for the ActionView::LogSubscriber. If a logger is not present, nothing will be logged.
4
- ActionView::Base.logger = Rails.logger if ActionView::Base.respond_to?(:logger=)
@@ -1,2 +0,0 @@
1
- require 'coveralls'
2
- Coveralls.wear!
@@ -1,9 +0,0 @@
1
- require 'simplecov'
2
-
3
- # save to CircleCI's artifacts directory if we're on CircleCI
4
- if ENV['CIRCLE_ARTIFACTS']
5
- dir = File.join(ENV['CIRCLE_ARTIFACTS'], "coverage")
6
- SimpleCov.coverage_dir(dir)
7
- end
8
-
9
- SimpleCov.start
@@ -1,26 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Timber::Overrides::LoggerAdd, :rails_23 => true do
4
- describe "#add" do
5
- let(:io) { StringIO.new }
6
- let(:logger) do
7
- logger = ::Logger.new(io)
8
- logger.formatter = proc do |severity, datetime, progname, msg|
9
- "#{msg}\n"
10
- end
11
- logger
12
- end
13
-
14
- it "should display the message only when passed to a default logger" do
15
- event = Timber::Events::Custom.new(message: "Build version 1.0.0", type: :build, data: {version: "1.0.0"})
16
- logger.info(event)
17
- expect(io.string).to eq("Build version 1.0.0\n")
18
- end
19
-
20
- it "should work with blocks" do
21
- event = Timber::Events::Custom.new(message: "Build version 1.0.0", type: :build, data: {version: "1.0.0"})
22
- logger.info { event }
23
- expect(io.string).to eq("Build version 1.0.0\n")
24
- end
25
- end
26
- end
@@ -1,65 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Timber::Probes::ActionControllerLogSubscriber do
4
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
5
- let(:io) { StringIO.new }
6
- let(:logger) do
7
- logger = Timber::Logger.new(io)
8
- logger.level = ::Logger::WARN
9
- logger
10
- end
11
-
12
- describe "#insert!" do
13
- around(:each) do |example|
14
- class LogSubscriberController < ActionController::Base
15
- layout nil
16
-
17
- def index
18
- render json: {}
19
- end
20
-
21
- def method_for_action(action_name)
22
- action_name
23
- end
24
- end
25
-
26
- ::RailsApp.routes.draw do
27
- get 'log_subscriber' => 'log_subscriber#index'
28
- end
29
-
30
- old_logger = ::ActionController::Base.logger
31
- ::ActionController::Base.logger = logger
32
-
33
- Timecop.freeze(time) { example.run }
34
-
35
- Object.send(:remove_const, :LogSubscriberController)
36
- ::ActionController::Base.logger = old_logger
37
- end
38
-
39
- it "should not log if the level is not sufficient" do
40
- dispatch_rails_request("/log_subscriber")
41
- expect(io.string).to eq("")
42
- end
43
-
44
- context "with an info level" do
45
- around(:each) do |example|
46
- old_level = logger.level
47
- logger.level = ::Logger::INFO
48
- example.run
49
- logger.level = old_level
50
- end
51
-
52
- it "should log the controller call event" do
53
- # Rails uses this to calculate the view runtime below
54
- allow(Benchmark).to receive(:ms).and_return(1).and_yield
55
- dispatch_rails_request("/log_subscriber")
56
- lines = io.string.split("\n")
57
- expect(lines.length).to eq(2)
58
- expect(lines[0]).to start_with('Processing by LogSubscriberController#index as HTML @metadata {"level":"info","dt":"2016-09-01T12:00:00.000000Z"')
59
- expect(lines[0]).to include('"event":{"server_side_app":{"controller_call":{"controller":"LogSubscriberController","action":"index"}}}')
60
- expect(lines[1]).to start_with('Completed 200 OK in 0.0ms (Views: 1.0ms) @metadata {"level":"info","dt":"2016-09-01T12:00:00.000000Z"')
61
- expect(lines[1]).to include('"event":{"server_side_app":{"http_server_response":{"status":200,"time_ms":0.0}}}')
62
- end
63
- end
64
- end
65
- end
@@ -1,53 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Timber::Probes::ActionControllerUserContext do
4
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
5
- let(:io) { StringIO.new }
6
- let(:logger) do
7
- logger = Timber::Logger.new(io)
8
- logger.level = ::Logger::WARN
9
- logger
10
- end
11
-
12
- describe "#insert!" do
13
- around(:each) do |example|
14
- class UserContextController < ActionController::Base
15
- layout nil
16
-
17
- def index
18
- logger.error "test"
19
- render json: {}
20
- end
21
-
22
- def method_for_action(action_name)
23
- action_name
24
- end
25
-
26
- private
27
- def current_user
28
- @current_user ||= begin
29
- user_struct = Struct.new(:id, :name, :email)
30
- user_struct.new(1, "Ben Johnson", "hi@timber.io")
31
- end
32
- end
33
- end
34
-
35
- ::RailsApp.routes.draw do
36
- get 'user_context' => 'user_context#index'
37
- end
38
-
39
- old_logger = ::ActionController::Base.logger
40
- ::ActionController::Base.logger = logger
41
-
42
- Timecop.freeze(time) { example.run }
43
-
44
- Object.send(:remove_const, :UserContextController)
45
- ::ActionController::Base.logger = old_logger
46
- end
47
-
48
- it "should capture the user context" do
49
- dispatch_rails_request("/user_context")
50
- expect(io.string).to include("\"user\":{\"id\":\"1\",\"name\":\"Ben Johnson\",\"email\":\"hi@timber.io\"}")
51
- end
52
- end
53
- end
@@ -1,48 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Timber::Probes::ActionDispatchDebugExceptions do
4
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
5
- let(:io) { StringIO.new }
6
- let(:logger) do
7
- logger = Timber::Logger.new(io)
8
- logger.level = ::Logger::DEBUG
9
- logger
10
- end
11
-
12
- describe "#insert!" do
13
- around(:each) do |example|
14
- class ExceptionController < ActionController::Base
15
- layout nil
16
-
17
- def index
18
- raise "boom"
19
- end
20
-
21
- def method_for_action(action_name)
22
- action_name
23
- end
24
- end
25
-
26
- ::RailsApp.routes.draw do
27
- get 'exception' => 'exception#index'
28
- end
29
-
30
- Timecop.freeze(time) { example.run }
31
-
32
- Object.send(:remove_const, :ExceptionController)
33
- end
34
-
35
- it "should set the context" do
36
- mock_class
37
- dispatch_rails_request("/exception")
38
- # Because constantly updating the line numbers sucks :/
39
- expect(io.string).to include("RuntimeError (boom) @metadata")
40
- expect(io.string).to include("\"event\":{\"server_side_app\":{\"exception\":{\"name\":\"RuntimeError\",\"message\":\"boom\",\"backtrace\":[{\"file\":\"lib/timber/probes/action_controller_user_context.rb\",\"line\":33,\"function\":\"_timber_capture_user_context\"},")
41
- end
42
-
43
- def mock_class
44
- klass = defined?(::ActionDispatch::DebugExceptions) ? ::ActionDispatch::DebugExceptions : ::ActionDispatch::ShowExceptions
45
- allow_any_instance_of(klass).to receive(:logger).and_return(logger)
46
- end
47
- end
48
- end
@@ -1,107 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Timber::Probes::ActionViewLogSubscriber do
4
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
5
- let(:io) { StringIO.new }
6
- let(:logger) do
7
- logger = Timber::Logger.new(io)
8
- logger.level = ::Logger::WARN
9
- logger
10
- end
11
-
12
- describe "insert!" do
13
- around(:each) do |example|
14
- class ActionViewLogSubscriberController < ActionController::Base
15
- layout nil
16
-
17
- def index
18
- render template: "template"
19
- end
20
-
21
- def method_for_action(action_name)
22
- action_name
23
- end
24
- end
25
-
26
- ::RailsApp.routes.draw do
27
- get 'action_view_log_subscriber' => 'action_view_log_subscriber#index'
28
- end
29
-
30
- Timecop.freeze(time) { example.run }
31
-
32
- Object.send(:remove_const, :ActionViewLogSubscriberController)
33
- end
34
-
35
- describe "#render_template" do
36
- it "should not log if the level is not sufficient" do
37
- allow_any_instance_of(Timber::Probes::ActionViewLogSubscriber::LogSubscriber).to receive(:logger).and_return(logger)
38
- dispatch_rails_request("/action_view_log_subscriber")
39
- expect(io.string).to eq("")
40
- end
41
-
42
- context "with an info level" do
43
- around(:each) do |example|
44
- old_level = logger.level
45
- logger.level = ::Logger::INFO
46
- example.run
47
- logger.level = old_level
48
- end
49
-
50
- it "should log the controller call event" do
51
- allow_any_instance_of(Timber::Probes::ActionViewLogSubscriber::LogSubscriber).to receive(:logger).and_return(logger)
52
- dispatch_rails_request("/action_view_log_subscriber")
53
- expect(io.string).to start_with(" Rendered spec/support/rails/templates/template.html (0.0ms) @metadata {\"level\":\"info\"")
54
- expect(io.string).to include("\"event\":{\"server_side_app\":{\"template_render\":{\"name\":\"spec/support/rails/templates/template.html\",\"time_ms\":0.0}}},")
55
- end
56
- end
57
- end
58
- end
59
-
60
- if defined?(described_class::LogSubscriber)
61
- describe described_class::LogSubscriber do
62
- let(:event) do
63
- event = Struct.new(:duration, :payload)
64
- event.new(2, identifier: "path/to/template.html")
65
- end
66
-
67
- around(:each) do |example|
68
- old_level = logger.level
69
- logger.level = ::Logger::INFO
70
- example.run
71
- logger.level = old_level
72
- end
73
-
74
- describe "#render_template" do
75
- it "should render the collection" do
76
- log_subscriber = described_class.new
77
- log_subscriber.stub(:logger) { logger }
78
- log_subscriber.render_template(event)
79
- expect(io.string).to start_with(" Rendered path/to/template.html (2.0ms) @metadata")
80
- end
81
- end
82
-
83
- describe "#render_partial" do
84
- it "should render the collection" do
85
- log_subscriber = described_class.new
86
- log_subscriber.stub(:logger) { logger }
87
- log_subscriber.render_partial(event)
88
- expect(io.string).to start_with(" Rendered path/to/template.html (2.0ms) @metadata")
89
- end
90
- end
91
-
92
- describe "#render_collection" do
93
- it "should render the collection" do
94
- log_subscriber = described_class.new
95
- log_subscriber.stub(:logger) { logger }
96
- log_subscriber.render_collection(event)
97
-
98
- if log_subscriber.respond_to?(:render_count, true)
99
- expect(io.string).to start_with(" Rendered collection of path/to/template.html [ times] (2.0ms) @metadata ")
100
- else
101
- expect(io.string).to start_with(" Rendered path/to/template.html (2.0ms) @metadata")
102
- end
103
- end
104
- end
105
- end
106
- end
107
- end