timber 2.6.2 → 3.0.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.
Files changed (142) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +8 -38
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +30 -284
  5. data/Rakefile +78 -0
  6. data/lib/timber.rb +6 -6
  7. data/lib/timber/config.rb +1 -83
  8. data/lib/timber/config/integrations.rb +1 -47
  9. data/lib/timber/context.rb +3 -24
  10. data/lib/timber/contexts.rb +2 -30
  11. data/lib/timber/contexts/http.rb +16 -36
  12. data/lib/timber/contexts/release.rb +12 -23
  13. data/lib/timber/contexts/runtime.rb +9 -36
  14. data/lib/timber/contexts/session.rb +8 -21
  15. data/lib/timber/contexts/system.rb +9 -16
  16. data/lib/timber/contexts/user.rb +13 -33
  17. data/lib/timber/current_context.rb +16 -78
  18. data/lib/timber/event.rb +12 -9
  19. data/lib/timber/events.rb +1 -33
  20. data/lib/timber/events/controller_call.rb +20 -31
  21. data/lib/timber/events/error.rb +18 -26
  22. data/lib/timber/events/exception.rb +1 -0
  23. data/lib/timber/events/sql_query.rb +14 -24
  24. data/lib/timber/events/template_render.rb +13 -24
  25. data/lib/timber/integration.rb +1 -1
  26. data/lib/timber/integrator.rb +1 -1
  27. data/lib/timber/log_devices/http.rb +98 -19
  28. data/lib/timber/log_entry.rb +6 -24
  29. data/lib/timber/logger.rb +5 -14
  30. data/lib/timber/util.rb +1 -6
  31. data/lib/timber/util/non_nil_hash_builder.rb +3 -1
  32. data/lib/timber/version.rb +1 -1
  33. data/spec/README.md +2 -8
  34. data/spec/spec_helper.rb +0 -7
  35. data/spec/support/timber.rb +1 -3
  36. data/spec/timber/current_context_spec.rb +12 -50
  37. data/spec/timber/events/controller_call_spec.rb +4 -4
  38. data/spec/timber/events/error_spec.rb +4 -9
  39. data/spec/timber/log_devices/http_spec.rb +26 -2
  40. data/spec/timber/log_entry_spec.rb +12 -6
  41. data/spec/timber/logger_spec.rb +27 -68
  42. data/timber.gemspec +1 -1
  43. metadata +5 -139
  44. data/gemfiles/rails-3.0.gemfile +0 -5
  45. data/gemfiles/rails-3.1.gemfile +0 -5
  46. data/gemfiles/rails-3.2.gemfile +0 -5
  47. data/gemfiles/rails-4.0.gemfile +0 -9
  48. data/gemfiles/rails-4.1.gemfile +0 -9
  49. data/gemfiles/rails-4.2.gemfile +0 -9
  50. data/gemfiles/rails-5.0.gemfile +0 -9
  51. data/gemfiles/rails-5.1.gemfile +0 -9
  52. data/gemfiles/rails-edge.gemfile +0 -7
  53. data/lib/timber/cli.rb +0 -60
  54. data/lib/timber/cli/api.rb +0 -183
  55. data/lib/timber/cli/api/application.rb +0 -34
  56. data/lib/timber/cli/config_file.rb +0 -71
  57. data/lib/timber/cli/file_helper.rb +0 -53
  58. data/lib/timber/cli/installer.rb +0 -70
  59. data/lib/timber/cli/installers.rb +0 -102
  60. data/lib/timber/cli/installers/config_file.rb +0 -51
  61. data/lib/timber/cli/installers/other.rb +0 -59
  62. data/lib/timber/cli/installers/rails.rb +0 -225
  63. data/lib/timber/cli/installers/root.rb +0 -116
  64. data/lib/timber/cli/io.rb +0 -100
  65. data/lib/timber/cli/io/ansi.rb +0 -22
  66. data/lib/timber/cli/io/messages.rb +0 -198
  67. data/lib/timber/cli/os_helper.rb +0 -74
  68. data/lib/timber/config/integrations/rack.rb +0 -74
  69. data/lib/timber/contexts/custom.rb +0 -44
  70. data/lib/timber/contexts/organization.rb +0 -48
  71. data/lib/timber/events/custom.rb +0 -53
  72. data/lib/timber/events/http_request.rb +0 -71
  73. data/lib/timber/events/http_response.rb +0 -81
  74. data/lib/timber/frameworks.rb +0 -19
  75. data/lib/timber/frameworks/rails.rb +0 -27
  76. data/lib/timber/integrations.rb +0 -29
  77. data/lib/timber/integrations/action_controller.rb +0 -18
  78. data/lib/timber/integrations/action_controller/log_subscriber.rb +0 -27
  79. data/lib/timber/integrations/action_controller/log_subscriber/timber_log_subscriber.rb +0 -46
  80. data/lib/timber/integrations/action_dispatch.rb +0 -23
  81. data/lib/timber/integrations/action_dispatch/debug_exceptions.rb +0 -53
  82. data/lib/timber/integrations/action_view.rb +0 -18
  83. data/lib/timber/integrations/action_view/log_subscriber.rb +0 -27
  84. data/lib/timber/integrations/action_view/log_subscriber/timber_log_subscriber.rb +0 -83
  85. data/lib/timber/integrations/active_record.rb +0 -18
  86. data/lib/timber/integrations/active_record/log_subscriber.rb +0 -26
  87. data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +0 -53
  88. data/lib/timber/integrations/rack.rb +0 -27
  89. data/lib/timber/integrations/rack/error_event.rb +0 -64
  90. data/lib/timber/integrations/rack/http_context.rb +0 -27
  91. data/lib/timber/integrations/rack/http_events.rb +0 -210
  92. data/lib/timber/integrations/rack/middleware.rb +0 -28
  93. data/lib/timber/integrations/rack/session_context.rb +0 -65
  94. data/lib/timber/integrations/rack/user_context.rb +0 -135
  95. data/lib/timber/integrations/rails.rb +0 -22
  96. data/lib/timber/integrations/rails/rack_logger.rb +0 -60
  97. data/lib/timber/overrides.rb +0 -12
  98. data/lib/timber/overrides/active_support_3_tagged_logging.rb +0 -111
  99. data/lib/timber/overrides/active_support_buffered_logger.rb +0 -22
  100. data/lib/timber/overrides/active_support_tagged_logging.rb +0 -66
  101. data/lib/timber/overrides/lograge.rb +0 -18
  102. data/lib/timber/overrides/rails_stdout_logging.rb +0 -21
  103. data/lib/timber/util/active_support_log_subscriber.rb +0 -37
  104. data/lib/timber/util/attribute_normalizer.rb +0 -89
  105. data/lib/timber/util/hash.rb +0 -90
  106. data/lib/timber/util/request.rb +0 -72
  107. data/lib/timber/util/struct.rb +0 -16
  108. data/spec/rails/tagged_logging_spec.rb +0 -44
  109. data/spec/support/action_controller.rb +0 -8
  110. data/spec/support/active_record.rb +0 -32
  111. data/spec/support/rails.rb +0 -67
  112. data/spec/support/rails/templates/_partial.html +0 -1
  113. data/spec/support/rails/templates/template.html +0 -1
  114. data/spec/timber/cli/config_file_spec.rb +0 -26
  115. data/spec/timber/cli/installers/config_file_spec.rb +0 -36
  116. data/spec/timber/cli/installers/other_spec.rb +0 -49
  117. data/spec/timber/cli/installers/rails_spec.rb +0 -364
  118. data/spec/timber/cli/installers/root_spec.rb +0 -73
  119. data/spec/timber/config_spec.rb +0 -28
  120. data/spec/timber/contexts/custom_spec.rb +0 -11
  121. data/spec/timber/contexts/organization_spec.rb +0 -11
  122. data/spec/timber/contexts/runtime_spec.rb +0 -11
  123. data/spec/timber/contexts/system_spec.rb +0 -11
  124. data/spec/timber/contexts/user_spec.rb +0 -11
  125. data/spec/timber/contexts_spec.rb +0 -49
  126. data/spec/timber/event_spec.rb +0 -10
  127. data/spec/timber/events/custom_spec.rb +0 -36
  128. data/spec/timber/events/http_request_spec.rb +0 -32
  129. data/spec/timber/events/http_response_spec.rb +0 -12
  130. data/spec/timber/events_spec.rb +0 -55
  131. data/spec/timber/integrations/action_controller/log_subscriber_spec.rb +0 -55
  132. data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +0 -53
  133. data/spec/timber/integrations/action_view/log_subscriber_spec.rb +0 -115
  134. data/spec/timber/integrations/active_record/log_subscriber_spec.rb +0 -46
  135. data/spec/timber/integrations/rack/error_event_spec.rb +0 -63
  136. data/spec/timber/integrations/rack/http_context_spec.rb +0 -60
  137. data/spec/timber/integrations/rack/http_events_spec.rb +0 -101
  138. data/spec/timber/integrations/rack/session_context_spec.rb +0 -62
  139. data/spec/timber/integrations/rails/rack_logger_spec.rb +0 -58
  140. data/spec/timber/util/attribute_normalizer_spec.rb +0 -90
  141. data/spec/timber/util/hash_spec.rb +0 -30
  142. data/spec/timber/util/request_spec.rb +0 -10
