timber 2.1.0.rc2 → 2.1.0.rc3

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: afb17c6cddef2161cdea1673f0ff79a60e0738d9
4
- data.tar.gz: 2ff32da4c3329a55a0c7c8a76c56c165fd2d7459
3
+ metadata.gz: 5f1b00e64f1666ef47d33c347cea42bcc4d7b262
4
+ data.tar.gz: cbde1d3d51a40c4e08eb3357f8d1fa72beae5d19
5
5
  SHA512:
6
- metadata.gz: f9c7f09df8f61f7c3d97c589a098e5db6bc4d785ca52e01b70d21d382a3c662b7802b7fc05a63b8e83f495b8e0fdef0a878b439a42e3b2edce161e1320d21610
7
- data.tar.gz: 565dc4e47de83e6f430828a2d953a9071f1398ce062cfe4ff3375b064ca721bdcd5dea47c70e4492c28c2449ac36591e77e0fe50f63c7efec82193a8def471e3
6
+ metadata.gz: 374705c1b1a8f0e0091d92a4ee0186246af3126a8c4e5e5358591deac6a1f2174052347350d42d1c8d1e79548a9a159438e39bdcbc95a2753182d5b52f18b921
7
+ data.tar.gz: baa0ba4b26cc7157710213635f12750da54ee3bde50e7b1fdac74a06da5ba2b1314c66db5aa258cfd8a170d4299b4f866520ba9a63a31a6ee39f200f95c9331e
data/README.md CHANGED
@@ -329,7 +329,8 @@ logger.formatter = Timber::Logger::JSONFormatter.new
329
329
  Your options are:
330
330
 
331
331
  1. [`Timber::Logger::AugmentedFormatter`](http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Logger/AugmentedFormatter) -
332
- (default) A human readable format that _appends_ metadata to the original log line.
332
+ (default) A human readable format that _appends_ metadata to the original log line. The Timber
333
+ service can parse this data appropriately.
333
334
  Ex: `My log message @metadata {"level":"info","dt":"2017-01-01T01:02:23.234321Z"}`
334
335
 
335
336
  2. [`Timber::Logger::JSONFormatter`](http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Logger/JSONFormatter) -
@@ -397,7 +398,7 @@ All variables are optional, but at least one must be present.
397
398
 
398
399
  ## Jibber-Jabber
399
400
 
400
- <details><summary><strong>Which events and context does Timber capture for me?</strong></summary><p>
401
+ <details><summary><strong>Which events and contexts does Timber capture for me?</strong></summary><p>
401
402
 
402
403
  Out of the box you get everything in the
403
404
  [`Timber::Events`](http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Events) namespace.
@@ -408,13 +409,31 @@ namespace. Context is structured data representing the current environment when
408
409
  was written. It is included in every log line. Think of it like join data for your logs. It's
409
410
  how Timber is able to accomplished tailing users (`context.user.id:1`).
410
411
 
411
- Lastly, you can checkout the specific integrations in
412
+ Lastly, you can checkout how we capture these events in
412
413
  [`Timber::Integrations`](lib/timber/integrations).
413
414
 
414
415
  ---
415
416
 
416
417
  </p></details>
417
418
 
