timber 1.0.3

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.yardopts +6 -0
  5. data/Appraisals +41 -0
  6. data/Gemfile +30 -0
  7. data/LICENSE.md +15 -0
  8. data/README.md +194 -0
  9. data/circle.yml +33 -0
  10. data/lib/timber/config.rb +18 -0
  11. data/lib/timber/context.rb +17 -0
  12. data/lib/timber/contexts/custom.rb +27 -0
  13. data/lib/timber/contexts/http.rb +28 -0
  14. data/lib/timber/contexts/organization.rb +35 -0
  15. data/lib/timber/contexts/user.rb +36 -0
  16. data/lib/timber/contexts.rb +10 -0
  17. data/lib/timber/current_context.rb +43 -0
  18. data/lib/timber/event.rb +17 -0
  19. data/lib/timber/events/controller_call.rb +40 -0
  20. data/lib/timber/events/custom.rb +42 -0
  21. data/lib/timber/events/exception.rb +35 -0
  22. data/lib/timber/events/http_request.rb +50 -0
  23. data/lib/timber/events/http_response.rb +36 -0
  24. data/lib/timber/events/sql_query.rb +26 -0
  25. data/lib/timber/events/template_render.rb +26 -0
  26. data/lib/timber/events.rb +37 -0
  27. data/lib/timber/frameworks/rails.rb +13 -0
  28. data/lib/timber/frameworks.rb +19 -0
  29. data/lib/timber/log_devices/http.rb +87 -0
  30. data/lib/timber/log_devices.rb +8 -0
  31. data/lib/timber/log_entry.rb +59 -0
  32. data/lib/timber/logger.rb +142 -0
  33. data/lib/timber/probe.rb +23 -0
  34. data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +64 -0
  35. data/lib/timber/probes/action_controller_log_subscriber.rb +20 -0
  36. data/lib/timber/probes/action_dispatch_debug_exceptions.rb +80 -0
  37. data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +62 -0
  38. data/lib/timber/probes/action_view_log_subscriber.rb +20 -0
  39. data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +29 -0
  40. data/lib/timber/probes/active_record_log_subscriber.rb +20 -0
  41. data/lib/timber/probes/rack_http_context.rb +51 -0
  42. data/lib/timber/probes/rails_rack_logger.rb +76 -0
  43. data/lib/timber/probes.rb +21 -0
  44. data/lib/timber/util/active_support_log_subscriber.rb +33 -0
  45. data/lib/timber/util/hash.rb +14 -0
  46. data/lib/timber/util.rb +8 -0
  47. data/lib/timber/version.rb +3 -0
  48. data/lib/timber.rb +22 -0
  49. data/spec/spec_helper.rb +30 -0
  50. data/spec/support/action_controller.rb +4 -0
  51. data/spec/support/action_view.rb +4 -0
  52. data/spec/support/active_record.rb +28 -0
  53. data/spec/support/coveralls.rb +2 -0
  54. data/spec/support/rails/templates/_partial.html +1 -0
  55. data/spec/support/rails/templates/template.html +1 -0
  56. data/spec/support/rails.rb +37 -0
  57. data/spec/support/simplecov.rb +9 -0
  58. data/spec/support/socket_hostname.rb +12 -0
  59. data/spec/support/timber.rb +4 -0
  60. data/spec/support/timecop.rb +3 -0
  61. data/spec/support/webmock.rb +2 -0
  62. data/spec/timber/events_spec.rb +55 -0
  63. data/spec/timber/log_devices/http_spec.rb +62 -0
  64. data/spec/timber/logger_spec.rb +89 -0
  65. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +70 -0
  66. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +51 -0
  67. data/spec/timber/probes/action_view_log_subscriber_spec.rb +61 -0
  68. data/spec/timber/probes/active_record_log_subscriber_spec.rb +52 -0
  69. data/spec/timber/probes/rack_http_context_spec.rb +54 -0
  70. data/spec/timber/probes/rails_rack_logger_spec.rb +46 -0
  71. data/timber.gemspec +22 -0
  72. metadata +149 -0
