timber 2.0.7 → 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8e5de46982d4346797f2fcefba7f45d601bc6cd
4
- data.tar.gz: 2a46a4fbc36cb8b6de0901cb138aeb7249ddd931
3
+ metadata.gz: 39440c7ae6a4d416b54191200b5a406681750be5
4
+ data.tar.gz: 04de3467c2bc3bdc363d1816ea892a74b4b237cc
5
5
  SHA512:
6
- metadata.gz: 81c9834d338f1d54f15df5c36802e761c3725da1cc36de4c46992fc7cc536ff6d0630678666937d22e0181dffdc7c1790ff2c4a4046732d8cdf352ccee60cb36
7
- data.tar.gz: 8167bb8a446d336b4f798da86f10d66b1b67cba12f1d95f4c0a1be828d08526add3346916451f4a02226f469320c476a43ff1372a2f67384d68500e63a0553a9
6
+ metadata.gz: c2d65105138fa4e900262dc15274c4a4dbc79b1ecb89a91ffedefcdc64371933d12e5157cb16ffe8999e48375255d2186f7e0cd62ab30efafe13ee9074d2d2a8
7
+ data.tar.gz: 9e1562e6465a72a7e491841617d58ec5dd1dd10d6174a34a92fba8817fcd80e9d8433555c7e1ead74022fd0bb90b314dc3b3ea8cbb78b61c31c92dba8dcda6a7
data/README.md CHANGED
@@ -15,10 +15,10 @@
15
15
 
16
16
  Timber for Ruby is an optional upgrade you can install for Ruby apps on the