419
+ <details><summary><strong>Won't this increase the size of my log data?</strong></summary><p>
420
+
421
+ Yes. In terms of size, it's no different than adding tags to your logs or any other useful
422
+ data. A few things to point out though:
423
+
424
+ 1. Timber generally _reduces_ the amount of logs your app generates by providing options to
425
+ consolidate request / response logs, template logs, and even silence logs that are not
426
+ of value to you. (see [configuration](#configuration) for examples).
427
+ 2. Your log provider should be compressing your data and charging you accordingly. Log data
428
+ is notoriously repetitive, and the context Timber generates is repetitive as well.
429
+ Because of compression we've seen somes apps only incur a 10% increase in data size.
430
+
431
+ Finally, log what is useful to you. Quality over quantity certainly applies to logging.
432
+
433
+ ---
434
+
435
+ </p></details>
436
+
418
437
  <details><summary><strong>What about my current log statements?</strong></summary><p>
419
438
 
420
439
  They'll continue to work as expected. Timber adheres to the default `::Logger` interface.
@@ -15,6 +15,14 @@ module Timber
15
15
  end
16
16
 
17
17
  private
18
+ def get_delivery_strategy(app)
19
+ if app.heroku?
20
+ :stdout
21
+ else
22
+ :http
23
+ end
24
+ end
25
+
18
26
  # Determines the API key storage prference (environment variable or inline)
19
27
  def get_api_key_storage_preference
20
28
  io.puts ""
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require "timber/cli/api"
2
4
  require "timber/cli/installers/root"
3
5
  require "timber/cli/io/messages"
@@ -14,13 +16,41 @@ module Timber
14
16
  io.puts ""
15
17
 
16
18
  if !api_key
17
- io.puts IO::Messages.no_api_key_provided
19
+ app_url = IO::Messages::APP_URL
20
+
21
+ io.puts "Hey there! Welcome to Timber. In order to proceed, you'll need an API key."
22
+ io.puts "You can grab one by registering at #{IO::ANSI.colorize(app_url, :blue)}."
23
+ io.puts ""
24
+ io.puts "It takes less than a minute, with one click Google and Github registration."
25
+ io.puts ""
18
26
 
19
- case io.ask_yes_no("Open the Timber app in your brower now?")
20
- when :yes
21
- OSHelper.open(IO::Messages::APP_URL)
27
+ if OSHelper.can_open?
28
+ case io.ask_yes_no("Open #{app_url}?")
29
+ when :yes
30
+ puts ""
31
+ io.task("Opening #{app_url}") do
32
+ OSHelper.open(app_url)
33
+ end
34
+ when :no
35
+ io.puts ""
36
+ io.puts "No problem, navigate to the following URL:"
37
+ io.puts ""
38
+ io.puts " #{IO::ANSI.colorize(app_url, :blue)}"
39
+ end
40
+ else
41
+ io.puts ""
42
+ io.puts "Please navigate to:"
43
+ io.puts ""
44
+ io.puts " #{IO::ANSI.colorize(app_url, :blue)}"
22
45
  end
23
46
 
47
+ io.puts ""
48
+ io.puts "Once you obtain your API key, you can run the installer like"
49
+ io.puts ""
50
+ io.puts " #{IO::ANSI.colorize("bundle exec timber my-api-key", :blue)}"
51
+ io.puts ""
52
+ io.puts "See you soon! 🎈"
53
+ io.puts ""
24
54
  else
25
55
  api = API.new(api_key)
26
56
  api.event(:started)
@@ -6,40 +6,47 @@ module Timber
6
6
  module Installers
7
7
  class Other < Installer
8
8
  def run(app)
9
- puts ""
10
- puts IO::Messages.separator
11
- puts ""
12
-
13
9
  if app.heroku?
14
10
  install_stdout
15
11
  else
16
12
  api_key_storage_preference = get_api_key_storage_preference
17
- api_key_code = get_api_key_code(api_key_storage_type)
18
-
13
+ api_key_code = get_api_key_code(api_key_storage_preference)
19
14
  install_http(api_key_code)
20
15
  end
16
+
17
+ io.puts ""
18
+ io.puts IO::Messages.separator
19
+ io.puts ""
20
+ io.puts "We're going to send a few test messages to ensure communication is working."
21
+ io.puts ""
22
+ io.ask_to_proceed
23
+ io.puts ""
21
24
  end
22
25
 
23
26
  private
24
27
  def install_stdout
25
- puts ""
26
- puts IO::Messages.separator
27
- puts ""
28
- puts "To integrate Timber, we need to instantiate the logger. Your global"
29
- puts "logger should be set to something like this:"
30
- puts ""
31
- puts colorize(" LOGGER = Timber::Logger.new(STDOUT)", :blue)
28
+ io.puts ""
29
+ io.puts IO::Messages.separator
30
+ io.puts ""
31
+ io.puts "To integrate Timber, simply use the Timber::Logger. Just set your"
32
+ io.puts "global logger to something like this:"
33
+ io.puts ""
34
+ io.puts IO::ANSI.colorize(" LOGGER = Timber::Logger.new(STDOUT)", :blue)
35
+ io.puts ""
36
+ io.ask_to_proceed
32
37
  end
33
38
 
34
39
  def install_http(api_key_code)
35
- puts ""
36
- puts IO::Messages.separator
37
- puts ""
38
- puts "To integrate Timber, we need to instantiate the logger. Your global"
39
- puts "logger should be set to something like this:"
40
- puts ""
41
- puts colorize(" log_device = Timber::LogDevices::HTTP.new(#{api_key_code})", :blue)
42
- puts colorize(" LOGGER = Timber::Logger.new(log_device)", :blue)
40
+ io.puts ""
41
+ io.puts IO::Messages.separator
42
+ io.puts ""
43
+ io.puts "To integrate Timber, simply use the Timber::Logger. Just set your"
44
+ io.puts "global logger to something like this:"
45
+ io.puts ""
46
+ io.puts IO::ANSI.colorize(" log_device = Timber::LogDevices::HTTP.new(#{api_key_code})", :blue)
47
+ io.puts IO::ANSI.colorize(" LOGGER = Timber::Logger.new(log_device)", :blue)
48
+ io.puts ""
49
+ io.ask_to_proceed
43
50
  end
44
51
  end
45
52
  end
@@ -17,7 +17,13 @@ module Timber
17
17
  # Ask all of the questions up front. This allows us to to apply the
18
18
  # changes as a neat task list when done.
19
19
  development_preference = get_development_preference
20
- api_key_storage_preference = get_api_key_storage_preference
20
+
21
+ api_key_storage_preference = if get_delivery_strategy(app) == :http
22
+ get_api_key_storage_preference
23
+ else
24
+ nil
25
+ end
26
+
21
27
  should_logrageify = logrageify?
22
28
 
23
29
  io.puts ""
@@ -135,11 +141,11 @@ module Timber
135
141
  case development_preference
136
142
  when :send
137
143
  extra_comment = <<-NOTE
138
- # Note: When you are done testing, simply instantiate the logger like this:
139
- #
140
- # logger = Timber::Logger.new(STDOUT)
141
- #
142
- # Be sure to remove the "log_device =" and "logger =" lines below.
144
+ # Note: When you are done testing, simply instantiate the logger like this:
145
+ #
146
+ # logger = Timber::Logger.new(STDOUT)
147
+ #
148
+ # Be sure to remove the "log_device =" and "logger =" lines below.
143
149
  NOTE
144
150
  extra_comment = extra_comment.rstrip
145
151
  install_http(environment_file_path, :inline, extra_comment: extra_comment)
@@ -166,10 +172,11 @@ NOTE
166
172
  return true
167
173
  end
168
174
 
169
- if app.heroku?
170
- install_stdout(environment_file_path)
171
- else
175
+ case get_delivery_strategy(app)
176
+ when :http
172
177
  install_http(environment_file_path, api_key_storage_preference)
178
+ when :stdout
179
+ install_stdout(environment_file_path)
173
180
  end
174
181
  end
175
182
 
@@ -1,7 +1,7 @@
1
1
  module Timber
2
2
  class CLI
3
3
  module OSHelper
4
- def self.copy_to_clipboard?
4
+ def self.can_copy_to_clipboard?
5
5
  `which pbcopy` != ""
6
6
  rescue Exception
7
7
  false
@@ -34,20 +34,33 @@ module Timber
34
34
  end
35
35
  end
36
36
 
37
+ def self.can_open?
38
+ begin
39
+ `which #{open_command}` != ""
40
+ rescue Exception
41
+ false
42
+ end
43
+ end
44
+
37
45
  # Attemps to open a URL in the user's default browser across
38
46
  # the popular operating systems.
39
47
  def self.open(link)
40
- if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
41
- system "start #{link}"
42
- elsif RbConfig::CONFIG['host_os'] =~ /darwin/
43
- system "open #{link}"
44
- elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
45
- system "xdg-open #{link}"
46
- end
48
+ `#{open_command} #{link}`
47
49
  true
48
50
  rescue Exception
49
51
  false
50
52
  end
53
+
54
+ private
55
+ def self.open_command
56
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
57
+ "start"
58
+ elsif RbConfig::CONFIG['host_os'] =~ /darwin/
59
+ "open"
60
+ elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
61
+ "xdg-open"
62
+ end
63
+ end
51
64
  end
52
65
  end
53
66
  end
@@ -25,8 +25,10 @@ module Timber
25
25
  end
26
26
  end
27
27
 
28
+ DEVELOPMENT_NAME = "development".freeze
28
29
  PRODUCTION_NAME = "production".freeze
29
30
  STAGING_NAME = "staging".freeze
31
+ TEST_NAME = "test".freeze
30
32
 
31
33
  include Singleton
32
34
 
@@ -37,10 +39,22 @@ module Timber
37
39
  @http_body_limit = 2000
38
40
  end
39
41
 
42
+ # Convenience method for logging debug statements to the debug logger
43
+ # set in this class.
44
+ # @private
45
+ def debug(&block)
46
+ debug_logger = Config.instance.debug_logger
47
+ if debug_logger
48
+ message = yield
49
+ debug_logger.debug(message)
50
+ end
51
+ true
52
+ end
53
+
40
54
  # This is useful for debugging. This Sets a debug_logger to view internal Timber library
41
55
  # log messages. The default is `nil`. Meaning log to nothing.
42
56
  #
43
- # See {#debug_to_file} and {#debug_to_stdout} for convenience methods that handle creating
57
+ # See {#debug_to_file!} and {#debug_to_stdout!} for convenience methods that handle creating
44
58
  # and setting the logger.
45
59
  #
46
60
  # @example Rails
@@ -59,10 +73,10 @@ module Timber
59
73
  # A convenience method for writing internal Timber debug messages to a file.
60
74
  #
61
75
  # @example Rails
62
- # config.timber.debug_to_file("#{Rails.root}/log/timber.log")
76
+ # config.timber.debug_to_file!("#{Rails.root}/log/timber.log")
63
77
  # @example Everything else
64
- # Timber::Config.instance.debug_to_file("log/timber.log")
65
- def debug_to_file(file_path)
78
+ # Timber::Config.instance.debug_to_file!("log/timber.log")
79
+ def debug_to_file!(file_path)
66
80
  unless File.exist? File.dirname path
67
81
  FileUtils.mkdir_p File.dirname path
68
82
  end
@@ -77,10 +91,10 @@ module Timber
77
91
  # A convenience method for writing internal Timber debug messages to STDOUT.
78
92
  #
79
93
  # @example Rails
80
- # config.timber.debug_to_stdout
94
+ # config.timber.debug_to_stdout!
81
95
  # @example Everything else
82
- # Timber::Config.instance.debug_to_stdout
83
- def debug_to_stdout
96
+ # Timber::Config.instance.debug_to_stdout!
97
+ def debug_to_stdout!
84
98
  stdout_logger = ::Logger.new(STDOUT)
85
99
  stdout_logger.formatter = SimpleLogFormatter.new
86
100
  self.debug_logger = stdout_logger
@@ -203,6 +217,16 @@ module Timber
203
217
  end
204
218
  end
205
219
 
220
+ # @private
221
+ def development?
222
+ environment == DEVELOPMENT_NAME
223
+ end
224
+
225
+ # @private
226
+ def test?
227
+ environment == TEST_NAME
228
+ end
229
+
206
230
  # @private
207
231
  def production?
208
232
  environment == PRODUCTION_NAME
@@ -1,3 +1,4 @@
1
+ require "timber/config"
1
2
  require "timber/context"
2
3
  require "timber/util"
3
4
 
@@ -22,8 +23,10 @@ module Timber
22
23
  version = ENV['RELEASE_VERSION'] || ENV['HEROKU_RELEASE_VERSION']
23
24
 
24
25
  if commit_hash || created_at || version
26
+ Timber::Config.instance.debug { "Release env vars detected, adding to context" }
25
27
  new(commit_hash: commit_hash, created_at: created_at, version: version)
26
28
  else
29
+ Timber::Config.instance.debug { "Release env vars _not_ detected" }
27
30
  nil
28
31
  end
29
32
  end
@@ -1,5 +1,4 @@
1
- require "singleton"
2
-
1
+ require "timber/config"
3
2
  require "timber/contexts/release"
4
3
 
5
4
  module Timber
@@ -10,11 +9,15 @@ module Timber
10
9
  # @note Because context is appended to every log line, it is recommended that you limit this
11
10
  # to only neccessary data needed to relate your log lines.
12
11
  class CurrentContext
13
- include Singleton
14
-
15
12
  THREAD_NAMESPACE = :_timber_current_context.freeze
16
13
 
17
14
  class << self
15
+ # Impelements the Singleton pattern in a thread specific way. Each thread receives
16
+ # its own context.
17
+ def instance
18
+ Thread.current[THREAD_NAMESPACE] ||= new
19
+ end
20
+
18
21
  # Convenience method for {CurrentContext#with}. See {CurrentContext#with} for more info.
19
22
  def with(*args, &block)
20
23
  instance.with(*args, &block)
@@ -41,17 +44,6 @@ module Timber
41
44
  end
42
45
  end
43
46
 
44
- # Instantiates a new object, automatically adding context based on env variables (if present).
45
- # For example, the {Contexts::ReleaseContext} is automatically added if the proper environment
46
- # variables are present. Please see that class for more details.
47
- def initialize
48
- super
49
- release_context = Contexts::Release.from_env
50
- if release_context
51
- add(release_context)
52
- end
53
- end
54
-
55
47
  # Adds a context and then removes it when the block is finished executing.
56
48
  #
57
49
  # @note Because context is included with every log line, it is recommended that you limit this
@@ -89,16 +81,7 @@ module Timber
89
81
  # to only neccessary data.
90
82
  def add(*objects)
91
83
  objects.each do |object|
92
- context = Contexts.build(object) # Normalizes objects into a Timber::Context descendant.
93
- key = context.keyspace
94
- json = context.as_json # Convert to json now so that we aren't doing it for every line
95
- if key == :custom
96
- # Custom contexts are merged into the space
97
- hash[key] ||= {}
98
- hash[key].merge!(json)
99
- else
100
- hash[key] = json
101
- end
84
+ add_to(hash, object)
102
85
  end
103
86
  expire_cache!
104
87
  self
@@ -151,7 +134,33 @@ module Timber
151
134
  private
152
135
  # The internal hash that is maintained. Use {#with} and {#add} for hash maintenance.
153
136
  def hash
154
- Thread.current[THREAD_NAMESPACE] ||= {}
137
+ @hash ||= build_initial_hash
138
+ end
139
+
140
+ # Builds the initial hash. This is extract into a method to support a threaded
141
+ # environment. Each thread holds it's own context and also needs to instantiate
142
+ # it's hash properly.
143
+ def build_initial_hash
144
+ new_hash = {}
145
+ release_context = Contexts::Release.from_env
146
+ if release_context
147
+ add_to(new_hash, release_context)
148
+ end
149
+ new_hash
150
+ end
151
+
152
+ def add_to(hash, object)
153
+ context = Contexts.build(object) # Normalizes objects into a Timber::Context descendant.
154
+ key = context.keyspace
155
+ json = context.as_json # Convert to json now so that we aren't doing it for every line
156
+ if key == :custom
157
+ # Custom contexts are merged into the space
158
+ hash[key] ||= {}
159
+ hash[key].merge!(json)
160
+ else
161
+ hash[key] = json
162
+ end
163
+ hash
155
164
  end
156
165
 
157
166
  # Hook to clear any caching implement in this class
@@ -1,9 +1,15 @@
1
1
  begin
2
+ # Rails 3.2 requires you to require all of Rails before requiring
3
+ # the exception wrapper.
4
+ require "rails"
2
5
  require "action_dispatch/middleware/exception_wrapper"
3
6
  rescue Exception
4
7
  end
5
8
 
9
+ require "timber/config"
10
+ require "timber/events/exception"
6
11
  require "timber/integrations/rack/middleware"
12
+ require "timber/util"
7
13
 
8
14
  module Timber
9
15
  module Integrations
@@ -1,4 +1,7 @@
1
+ require "timber/contexts/http"
2
+ require "timber/current_context"
1
3
  require "timber/integrations/rack/middleware"
4
+ require "timber/util"
2
5
 
3
6
  module Timber
4
7
  module Integrations
@@ -1,5 +1,10 @@
1
1
  require "set"
2
2
 
3
+ require "timber/config"
4
+ require "timber/contexts/http"
5
+ require "timber/current_context"
6
+ require "timber/events/http_server_request"
7
+ require "timber/events/http_server_response"
3
8
  require "timber/integrations/rack/middleware"
4
9
 
5
10
  module Timber
@@ -1,3 +1,10 @@
1
+ begin
2
+ require "rails"
3
+ rescue Exception
4
+ end
5
+
6
+ require "timber/config"
7
+ require "timber/contexts/session"
1
8
  require "timber/integrations/rack/middleware"
2
9
 
3
10
  module Timber
@@ -9,7 +16,7 @@ module Timber
9
16
  def call(env)
10
17
  id = get_session_id(env)
11
18
  if id
12
- context = Contexts::Session.new(id: get_session_id(env))
19
+ context = Contexts::Session.new(id: id)
13
20
  CurrentContext.with(context) do
14
21
  @app.call(env)
15
22
  end
@@ -20,15 +27,37 @@ module Timber
20
27
 
21
28
  private
22
29
  def get_session_id(env)
23
- if env['rack.session']
24
- begin
25
- env['rack.session'].id
26
- rescue Exception
30
+ if defined?(::Rails)
31
+ session_key = ::Rails.application.config.session_options[:key]
32
+ request = ::ActionDispatch::Request.new(env)
33
+ Timber::Config.instance.debug { "Rails detected, extracting session_id from cookie" }
34
+ extract_from_cookie(request, session_key)
35
+
36
+ elsif session = env['rack.session']
37
+ if session.respond_to?(:id)
38
+ Timber::Config.instance.debug { "Rack env session detected, using id attribute" }
39
+ session.id
40
+ elsif session.respond_to?(:[])
41
+ Timber::Config.instance.debug { "Rack env session detected, using the session_id key" }
42
+ session["session_id"]
43
+ else
44
+ Timber::Config.instance.debug { "Rack env session detected but could not extract id" }
27
45
  nil
28
46
  end
29
47
  else
48
+ Timber::Config.instance.debug { "No session data could be detected, skipping" }
49
+
30
50
  nil
31
51
  end
52
+ rescue Exception => e
53
+ nil
54
+ end
55
+
56
+ def extract_from_cookie(request, session_key)
57
+ data = request
58
+ .cookie_jar
59
+ .signed_or_encrypted[session_key] || {}
60
+ data["session_id"]
32
61
  end
33
62
  end
34
63
  end
@@ -1,3 +1,5 @@
1
+ require "timber/config"
2
+ require "timber/contexts/user"
1
3
  require "timber/integrations/rack/middleware"
2
4
 
3
5
  module Timber
@@ -79,20 +81,20 @@ module Timber
79
81
  # not return a user, in which case the user data might be in the omniauth
80
82
  # data.
81
83
  if self.class.custom_user_hash.is_a?(Proc)
82
- debug { "Obtaining user context from the custom user hash" }
84
+ Timber::Config.instance.debug { "Obtaining user context from the custom user hash" }
83
85
  self.class.custom_user_hash.call(env)
84
86
  elsif (auth_hash = env['omniauth.auth'])
85
- debug { "Obtaining user context from the omniauth auth hash" }
87
+ Timber::Config.instance.debug { "Obtaining user context from the omniauth auth hash" }
86
88
  get_omniauth_user_hash(auth_hash)
87
89
  elsif env[:clearance] && env[:clearance].signed_in?
88
- debug { "Obtaining user context from the clearance user" }
90
+ Timber::Config.instance.debug { "Obtaining user context from the clearance user" }
89
91
  user = env[:clearance].current_user
90
92
  get_user_object_hash(user)
91
93
  elsif env['warden'] && (user = env['warden'].user)
92
- debug { "Obtaining user context from the warden user" }
94
+ Timber::Config.instance.debug { "Obtaining user context from the warden user" }
93
95
  get_user_object_hash(user)
94
96
  else
95
- debug { "Could not locate any user data" }
97
+ Timber::Config.instance.debug { "Could not locate any user data" }
96
98
  nil
97
99
  end
98
100
  end
@@ -140,17 +142,6 @@ module Timber
140
142
  nil
141
143
  end
142
144
  end
143
-
144
- def debug_logger
145
- Timber::Config.instance.debug_logger
146
- end
147
-
148
- def debug(&block)
149
- if debug_logger
150
- message = yield
151
- debug_logger.debug(message)
152
- end
153
- end
154
145
  end
155
146
  end
156
147
  end
@@ -94,7 +94,7 @@ module Timber
94
94
  ensure_flush_threads_are_started
95
95
 
96
96
  if @msg_queue.full?
97
- debug { "Flushing HTTP buffer via write" }
97
+ Timber::Config.instance.debug { "Flushing HTTP buffer via write" }
98
98
  flush_async
99
99
  end
100
100
  true
@@ -122,18 +122,6 @@ module Timber
122
122
  end
123
123
 
124
124
  private
125
- def debug_logger
126
- Timber::Config.instance.debug_logger
127
- end
128
-
129
- # Convenience method for writing debug messages.
130
- def debug(&block)
131
- if debug_logger
132
- message = yield
133
- debug_logger.debug(message)
134
- end
135
- end
136
-
137
125
  # This is a convenience method to ensure the flush thread are
138
126
  # started. This is called lazily from {#write} so that we
139
127
  # only start the threads as needed, but it also ensures
@@ -172,7 +160,7 @@ module Timber
172
160
  @last_async_flush = Time.now
173
161
  req = build_request
174
162
  if !req.nil?
175
- debug { "New request placed on queue" }
163
+ Timber::Config.instance.debug { "New request placed on queue" }
176
164
  @request_queue.enq(req)
177
165
  end
178
166
  end
@@ -183,10 +171,10 @@ module Timber
183
171
  # Wait 20 seconds
184
172
  40.times do |i|
185
173
  if @request_queue.size == 0 && @requests_in_flight == 0
186
- debug { "Request queue is empty and no requests are in flight, finish waiting" }
174
+ Timber::Config.instance.debug { "Request queue is empty and no requests are in flight, finish waiting" }
187
175
  return true
188
176
  end
189
- debug do
177
+ Timber::Config.instance.debug do
190
178
  "Request size #{@request_queue.size}, reqs in-flight #{@requests_in_flight}, " \
191
179
  "continue waiting (iteration #{i + 1})"
192
180
  end
@@ -204,13 +192,13 @@ module Timber
204
192
  loop do
205
193
  begin
206
194
  if intervaled_flush_ready?
207
- debug { "Flushing HTTP buffer via the interval" }
195
+ Timber::Config.instance.debug { "Flushing HTTP buffer via the interval" }
208
196
  flush_async
209
197
  end
210
198
 
211
199
  sleep(0.5)
212
200
  rescue Exception => e
213
- debug { "Intervaled HTTP flush failed: #{e.inspect}\n\n#{e.backtrace}" }
201
+ Timber::Config.instance.debug { "Intervaled HTTP flush failed: #{e.inspect}\n\n#{e.backtrace}" }
214
202
  end
215
203
  end
216
204
  end
@@ -225,7 +213,7 @@ module Timber
225
213
  # Builds an `Net::HTTP` object to deliver requests over.
226
214
  def build_http
227
215
  http = Net::HTTP.new(@timber_url.host, @timber_url.port)
228
- http.set_debug_output(debug_logger) if debug_logger
216
+ http.set_debug_output(Config.instance.debug_logger) if Config.instance.debug_logger
229
217
  http.use_ssl = true if @timber_url.scheme == 'https'
230
218
  http.read_timeout = 30
231
219
  http.ssl_timeout = 10
@@ -239,15 +227,15 @@ module Timber
239
227
  http = build_http
240
228
 
241
229
  begin
242
- debug { "Starting HTTP connection" }
230
+ Timber::Config.instance.debug { "Starting HTTP connection" }
243
231
 
244
232
  http.start do |conn|
245
233
  deliver_requests(conn)
246
234
  end
247
235
  rescue => e
248
- debug { "#request_outlet error: #{e.message}" }
236
+ Timber::Config.instance.debug { "#request_outlet error: #{e.message}" }
249
237
  ensure
250
- debug { "Finishing HTTP connection" }
238
+ Timber::Config.instance.debug { "Finishing HTTP connection" }
251
239
  http.finish if http.started?
252
240
  end
253
241
  end
@@ -261,7 +249,7 @@ module Timber
261
249
  num_reqs = 0
262
250
 
263
251
  while num_reqs < @requests_per_conn
264
- debug { "Waiting on next request, threads waiting: #{@request_queue.num_waiting}" }
252
+ Timber::Config.instance.debug { "Waiting on next request, threads waiting: #{@request_queue.num_waiting}" }
265
253
 
266
254
  # Blocks waiting for a request.
267
255
  req = @request_queue.deq
@@ -270,7 +258,7 @@ module Timber
270
258
  begin
271
259
  resp = conn.request(req)
272
260
  rescue => e
273
- debug { "#deliver_request error: #{e.message}" }
261
+ Timber::Config.instance.debug { "#deliver_request error: #{e.message}" }
274
262
 
275
263
  @successive_error_count += 1
276
264
 
@@ -278,7 +266,7 @@ module Timber
278
266
  calculated_backoff = @successive_error_count * 2
279
267
  backoff = calculated_backoff > 30 ? 30 : calculated_backoff
280
268
 
281
- debug { "Backing off #{backoff} seconds, error ##{@successive_error_count}" }
269
+ Timber::Config.instance.debug { "Backing off #{backoff} seconds, error ##{@successive_error_count}" }
282
270
 
283
271
  sleep backoff
284
272
 
@@ -291,7 +279,7 @@ module Timber
291
279
 
292
280
  @successive_error_count = 0
293
281
  num_reqs += 1
294
- debug { "Request successful: #{resp.code}" }
282
+ Timber::Config.instance.debug { "Request successful: #{resp.code}" }
295
283
  end
296
284
  end
297
285
 
@@ -1,6 +1,7 @@
1
1
  require "logger"
2
2
  require "msgpack"
3
3
 
4
+ require "timber/config"
4
5
  require "timber/current_context"
5
6
  require "timber/event"
6
7
  require "timber/log_devices/http"
@@ -195,8 +196,12 @@ module Timber
195
196
  args.first.sync = true
196
197
  end
197
198
 
199
+ # Set the default formatter. The formatter cannot be set during
200
+ # initialization, and can be changed with #formatter=.
198
201
  if args.size == 1 and args.first.is_a?(LogDevices::HTTP)
199
202
  self.formatter = PassThroughFormatter.new
203
+ elsif Config.instance.development? || Config.instance.test?
204
+ self.formatter = MessageOnlyFormatter.new
200
205
  else
201
206
  self.formatter = AugmentedFormatter.new
202
207
  end
@@ -205,6 +210,8 @@ module Timber
205
210
 
206
211
  after_initialize if respond_to?(:after_initialize)
207
212
 
213
+ Timber::Config.instance.debug { "Timber::Logger instantiated, level: #{level}, formatter: #{formatter.class}" }
214
+
208
215
  @initialized = true
209
216
  end
210
217
 
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "2.1.0.rc2"
2
+ VERSION = "2.1.0.rc3"
3
3
  end
@@ -1,3 +1,7 @@
1
1
  require "timber"
2
2
  require "timber/cli"
3
- require "timber/cli/io"
3
+ require "timber/cli/io"
4
+ require "timber/config"
5
+
6
+ config = Timber::Config.instance
7
+ config.environment = "production"
@@ -102,7 +102,7 @@ describe Timber::CLI::Installers::Rails, :rails_23 => true do
102
102
  and_return("\nend")
103
103
 
104
104
  logger_code = defined?(ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger"
105
- new_contents = "\n\n # Install the Timber.io logger, send logs over HTTP.\n # Note: When you are done testing, simply instantiate the logger like this:\n#\n# logger = Timber::Logger.new(STDOUT)\n#\n# Be sure to remove the \"log_device =\" and \"logger =\" lines below.\n log_device = Timber::LogDevices::HTTP.new('abcd1234')\n logger = Timber::Logger.new(log_device)\n logger.level = config.log_level\n config.logger = #{logger_code}\n\nend"
105
+ new_contents = "\n\n # Install the Timber.io logger, send logs over HTTP.\n # Note: When you are done testing, simply instantiate the logger like this:\n #\n # logger = Timber::Logger.new(STDOUT)\n #\n # Be sure to remove the \"log_device =\" and \"logger =\" lines below.\n log_device = Timber::LogDevices::HTTP.new('abcd1234')\n logger = Timber::Logger.new(log_device)\n logger.level = config.log_level\n config.logger = #{logger_code}\n\nend"
106
106
 
107
107
  expect(Timber::CLI::FileHelper).to receive(:write).
108
108
  with(env_file_path, new_contents).
@@ -55,7 +55,7 @@ describe Timber::CLI::Installers::Root, :rails_23 => true do
55
55
 
56
56
  expect(installer.send(:install_platform, app)).to eq(true)
57
57
 
58
- copy_to_clipboard_message = Timber::CLI::OSHelper.copy_to_clipboard? ? "\n \e[32m(✓ copied to clipboard)\e[0m" : ""
58
+ copy_to_clipboard_message = Timber::CLI::OSHelper.can_copy_to_clipboard? ? "\n \e[32m(✓ copied to clipboard)\e[0m" : ""
59
59
  expected_output = "\n--------------------------------------------------------------------------------\n\nFirst, let's setup your Heroku drain. Run this command in a separate window:\n\n \e[34mheroku drains:add http://drain.heroku.com\e[0m#{copy_to_clipboard_message}\n\nReady to proceed? (y/n) "
60
60
  expect(output.string).to eq(expected_output)
61
61
  end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ if defined?(::Rack)
4
+ describe Timber::Integrations::Rack::SessionContext do
5
+ let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
+ let(:io) { StringIO.new }
7
+ let(:logger) do
8
+ logger = Timber::Logger.new(io)
9
+ logger.level = ::Logger::INFO
10
+ logger
11
+ end
12
+
13
+ around(:each) do |example|
14
+ class RackHttpController < ActionController::Base
15
+ layout nil
16
+
17
+ def index
18
+ Thread.current[:_timber_context_snapshot] = Timber::CurrentContext.instance.snapshot
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 '/rack_http' => 'rack_http#index'
29
+ end
30
+
31
+ with_rails_logger(logger) do
32
+ Timecop.freeze(time) { example.run }
33
+ end
34
+
35
+ Object.send(:remove_const, :RackHttpController)
36
+ end
37
+
38
+ describe "#process" do
39
+ it "should set the context" do
40
+ allow(Benchmark).to receive(:ms).and_return(1).and_yield
41
+
42
+ expect_any_instance_of(described_class).to receive(:extract_from_cookie).exactly(1).times.and_return("1234")
43
+
44
+ dispatch_rails_request("/rack_http")
45
+ session_context = Thread.current[:_timber_context_snapshot][:session]
46
+
47
+ expect(session_context).to eq({:id => "1234"})
48
+
49
+ lines = clean_lines(io.string.split("\n"))
50
+ expect(lines.length).to eq(3)
51
+ lines.each do |line|
52
+ expect(line).to include("\"session\":{\"id\":\"1234\"}")
53
+ end
54
+ end
55
+ end
56
+
57
+ # Remove blank lines since Rails does this to space out requests in the logs
58
+ def clean_lines(lines)
59
+ lines.select { |line| !line.start_with?(" @metadat") }
60
+ end
61
+ end
62
+ end
@@ -1,6 +1,27 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Timber::Logger, :rails_23 => true do
4
+ describe "#initialize" do
5
+ it "shoud select the augmented formatter" do
6
+ logger = described_class.new(nil)
7
+ expect(logger.formatter).to be_kind_of(Timber::Logger::AugmentedFormatter)
8
+ end
9
+
10
+ context "development environment" do
11
+ around(:each) do |example|
12
+ old_env = Timber::Config.instance.environment
13
+ Timber::Config.instance.environment = "development"
14
+ example.run
15
+ Timber::Config.instance.environment = old_env
16
+ end
17
+
18
+ it "shoud select the augmented formatter" do
19
+ logger = described_class.new(nil)
20
+ expect(logger.formatter).to be_kind_of(Timber::Logger::MessageOnlyFormatter)
21
+ end
22
+ end
23
+ end
24
+
4
25
  describe "#add" do
5
26
  let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
6
27
  let(:io) { StringIO.new }
@@ -124,6 +145,19 @@ describe Timber::Logger, :rails_23 => true do
124
145
  end
125
146
  end
126
147
 
148
+ describe "#silence" do
149
+ let(:io) { StringIO.new }
150
+ let(:logger) { Timber::Logger.new(io) }
151
+
152
+ it "should silence the logs" do
153
+ logger.silence do
154
+ logger.info("test")
155
+ end
156
+
157
+ expect(io.string).to eq("")
158
+ end
159
+ end
160
+
127
161
  describe "#with_context" do
128
162
  let(:io) { StringIO.new }
129
163
  let(:logger) { Timber::Logger.new(io) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timber
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0.rc2
4
+ version: 2.1.0.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timber Technologies, Inc.
@@ -267,6 +267,7 @@ files:
267
267
  - spec/timber/integrations/active_record/log_subscriber_spec.rb
268
268
  - spec/timber/integrations/rack/http_context_spec.rb
269
269
  - spec/timber/integrations/rack/http_events_spec.rb
270
+ - spec/timber/integrations/rack/session_context_spec.rb
270
271
  - spec/timber/integrations/rails/rack_logger_spec.rb
271
272
  - spec/timber/log_devices/http_spec.rb
272
273
  - spec/timber/log_entry_spec.rb
@@ -331,6 +332,7 @@ test_files:
331
332
  - spec/timber/integrations/active_record/log_subscriber_spec.rb
332
333
  - spec/timber/integrations/rack/http_context_spec.rb
333
334
  - spec/timber/integrations/rack/http_events_spec.rb
335
+ - spec/timber/integrations/rack/session_context_spec.rb
334
336
  - spec/timber/integrations/rails/rack_logger_spec.rb
335
337
  - spec/timber/log_devices/http_spec.rb
336
338
  - spec/timber/log_entry_spec.rb