@@ -0,0 +1,62 @@
1
+ # require "spec_helper"
2
+
3
+ # describe Timber::LogDevices::HTTP do
4
+ # # We have to define our own at_exit method, because the mocks and
5
+ # # everything are stripped out before. Otherwise it tries to issue
6
+ # # a request :(
7
+ # before(:each) do
8
+ # described_class.class_eval do
9
+ # def at_exit; true; end
10
+ # end
11
+ # end
12
+
13
+ # describe "#initialize" do
14
+ # it "should start a thread for delivery" do
15
+ # allow_any_instance_of(described_class).to receive(:at_exit).exactly(1).times.and_return(true)
16
+ # expect_any_instance_of(described_class).to receive(:deliver).exactly(2).times.and_return(true)
17
+ # http = described_class.new("MYKEY", frequency_seconds: 0.1)
18
+ # thread = http.instance_variable_get(:@delivery_thread)
19
+ # expect(thread).to be_alive
20
+ # sleep 0.25 # allow 2 iterations
21
+ # http.close
22
+ # end
23
+ # end
24
+
25
+ # describe "#write" do
26
+ # let(:http) { described_class.new("MYKEY") }
27
+ # let(:buffer) { http.instance_variable_get(:@buffer) }
28
+
29
+ # after(:each) { http.close }
30
+
31
+ # it "should buffer the messages" do
32
+ # http.write("test log message")
33
+ # expect(buffer.read).to eq("test log message")
34
+ # end
35
+ # end
36
+
37
+ # describe "#deliver" do
38
+ # let(:http) { described_class.new("MYKEY") }
39
+ # let(:buffer) { http.instance_variable_get(:@buffer) }
40
+
41
+ # after(:each) { http.close }
42
+
43
+ # it "should delivery properly and flush the buffer" do
44
+ # expect_any_instance_of(described_class).to receive(:at_exit).exactly(1).times.and_return(true)
45
+ # stub = stub_request(:post, "https://api.timber.io/http_frames").
46
+ # with(
47
+ # :body => "test log message",
48
+ # :headers => {'Authorization'=>'Basic TVlLRVk=', 'Connection'=>'keep-alive', 'Content-Type'=>'application/json', 'User-Agent'=>'Timber Ruby Gem/1.0.0'}
49
+ # ).
50
+ # to_return(:status => 200, :body => "", :headers => {})
51
+
52
+ # http.write("test log message")
53
+
54
+ # expect(buffer).to_not be_empty
55
+
56
+ # http.send(:deliver)
57
+
58
+ # expect(stub).to have_been_requested.times(1)
59
+ # expect(buffer).to be_empty
60
+ # end
61
+ # end
62
+ # end
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Logger, :rails_23 => true do
4
+ describe "#add" do
5
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
+ let(:io) { StringIO.new }
7
+ let(:logger) { Timber::Logger.new(io) }
8
+
9
+ around(:each) do |example|
10
+ Timecop.freeze(time) { example.run }
11
+ end
12
+
13
+ context "with the :hybrid format" do
14
+ before(:each) { logger.formatter = Timber::Logger::HybridFormatter.new }
15
+
16
+ it "should accept strings" do
17
+ logger.info("this is a test")
18
+ expect(io.string).to eq("this is a test @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\"}\n")
19
+ end
20
+
21
+ context "with a context" do
22
+ let(:http_context) do
23
+ Timber::Contexts::HTTP.new(
24
+ method: "POST",
25
+ path: "/checkout",
26
+ remote_addr: "123.456.789.10",
27
+ request_id: "abcd1234"
28
+ )
29
+ end
30
+
31
+ around(:each) do |example|
32
+ Timber::CurrentContext.instance.with(http_context) do
33
+ example.run
34
+ end
35
+ end
36
+
37
+ it "should snapshot and include the context" do
38
+ expect(Timber::CurrentContext.instance).to receive(:snapshot).and_call_original
39
+ logger.info("this is a test")
40
+ expect(io.string).to eq("this is a test @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"context\":{\"http\":{\"method\":\"POST\",\"path\":\"/checkout\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"abcd1234\"}}}\n")
41
+ end
42
+ end
43
+
44
+ it "should call and use Timber::Events.build" do
45
+ message = {message: "payment rejected", type: :payment_rejected, data: {customer_id: "abcde1234", amount: 100}}
46
+ expect(Timber::Events).to receive(:build).with(message).and_call_original
47
+ logger.info(message)
48
+ expect(io.string).to eq("payment rejected @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"custom\":{\"payment_rejected\":{\"customer_id\":\"abcde1234\",\"amount\":100}}}}\n")
49
+ end
50
+
51
+ it "should log properly when an event is passed" do
52
+ message = Timber::Events::SQLQuery.new(sql: "select * from users", time_ms: 56, message: "select * from users")
53
+ logger.info(message)
54
+ expect(io.string).to eq("select * from users @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"sql_query\":{\"sql\":\"select * from users\",\"time_ms\":56}}}\n")
55
+ end
56
+
57
+ it "should allow functions" do
58
+ logger.info do
59
+ {message: "payment rejected", type: :payment_rejected, data: {customer_id: "abcde1234", amount: 100}}
60
+ end
61
+ expect(io.string).to eq("payment rejected @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"custom\":{\"payment_rejected\":{\"customer_id\":\"abcde1234\",\"amount\":100}}}}\n")
62
+ end
63
+
64
+ it "should escape new lines" do
65
+ logger.info "first\nsecond"
66
+ expect(io.string).to eq("first\\nsecond @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\"}\n")
67
+ end
68
+ end
69
+
70
+ context "with the :json format" do
71
+ before(:each) { logger.formatter = Timber::Logger::JSONFormatter.new }
72
+
73
+ it "should log in the correct format" do
74
+ logger.info("this is a test")
75
+ expect(io.string).to eq("{\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"message\":\"this is a test\"}\n")
76
+ end
77
+ end
78
+
79
+ context "with TaggedLogging" do
80
+ let(:logger) { ActiveSupport::TaggedLogging.new(Timber::Logger.new(io)) }
81
+
82
+ it "should format properly with events" do
83
+ message = Timber::Events::SQLQuery.new(sql: "select * from users", time_ms: 56, message: "select * from users")
84
+ logger.info(message)
85
+ expect(io.string).to eq("select * from users @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"sql_query\":{\"sql\":\"select * from users\",\"time_ms\":56}}}\n")
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::ActionControllerLogSubscriber do
4
+ if defined?(described_class::LogSubscriber)
5
+ describe described_class::LogSubscriber do
6
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
7
+ let(:io) { StringIO.new }
8
+ let(:logger) do
9
+ logger = Timber::Logger.new(io)
10
+ logger.level = ::Logger::WARN
11
+ logger
12
+ end
13
+
14
+ around(:each) do |example|
15
+ class LogSubscriberController < ActionController::Base
16
+ layout nil
17
+
18
+ def index
19
+ render json: {}
20
+ end
21
+
22
+ def method_for_action(action_name)
23
+ action_name
24
+ end
25
+ end
26
+
27
+ ::RailsApp.routes.draw do
28
+ get 'log_subscriber' => 'log_subscriber#index'
29
+ end
30
+
31
+ old_logger = ::ActionController::Base.logger
32
+ ::ActionController::Base.logger = logger
33
+
34
+ Timecop.freeze(time) { example.run }
35
+
36
+ Object.send(:remove_const, :LogSubscriberController)
37
+ ::ActionController::Base.logger = old_logger
38
+ end
39
+
40
+ describe "#start_processing, #process_action" do
41
+ it "should not log if the level is not sufficient" do
42
+ dispatch_rails_request("/log_subscriber")
43
+ expect(io.string).to eq("")
44
+ end
45
+
46
+ context "with an info level" do
47
+ around(:each) do |example|
48
+ old_level = logger.level
49
+ logger.level = ::Logger::INFO
50
+ example.run
51
+ logger.level = old_level
52
+ end
53
+
54
+ it "should log the controller call event" do
55
+ # Rails uses this to calculate the view runtime below
56
+ allow(Benchmark).to receive(:ms).and_return(1).and_yield
57
+ dispatch_rails_request("/log_subscriber")
58
+ message1 = <<-MSG
59
+ Processing by LogSubscriberController#index as HTML @timber.io {"level":"info","dt":"2016-09-01T12:00:00.000000Z","event":{"controller_call":{"controller":"LogSubscriberController","action":"index"}},"context":{"http":{"method":"GET","path":"/log_subscriber","remote_addr":"123.456.789.10","request_id":"unique-request-id-1234"}}}
60
+ MSG
61
+ message2 = <<-MSG
62
+ Completed 200 OK in 0.0ms (Views: 1.0ms) @timber.io {"level":"info","dt":"2016-09-01T12:00:00.000000Z","event":{"http_response":{"status":200,"time_ms":0.0}},"context":{"http":{"method":"GET","path":"/log_subscriber","remote_addr":"123.456.789.10","request_id":"unique-request-id-1234"}}}
63
+ MSG
64
+ expect(io.string).to eq(message1.strip + "\n" + message2.strip + "\n")
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::ActionDispatchDebugExceptions do
4
+ describe "#{described_class}::*InstanceMethods" do
5
+ describe "#log_error" do
6
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
7
+ let(:io) { StringIO.new }
8
+ let(:logger) do
9
+ logger = Timber::Logger.new(io)
10
+ logger.level = ::Logger::DEBUG
11
+ logger
12
+ end
13
+
14
+ around(:each) do |example|
15
+ class ExceptionController < ActionController::Base
16
+ layout nil
17
+
18
+ def index
19
+ raise "boom"
20
+ end
21
+
22
+ def method_for_action(action_name)
23
+ action_name
24
+ end
25
+ end
26
+
27
+ ::RailsApp.routes.draw do
28
+ get 'exception' => 'exception#index'
29
+ end
30
+
31
+ Timecop.freeze(time) { example.run }
32
+
33
+ Object.send(:remove_const, :ExceptionController)
34
+ end
35
+
36
+ it "should set the context" do
37
+ mock_class
38
+ dispatch_rails_request("/exception")
39
+ # Because constantly updating the line numbers sucks :/
40
+ expect(io.string).to include("RuntimeError (boom):\\n\\n")
41
+ expect(io.string).to include("@timber.io")
42
+ expect(io.string).to include("\"event\":{\"exception\":{\"name\":\"RuntimeError\",\"message\":\"boom\",\"backtrace\":[\"")
43
+ end
44
+
45
+ def mock_class
46
+ klass = defined?(::ActionDispatch::DebugExceptions) ? ::ActionDispatch::DebugExceptions : ::ActionDispatch::ShowExceptions
47
+ allow_any_instance_of(klass).to receive(:logger).and_return(logger)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::ActionViewLogSubscriber do
4
+ if defined?(described_class::LogSubscriber)
5
+ describe described_class::LogSubscriber do
6
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
7
+ let(:io) { StringIO.new }
8
+ let(:logger) do
9
+ logger = Timber::Logger.new(io)
10
+ logger.level = ::Logger::WARN
11
+ logger
12
+ end
13
+
14
+ around(:each) do |example|
15
+ class ActionViewLogSubscriberController < ActionController::Base
16
+ layout nil
17
+
18
+ def index
19
+ render template: "template"
20
+ end
21
+
22
+ def method_for_action(action_name)
23
+ action_name
24
+ end
25
+ end
26
+
27
+ ::RailsApp.routes.draw do
28
+ get 'action_view_log_subscriber' => 'action_view_log_subscriber#index'
29
+ end
30
+
31
+ Timecop.freeze(time) { example.run }
32
+
33
+ Object.send(:remove_const, :ActionViewLogSubscriberController)
34
+ end
35
+
36
+ describe "#sql" do
37
+ it "should not log if the level is not sufficient" do
38
+ allow_any_instance_of(Timber::Probes::ActionViewLogSubscriber::LogSubscriber).to receive(:logger).and_return(logger)
39
+ dispatch_rails_request("/action_view_log_subscriber")
40
+ expect(io.string).to eq("")
41
+ end
42
+
43
+ context "with an info level" do
44
+ around(:each) do |example|
45
+ old_level = logger.level
46
+ logger.level = ::Logger::INFO
47
+ example.run
48
+ logger.level = old_level
49
+ end
50
+
51
+ it "should log the controller call event" do
52
+ allow_any_instance_of(Timber::Probes::ActionViewLogSubscriber::LogSubscriber).to receive(:logger).and_return(logger)
53
+ dispatch_rails_request("/action_view_log_subscriber")
54
+ message = " Rendered spec/support/rails/templates/template.html (0.0ms) @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"template_render\":{\"name\":\"spec/support/rails/templates/template.html\",\"time_ms\":0.0}},\"context\":{\"http\":{\"method\":\"GET\",\"path\":\"/action_view_log_subscriber\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}}}\n"
55
+ expect(io.string).to eq(message)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::ActiveRecordLogSubscriber do
4
+ if defined?(described_class::LogSubscriber)
5
+ describe described_class::LogSubscriber do
6
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
7
+ let(:io) { StringIO.new }
8
+ let(:logger) do
9
+ logger = Timber::Logger.new(io)
10
+ logger.level = ::Logger::INFO
11
+ logger
12
+ end
13
+
14
+ around(:each) do |example|
15
+ old_logger = ::ActiveRecord::Base.logger
16
+ ::ActiveRecord::Base.logger = logger
17
+
18
+ Timecop.freeze(time) { example.run }
19
+
20
+ ::ActiveRecord::Base.logger = old_logger
21
+ end
22
+
23
+ describe "#sql" do
24
+ it "should not log if the level is not sufficient" do
25
+ User.order("users.id DESC").all.collect # collect kicks the sql because it is lazily executed
26
+ expect(io.string).to eq("")
27
+ end
28
+
29
+ context "with an info level" do
30
+ around(:each) do |example|
31
+ old_level = logger.level
32
+ logger.level = ::Logger::DEBUG
33
+ example.run
34
+ logger.level = old_level
35
+ end
36
+
37
+ it "should log the sql query" do
38
+ User.order("users.id DESC").all.collect # collect kicks the sql because it is lazily executed
39
+ message = " \e[1m\e[36mUser Load (0.0ms)\e[0m \e[1m\e[34mSELECT \"users\".* FROM \"users\" ORDER BY users.id DESC\e[0m @timber.io {\"level\":\"debug\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"sql_query\":{\"sql\":\"SELECT \\\"users\\\".* FROM \\\"users\\\" ORDER BY users.id DESC\",\"time_ms\":0.0}}}\n"
40
+ # Rails 4.X adds random spaces :/
41
+ string = io.string.gsub(" ORDER BY", " ORDER BY")
42
+ string = string.gsub(" ORDER BY", " ORDER BY")
43
+ expect(string).to include("users.id DESC")
44
+ expect(string).to include("@timber.io")
45
+ expect(string).to include("\"level\":\"debug\"")
46
+ expect(string).to include("\"sql\":")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::RackHTTPContext do
4
+ describe described_class::Middleware do
5
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
+ let(:io) { StringIO.new }
7
+ let(:logger) do
8
+ logger = Timber::Logger.new(io)
9
+ logger.level = ::Logger::INFO
10
+ logger
11
+ end
12
+
13
+ around(:each) do |example|
14
+ class RackHttpController < ActionController::Base
15
+ layout nil
16
+
17
+ def index
18
+ Thread.current[:_timber_context] = Timber::CurrentContext.instance.snapshot
19
+ render json: {}
20
+ end
21
+
22
+ def method_for_action(action_name)
23
+ action_name
24
+ end
25
+ end
26
+
27
+ ::RailsApp.routes.draw do
28
+ get '/rack_http' => 'rack_http#index'
29
+ end
30
+
31
+ Timecop.freeze(time) { example.run }
32
+
33
+ Object.send(:remove_const, :RackHttpController)
34
+ end
35
+
36
+ describe "#process" do
37
+ it "should set the context" do
38
+ allow(Benchmark).to receive(:ms).and_return(1).and_yield
39
+ allow_any_instance_of(Timber::Probes::ActionControllerLogSubscriber::LogSubscriber).to receive(:logger).and_return(logger)
40
+
41
+ dispatch_rails_request("/rack_http")
42
+ http_context = Thread.current[:_timber_context][:http]
43
+
44
+ expect(http_context).to be_kind_of(Timber::Contexts::HTTP)
45
+ expect(http_context.method).to eq("GET")
46
+ expect(http_context.path).to eq("/rack_http")
47
+ expect(http_context.remote_addr).to eq("123.456.789.10")
48
+ expect(http_context.request_id).to_not be_nil
49
+ message = "Processing by RackHttpController#index as HTML @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"controller_call\":{\"controller\":\"RackHttpController\",\"action\":\"index\"}},\"context\":{\"http\":{\"method\":\"GET\",\"path\":\"/rack_http\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}}}\nCompleted 200 OK in 0.0ms (Views: 1.0ms) @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"http_response\":{\"status\":200,\"time_ms\":0.0}},\"context\":{\"http\":{\"method\":\"GET\",\"path\":\"/rack_http\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}}}\n"
50
+ expect(io.string).to eq(message)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Probes::RailsRackLogger do
4
+ describe described_class::InstanceMethods do
5
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
+ let(:io) { StringIO.new }
7
+ let(:logger) do
8
+ logger = Timber::Logger.new(io)
9
+ logger.level = ::Logger::INFO
10
+ logger
11
+ end
12
+
13
+ around(:each) do |example|
14
+ class RailsRackLoggerController < 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 '/rails_rack_logger' => 'rails_rack_logger#index'
28
+ end
29
+
30
+ Timecop.freeze(time) { example.run }
31
+
32
+ Object.send(:remove_const, :RailsRackLoggerController)
33
+ end
34
+
35
+ describe "#started_request_message" do
36
+ it "should set the context" do
37
+ allow(::Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production")) # Rails 3.2.X
38
+ allow(::Rails).to receive(:logger).and_return(logger) # Rails 3.2.X
39
+ allow_any_instance_of(::Rails::Rack::Logger).to receive(:logger).and_return(logger)
40
+ dispatch_rails_request("/rails_rack_logger")
41
+ message = "Started GET \"/rails_rack_logger\" for 123.456.789.10 @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"event\":{\"http_request\":{\"host\":\"example.org\",\"method\":\"GET\",\"path\":\"/rails_rack_logger\",\"port\":80,\"headers\":{\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}}},\"context\":{\"http\":{\"method\":\"GET\",\"path\":\"/rails_rack_logger\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}}}\n"
42
+ expect(io.string).to eq(message)
43
+ end
44
+ end
45
+ end
46
+ end
data/timber.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
3
+ require "timber/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "timber"
7
+ s.version = Timber::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Timber Technologies, Inc."]
10
+ s.email = ["hi@timber.io"]
11
+ s.homepage = "http://timber.io"
12
+ s.summary = "Logs you'll actually use."
13
+
14
+ s.required_ruby_version = '>= 1.9.0'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency("msgpack", "~> 1.0")
22
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timber
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Timber Technologies, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: msgpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ description:
28
+ email:
29
+ - hi@timber.io
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".yardopts"
37
+ - Appraisals
38
+ - Gemfile
39
+ - LICENSE.md
40
+ - README.md
41
+ - circle.yml
42
+ - lib/timber.rb
43
+ - lib/timber/config.rb
44
+ - lib/timber/context.rb
45
+ - lib/timber/contexts.rb
46
+ - lib/timber/contexts/custom.rb
47
+ - lib/timber/contexts/http.rb
48
+ - lib/timber/contexts/organization.rb
49
+ - lib/timber/contexts/user.rb
50
+ - lib/timber/current_context.rb
51
+ - lib/timber/event.rb
52
+ - lib/timber/events.rb
53
+ - lib/timber/events/controller_call.rb
54
+ - lib/timber/events/custom.rb
55
+ - lib/timber/events/exception.rb
56
+ - lib/timber/events/http_request.rb
57
+ - lib/timber/events/http_response.rb
58
+ - lib/timber/events/sql_query.rb
59
+ - lib/timber/events/template_render.rb
60
+ - lib/timber/frameworks.rb
61
+ - lib/timber/frameworks/rails.rb
62
+ - lib/timber/log_devices.rb
63
+ - lib/timber/log_devices/http.rb
64
+ - lib/timber/log_entry.rb
65
+ - lib/timber/logger.rb
66
+ - lib/timber/probe.rb
67
+ - lib/timber/probes.rb
68
+ - lib/timber/probes/action_controller_log_subscriber.rb
69
+ - lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb
70
+ - lib/timber/probes/action_dispatch_debug_exceptions.rb
71
+ - lib/timber/probes/action_view_log_subscriber.rb
72
+ - lib/timber/probes/action_view_log_subscriber/log_subscriber.rb
73
+ - lib/timber/probes/active_record_log_subscriber.rb
74
+ - lib/timber/probes/active_record_log_subscriber/log_subscriber.rb
75
+ - lib/timber/probes/rack_http_context.rb
76
+ - lib/timber/probes/rails_rack_logger.rb
77
+ - lib/timber/util.rb
78
+ - lib/timber/util/active_support_log_subscriber.rb
79
+ - lib/timber/util/hash.rb
80
+ - lib/timber/version.rb
81
+ - spec/spec_helper.rb
82
+ - spec/support/action_controller.rb
83
+ - spec/support/action_view.rb
84
+ - spec/support/active_record.rb
85
+ - spec/support/coveralls.rb
86
+ - spec/support/rails.rb
87
+ - spec/support/rails/templates/_partial.html
88
+ - spec/support/rails/templates/template.html
89
+ - spec/support/simplecov.rb
90
+ - spec/support/socket_hostname.rb
91
+ - spec/support/timber.rb
92
+ - spec/support/timecop.rb
93
+ - spec/support/webmock.rb
94
+ - spec/timber/events_spec.rb
95
+ - spec/timber/log_devices/http_spec.rb
96
+ - spec/timber/logger_spec.rb
97
+ - spec/timber/probes/action_controller_log_subscriber_spec.rb
98
+ - spec/timber/probes/action_dispatch_debug_exceptions_spec.rb
99
+ - spec/timber/probes/action_view_log_subscriber_spec.rb
100
+ - spec/timber/probes/active_record_log_subscriber_spec.rb
101
+ - spec/timber/probes/rack_http_context_spec.rb
102
+ - spec/timber/probes/rails_rack_logger_spec.rb
103
+ - timber.gemspec
104
+ homepage: http://timber.io
105
+ licenses: []
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: 1.9.0
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.6.8
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Logs you'll actually use.
127
+ test_files:
128
+ - spec/spec_helper.rb
129
+ - spec/support/action_controller.rb
130
+ - spec/support/action_view.rb
131
+ - spec/support/active_record.rb
132
+ - spec/support/coveralls.rb
133
+ - spec/support/rails.rb
134
+ - spec/support/rails/templates/_partial.html
135
+ - spec/support/rails/templates/template.html
136
+ - spec/support/simplecov.rb
137
+ - spec/support/socket_hostname.rb
138
+ - spec/support/timber.rb
139
+ - spec/support/timecop.rb
140
+ - spec/support/webmock.rb
141
+ - spec/timber/events_spec.rb
142
+ - spec/timber/log_devices/http_spec.rb
143
+ - spec/timber/logger_spec.rb
144
+ - spec/timber/probes/action_controller_log_subscriber_spec.rb
145
+ - spec/timber/probes/action_dispatch_debug_exceptions_spec.rb
146
+ - spec/timber/probes/action_view_log_subscriber_spec.rb
147
+ - spec/timber/probes/active_record_log_subscriber_spec.rb
148
+ - spec/timber/probes/rack_http_context_spec.rb
149
+ - spec/timber/probes/rails_rack_logger_spec.rb