timber 1.0.13 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +278 -121
  3. data/lib/timber.rb +1 -0
  4. data/lib/timber/context.rb +1 -1
  5. data/lib/timber/contexts.rb +29 -2
  6. data/lib/timber/contexts/runtime.rb +24 -0
  7. data/lib/timber/contexts/system.rb +19 -0
  8. data/lib/timber/current_context.rb +14 -5
  9. data/lib/timber/event.rb +1 -1
  10. data/lib/timber/events.rb +11 -6
  11. data/lib/timber/events/controller_call.rb +1 -1
  12. data/lib/timber/events/custom.rb +1 -1
  13. data/lib/timber/events/exception.rb +1 -1
  14. data/lib/timber/events/{http_request.rb → http_server_request.rb} +1 -1
  15. data/lib/timber/events/{http_response.rb → http_server_response.rb} +2 -1
  16. data/lib/timber/events/sql_query.rb +2 -1
  17. data/lib/timber/events/template_render.rb +2 -1
  18. data/lib/timber/frameworks/rails.rb +12 -1
  19. data/lib/timber/log_devices/http.rb +29 -24
  20. data/lib/timber/log_entry.rb +23 -9
  21. data/lib/timber/logger.rb +20 -6
  22. data/lib/timber/probes.rb +1 -3
  23. data/lib/timber/probes/active_support_tagged_logging.rb +0 -43
  24. data/lib/timber/probes/rails_rack_logger.rb +1 -1
  25. data/lib/timber/rack_middlewares.rb +12 -0
  26. data/lib/timber/rack_middlewares/http_context.rb +30 -0
  27. data/lib/timber/util.rb +1 -0
  28. data/lib/timber/util/struct.rb +16 -0
  29. data/lib/timber/version.rb +1 -1
  30. data/spec/README.md +23 -0
  31. data/spec/support/timber.rb +1 -1
  32. data/spec/timber/contexts_spec.rb +49 -0
  33. data/spec/timber/events_spec.rb +1 -1
  34. data/spec/timber/log_devices/http_spec.rb +7 -7
  35. data/spec/timber/log_entry_spec.rb +15 -0
  36. data/spec/timber/logger_spec.rb +14 -10
  37. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +6 -7
  38. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +1 -1
  39. data/spec/timber/probes/action_view_log_subscriber_spec.rb +2 -2
  40. data/spec/timber/probes/rails_rack_logger_spec.rb +3 -3
  41. data/spec/timber/rack_middlewares/http_context_spec.rb +47 -0
  42. data/timber.gemspec +1 -0
  43. metadata +31 -8
  44. data/lib/timber/contexts/tags.rb +0 -22
  45. data/lib/timber/probes/rack_http_context.rb +0 -51
  46. data/spec/timber/probes/rack_http_context_spec.rb +0 -50
@@ -13,12 +13,15 @@ module Timber
13
13
  # @example Basic example (the original ::Logger interface remains untouched):
14
14
  # logger.info "Payment rejected for customer #{customer_id}"
15
15
  #
16
- # @example Using a map
17
- # # The :message, :type, and :data keys are required
18
- # logger.info message: "Payment rejected", type: :payment_rejected, data: {customer_id: customer_id, amount: 100}
16
+ # @example Using a Hash
17
+ # # The :message key is required, the other additional key is your event type and data
18
+ # # :type is the namespace used in timber for the :data
19
+ # logger.info message: "Payment rejected", payment_rejected: {customer_id: customer_id, amount: 100}
19
20
  #
20
21
  # @example Using a Struct (a simple, more structured way, to define events)
21
22
  # PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
23
+ # # `#message` and `#type` are required, otherwise they will not be logged properly.
24
+ # # `#type` is the namespace used in timber for the struct data
22
25
  # def message; "Payment rejected for #{customer_id}"; end
23
26
  # def type; :payment_rejected; end
24
27
  # end
@@ -72,14 +75,25 @@ module Timber
72
75
  private
73
76
  def build_log_entry(severity, time, progname, msg)
74
77
  level = SEVERITY_MAP.fetch(severity)