@@ -1,66 +0,0 @@
1
- # This is an override instead of an integration because without this Timber would not
2
- # work properly if ActiveSupport::TaggedLogging is used.
3
- #
4
- # This is called after 'active_support_3_tagged_logging' where the constant is loaded and
5
- # replaced. I want to make sure we don't attempt to load it again undoing the patches
6
- # applied there.
7
- if defined?(ActiveSupport::TaggedLogging)
8
- module Timber
9
- module Overrides
10
- # @private
11
- module ActiveSupportTaggedLogging
12
- # @private
13
- module FormatterMethods
14
- def self.included(mod)
15
- mod.module_eval do
16
- alias_method :_timber_original_push_tags, :push_tags
17
- alias_method :_timber_original_pop_tags, :pop_tags
18
-
19
- def call(severity, timestamp, progname, msg)
20
- if is_a?(Timber::Logger::Formatter)
21
- # Don't convert the message into a string
22
- super(severity, timestamp, progname, msg)
23
- else
24
- super(severity, timestamp, progname, "#{tags_text}#{msg}")
25
- end
26
- end
27
- end
28
- end
29
- end
30
-
31
- # @private
32
- module LoggerMethods
33
- def self.included(klass)
34
- klass.class_eval do
35
- def add(severity, message = nil, progname = nil, &block)
36
- if message.nil?
37
- if block_given?
38
- message = block.call
39
- else
40
- message = progname
41
- progname = nil #No instance variable for this like Logger
42
- end
43
- end
44
- if @logger.is_a?(Timber::Logger)
45
- @logger.add(severity, message, progname)
46
- else
47
- @logger.add(severity, "#{tags_text}#{message}", progname)
48
- end
49
- end
50
- end
51
- end
52
- end
53
-
54
- if defined?(::ActiveSupport::TaggedLogging::Formatter)
55
- if !::ActiveSupport::TaggedLogging::Formatter.include?(FormatterMethods)
56
- ::ActiveSupport::TaggedLogging::Formatter.send(:include, FormatterMethods)
57
- end
58
- else
59
- if !::ActiveSupport::TaggedLogging.include?(LoggerMethods)
60
- ::ActiveSupport::TaggedLogging.send(:include, LoggerMethods)
61
- end
62
- end
63
- end
64
- end
65
- end
66
- end
@@ -1,18 +0,0 @@
1
- # Timber and lograge are not compatible installed together. Using lograge
2
- # with the Timber.io *service* is perfectly fine, but not with the Timber *gem*.
3
- #
4
- # Timber does ship with a {Timber::Config#logrageify!} option that configures
5
- # Timber to behave similarly to Lograge (silencing various logs). Check out
6
- # the aforementioned method or the README for info.
7
- begin
8
- require "lograge"
9
-
10
- module Lograge
11
- module_function
12
-
13
- def setup(app)
14
- return true
15
- end
16
- end
17
- rescue Exception
18
- end
@@ -1,21 +0,0 @@
1
- # See https://github.com/heroku/rails_stdout_logging
2
- # I have no idea why this library was created, but most Heroku / Rails apps use it.
3
- # This library completely obliterates any logger configuration you set.
4
- # So this patch fixes that.
5
-
6
- begin
7
- require "rails_stdout_logging"
8
-
9
- module RailsStdoutLogging
10
- class Rails2 < Rails
11
- def self.set_logger
12
- end
13
- end
14
-
15
- class Rails3 < Rails
16
- def self.set_logger(config)
17
- end
18
- end
19
- end
20
- rescue Exception
21
- end
@@ -1,37 +0,0 @@
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
- # I don't know why this has to be so complicated, but it is. This code was taken from
18
- # lograge :/
19
- def unsubscribe!(component, type)
20
- subscriber = find(component, type)
21
-
22
- if !subscriber
23
- raise "We could not find a log subscriber for #{component.inspect} of type #{type.inspect}"
24
- end
25
-
26
- events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
27
- events.each do |event|
28
- ::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
29
- if listener.instance_variable_get('@delegate') == subscriber
30
- ::ActiveSupport::Notifications.unsubscribe listener
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,89 +0,0 @@
1
- module Timber
2
- module Util
3
- # @private
4
- #
5
- # The purpose of this class is to normalize parameters passed to events
6
- # and contexts. Timber validates a rigid JSON schema against the defined
7
- # Timber log event JSON schema. This normalization process ensures the
8
- # data passed to events and contexts conforms to this structure.
9
- class AttributeNormalizer
10
- def initialize(attributes)
11
- @attributes = attributes
12
- end
13
-
14
- def fetch!(key, type, options = {})
15
- v = fetch(key, type, options)
16
- if v.nil?
17
- raise ArgumentError.new("The #{key.inspect} attribute is required")
18
- end
19
- v
20
- end
21
-
22
- def fetch(key, type, options = {})
23
- v = @attributes[key]
24
-
25
- if blank?(v)
26
- options[:default] || nil
27
- else
28
- case type
29
- when :array
30
- if !v.is_a?(Array)
31
- raise ArgumentError.new("The #{key.inspect} attribute must be a list if provided")
32
- end
33
-
34
- v
35
-
36
- when :float
37
- v = v.to_f
38
-
39
- if options[:precision]
40
- v = v.round(options[:precision])
41
- end
42
-
43
- v
44
-
45
- when :hash
46
- if options[:sanitize]
47
- v = Util::Hash.sanitize_keys(v, options[:sanitize])
48
- end
49
-
50
- v = Util::Hash.jsonify(v)
51
-
52
- if v == {}
53
- nil
54
- else
55
- v
56
- end
57
-
58
- when :integer
59
- v.to_i
60
-
61
- when :string
62
- v = v.to_s
63
-
64
- if options[:limit]
65
- v = v.byteslice(0, options[:limit])
66
- end
67
-
68
- if options[:upcase]
69
- v = v.upcase
70
- end
71
-
72
- v
73
-
74
- when :symbol
75
- v.to_sym
76
-
77
- else
78
- raise ArgumentError.new("Unknown normalization type #{type}")
79
- end
80
- end
81
- end
82
-
83
- private
84
- def blank?(v)
85
- v.nil? || (v.respond_to?(:length) && v.length == 0)
86
- end
87
- end
88
- end
89
- end
@@ -1,90 +0,0 @@
1
- module Timber
2
- module Util
3
- # @private
4
- module Hash
5
- BINARY_LIMIT_THRESHOLD = 1_000.freeze
6
- SANITIZED_VALUE = '[sanitized]'.freeze
7
-
8
- extend self
9
-
10
- # Deeply reduces a hash into a new hash, passing the current key, value,
11
- # and accumulated map up to that point. This allows the caller to
12
- # conditionally rebuild the hash.
13
- def deep_reduce(hash, &block)
14
- new_hash = {}
15
-
16
- hash.each do |k, v|
17
- v = if v.is_a?(::Hash)
18
- deep_reduce(v, &block)
19
- else
20
- v
21
- end
22
-
23
- block.call(k, v, new_hash)
24
- end
25
-
26
- new_hash
27
- end
28
-
29
- # Recursively traverses a hash, dropping non-JSON compatible types.
30
- # If the string is a binary, and it is > 1000 characters, it is dropped.
31
- # We are assuming it represents file contents that should not be included
32
- # in the logs.
33
- def jsonify(hash)
34
- deep_reduce(hash) do |k, v, h|
35
- if v.is_a?(String)
36
- if v.encoding == ::Encoding::ASCII_8BIT
37
- # Only keep binary values less than a certain size. Sizes larger than this
38
- # are almost always file uploads and data we do not want to log.
39
- if v.length < BINARY_LIMIT_THRESHOLD
40
- # Attempt to safely encode the data to UTF-8
41
- encoded_value = encode_string(v)
42
- if !encoded_value.nil?
43
- h[k] = encoded_value
44
- end
45
- end
46
- elsif v.encoding != ::Encoding::UTF_8
47
- h[k] = encode_string(v)
48
- else
49
- h[k] = v
50
- end
51
- elsif is_a_primitive_type?(v)
52
- # Keep all other primitive types
53
- h[k] = v
54
- end
55
- end
56
- end
57
-
58
- # Replaces matching keys with a `[Sanitized]` value.
59
- def sanitize_keys(hash, keys_to_sanitize)
60
- hash.each_with_object({}) do |(k, v), h|
61
- k = k.to_s.downcase
62
- if keys_to_sanitize.include?(k)
63
- h[k] = SANITIZED_VALUE
64
- else
65
- h[k] = v
66
- end
67
- end
68
- end
69
-
70
- private
71
- # Attempts to encode a non UTF-8 string into UTF-8, discarding invalid characters.
72
- # If it fails, a nil is returned.
73
- def encode_string(string)
74
- string.encode('UTF-8', {
75
- :invalid => :replace,
76
- :undef => :replace,
77
- :replace => '?'
78
- })
79
- rescue Exception
80
- nil
81
- end
82
-
83
- # We use is_a? because it accounts for inheritance.
84
- def is_a_primitive_type?(v)
85
- v.is_a?(Array) || v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(TrueClass) ||
86
- v.is_a?(FalseClass) || v.is_a?(String) || v.is_a?(Time) || v.is_a?(::Hash)
87
- end
88
- end
89
- end
90
- end
@@ -1,72 +0,0 @@
1
- begin
2
- require "rack"
3
- rescue LoadError
4
- end
5
-
6
- if defined?(::Rack::Request)
7
- module Timber
8
- module Util
9
- # @private
10
- class Request < ::Rack::Request
11
- # We store strings as constants since they are reused on a per request basis.
12
- # This avoids string allocations.
13
- HTTP_HEADER_ORIGINAL_DELIMITER = '_'.freeze
14
- HTTP_HEADER_NEW_DELIMITER = '_'.freeze
15
- HTTP_PREFIX = 'HTTP_'.freeze
16
-
17
- REMOTE_IP_KEY_NAME = 'action_dispatch.remote_ip'.freeze
18
- REQUEST_ID_KEY_NAME1 = 'action_dispatch.request_id'.freeze
19
- REQUEST_ID_KEY_NAME2 = 'X-Request-ID'.freeze
20
- REQUEST_ID_KEY_NAME3 = 'X-Request-Id'.freeze
21
-
22
- def body_content
23
- content = body.read
24
- body.rewind
25
- content
26
- end
27
-
28
- # Returns a list of request headers. The rack env contains a lot of data, this function
29
- # identifies those that were the actual request headers.
30
- #
31
- # This was extracted from: https://github.com/ruby-grape/grape/blob/91c6c78ae3d3f3ffabaf57ffc4dc35ab7cfc7b5f/lib/grape/request.rb#L30
32
- def headers
33
- @headers ||= begin
34
- headers = {}
35
-
36
- @env.each_pair do |k, v|
37
- next unless k.is_a?(String) && k.to_s.start_with?(HTTP_PREFIX)
38
-
39
- k = k[5..-1].
40
- split(HTTP_HEADER_ORIGINAL_DELIMITER).
41
- each(&:capitalize!).
42
- join(HTTP_HEADER_NEW_DELIMITER)
43
-
44
- headers[k] = v
45
- end
46
-
47
- headers
48
- end
49
- end
50
-
51
- def ip
52
- @ip ||= if @env[REMOTE_IP_KEY_NAME]
53
- @env[REMOTE_IP_KEY_NAME].to_s || super
54
- else
55
- super
56
- end
57
- end
58
-
59
- def referer
60
- # Rails 3.X returns "/" for some reason
61
- @referer ||= super == "/" ? nil : super
62
- end
63
-
64
- def request_id
65
- @request_id ||= @env[REQUEST_ID_KEY_NAME1] ||
66
- @env[REQUEST_ID_KEY_NAME2] ||
67
- @env[REQUEST_ID_KEY_NAME3]
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,16 +0,0 @@
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,44 +0,0 @@
1
- require "spec_helper"
2
-
3
- # ActiveSupport::TaggedLogging is not defined in <= 3.1
4
- if defined?(::ActiveSupport::TaggedLogging)
5
- describe ActiveSupport::TaggedLogging, :rails_23 => true do
6
- describe "#new" do
7
- let(:io) { StringIO.new }
8
-
9
- it "should instantiate for Timber::Logger object" do
10
- ActiveSupport::TaggedLogging.new(Timber::Logger.new(io))
11
- end
12
-
13
- if defined?(ActiveSupport::BufferedLogger)
14
- it "should instantiate for a ActiveSupport::BufferedLogger object" do
15
- ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(io))
16
- end
17
- end
18
- end
19
-
20
- describe "#info" do
21
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
22
- let(:io) { StringIO.new }
23
- let(:logger) { ActiveSupport::TaggedLogging.new(Timber::Logger.new(io)) }
24
-
25
- around(:each) do |example|
26
- Timecop.freeze(time) { example.run }
27
- end
28
-
29
- it "should format properly with events" do
30
- event = Timber::Events::SQLQuery.new(sql: "select * from users", time_ms: 56, message: "select * from users")
31
- logger.tagged("tag") do
32
- logger.info(event)
33
- end
34
- expect(io.string).to include("\"tags\":[\"tag\"]")
35
- end
36
-
37
- it "should accept events as the second argument" do
38
- logger.info("SQL query", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"})
39
- expect(io.string).to start_with("SQL query @metadata")
40
- expect(io.string).to include("\"event\":{\"custom\":{\"payment_rejected\":")
41
- end
42
- end
43
- end
44
- end