timberio 1.0.0.beta1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -2
- data/.rspec +2 -0
- data/.yardopts +6 -0
- data/Appraisals +4 -0
- data/Gemfile +9 -1
- data/LICENSE.md +15 -0
- data/README.md +170 -8
- data/circle.yml +11 -8
- data/lib/timber/config.rb +11 -18
- data/lib/timber/context.rb +9 -68
- data/lib/timber/contexts/custom.rb +27 -0
- data/lib/timber/contexts/http.rb +28 -0
- data/lib/timber/contexts/organization.rb +24 -22
- data/lib/timber/contexts/user.rb +25 -28
- data/lib/timber/contexts.rb +7 -20
- data/lib/timber/current_context.rb +26 -41
- data/lib/timber/event.rb +13 -0
- data/lib/timber/events/controller_call.rb +40 -0
- data/lib/timber/events/custom.rb +42 -0
- data/lib/timber/events/exception.rb +35 -0
- data/lib/timber/events/http_request.rb +50 -0
- data/lib/timber/events/http_response.rb +36 -0
- data/lib/timber/events/sql_query.rb +26 -0
- data/lib/timber/events/template_render.rb +26 -0
- data/lib/timber/events.rb +37 -0
- data/lib/timber/frameworks/rails.rb +3 -14
- data/lib/timber/frameworks.rb +8 -10
- data/lib/timber/log_devices/http.rb +72 -13
- data/lib/timber/log_devices.rb +8 -4
- data/lib/timber/log_entry.rb +59 -0
- data/lib/timber/logger.rb +136 -13
- data/lib/timber/probe.rb +6 -4
- data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +64 -0
- data/lib/timber/probes/action_controller_log_subscriber.rb +20 -0
- data/lib/timber/probes/action_dispatch_debug_exceptions.rb +59 -35
- data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +62 -0
- data/lib/timber/probes/action_view_log_subscriber.rb +20 -0
- data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +72 -0
- data/lib/timber/probes/active_record_log_subscriber.rb +20 -0
- data/lib/timber/probes/rack_http_context.rb +51 -0
- data/lib/timber/probes/rails_rack_logger.rb +76 -0
- data/lib/timber/probes.rb +13 -16
- data/lib/timber/util/active_support_log_subscriber.rb +33 -0
- data/lib/timber/util/hash.rb +14 -0
- data/lib/timber/util.rb +8 -0
- data/lib/timber/version.rb +2 -2
- data/lib/timber.rb +6 -11
- data/spec/spec_helper.rb +7 -4
- data/spec/support/rails.rb +9 -5
- data/spec/support/timber.rb +1 -20
- data/spec/timber/events_spec.rb +55 -0
- data/spec/timber/log_devices/http_spec.rb +62 -0
- data/spec/timber/logger_spec.rb +68 -0
- data/spec/timber/probes/action_controller_log_subscriber_spec.rb +70 -0
- data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +24 -18
- data/spec/timber/probes/action_view_log_subscriber_spec.rb +61 -0
- data/spec/timber/probes/active_record_log_subscriber_spec.rb +49 -0
- data/spec/timber/probes/rack_http_context_spec.rb +54 -0
- data/spec/timber/probes/rails_rack_logger_spec.rb +46 -0
- data/timberio.gemspec +2 -0
- metadata +62 -123
- data/.codeclimate.yml +0 -34
- data/LICENSE +0 -38
- data/Rakefile +0 -4
- data/TODO +0 -4
- data/benchmark/README.md +0 -26
- data/benchmark/rails_request.rb +0 -68
- data/benchmark/support/rails.rb +0 -69
- data/docs/installation/rails_on_heroku.md +0 -31
- data/docs/installation/rails_over_http.md +0 -22
- data/gemfiles/rails_3.0.X.gemfile +0 -25
- data/gemfiles/rails_3.1.X.gemfile +0 -25
- data/gemfiles/rails_3.2.X.gemfile +0 -25
- data/gemfiles/rails_4.0.X.gemfile +0 -26
- data/gemfiles/rails_4.1.X.gemfile +0 -26
- data/gemfiles/rails_4.2.X.gemfile +0 -26
- data/gemfiles/rails_5.0.X.gemfile +0 -26
- data/gemfiles/rails_edge.gemfile +0 -27
- data/lib/timber/api_settings.rb +0 -17
- data/lib/timber/bootstrap.rb +0 -45
- data/lib/timber/context_snapshot.rb +0 -64
- data/lib/timber/contexts/dynamic_values.rb +0 -59
- data/lib/timber/contexts/exception.rb +0 -40
- data/lib/timber/contexts/http_request.rb +0 -22
- data/lib/timber/contexts/http_requests/action_controller_specific.rb +0 -48
- data/lib/timber/contexts/http_requests/rack/params.rb +0 -26
- data/lib/timber/contexts/http_requests/rack.rb +0 -105
- data/lib/timber/contexts/http_response.rb +0 -19
- data/lib/timber/contexts/http_responses/action_controller.rb +0 -76
- data/lib/timber/contexts/logger.rb +0 -33
- data/lib/timber/contexts/organizations/action_controller.rb +0 -34
- data/lib/timber/contexts/server.rb +0 -21
- data/lib/timber/contexts/servers/heroku_specific.rb +0 -48
- data/lib/timber/contexts/sql_queries/active_record.rb +0 -30
- data/lib/timber/contexts/sql_queries/active_record_specific/binds.rb +0 -37
- data/lib/timber/contexts/sql_queries/active_record_specific.rb +0 -59
- data/lib/timber/contexts/sql_query.rb +0 -18
- data/lib/timber/contexts/template_render.rb +0 -17
- data/lib/timber/contexts/template_renders/action_view.rb +0 -29
- data/lib/timber/contexts/template_renders/action_view_specific.rb +0 -51
- data/lib/timber/contexts/users/action_controller.rb +0 -34
- data/lib/timber/current_line_indexes.rb +0 -35
- data/lib/timber/internal_logger.rb +0 -35
- data/lib/timber/log_device.rb +0 -40
- data/lib/timber/log_devices/heroku_logplex/hybrid_formatter.rb +0 -14
- data/lib/timber/log_devices/heroku_logplex.rb +0 -14
- data/lib/timber/log_devices/http/log_pile.rb +0 -86
- data/lib/timber/log_devices/http/log_truck/delivery.rb +0 -116
- data/lib/timber/log_devices/http/log_truck.rb +0 -87
- data/lib/timber/log_devices/io/formatter.rb +0 -46
- data/lib/timber/log_devices/io/hybrid_formatter.rb +0 -41
- data/lib/timber/log_devices/io/hybrid_hidden_formatter.rb +0 -36
- data/lib/timber/log_devices/io/json_formatter.rb +0 -11
- data/lib/timber/log_devices/io/logfmt_formatter.rb +0 -11
- data/lib/timber/log_devices/io.rb +0 -41
- data/lib/timber/log_line.rb +0 -33
- data/lib/timber/macros/compactor.rb +0 -16
- data/lib/timber/macros/date_formatter.rb +0 -9
- data/lib/timber/macros/deep_merger.rb +0 -11
- data/lib/timber/macros/logfmt_encoder.rb +0 -77
- data/lib/timber/macros.rb +0 -4
- data/lib/timber/patterns/delegated_singleton.rb +0 -21
- data/lib/timber/patterns/to_json.rb +0 -22
- data/lib/timber/patterns/to_logfmt.rb +0 -9
- data/lib/timber/patterns.rb +0 -3
- data/lib/timber/probes/action_controller_base.rb +0 -31
- data/lib/timber/probes/active_support_log_subscriber/action_controller.rb +0 -15
- data/lib/timber/probes/active_support_log_subscriber/action_view.rb +0 -26
- data/lib/timber/probes/active_support_log_subscriber/active_record.rb +0 -13
- data/lib/timber/probes/active_support_log_subscriber.rb +0 -62
- data/lib/timber/probes/heroku.rb +0 -30
- data/lib/timber/probes/logger.rb +0 -31
- data/lib/timber/probes/rack.rb +0 -36
- data/lib/timber/probes/server.rb +0 -18
- data/spec/timber/bootstrap_spec.rb +0 -31
- data/spec/timber/context_snapshot_spec.rb +0 -10
- data/spec/timber/context_spec.rb +0 -4
- data/spec/timber/contexts/exception_spec.rb +0 -34
- data/spec/timber/contexts/organizations/action_controller_spec.rb +0 -49
- data/spec/timber/contexts/users/action_controller_spec.rb +0 -65
- data/spec/timber/current_line_indexes_spec.rb +0 -40
- data/spec/timber/frameworks/rails_spec.rb +0 -9
- data/spec/timber/log_devices/heroku_logplex_spec.rb +0 -45
- data/spec/timber/log_devices/http/log_truck/delivery_spec.rb +0 -66
- data/spec/timber/log_devices/http/log_truck_spec.rb +0 -65
- data/spec/timber/log_devices/io/hybrid_hidden_formatter_spec.rb +0 -28
- data/spec/timber/log_line_spec.rb +0 -49
- data/spec/timber/macros/compactor_spec.rb +0 -19
- data/spec/timber/macros/logfmt_encoder_spec.rb +0 -89
- data/spec/timber/patterns/to_json_spec.rb +0 -40
- data/spec/timber/probes/action_controller_base_spec.rb +0 -43
- data/spec/timber/probes/action_controller_log_subscriber/action_controller_spec.rb +0 -35
- data/spec/timber/probes/action_controller_log_subscriber/action_view_spec.rb +0 -44
- data/spec/timber/probes/action_controller_log_subscriber/active_record_spec.rb +0 -26
- data/spec/timber/probes/logger_spec.rb +0 -20
- data/spec/timber/probes/rack_spec.rb +0 -26
@@ -0,0 +1,76 @@
|
|
1
|
+
module Timber
|
2
|
+
module Probes
|
3
|
+
# Responsible for automatically tracking the http request events for applications
|
4
|
+
# that use `Rack`.
|
5
|
+
class RailsRackLogger < Probe
|
6
|
+
module InstanceMethods
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
protected
|
10
|
+
if klass.method_defined?(:started_request_message)
|
11
|
+
def started_request_message(request)
|
12
|
+
http_request_event(request)
|
13
|
+
end
|
14
|
+
elsif klass.method_defined?(:before_dispatch)
|
15
|
+
def before_dispatch(env)
|
16
|
+
request = ActionDispatch::Request.new(env)
|
17
|
+
info do
|
18
|
+
http_request_event(request)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def http_request_event(request)
|
24
|
+
# No idea why rails 3.X returns a "/" :/
|
25
|
+
referrer = request.referer == "/" ? nil : request.referer
|
26
|
+
Events::HTTPRequest.new(
|
27
|
+
host: request.host,
|
28
|
+
method: request.request_method,
|
29
|
+
path: request.filtered_path,
|
30
|
+
port: request.port,
|
31
|
+
query_params: request.GET,
|
32
|
+
content_type: request.content_type,
|
33
|
+
remote_addr: request.ip,
|
34
|
+
referrer: referrer,
|
35
|
+
request_id: request_id(request.env),
|
36
|
+
user_agent: request.user_agent
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def request_id(env)
|
41
|
+
env["X-Request-ID"] ||
|
42
|
+
env["X-Request-Id"] ||
|
43
|
+
env["action_dispatch.request_id"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module BeforeDispatchInstanceMethods
|
50
|
+
def self.included(klass)
|
51
|
+
klass.class_eval do
|
52
|
+
protected
|
53
|
+
def before_dispatch(env)
|
54
|
+
request = ActionDispatch::Request.new(env)
|
55
|
+
path = request.filtered_path
|
56
|
+
|
57
|
+
info "\n\nStarted #{request.request_method} \"#{path}\" " \
|
58
|
+
"for #{request.ip} at #{Time.now.to_default_s}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
require "rails/rack/logger"
|
66
|
+
rescue LoadError => e
|
67
|
+
raise RequirementNotMetError.new(e.message)
|
68
|
+
end
|
69
|
+
|
70
|
+
def insert!
|
71
|
+
return true if ::Rails::Rack::Logger.include?(InstanceMethods)
|
72
|
+
::Rails::Rack::Logger.send(:include, InstanceMethods)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/timber/probes.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
|
-
require "timber/probes/
|
1
|
+
require "timber/probes/action_controller_log_subscriber"
|
2
2
|
require "timber/probes/action_dispatch_debug_exceptions"
|
3
|
-
require "timber/probes/
|
4
|
-
require "timber/probes/
|
5
|
-
require "timber/probes/
|
6
|
-
require "timber/probes/
|
7
|
-
require "timber/probes/server"
|
3
|
+
require "timber/probes/action_view_log_subscriber"
|
4
|
+
require "timber/probes/active_record_log_subscriber"
|
5
|
+
require "timber/probes/rack_http_context"
|
6
|
+
require "timber/probes/rails_rack_logger"
|
8
7
|
|
9
8
|
module Timber
|
9
|
+
# Namespace for all probes.
|
10
|
+
# @private
|
10
11
|
module Probes
|
11
12
|
def self.insert!(middleware, insert_before)
|
12
|
-
|
13
|
-
Server.insert!
|
14
|
-
Heroku.insert!
|
15
|
-
|
16
|
-
# Transient probes, sorted alphabetically
|
17
|
-
ActionControllerBase.insert!
|
13
|
+
ActionControllerLogSubscriber.insert!
|
18
14
|
ActionDispatchDebugExceptions.insert!
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
ActionViewLogSubscriber.insert!
|
16
|
+
ActiveRecordLogSubscriber.insert!
|
17
|
+
RackHTTPContext.insert!(middleware, insert_before)
|
18
|
+
RailsRackLogger.insert!
|
22
19
|
end
|
23
20
|
end
|
24
|
-
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Timber
|
2
|
+
module Util
|
3
|
+
# @private
|
4
|
+
module ActiveSupportLogSubscriber
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def find(component, type)
|
8
|
+
ActiveSupport::LogSubscriber.log_subscribers.find do |subscriber|
|
9
|
+
subscriber.class == type
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def subscribed?(component, type)
|
14
|
+
!find(component, type).nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def unsubscribe(component, type)
|
18
|
+
subscriber = find(component, type)
|
19
|
+
|
20
|
+
if subscriber
|
21
|
+
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
|
22
|
+
events.each do |event|
|
23
|
+
ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
24
|
+
if listener.instance_variable_get('@delegate') == subscriber
|
25
|
+
ActiveSupport::Notifications.unsubscribe listener
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/timber/util.rb
ADDED
data/lib/timber/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Timber
|
2
|
-
VERSION = "1.0.0
|
3
|
-
end
|
2
|
+
VERSION = "1.0.0"
|
3
|
+
end
|
data/lib/timber.rb
CHANGED
@@ -2,26 +2,21 @@
|
|
2
2
|
require "json" # brings to_json to the core classes
|
3
3
|
|
4
4
|
# Base (must come first, order matters)
|
5
|
-
require "timber/macros"
|
6
|
-
require "timber/patterns"
|
7
5
|
require "timber/config"
|
8
6
|
require "timber/context"
|
9
|
-
require "timber/
|
7
|
+
require "timber/event"
|
10
8
|
require "timber/probe"
|
9
|
+
require "timber/util"
|
11
10
|
require "timber/version"
|
12
11
|
|
13
12
|
# Other (sorted alphabetically)
|
14
|
-
require "timber/api_settings"
|
15
|
-
require "timber/bootstrap"
|
16
|
-
require "timber/context_snapshot"
|
17
13
|
require "timber/contexts"
|
18
14
|
require "timber/current_context"
|
19
|
-
require "timber/
|
20
|
-
require "timber/internal_logger"
|
15
|
+
require "timber/events"
|
21
16
|
require "timber/log_devices"
|
22
|
-
require "timber/
|
17
|
+
require "timber/log_entry"
|
23
18
|
require "timber/logger"
|
24
19
|
require "timber/probes"
|
25
20
|
|
26
|
-
# Load frameworks
|
27
|
-
require "timber/frameworks"
|
21
|
+
# Load frameworks
|
22
|
+
require "timber/frameworks"
|
data/spec/spec_helper.rb
CHANGED
@@ -15,10 +15,13 @@ require File.join(File.dirname(__FILE__), 'support', 'simplecov')
|
|
15
15
|
require File.join(File.dirname(__FILE__), 'support', 'timecop')
|
16
16
|
require File.join(File.dirname(__FILE__), 'support', 'webmock')
|
17
17
|
require File.join(File.dirname(__FILE__), 'support', 'timber')
|
18
|
-
|
19
|
-
|
20
|
-
require File.join(File.dirname(__FILE__), 'support', '
|
21
|
-
require File.join(File.dirname(__FILE__), 'support', '
|
18
|
+
|
19
|
+
if !ENV["RAILS_23"]
|
20
|
+
require File.join(File.dirname(__FILE__), 'support', 'rails')
|
21
|
+
require File.join(File.dirname(__FILE__), 'support', 'action_controller')
|
22
|
+
require File.join(File.dirname(__FILE__), 'support', 'action_view')
|
23
|
+
require File.join(File.dirname(__FILE__), 'support', 'active_record')
|
24
|
+
end
|
22
25
|
|
23
26
|
RSpec.configure do |config|
|
24
27
|
config.color = true
|
data/spec/support/rails.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require "rails"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# Defualt the rails logger to nothing, each test shoould be
|
4
|
+
# responsible for setting up the logger
|
5
|
+
logger = ::Logger.new(nil)
|
6
|
+
Rails.logger = logger
|
6
7
|
|
7
8
|
class RailsApp < Rails::Application
|
8
9
|
if ::Rails.version =~ /^3\./
|
@@ -12,17 +13,20 @@ class RailsApp < Rails::Application
|
|
12
13
|
end
|
13
14
|
config.active_support.deprecation = :stderr
|
14
15
|
config.eager_load = false
|
15
|
-
config.log_level = :fatal
|
16
16
|
end
|
17
17
|
|
18
18
|
RailsApp.initialize!
|
19
19
|
|
20
20
|
module Support
|
21
21
|
module Rails
|
22
|
-
def dispatch_rails_request(path)
|
22
|
+
def dispatch_rails_request(path, additional_env_options = {})
|
23
23
|
application = ::Rails.application
|
24
24
|
env = application.respond_to?(:env_config) ? application.env_config.clone : application.env_defaults.clone
|
25
25
|
env["rack.request.cookie_hash"] = {}.with_indifferent_access
|
26
|
+
env["REMOTE_ADDR"] = "123.456.789.10"
|
27
|
+
env["X-Request-Id"] = "unique-request-id-1234"
|
28
|
+
env["action_dispatch.request_id"] = env["X-Request-Id"]
|
29
|
+
env = env.merge(additional_env_options)
|
26
30
|
::Rack::MockRequest.new(application).get(path, env)
|
27
31
|
end
|
28
32
|
end
|
data/spec/support/timber.rb
CHANGED
@@ -1,23 +1,4 @@
|
|
1
1
|
# Must require last in order to be mocked via webmock
|
2
2
|
require 'timber'
|
3
3
|
|
4
|
-
|
5
|
-
Timber::Config.tap do |config|
|
6
|
-
config.application_key = "my_key"
|
7
|
-
config.logger.level = ::Logger::FATAL
|
8
|
-
end
|
9
|
-
|
10
|
-
RSpec.configure do |config|
|
11
|
-
config.after(:each) do
|
12
|
-
Timber::CurrentLineIndexes.reset!
|
13
|
-
Timber::LogDevices::HTTP::LogPile.each { |log_pile| log_pile.empty }
|
14
|
-
|
15
|
-
# Reset permanent context caches since we mock, etc.
|
16
|
-
Timber::CurrentContext.send(:stack).each do |context|
|
17
|
-
context.instance_variable_set(:"@as_json", nil)
|
18
|
-
context.instance_variable_set(:"@json_payload", nil)
|
19
|
-
context.instance_variable_set(:"@to_json", nil)
|
20
|
-
context.instance_variable_set(:"@to_logfmt", nil)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
4
|
+
Timber::Config.instance.logger = ::Logger.new(nil)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Timber::Events, :rails_23 => true do
|
4
|
+
describe ".build" do
|
5
|
+
it "should build a Timber::Event" do
|
6
|
+
event = Timber::Events::Custom.new(
|
7
|
+
type: :payment_rejected,
|
8
|
+
message: "Payment rejected",
|
9
|
+
data: {customer_id: "abcd1234", amount: 100}
|
10
|
+
)
|
11
|
+
built_event = Timber::Events.build(event)
|
12
|
+
expect(built_event).to eq(event)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should use #to_timber_event" do
|
16
|
+
PaymentRejectedEvent = Struct.new(:customer_id, :amount) do
|
17
|
+
def to_timber_event
|
18
|
+
Timber::Events::Custom.new(
|
19
|
+
type: :payment_rejected,
|
20
|
+
message: "Payment rejected for #{customer_id}",
|
21
|
+
data: respond_to?(:hash) ? hash : to_hash
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
built_event = Timber::Events.build(PaymentRejectedEvent.new("abcd1234", 100))
|
26
|
+
expect(built_event).to be_kind_of(Timber::Events::Custom)
|
27
|
+
expect(built_event.type).to eq(:payment_rejected)
|
28
|
+
expect(built_event.message).to eq("Payment rejected for abcd1234")
|
29
|
+
Object.send(:remove_const, :PaymentRejectedEvent)
|
30
|
+
end
|
31
|
+
|
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}})
|
34
|
+
expect(built_event).to be_kind_of(Timber::Events::Custom)
|
35
|
+
expect(built_event.type).to eq(:payment_rejected)
|
36
|
+
expect(built_event.message).to eq("Payment rejected")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should accept a struct" do
|
40
|
+
PaymentRejectedEvent = Struct.new(:customer_id, :amount) do
|
41
|
+
def message; "Payment rejected for #{customer_id}"; end
|
42
|
+
def type; :payment_rejected; end
|
43
|
+
end
|
44
|
+
built_event = Timber::Events.build(PaymentRejectedEvent.new("abcd1234", 100))
|
45
|
+
expect(built_event).to be_kind_of(Timber::Events::Custom)
|
46
|
+
expect(built_event.type).to eq(:payment_rejected)
|
47
|
+
expect(built_event.message).to eq("Payment rejected for abcd1234")
|
48
|
+
Object.send(:remove_const, :PaymentRejectedEvent)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return nil for unsupported" do
|
52
|
+
expect(Timber::Events.build(1)).to be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -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,68 @@
|
|
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 allow functions" do
|
52
|
+
logger.info do
|
53
|
+
{message: "payment rejected", type: :payment_rejected, data: {customer_id: "abcde1234", amount: 100}}
|
54
|
+
end
|
55
|
+
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")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with the :json format" do
|
60
|
+
before(:each) { logger.formatter = Timber::Logger::JSONFormatter.new }
|
61
|
+
|
62
|
+
it "should log in the correct format" do
|
63
|
+
logger.info("this is a test")
|
64
|
+
expect(io.string).to eq("{\"level\":\"info\",\"dt\":\"2016-09-01T12:00:00.000000Z\",\"message\":\"this is a test\"}\n")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
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
|
@@ -1,9 +1,17 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Timber::Probes::ActionDispatchDebugExceptions do
|
4
|
-
describe described_class
|
5
|
-
describe "
|
6
|
-
|
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|
|
7
15
|
class ExceptionController < ActionController::Base
|
8
16
|
layout nil
|
9
17
|
|
@@ -19,27 +27,25 @@ describe Timber::Probes::ActionDispatchDebugExceptions do
|
|
19
27
|
::RailsApp.routes.draw do
|
20
28
|
get 'exception' => 'exception#index'
|
21
29
|
end
|
22
|
-
end
|
23
30
|
|
24
|
-
|
31
|
+
Timecop.freeze(time) { example.run }
|
32
|
+
|
25
33
|
Object.send(:remove_const, :ExceptionController)
|
26
34
|
end
|
27
35
|
|
28
|
-
let(:logger_context_class) { Timber::Contexts::Logger }
|
29
|
-
let(:rack_request_context_class) { Timber::Contexts::HTTPRequests::Rack }
|
30
|
-
let(:request_context_class) { Timber::Contexts::HTTPRequests::ActionControllerSpecific }
|
31
|
-
let(:organization_context_class) { Timber::Contexts::Organizations::ActionController }
|
32
|
-
let(:user_context_class) { Timber::Contexts::Users::ActionController }
|
33
|
-
let(:response_context_class) { Timber::Contexts::HTTPResponses::ActionController }
|
34
|
-
let(:exception_context_class) { Timber::Contexts::Exception }
|
35
|
-
|
36
36
|
it "should set the context" do
|
37
|
-
|
38
|
-
expect(Timber::CurrentContext).to receive(:add).with(kind_of(rack_request_context_class)).and_yield.once
|
39
|
-
expect(Timber::CurrentContext).to receive(:add).with(kind_of(request_context_class), kind_of(organization_context_class), kind_of(user_context_class), kind_of(response_context_class)).and_yield.once
|
40
|
-
expect(Timber::CurrentContext).to receive(:add).with(kind_of(exception_context_class)).and_yield
|
37
|
+
mock_class
|
41
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)
|
42
48
|
end
|
43
49
|
end
|
44
50
|
end
|
45
|
-
end
|
51
|
+
end
|