17
17
  [Timber.io logging platform](https://timber.io). Instead of completely replacing your log messages,
18
- Timber automatically augments your logs with JSON metadata. Essentially turning them into
18
+ Timber efficiently augments your logs with critical metadata. Turning them into
19
19
  [rich events with context](https://timber.io/docs/ruby/events-and-context). This preserves the
20
- readability of your logs while still dramatically improving the quality of your data.
21
- The end result: better logging and faster problem solving.
20
+ readability of your logs while still adding the critical context needed to properly analyze your
21
+ logs.
22
22
 
23
23
 
24
24
  ## How it works
@@ -61,21 +61,6 @@ For a complete overview, see the [Timber for Ruby docs](https://timber.io/docs/r
61
61
  3. In your `shell`, run `bundle exec timber install`
62
62
 
63
63
 
64
- ## Configuration
65
-
66
- All configuration options can be seen in the
67
- [`Timber::Config docs`](http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config).
68
- Here are a few popular options:
69
-
70
- 1. `config.timber.format =`
71
-
72
- * `:default` - This is the default. It's the original, default, unchanged log messages.
73
-
74
- * `:lograge` - Works exactly like [lograge](https://github.com/roidrage/lograge), except Timber's
75
- additional context and metadata is also appended. Lograge++.
76
-
77
-
78
-
79
64
  ## Usage
80
65
 
81
66
  <details><summary><strong>Basic logging</strong></summary><p>
@@ -88,8 +73,6 @@ logger.info("My log message")
88
73
  # => My log message @metadata {"level": "info", "context": {...}}
89
74
  ```
90
75
 
91
- Timber will *never* deviate from the public `::Logger` interface in *any* way.
92
-
93
76
  ---
94
77
 
95
78
  </p></details>
@@ -100,7 +83,7 @@ Custom events allow you to extend beyond events already defined in
100
83
  the [`Timber::Events`](lib/timber/events) namespace.
101
84
 
102
85
  ```ruby
103
- Logger.warn "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
86
+ logger.warn "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
104
87
 
105
88
  # => Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
106
89
  ```
@@ -120,7 +103,7 @@ Custom contexts allow you to extend beyond contexts already defined in
120
103
  the [`Timber::Contexts`](lib/timber/contexts) namespace.
121
104
 
122
105
  ```ruby
123
- Timber::CurrentContext.with({build: {version: "1.0.0"}}) do
106
+ logger.with_context(build: {version: "1.0.0"}) do
124
107
  logger.info("My log message")
125
108
  end
126
109
 
@@ -0,0 +1,122 @@
1
+ require 'benchmark'
2
+ require 'benchmark-memory'
3
+ require 'bundler/setup'
4
+ require 'rails'
5
+ require 'action_controller'
6
+
7
+ io = StringIO.new # ensure we are logging to something
8
+ logger = Logger.new(io)
9
+ logger.level = Logger::DEBUG
10
+ Rails.logger = logger
11
+
12
+ #
13
+ # Setup
14
+ #
15
+
16
+ # Setup the rails app to test
17
+ class RailsApp < Rails::Application
18
+ if ::Rails.version =~ /^3\./
19
+ config.secret_token = '1e05af2b349457936a41427e63450937'
20
+ else
21
+ config.secret_key_base = '1e05af2b349457936a41427e63450937'
22
+ end
23
+
24
+ # This ensures our tests fail, otherwise exceptions get swallowed by ActionDispatch::DebugExceptions
25
+ config.action_dispatch.show_exceptions = false
26
+ config.active_support.deprecation = :stderr
27
+ config.eager_load = false
28
+ end
29
+
30
+ # Create a controller to test against
31
+ class HomeController < ActionController::Base
32
+ layout nil
33
+
34
+ def index
35
+ render json: {}
36
+ end
37
+
38
+ def method_for_action(action_name)
39
+ action_name
40
+ end
41
+ end
42
+
43
+ # Define the routes
44
+ ::RailsApp.routes.draw do
45
+ get '/' => 'home#index'
46
+ end
47
+
48
+ # Initialize the app
49
+ RailsApp.initialize!
50
+
51
+ # Helper function to issue requests.
52
+ def dispatch_rails_request(path, additional_env_options = {})
53
+ application = ::Rails.application
54
+ env = application.respond_to?(:env_config) ? application.env_config.clone : application.env_defaults.clone
55
+ env["rack.request.cookie_hash"] = {}.with_indifferent_access
56
+ env["REMOTE_ADDR"] = "123.456.789.10"
57
+ env["HTTP_X_REQUEST_ID"] = "unique-request-id-1234"
58
+ env["action_dispatch.request_id"] = env["HTTP_X_REQUEST_ID"]
59
+ env = env.merge(additional_env_options)
60
+ ::Rack::MockRequest.new(application).get(path, env)
61
+ end
62
+
63
+ # How many iterations to perform
64
+ iterations = 1_000
65
+
66
+ puts "############################################################"
67
+ puts ""
68
+ puts "Testing Without Timber (#{iterations} iterations)"
69
+ puts ""
70
+ puts "############################################################"
71
+ puts
72
+
73
+ # Use bmbm to mimimize initial GC differences.
74
+ puts "Timing via benchmark:"
75
+ puts ""
76
+
77
+ Benchmark.bmbm do |x|
78
+ x.report("Without Timber") { iterations.times { dispatch_rails_request("/") } }
79
+ end
80
+
81
+ puts "\n"
82
+ puts "Memory profiling via benchmark-memory:"
83
+ puts
84
+
85
+ Benchmark.memory do |x|
86
+ x.report("Without Timber") { iterations.times { dispatch_rails_request("/") } }
87
+ end
88
+
89
+ puts "\n\n\n\n"
90
+ puts "############################################################"
91
+ puts ""
92
+ puts "Testing With Timber (#{iterations} iterations)"
93
+ puts ""
94
+ puts "############################################################"
95
+ puts ""
96
+
97
+ # Integrate Timber (this is handled in our Railtie, but we cna't use that here since we already
98
+ # initialized the app.)
99
+ require 'timber'
100
+ io = StringIO.new # ensure we are logging to something
101
+ logger = Timber::Logger.new(io)
102
+ logger.level = Logger::DEBUG
103
+ Timber::Frameworks::Rails.set_logger(logger)
104
+ Timber::Frameworks::Rails.configure_middlewares(Rails.application.config.app_middleware)
105
+ Timber::Integrations.integrate!
106
+ Timber::Config.instance.append_metadata = false
107
+
108
+
109
+ puts "Timing via benchmark:"
110
+ puts ""
111
+
112
+ Benchmark.bmbm do |x|
113
+ x.report("With Timber") { iterations.times { dispatch_rails_request("/") } }
114
+ end
115
+
116
+ puts "\n"
117
+ puts "Memory profiling via benchmark-memory:"
118
+ puts ""
119
+
120
+ Benchmark.memory do |x|
121
+ x.report("With Timber") { iterations.times { dispatch_rails_request("/") } }
122
+ end
@@ -44,6 +44,13 @@ module Timber
44
44
  yield iteration
45
45
  end
46
46
 
47
+ case iteration
48
+ when 0
49
+ event!(:waiting_for_logs)
50
+ when 30
51
+ event!(:excessively_waiting_for_logs)
52
+ end
53
+
47
54
  sleep 0.5
48
55
 
49
56
  res = get!(HAS_LOGS_PATH)
@@ -29,10 +29,10 @@ module Timber
29
29
  puts Messages.application_details(app)
30
30
  puts ""
31
31
 
32
- case ask_yes_no("Are the above details correct?")
32
+ case ask_yes_no("Are the above details correct?", api)
33
33
  when :yes
34
34
  if app.heroku?
35
- update_environment_config("production", :stdout)
35
+ update_environment_config("production", :stdout, api)
36
36
 
37
37
  puts ""
38
38
  puts Messages.separator
@@ -40,7 +40,7 @@ module Timber
40
40
  puts Messages.heroku_install(app)
41
41
  puts ""
42
42
 
43
- ask_yes_no("Ready to proceed?")
43
+ ask_yes_no("Ready to proceed?", api)
44
44
  puts ""
45
45
 
46
46
  else
@@ -53,19 +53,19 @@ module Timber
53
53
  puts "2) Configuring in my app"
54
54
  puts ""
55
55
 
56
- case ask("Enter your choice: (1/2) ")
56
+ case ask("Enter your choice: (1/2) ", api)
57
57
  when "1"
58
- update_environment_config("production", :http, :api_key_code => "ENV['TIMBER_API_KEY']")
58
+ update_environment_config("production", :http, api, :api_key_code => "ENV['TIMBER_API_KEY']")
59
59
 
60
60
  puts ""
61
61
  puts Messages.http_environment_variables(app.api_key)
62
62
  puts ""
63
63
 
64
- ask_yes_no("Ready to proceed?")
64
+ ask_yes_no("Ready to proceed?", api)
65
65
  puts ""
66
66
 
67
67
  when "2"
68
- update_environment_config("production", :http, :api_key_code => "'#{app.api_key}'")
68
+ update_environment_config("production", :http, api, :api_key_code => "'#{app.api_key}'")
69
69
 
70
70
  end
71
71
 
@@ -107,7 +107,7 @@ module Timber
107
107
  end
108
108
 
109
109
  private
110
- def update_environment_config(name, log_device_type, options = {})
110
+ def update_environment_config(name, log_device_type, api, options = {})
111
111
  path = File.join("config", "environments", "#{name}.rb")
112
112
 
113
113
  puts ""
@@ -146,6 +146,7 @@ CODE
146
146
  if !current_contents.include?("Timber::Logger.new")
147
147
  new_contents = current_contents.sub(/\nend/, "\n\n#{logger_code}\nend")
148
148
  File.write(path, new_contents)
149
+ api.event!(:file_written, path: path)
149
150
  end
150
151
 
151
152
  puts colorize(Messages.task_complete(task_message), :green)
@@ -156,7 +157,9 @@ CODE
156
157
 
157
158
  http_device = LogDevices::HTTP.new(api_key)
158
159
  logger = Logger.new(http_device)
159
- logger.info("test")
160
+ logger.info("Welcome to Timber!")
161
+ logger.info("This is a test log to ensure the pipes are working")
162
+ logger.info("Be sure to commit and deploy your app to start seeing real logs")
160
163
 
161
164
  puts colorize(Messages.task_complete("Sending test logs"), :green)
162
165
  end
@@ -165,7 +168,9 @@ CODE
165
168
  puts ""
166
169
  puts Messages.separator
167
170
  puts ""
168
- rating = ask("How would rate this install experience? 1 (bad) - 5 (perfect)")
171
+
172
+ rating = ask("How would rate this install experience? 1 (bad) - 5 (perfect)", api)
173
+
169
174
  case rating
170
175
  when "4", "5"
171
176
  api.event!(:feedback, rating: rating.to_i)
@@ -177,7 +182,7 @@ CODE
177
182
  puts Messages.bad_experience_message
178
183
  puts ""
179
184
 
180
- comments = ask("Type your comments (enter sends)")
185
+ comments = ask("Type your comments (enter sends)", api)
181
186
 
182
187
  api.event!(:feedback, rating: rating.to_i, comments: comments)
183
188
 
@@ -1,20 +1,26 @@
1
1
  module Timber
2
2
  class CLI
3
3
  module IOHelper
4
- def ask(message)
4
+ def ask(message, api)
5
+ api.event!(:waiting_for_input, prompt: message)
6
+
5
7
  write message + " "
6
- gets
8
+ input = gets
9
+
10
+ api.event!(:received_input, prompt: message, value: input)
11
+
12
+ input
7
13
  end
8
14
 
9
- def ask_yes_no(message)
10
- case ask(message + " (y/n)")
15
+ def ask_yes_no(message, api)
16
+ case ask(message + " (y/n)", api)
11
17
  when "y", "Y"
12
18
  :yes
13
19
  when "n", "N"
14
20
  :no
15
21
  else
16
22
  puts "Woops! That's not a valid input. Please try again."
17
- ask_yes_no(message)
23
+ ask_yes_no(message, api)
18
24
  end
19
25
  end
20
26
 
@@ -45,8 +45,7 @@ message.rstrip
45
45
  message = <<-MESSAGE
46
46
  Last step! Commit and deploy:
47
47
 
48
- #{colorize("git add config/initializers/timber.rb", :blue)}
49
- #{colorize("git commit -am 'Install Timber'", :blue)}
48
+ #{colorize("git commit -m 'Install Timber' config/environments/production.rb", :blue)}
50
49
 
51
50
  #{colorize("push and deploy", :blue)} 🚀
52
51
  MESSAGE
@@ -3,8 +3,7 @@ module Timber
3
3
  # Custom contexts allow you to add application specific context not covered elsewhere.
4
4
  #
5
5
  # @example Adding a context
6
- # custom_context = Timber::Contexts::Custom.new(type: :keyspace, data: %{my: "data"})
7
- # Timber::CurrentContext.with(custom_context) do
6
+ # logger.with_context(build: {version: "1.0.0"}) do
8
7
  # # ... anything logged here will have the context ...
9
8
  # end
10
9
  class Custom < Context
@@ -10,7 +10,7 @@ module Timber
10
10
  # Example:
11
11
  #
12
12
  # organization_context = Timber::Contexts::Organization.new(id: "abc1234", name: "Timber Inc")
13
- # Timber::CurrentContext.with(organization_context) do
13
+ # logger.with_context(organization_context) do
14
14
  # # Logging will automatically include this context
15
15
  # logger.info("This is a log message")
16
16
  # end
@@ -13,7 +13,7 @@ module Timber
13
13
  @headers = Util::HTTPEvent.normalize_headers(attributes[:headers])
14
14
  @host = attributes[:host] || raise(ArgumentError.new(":host is required"))
15
15
  @method = Util::HTTPEvent.normalize_method(attributes[:method]) || raise(ArgumentError.new(":method is required"))
16
- @path = attributes[:path] || raise(ArgumentError.new(":path is required"))
16
+ @path = attributes[:path]
17
17
  @port = attributes[:port]
18
18
  @query_string = Util::HTTPEvent.normalize_query_string(attributes[:query_string])
19
19
  @request_id = attributes[:request_id]
@@ -13,7 +13,7 @@ module Timber
13
13
  @headers = Util::HTTPEvent.normalize_headers(attributes[:headers])
14
14
  @host = attributes[:host] || raise(ArgumentError.new(":host is required"))
15
15
  @method = Util::HTTPEvent.normalize_method(attributes[:method]) || raise(ArgumentError.new(":method is required"))
16
- @path = attributes[:path] || raise(ArgumentError.new(":path is required"))
16
+ @path = attributes[:path]
17
17
  @port = attributes[:port]
18
18
  @query_string = Util::HTTPEvent.normalize_query_string(attributes[:query_string])
19
19
  @scheme = attributes[:scheme] || raise(ArgumentError.new(":scheme is required"))
data/lib/timber/logger.rb CHANGED
@@ -212,6 +212,12 @@ module Timber
212
212
  super
213
213
  end
214
214
 
215
+ # Convenience method for adding context. Please see {{Timber::CurrentContext.with}} for
216
+ # a more detailed description and examples.
217
+ def with_context(context, &block)
218
+ Timber::CurrentContext.with(context, &block)
219
+ end
220
+
215
221
  # Backwards compatibility with older ActiveSupport::Logger versions
216
222
  Logger::Severity.constants.each do |severity|
217
223
  class_eval(<<-EOT, __FILE__, __LINE__ + 1)
@@ -34,7 +34,10 @@ module Timber
34
34
  if Config.instance.header_filters && Config.instance.header_filters.include?(k)
35
35
  h[k] = SANITIZED_VALUE
36
36
  else
37
- h[k] = v
37
+ # Force the header into a valid UTF-8 string, otherwise we will encounter
38
+ # encoding issues when we convert this data to json. Moreoever, if the
39
+ # data is already valid UTF-8 we don't pay a penalty.
40
+ h[k] = Timber::Util::String.normalize_to_utf8(v)
38
41
  end
39
42
  end
40
43
  end
@@ -0,0 +1,21 @@
1
+ module Timber
2
+ module Util
3
+ # @private
4
+ module String
5
+ UTF8 = "UTF-8".freeze
6
+
7
+ # @private
8
+ def self.normalize_to_utf8(string)
9
+ if string.encoding.to_s == UTF8
10
+ string
11
+ else
12
+ string.encode('UTF-8', {
13
+ :invalid => :replace,
14
+ :undef => :replace,
15
+ :replace => '?'
16
+ })
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/timber/util.rb CHANGED
@@ -3,6 +3,7 @@ require "timber/util/hash"
3
3
  require "timber/util/http_event"
4
4
  require "timber/util/object"
5
5
  require "timber/util/request"
6
+ require "timber/util/string"
6
7
  require "timber/util/struct"
7
8
 
8
9
  module Timber
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "2.0.7"
2
+ VERSION = "2.0.8"
3
3
  end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Timber::Events::HTTPServerRequest, :rails_23 => true do
6
+ describe ".initialize" do
7
+ context "with a header filters" do
8
+ around(:each) do |example|
9
+ old_header_filters = Timber::Config.instance.header_filters
10
+ Timber::Config.instance.header_filters += ['api-key']
11
+ example.run
12
+ Timber::Config.instance.header_filters = old_header_filters
13
+ end
14
+
15
+ it "should sanitize headers when a config option is set" do
16
+ event = described_class.new(:headers => {'Api-Key' => 'abcde'}, :host => 'my.host.com', :method => 'GET', :path => '/path', :scheme => 'https')
17
+ expect(event.headers).to eq({'api-key' => '[sanitized]'})
18
+ end
19
+ end
20
+
21
+ it "should handle header encoding" do
22
+ referer = 'http://www.metrojobb.se/jobb/1013893-skadeadministratör'.force_encoding('ASCII-8BIT')
23
+ event = described_class.new(:headers => {'Referer' => referer}, :host => 'my.host.com', :method => 'GET', :path => '/path', :scheme => 'https')
24
+ expect(event.headers["referer"].encoding.to_s).to eq("UTF-8")
25
+ end
26
+ end
27
+ end
@@ -1,9 +1,9 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Timber::LogEntry, :rails_23 => true do
4
- describe "#to_msgpack" do
5
- let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
4
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
5
 
6
+ describe "#to_msgpack" do
7
7
  it "should encode properly with an event and context" do
8
8
  event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: 1})
9
9
  context = {custom: Timber::Contexts::Custom.new(type: :context_type, data: {b: 1})}
@@ -133,6 +133,27 @@ describe Timber::Logger, :rails_23 => true do
133
133
  end
134
134
  end
135
135
 
136
+ describe "#with_context" do
137
+ let(:io) { StringIO.new }
138
+ let(:logger) { Timber::Logger.new(io) }
139
+
140
+ it "should add context" do
141
+ expect(Timber::CurrentContext.hash).to eq({})
142
+
143
+ logger.with_context(build: {version: "1.0.0"}) do
144
+ expect(Timber::CurrentContext.hash).to eq({:custom=>{:build=>{:version=>"1.0.0"}}})
145
+
146
+ logger.with_context({testing: {key: "value"}}) do
147
+ expect(Timber::CurrentContext.hash).to eq({:custom=>{:build=>{:version=>"1.0.0"}, :testing=>{:key=>"value"}}})
148
+ end
149
+
150
+ expect(Timber::CurrentContext.hash).to eq({:custom=>{:build=>{:version=>"1.0.0"}}})
151
+ end
152
+
153
+ expect(Timber::CurrentContext.hash).to eq({})
154
+ end
155
+ end
156
+
136
157
  describe "#info" do
137
158
  let(:io) { StringIO.new }
138
159
  let(:logger) { Timber::Logger.new(io) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timber
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.7
4
+ version: 2.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timber Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-29 00:00:00.000000000 Z
11
+ date: 2017-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -137,6 +137,7 @@ files:
137
137
  - Gemfile
138
138
  - LICENSE.md
139
139
  - README.md
140
+ - benchmarks/rails.rb
140
141
  - bin/timber
141
142
  - gemfiles/rails-3.0.gemfile
142
143
  - gemfiles/rails-3.1.gemfile
@@ -208,6 +209,7 @@ files:
208
209
  - lib/timber/util/http_event.rb
209
210
  - lib/timber/util/object.rb
210
211
  - lib/timber/util/request.rb
212
+ - lib/timber/util/string.rb
211
213
  - lib/timber/util/struct.rb
212
214
  - lib/timber/version.rb
213
215
  - spec/README.md
@@ -229,6 +231,7 @@ files:
229
231
  - spec/timber/current_context_spec.rb
230
232
  - spec/timber/event_spec.rb
231
233
  - spec/timber/events/custom_spec.rb
234
+ - spec/timber/events/http_server_request_spec.rb
232
235
  - spec/timber/events_spec.rb
233
236
  - spec/timber/integrations/action_controller/log_subscriber_spec.rb
234
237
  - spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb
@@ -283,6 +286,7 @@ test_files:
283
286
  - spec/timber/current_context_spec.rb
284
287
  - spec/timber/event_spec.rb
285
288
  - spec/timber/events/custom_spec.rb
289
+ - spec/timber/events/http_server_request_spec.rb
286
290
  - spec/timber/events_spec.rb
287
291
  - spec/timber/integrations/action_controller/log_subscriber_spec.rb
288
292
  - spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb