timber 2.5.1 → 2.6.0.pre.beta1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/lib/timber/config.rb +2 -1
  4. data/lib/timber/contexts/custom.rb +10 -3
  5. data/lib/timber/contexts/http.rb +23 -7
  6. data/lib/timber/contexts/organization.rb +14 -3
  7. data/lib/timber/contexts/release.rb +17 -4
  8. data/lib/timber/contexts/runtime.rb +28 -9
  9. data/lib/timber/contexts/session.rb +11 -2
  10. data/lib/timber/contexts/system.rb +13 -3
  11. data/lib/timber/contexts/user.rb +22 -6
  12. data/lib/timber/events/controller_call.rb +14 -24
  13. data/lib/timber/events/custom.rb +8 -5
  14. data/lib/timber/events/error.rb +11 -31
  15. data/lib/timber/events/http_request.rb +39 -13
  16. data/lib/timber/events/http_response.rb +32 -14
  17. data/lib/timber/events/sql_query.rb +10 -7
  18. data/lib/timber/events/template_render.rb +11 -5
  19. data/lib/timber/log_entry.rb +7 -31
  20. data/lib/timber/logger.rb +1 -5
  21. data/lib/timber/util.rb +2 -2
  22. data/lib/timber/util/attribute_normalizer.rb +90 -0
  23. data/lib/timber/util/hash.rb +51 -1
  24. data/lib/timber/util/non_nil_hash_builder.rb +38 -0
  25. data/lib/timber/version.rb +1 -1
  26. data/spec/timber/events/error_spec.rb +8 -22
  27. data/spec/timber/events/http_request_spec.rb +1 -1
  28. data/spec/timber/events_spec.rb +1 -1
  29. data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +1 -1
  30. data/spec/timber/log_entry_spec.rb +0 -39
  31. data/spec/timber/logger_spec.rb +0 -5
  32. data/spec/timber/util/attribute_normalizer_spec.rb +90 -0
  33. metadata +8 -8
  34. data/lib/timber/util/http_event.rb +0 -69
  35. data/lib/timber/util/object.rb +0 -15
  36. data/spec/timber/util/http_event_spec.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a87f39b30172987e5484e2cc7a7b8141df304872
4
- data.tar.gz: cbc461a99678fd533074bf6b8e9fdf91d4003bab
3
+ metadata.gz: 10838667c7f285fea9c51270f12594b2106299e1
4
+ data.tar.gz: f91eaaac75c0ed243686771c415a3f44d6c431b3
5
5
  SHA512:
6
- metadata.gz: d5af9920a09c610cc4fcdfb22c38db8b99e25f1b4232ed3c70350ec63965facef2ccd3f580e4b72cb08a8c795bcf8038a5ddc3ce22ea1c26968dc54f2453fe20
7
- data.tar.gz: 693d57eba475629b40c9bbbf639ebc6f87af2298eea376b9cc881a76ea224eeb75b0b9d08377a3ebde2d05854ce1d1c006c32679072cd5a721b7c80fc41e1848
6
+ metadata.gz: 8cc093229929a57566e15f4fe81a9f2fbf36c0259a85123e43cbe077e9a14828147620b60be1a7953560ac691923146dcccb2075adbe64fb331bae9a1e388206
7
+ data.tar.gz: 5478c747ded3aa62d3fcf0b877e5e09bccafb94c72e1b4812b2dea0cac2aa5fe2e86435532c66f16b35596178c64d2502a40687fe97437f13e6db641cbb296b8
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.6.0-beta1] - 2017-10-28
11
+
12
+ ### Fixed
13
+
14
+ - Encoding and rewind issues for file upload parameters have been resolved. Timber
15
+ improved attribute normalization across all contexts and events, ignoring binary
16
+ values like this in general.
17
+
10
18
  ## [2.5.1] - 2017-10-27
11
19
 
12
20
  ### Fixed
@@ -103,7 +111,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
103
111
  instead of applying back pressure.
104
112
 
105
113
 
106
- [Unreleased]: https://github.com/timberio/timber-ruby/compare/v2.5.1...HEAD
114
+ [Unreleased]: https://github.com/timberio/timber-ruby/compare/v2.6.0-beta1...HEAD
115
+ [2.6.0-beta1]: https://github.com/timberio/timber-ruby/compare/v2.5.1...v2.6.0-beta1
107
116
  [2.5.1]: https://github.com/timberio/timber-ruby/compare/v2.5.0...v2.5.1
