timber 1.0.13 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +278 -121
- data/lib/timber.rb +1 -0
- data/lib/timber/context.rb +1 -1
- data/lib/timber/contexts.rb +29 -2
- data/lib/timber/contexts/runtime.rb +24 -0
- data/lib/timber/contexts/system.rb +19 -0
- data/lib/timber/current_context.rb +14 -5
- data/lib/timber/event.rb +1 -1
- data/lib/timber/events.rb +11 -6
- data/lib/timber/events/controller_call.rb +1 -1
- data/lib/timber/events/custom.rb +1 -1
- data/lib/timber/events/exception.rb +1 -1
- data/lib/timber/events/{http_request.rb → http_server_request.rb} +1 -1
- data/lib/timber/events/{http_response.rb → http_server_response.rb} +2 -1
- data/lib/timber/events/sql_query.rb +2 -1
- data/lib/timber/events/template_render.rb +2 -1
- data/lib/timber/frameworks/rails.rb +12 -1
- data/lib/timber/log_devices/http.rb +29 -24
- data/lib/timber/log_entry.rb +23 -9
- data/lib/timber/logger.rb +20 -6
- data/lib/timber/probes.rb +1 -3
- data/lib/timber/probes/active_support_tagged_logging.rb +0 -43
- data/lib/timber/probes/rails_rack_logger.rb +1 -1
- data/lib/timber/rack_middlewares.rb +12 -0
- data/lib/timber/rack_middlewares/http_context.rb +30 -0
- data/lib/timber/util.rb +1 -0
- data/lib/timber/util/struct.rb +16 -0
- data/lib/timber/version.rb +1 -1
- data/spec/README.md +23 -0
- data/spec/support/timber.rb +1 -1
- data/spec/timber/contexts_spec.rb +49 -0
- data/spec/timber/events_spec.rb +1 -1
- data/spec/timber/log_devices/http_spec.rb +7 -7
- data/spec/timber/log_entry_spec.rb +15 -0
- data/spec/timber/logger_spec.rb +14 -10
- data/spec/timber/probes/action_controller_log_subscriber_spec.rb +6 -7
- data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +1 -1
- data/spec/timber/probes/action_view_log_subscriber_spec.rb +2 -2
- data/spec/timber/probes/rails_rack_logger_spec.rb +3 -3
- data/spec/timber/rack_middlewares/http_context_spec.rb +47 -0
- data/timber.gemspec +1 -0
- metadata +31 -8
- data/lib/timber/contexts/tags.rb +0 -22
- data/lib/timber/probes/rack_http_context.rb +0 -51
- data/spec/timber/probes/rack_http_context_spec.rb +0 -50
data/lib/timber/logger.rb
CHANGED
@@ -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
|
17
|
-
# # The :message,
|
18
|
-
#
|
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
|
-
|
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,
|
85
|
+
LogEntry.new(level, time, progname, event.message, context_snapshot, event, tags)
|
79
86
|
else
|
80
|
-
LogEntry.new(level, time, progname, msg,
|
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
|
data/lib/timber/probes.rb
CHANGED
@@ -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!
|
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
|
data/lib/timber/util.rb
CHANGED
data/lib/timber/version.rb
CHANGED
data/spec/README.md
ADDED
@@ -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
|
+
```
|
data/spec/support/timber.rb
CHANGED
@@ -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
|
data/spec/timber/events_spec.rb
CHANGED
@@ -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({
|
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
|
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\
|
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
|
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
|
data/spec/timber/logger_spec.rb
CHANGED
@@ -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
|
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
|
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",
|
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
|
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
|
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",
|
62
|
+
{message: "payment rejected", payment_rejected: {customer_id: "abcde1234", amount: 100}}
|
60
63
|
end
|
61
|
-
expect(io.string).to
|
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
|
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
|
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
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|