timber 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
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