108
117
  [2.5.0]: https://github.com/timberio/timber-ruby/compare/v2.4.0...v2.5.0
109
118
  [2.4.0]: https://github.com/timberio/timber-ruby/compare/v2.3.4...v2.4.0
data/lib/timber/config.rb CHANGED
@@ -25,6 +25,7 @@ module Timber
25
25
  end
26
26
  end
27
27
 
28
+ DEFAULT_HTTP_BODY_LIMIT = 2048.freeze
28
29
  DEVELOPMENT_NAME = "development".freeze
29
30
  PRODUCTION_NAME = "production".freeze
30
31
  STAGING_NAME = "staging".freeze
@@ -36,7 +37,7 @@ module Timber
36
37
 
37
38
  # @private
38
39
  def initialize
39
- @http_body_limit = 2048
40
+ @http_body_limit = DEFAULT_HTTP_BODY_LIMIT
40
41
  end
41
42
 
42
43
  # Convenience method for logging debug statements to the debug logger
@@ -24,13 +24,20 @@ module Timber
24
24
  attr_reader :type, :data
25
25
 
26
26
  def initialize(attributes)
27
- @type = Timber::Util::Object.try(attributes[:type], :to_sym) || raise(ArgumentError.new(":type is required"))
28
- @data = attributes[:data] || raise(ArgumentError.new(":data is required"))
27
+ normalizer = Util::AttributeNormalizer.new(attributes)
28
+ @type = normalizer.fetch!(:type, :symbol)
29
+ @data = normalizer.fetch!(:data, :hash)
29
30
  end
30
31
 
31
32
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
33
+ def to_hash
34
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
35
+ h.add(type, data)
36
+ end
37
+ end
38
+
32
39
  def as_json(options = {})
33
- {type => data}
40
+ to_hash
34
41
  end
35
42
  end
36
43
  end
@@ -13,22 +13,38 @@ module Timber
13
13
  # @note This context should be installed automatically through the,
14
14
  # {Intregrations::Rack::HTTPContext} Rack middleware.
15
15
  class HTTP < Context
16
+ HOST_MAX_BYTES = 256.freeze
17
+ METHOD_MAX_BYTES = 20.freeze
18
+ PATH_MAX_BYTES = 2048.freeze
19
+ REMOTE_ADDR_MAX_BYTES = 256.freeze
20
+ REQUEST_ID_MAX_BYTES = 256.freeze
21
+
16
22
  @keyspace = :http
17
23
 
18
24
  attr_reader :host, :method, :path, :remote_addr, :request_id
19
25
 
20
26
  def initialize(attributes)
21
- @host = attributes[:host]
22
- @method = attributes[:method] || raise(ArgumentError.new(":method is required"))
23
- @path = attributes[:path]
24
- @remote_addr = attributes[:remote_addr]
25
- @request_id = attributes[:request_id]
27
+ normalizer = Util::AttributeNormalizer.new(attributes)
28
+ @host = normalizer.fetch(:host, :string, :limit => HOST_MAX_BYTES)
29
+ @method = normalizer.fetch!(:method, :string, :upcase => true, :limit => METHOD_MAX_BYTES)
30
+ @path = normalizer.fetch(:path, :string, :limit => PATH_MAX_BYTES)
31
+ @remote_addr = normalizer.fetch(:remote_addr, :string, :limit => REMOTE_ADDR_MAX_BYTES)
32
+ @request_id = normalizer.fetch(:request_id, :string, :limit => REQUEST_ID_MAX_BYTES)
26
33
  end
27
34
 
28
35
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
36
+ def to_hash
37
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
38
+ h.add(:host, host)
39
+ h.add(:method, method)
40
+ h.add(:path, path)
41
+ h.add(:remote_addr, remote_addr)
42
+ h.add(:request_id, request_id)
43
+ end
44
+ end
45
+
29
46
  def as_json(_options = {})
30
- {:host => host, :method => method, :path => path, :remote_addr => remote_addr,
31
- :request_id => request_id}
47
+ to_hash
32
48
  end
33
49
  end
34
50
  end
@@ -19,18 +19,29 @@ module Timber
19
19
  # end
20
20
  #
21
21
  class Organization < Context
22
+ ID_MAX_BYTES = 256.freeze
23
+ NAME_MAX_BYTES = 256.freeze
24
+
22
25
  @keyspace = :organization
23
26
 
24
27
  attr_reader :id, :name