75
- context = CurrentContext.instance.snapshot
78
+ context_snapshot = CurrentContext.instance.snapshot
79
+ tags = extract_active_support_tagged_logging_tags
80
+ tags += [msg.delete(:tag)] if msg.is_a?(Hash) && msg.key?(:tag)
81
+ tags += msg.delete(:tags) if msg.is_a?(Hash) && msg.key?(:tags)
76
82
  event = Events.build(msg)
83
+
77
84
  if event
78
- LogEntry.new(level, time, progname, event.message, context, event)
85
+ LogEntry.new(level, time, progname, event.message, context_snapshot, event, tags)
79
86
  else
80
- LogEntry.new(level, time, progname, msg, context, nil)
87
+ LogEntry.new(level, time, progname, msg, context_snapshot, nil, tags)
81
88
  end
82
89
  end
90
+
91
+ # Because of all the crazy ways Rails has attempted this we need this crazy method.
92
+ def extract_active_support_tagged_logging_tags
93
+ Thread.current[:activesupport_tagged_logging_tags] ||
94
+ Thread.current["activesupport_tagged_logging_tags:#{object_id}"] ||
95
+ []
96
+ end
83
97
  end
84
98
 
85
99
  # Structures your log messages into Timber's hybrid format, which makes
@@ -3,20 +3,18 @@ require "timber/probes/action_dispatch_debug_exceptions"
3
3
  require "timber/probes/action_view_log_subscriber"
4
4
  require "timber/probes/active_record_log_subscriber"
5
5
  require "timber/probes/active_support_tagged_logging"
6
- require "timber/probes/rack_http_context"
7
6
  require "timber/probes/rails_rack_logger"
8
7
 
9
8
  module Timber
10
9
  # Namespace for all probes.
11
10
  # @private
12
11
  module Probes
13
- def self.insert!(middleware, insert_before)
12
+ def self.insert!
14
13
  ActionControllerLogSubscriber.insert!
15
14
  ActionDispatchDebugExceptions.insert!
16
15
  ActionViewLogSubscriber.insert!
17
16
  ActiveRecordLogSubscriber.insert!
18
17
  ActiveSupportTaggedLogging.insert!
19
- RackHTTPContext.insert!(middleware, insert_before)
20
18
  RailsRackLogger.insert!
21
19
  end
22
20
  end
@@ -17,26 +17,6 @@ module Timber
17
17
  super(severity, timestamp, progname, "#{tags_text}#{msg}")
18
18
  end
19
19
  end
20
-
21
- def push_tags(*tags)
22
- _timber_original_push_tags(*tags).tap do
23
- if current_tags.size > 0
24
- context = Contexts::Tags.new(values: current_tags)
25
- CurrentContext.add(context)
26
- end
27
- end
28
- end
29
-
30
- def pop_tags(size = 1)
31
- _timber_original_pop_tags(size).tap do
32
- if current_tags.size == 0
33
- CurrentContext.remove(Contexts::Tags)
34
- else
35
- context = Contexts::Tags.new(values: current_tags)
36
- CurrentContext.add(context)
37
- end
38
- end
39
- end
40
20
  end
41
21
  end
42
22
  end
@@ -44,29 +24,6 @@ module Timber
44
24
  module LoggerMethods
45
25
  def self.included(klass)
46
26
  klass.class_eval do
47
- alias_method :_timber_original_push_tags, :push_tags
48
- alias_method :_timber_original_pop_tags, :pop_tags
49
-
50
- def push_tags(*tags)
51
- _timber_original_push_tags(*tags).tap do
52
- if current_tags.size > 0
53
- context = Contexts::Tags.new(values: current_tags)
54
- CurrentContext.add(context)
55
- end
56
- end
57
- end
58
-
59
- def pop_tags(size = 1)
60
- _timber_original_pop_tags(size).tap do
61
- if current_tags.size == 0
62
- CurrentContext.remove(Contexts::Tags)
63
- else
64
- context = Contexts::Tags.new(values: current_tags)
65
- CurrentContext.add(context)
66
- end
67
- end
68
- end
69
-
70
27
  def add(severity, message = nil, progname = nil, &block)
