timber 1.1.14 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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