25
28
 
26
29
  def initialize(attributes)
27
- @id = Timber::Util::Object.try(attributes[:id], :to_s)
28
- @name = attributes[:name]
30
+ normalizer = Util::AttributeNormalizer.new(attributes)
31
+ @id = normalizer.fetch(:id, :string, :limit => ID_MAX_BYTES)
32
+ @name = normalizer.fetch(:name, :string, :limit => NAME_MAX_BYTES)
29
33
  end
30
34
 
31
35
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
36
+ def to_hash
37
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
38
+ h.add(:id, id)
39
+ h.add(:name, name)
40
+ end
41
+ end
42
+
32
43
  def as_json(_options = {})
33
- {id: id, name: name}
44
+ to_hash
34
45
  end
35
46
  end
36
47
  end
@@ -8,6 +8,10 @@ module Timber
8
8
  #
9
9
  # @note To automatically set this context, see {.from_env}.
10
10
  class Release < Context
11
+ COMMIT_HASH_MAX_BYTES = 256.freeze
12
+ CREATED_AT_MAX_BYTES = 256.freeze
13
+ VERSION_MAX_BYTES = 256.freeze
14
+
11
15
  @keyspace = :release
12
16
 
13
17
  class << self
@@ -36,14 +40,23 @@ module Timber
36
40
  attr_reader :commit_hash, :created_at, :version
37
41
 
38
42
  def initialize(attributes)
39
- @commit_hash = attributes[:commit_hash]
40
- @created_at = attributes[:created_at]
41
- @version = attributes[:version]
43
+ normalizer = Util::AttributeNormalizer.new(attributes)
44
+ @commit_hash = normalizer.fetch(:commit_hash, :string, :limit => COMMIT_HASH_MAX_BYTES)
45
+ @created_at = normalizer.fetch(:created_at, :string, :limit => CREATED_AT_MAX_BYTES)
46
+ @version = normalizer.fetch(:version, :string, :limit => VERSION_MAX_BYTES)
42
47
  end
43
48
 
44
49
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
50
+ def to_hash
51
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
52
+ h.add(:commit_hash, commit_hash)
53
+ h.add(:created_at, created_at)
54
+ h.add(:version, version)
55
+ end
56
+ end
57
+
45
58
  def as_json(_options = {})
46
- {commit_hash: commit_hash, created_at: created_at, version: version}
59
+ to_hash
47
60
  end
48
61
  end
49
62
  end
@@ -7,24 +7,43 @@ module Timber
7
7
  # origin in your code. For example, if you are debugging a specific class, you can narrow
8
8
  # by that class and see only it's logs.
9
9
  class Runtime < Context
10
+ APPLICATION_MAX_BYTES = 256.freeze
11
+ CLASS_NAME_MAX_BYTES = 256.freeze
12
+ FILE_MAX_BYTES = 1024.freeze
13
+ FUNCTION_MAX_BYTES = 256.freeze
14
+ MODULE_NAME_MAX_BYTES = 256.freeze
15
+ VM_PID_MAX_BYTES = 256.freeze
16
+
10
17
  @keyspace = :runtime
11
18
 
12
19
  attr_reader :application, :class_name, :file, :function, :line, :module_name, :vm_pid
13
20
 
14
21
  def initialize(attributes)
15
- @application = attributes[:application]
16
- @class_name = attributes[:class_name]
17
- @file = attributes[:file]
18
- @function = attributes[:function]
19
- @line = attributes[:line]
20
- @module_name = attributes[:module_name]
21
- @vm_pid = Timber::Util::Object.try(attributes[:vm_pid], :to_s)
22
+ normalizer = Util::AttributeNormalizer.new(attributes)
23
+ @application = normalizer.fetch(:application, :string, :limit => APPLICATION_MAX_BYTES)
24
+ @class_name = normalizer.fetch(:class_name, :string, :limit => CLASS_NAME_MAX_BYTES)
25
+ @file = normalizer.fetch(:file, :string, :limit => FILE_MAX_BYTES)
26
+ @function = normalizer.fetch(:function, :string, :limit => FUNCTION_MAX_BYTES)
27
+ @line = normalizer.fetch(:line, :integer)
28
+ @module_name = normalizer.fetch(:module_name, :string, :limit => MODULE_NAME_MAX_BYTES)
29
+ @vm_pid = normalizer.fetch(:vm_pid, :string, :limit => VM_PID_MAX_BYTES)
22
30
  end