71
28
  if message.nil?
72
29
  if block_given?
@@ -7,7 +7,7 @@ module Timber
7
7
  def self.included(klass)
8
8
  klass.class_eval do
9
9
  protected
10
- if klass.method_defined?(:started_request_message)
10
+ if klass.private_instance_methods.include?(:started_request_message) || klass.method_defined?(:started_request_message)
11
11
  def started_request_message(request)
12
12
  http_request_event(request)
13
13
  end
@@ -0,0 +1,12 @@
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
@@ -0,0 +1,30 @@
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,5 +1,6 @@
1
1
  require "timber/util/active_support_log_subscriber"
2
2
  require "timber/util/hash"
3
+ require "timber/util/struct"
3
4
 
4
5
  module Timber
5
6
  # @private
@@ -0,0 +1,16 @@
1
+ module Timber
2
+ module Util
3
+ # @private
4
+ module Struct
5
+ extend self
6
+
7
+ def to_hash(struct)
8
+ h = {}
9
+ struct.each_pair do |k ,v|
10
+ h[k] = v
11
+ end
12
+ h
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "1.0.13"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -0,0 +1,23 @@
1
+ # Testing
2
+
3
+ Testing Timber uses [`appraisal`](https://github.com/thoughtbot/appraisal). This allows us to
4
+ test across multiple versions and combinations of libraries.
5
+
6
+ To get started:
7
+
8
+ ```shell
9
+ bundle install
10
+ bundle exec appraisal install
11
+ ```
12
+
13
+ To see all appraisal commands:
14
+
15
+ ```shell
16
+ appraisal --help
17
+ ```
18
+
19
+ You can run tests with:
20
+
21
+ ```shell
22
+ appraisal rails-3.2.X rspec
23
+ ```
@@ -1,4 +1,4 @@
1
1
  # Must require last in order to be mocked via webmock
2
2
  require 'timber'
3
3
 
4
- Timber::Config.instance.logger = ::Logger.new(nil)
4
+ Timber::Config.instance.logger = ::Logger.new(STDOUT)
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::Contexts, :rails_23 => true do
4
+ describe ".build" do
5
+ it "should build a Timber::Context" do
6
+ context = Timber::Contexts::Custom.new(
7
+ type: :build,
8
+ data: {version: "1.0.0"}
9
+ )
10
+ built_context = Timber::Contexts.build(context)
11
+ expect(built_context).to eq(context)
12
+ end
13
+
14
+ it "should use #to_timber_context" do
15
+ BuildContext = Struct.new(:version) do
16
+ def to_timber_context
17
+ Timber::Contexts::Custom.new(
18
+ type: :build,
19
+ data: respond_to?(:to_h) ? to_h : Timber::Util::Struct.to_hash(self)
20
+ )
21
+ end
22
+ end
23
+ built_context = Timber::Contexts.build(BuildContext.new("1.0.0"))
24
+ expect(built_context).to be_kind_of(Timber::Contexts::Custom)
25
+ expect(built_context.type).to eq(:build)
26
+ Object.send(:remove_const, :BuildContext)
27
+ end
28
+
29
+ it "should accept a properly structured hash" do
30
+ built_context = Timber::Contexts.build(build: {version: "1.0.0"})
31
+ expect(built_context).to be_kind_of(Timber::Contexts::Custom)
32
+ expect(built_context.type).to eq(:build)
33
+ end
34
+
35
+ it "should accept a struct" do
36
+ BuildContext = Struct.new(:version) do
37
+ def type; :build; end
38
+ end
39
+ built_context = Timber::Contexts.build(BuildContext.new("1.0.0"))
40
+ expect(built_context).to be_kind_of(Timber::Contexts::Custom)
41
+ expect(built_context.type).to eq(:build)
42
+ Object.send(:remove_const, :BuildContext)
43
+ end
44
+
45
+ it "should return nil for unsupported" do
46
+ expect(Timber::Contexts.build(1)).to be_nil
47
+ end
48
+ end
49
+ end
@@ -30,7 +30,7 @@ describe Timber::Events, :rails_23 => true do
30
30
  end
31
31
 
32
32
  it "should accept a properly structured hash" do
33
- built_event = Timber::Events.build({type: :payment_rejected, message: "Payment rejected", data: {customer_id: "abcd1234", amount: 100}})
33
+ built_event = Timber::Events.build({message: "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100}})
34
34
  expect(built_event).to be_kind_of(Timber::Events::Custom)
35
35
  expect(built_event.type).to eq(:payment_rejected)
36
36
  expect(built_event.message).to eq("Payment rejected")
@@ -58,15 +58,15 @@ describe Timber::LogDevices::HTTP do
58
58
 
59
59
  it "should add a request to the queue" do
60
60
  http = described_class.new("MYKEY", threads: false)
61
- log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 1", nil, nil)
61
+ log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 1", nil, nil, [])
62
62
  http.write(log_entry)
63
- log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 2", nil, nil)
63
+ log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 2", nil, nil, [])
64
64
  http.write(log_entry)
65
65
  http.send(:flush)
66
66
  request_queue = http.instance_variable_get(:@request_queue)
67
67
  request = request_queue.deq
68
68
  expect(request).to be_kind_of(Net::HTTP::Post)
69
- expect(request.body).to eq("\x92\x83\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 1\x83\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 2".force_encoding("ASCII-8BIT"))
69
+ expect(request.body).to start_with("\x92\x85\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 1\xA7context\x81".force_encoding("ASCII-8BIT"))
70
70
 
71
71
  message_queue = http.instance_variable_get(:@msg_queue)
72
72
  expect(message_queue.size).to eq(0)
@@ -98,20 +98,20 @@ describe Timber::LogDevices::HTTP do
98
98
  it "should start a intervaled flush thread and flush on an interval" do
99
99
  stub = stub_request(:post, "https://logs.timber.io/frames").
100
100
  with(
101
- :body => "\x92\x83\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 1\x83\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 2".force_encoding("ASCII-8BIT"),
101
+ :body => start_with("\x92\x85\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 1\xA7context\x81\xA6system".force_encoding("ASCII-8BIT")),
102
102
  :headers => {
103
103
  'Accept' => 'application/json',
104
104
  'Authorization' => 'Basic TVlLRVk=',
105
105
  'Content-Type' => 'application/msgpack',
106
- 'User-Agent' => "Timber Ruby Gem/#{Timber::VERSION}"
106
+ 'User-Agent' => "Timber Ruby/#{Timber::VERSION} (HTTP)"
107
107
  }
108
108
  ).
109
109
  to_return(:status => 200, :body => "", :headers => {})
110
110
 
111
111
  http = described_class.new("MYKEY", flush_interval: 0.1)
112
- log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 1", nil, nil)
112
+ log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 1", nil, nil, [])
113
113
  http.write(log_entry)
114
- log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 2", nil, nil)
114
+ log_entry = Timber::LogEntry.new("INFO", time, nil, "test log message 2", nil, nil, [])
115
115
  http.write(log_entry)
116
116
  sleep 0.3
117
117
 
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::LogEntry, :rails_23 => true do
4
+ describe "#to_msgpack" do
5
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
+
7
+ it "should encode properly with an event and context" do
8
+ event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: 1})
9
+ context = {custom: Timber::Contexts::Custom.new(type: :context_type, data: {b: 1})}
10
+ log_entry = described_class.new("INFO", time, nil, "log message", context, event, [])
11
+ msgpack = log_entry.to_msgpack
12
+ expect(msgpack).to start_with("\x86\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z".force_encoding("ASCII-8BIT"))
13
+ end
14
+ end
15
+ end
@@ -15,7 +15,7 @@ describe Timber::Logger, :rails_23 => true do
15
15
 
16
16
  it "should accept strings" do
17
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")
18
+ expect(io.string).to start_with("this is a test @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\"")
19
19
  end
20
20
 
21
21
  context "with a context" do
@@ -37,33 +37,37 @@ describe Timber::Logger, :rails_23 => true do
37
37
  it "should snapshot and include the context" do
38
38
  expect(Timber::CurrentContext.instance).to receive(:snapshot).and_call_original
39
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")
40
+ expect(io.string).to start_with("this is a test @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\"")
41
+ expect(io.string).to include("\"http\":{\"method\":\"POST\",\"path\":\"/checkout\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"abcd1234\"}")
41
42
  end
42
43
  end
43
44
 
44
45
  it "should call and use Timber::Events.build" do
45
- message = {message: "payment rejected", type: :payment_rejected, data: {customer_id: "abcde1234", amount: 100}}
46
+ message = {message: "payment rejected", payment_rejected: {customer_id: "abcde1234", amount: 100}}
46
47
  expect(Timber::Events).to receive(:build).with(message).and_call_original
47
48
  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
+ expect(io.string).to start_with("payment rejected @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",")
50
+ expect(io.string).to include("\"event\":{\"server_side_app\":{\"custom\":{\"payment_rejected\":{\"customer_id\":\"abcde1234\",\"amount\":100}}}}")
49
51
  end
50
52
 
51
53
  it "should log properly when an event is passed" do
52
54
  message = Timber::Events::SQLQuery.new(sql: "select * from users", time_ms: 56, message: "select * from users")
53
55
  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")
56
+ expect(io.string).to start_with("select * from users @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",")
57
+ expect(io.string).to include("\"event\":{\"server_side_app\":{\"sql_query\":{\"sql\":\"select * from users\",\"time_ms\":56.0}}}")
55
58
  end
56
59
 
57
60
  it "should allow functions" do
58
61
  logger.info do
59
- {message: "payment rejected", type: :payment_rejected, data: {customer_id: "abcde1234", amount: 100}}
62
+ {message: "payment rejected", payment_rejected: {customer_id: "abcde1234", amount: 100}}
60
63
  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")
64
+ expect(io.string).to start_with("payment rejected @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",")
65
+ expect(io.string).to include("\"event\":{\"server_side_app\":{\"custom\":{\"payment_rejected\":{\"customer_id\":\"abcde1234\",\"amount\":100}}}}")
62
66
  end
63
67
 
64
68
  it "should escape new lines" do
65
69
  logger.info "first\nsecond"
66
- expect(io.string).to eq("first\\nsecond @timber.io {\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\"}\n")
70
+ expect(io.string).to start_with("first\\nsecond @timber.io")
67
71
  end
68
72
  end
69
73
 
@@ -72,7 +76,7 @@ describe Timber::Logger, :rails_23 => true do
72
76
 
73
77
  it "should log in the correct format" do
74
78
  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")
79
+ expect(io.string).to start_with("{\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"message\":\"this is a test\"")
76
80
  end
77
81
  end
78
82
 
@@ -85,7 +89,7 @@ describe Timber::Logger, :rails_23 => true do
85
89
  logger.tagged("tag") do
86
90
  logger.info(message)
87
91
  end
88
- 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}},\"context\":{\"tags\":[\"tag\"]}}\n")
92
+ expect(io.string).to include("\"tags\":[\"tag\"]")
89
93
  end
90
94
  end
91
95
  end
@@ -55,13 +55,12 @@ describe Timber::Probes::ActionControllerLogSubscriber do
55
55
  # Rails uses this to calculate the view runtime below
56
56
  allow(Benchmark).to receive(:ms).and_return(1).and_yield
57
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")
58
+ lines = io.string.split("\n")
59
+ expect(lines.length).to eq(2)
60
+ expect(lines[0]).to start_with('Processing by LogSubscriberController#index as HTML @timber.io {"level":"info","dt":"2016-09-01T12:00:00.000000Z"')
61
+ expect(lines[0]).to include('"event":{"server_side_app":{"controller_call":{"controller":"LogSubscriberController","action":"index"}}}')
62
+ expect(lines[1]).to start_with('Completed 200 OK in 0.0ms (Views: 1.0ms) @timber.io {"level":"info","dt":"2016-09-01T12:00:00.000000Z"')
63
+ expect(lines[1]).to include('"event":{"server_side_app":{"http_server_response":{"status":200,"time_ms":0.0}}}')
65
64
  end
66
65
  end
67
66
  end