23
31
 
24
32
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
33
+ def to_hash
34
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
35
+ h.add(:application, application)
36
+ h.add(:class_name, class_name)
37
+ h.add(:file, file)
38
+ h.add(:function, function)
39
+ h.add(:line, line)
40
+ h.add(:module_name, module_name)
41
+ h.add(:vm_pid, vm_pid)
42
+ end
43
+ end
44
+
25
45
  def as_json(_options = {})
26
- {application: application, class_name: class_name, file: file, function: function,
27
- line: line, module_name: module_name, vm_pid: vm_pid}
46
+ to_hash
28
47
  end
29
48
  end
30
49
  end
@@ -11,17 +11,26 @@ module Timber
11
11
  # @note This is tracked automatically with the {Integrations::Rack::SessionContext} rack
12
12
  # middleware.
13
13
  class Session < Context
14
+ ID_MAX_BYTES = 256.freeze
15
+
14
16
  @keyspace = :session
15
17
 
16
18
  attr_reader :id
17
19
 
18
20
  def initialize(attributes)
19
- @id = Timber::Util::Object.try(attributes[:id], :to_s) || raise(ArgumentError.new(":id is required"))
21
+ normalizer = Util::AttributeNormalizer.new(attributes)
22
+ @id = normalizer.fetch!(:id, :string, :limit => ID_MAX_BYTES)
20
23
  end
21
24
 
22
25
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
26
+ def to_hash
27
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
28
+ h.add(:id, id)
29
+ end
30
+ end
31
+
23
32
  def as_json(_options = {})
24
- {id: id}
33
+ to_hash
25
34
  end
26
35
  end
27
36
  end
@@ -8,18 +8,28 @@ module Timber
8
8
  # @note This is tracked automatically in {CurrentContext}. When the current context
9
9
  # is initialized, the system context gets added automatically.
10
10
  class System < Context
11
+ HOSTNAME_MAX_BYTES = 256.freeze
12
+
11
13
  @keyspace = :system
12
14
 
13
15
  attr_reader :hostname, :pid
14
16
 
15
17
  def initialize(attributes)
16
- @hostname = attributes[:hostname]
17
- @pid = Timber::Util::Object.try(attributes[:pid], :to_i)
18
+ normalizer = Util::AttributeNormalizer.new(attributes)
19
+ @hostname = normalizer.fetch(:hostname, :string, :limit => HOSTNAME_MAX_BYTES)
20
+ @pid = normalizer.fetch(:pid, :integer)
18
21
  end
19
22
 
20
23
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
24
+ def to_hash
25
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
26
+ h.add(:hostname, hostname)
27
+ h.add(:pid, pid)
28
+ end
29
+ end
30
+
21
31
  def as_json(_options = {})
22
- {hostname: hostname, pid: pid}
32
+ to_hash
23
33
  end
24
34
  end
25
35
  end
@@ -11,21 +11,37 @@ module Timber
11
11
  # middleware for supported authentication frameworks. See {Integrations::Rack::UserContext}
12
12
  # for more details.
13
13
  class User < Context
14
+ ID_MAX_BYTES = 256.freeze
15
+ NAME_MAX_BYTES = 256.freeze
16
+ EMAIL_MAX_BYTES = 256.freeze
17
+ TYPE_MAX_BYTES = 256.freeze
18
+
14
19
  @keyspace = :user
15
20
 
16
21
  attr_reader :id, :name, :email, :type, :meta
17
22
 
18
23
  def initialize(attributes)
19
- @id = Timber::Util::Object.try(attributes[:id], :to_s)
20
- @name = attributes[:name]
21
- @email = attributes[:email]
22
- @type = attributes[:type]
23
- @meta = attributes[:meta]
24
+ normalizer = Util::AttributeNormalizer.new(attributes)
25
+ @id = normalizer.fetch(:id, :string, :limit => ID_MAX_BYTES)
26
+ @name = normalizer.fetch(:name, :string, :limit => NAME_MAX_BYTES)
27
+ @email = normalizer.fetch(:email, :string, :limit => EMAIL_MAX_BYTES)
28
+ @type = normalizer.fetch(:type, :string, :limit => TYPE_MAX_BYTES)
29
+ @meta = normalizer.fetch(:meta, :hash)
24
30
  end
25
31
 
26
32
  # Builds a hash representation containing simple objects, suitable for serialization (JSON).
33
+ def to_hash
34
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
35
+ h.add(:id, id)
36
+ h.add(:name, name)
37
+ h.add(:email, email)
38
+ h.add(:type, type)
39
+ h.add(:meta, meta)
40
+ end
41
+ end
42
+
27
43
  def as_json(_options = {})
28
- {id: id, name: name, email: email, type: type, meta: meta}
44
+ to_hash
29
45
  end
30
46
  end
31
47
  end
@@ -8,22 +8,30 @@ module Timber
8
8
  # Processing by PagesController#home as HTML
9
9
  #
10
10
  # @note This event should be installed automatically through integrations,
11
- # such as the {Integrations::ActionController::LogSubscriber} integration.
11
+ # such as the {Integrations::ActionController} integration.
12
12
  class ControllerCall < Timber::Event
13
+ ACTION_MAX_BYTES = 256.freeze
14
+ FORMAT_MAX_BYTES = 256.freeze
15
+ CONTROLLER_MAX_BYTES = 256.freeze
13
16
  PARAMS_JSON_MAX_BYTES = 32_768.freeze
14
17
  PASSWORD_NAME = 'password'.freeze
15
18
 
16
19
  attr_reader :controller, :action, :params, :format
17
20
 
18
21
  def initialize(attributes)
19
- @controller = attributes[:controller] || raise(ArgumentError.new(":controller is required"))
20
- @action = attributes[:action] || raise(ArgumentError.new(":action is required"))
21
- @params = sanitize_params(attributes[:params])
22
- @format = attributes[:format]
22
+ normalizer = Util::AttributeNormalizer.new(attributes)
23
+ @controller = normalizer.fetch!(:controller, :string, :limit => CONTROLLER_MAX_BYTES)
24
+ @action = normalizer.fetch!(:action, :string, :limit => ACTION_MAX_BYTES)
25
+ @params = normalizer.fetch(:params, :hash, :sanitize => [PASSWORD_NAME])
26
+ @format = normalizer.fetch(:format, :string, :limit => FORMAT_MAX_BYTES)
23
27
  end
24
28
 
25
29
  def to_hash
26
- {controller: controller, action: action, params_json: params_json}
30
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
31
+ h.add(:controller, controller)
32
+ h.add(:action, action)
33
+ h.add(:params_json, params.to_json.byteslice(0, PARAMS_JSON_MAX_BYTES))
34
+ end
27
35
  end
28
36
  alias to_h to_hash
29
37
 
@@ -42,24 +50,6 @@ module Timber
42
50
  end
43
51
  message
44
52
  end
45
-
46
- private
47
- def params_json
48
- @params_json ||=
49
- if params.nil? || params == {}
50
- nil
51
- else
52
- params.to_json.byteslice(0, PARAMS_JSON_MAX_BYTES)
53
- end
54
- end
55
-
56
- def sanitize_params(params)
57
- if params.is_a?(::Hash)
58
- Util::Hash.sanitize(params, [PASSWORD_NAME])
59
- else
60
- params
61
- end
62
- end
63
53
  end
64
54
  end
65
55
  end
@@ -23,12 +23,13 @@ module Timber
23
23
  # @option attributes [Hash] :data A hash of JSON encodable data to be stored with the
24
24
  # log line.
25
25
  def initialize(attributes)
26
- @type = attributes[:type] || raise(ArgumentError.new(":type is required"))
27
- @message = attributes[:message] || raise(ArgumentError.new(":message is required"))
26
+ normalizer = Util::AttributeNormalizer.new(attributes)
27
+ @type = normalizer.fetch!(:type, :symbol)
28
+ @message = normalizer.fetch!(:message, :string)
28
29
 
29
- data = attributes[:data]
30
+ data = normalizer.fetch!(:data, :hash)
30
31
 
31
- if data.is_a?(Hash) && data[:time_ms].is_a?(Time)
32
+ if !data.nil? && data[:time_ms].is_a?(Time)
32
33
  data[:time_ms] = Timer.duration_ms(data[:time_ms])
33
34
  @message << " in #{data[:time_ms]}ms"
34
35
  end
@@ -37,7 +38,9 @@ module Timber
37
38
  end
38
39
 
39
40
  def to_hash
40
- {Timber::Util::Object.try(type, :to_sym) => data}
41
+ @to_hash ||= Util::NonNilHashBuilder.build do |h|
42
+ h.add(type, data)
43
+ end
41
44
  end
42
45
  alias to_h to_hash
43
46