timber 2.0.3 → 2.0.4

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: a5285d17535de9890e141603c444772904265630
4
- data.tar.gz: 5ccb28e7a21bdcaa1d5d71822160114e422e5f7f
3
+ metadata.gz: 0432ed485c5f9ddbe423ae464cabe9365ac1eefc
4
+ data.tar.gz: 2051b18db981d2542497cb6b26813ce272625833
5
5
  SHA512:
6
- metadata.gz: ef8847f90d849dabed1702427574a3864095cf6098801cad33cc45302203bdfdd4ccc11fd0c37c9724342ff29bf2f40c3ae9b98bf8da71d07f1b022f71f4b970
7
- data.tar.gz: 8a200733730ff167b57ecbf844bd2aa1ab057bbab66dc3f6d407eec4830877c0b68e9437a1464123fd85bd1f150fdea044d3537cdf679d7414974e45f8d35210
6
+ metadata.gz: 7e9f7183d5447b599b50cd6ca3e566be9e12179209eb1bc26177a71a61d2238bde6abe806593fc5fa0ca08aa4ad5efebf4414c5a72e9afe9745af3276859da09
7
+ data.tar.gz: 680b421e9412c3e814cc4d116670d2ae583a019501769bd117347b960850fd656f8cc1eacc6cce26e1f0f92cb78c49ea97b0c74c2f7772ad23ccd6fa01004020
data/README.md CHANGED
@@ -30,7 +30,7 @@ Into this:
30
30
  Sent 200 in 45.2ms @metadata {"dt": "2017-02-02T01:33:21.154345Z", "level": "info", "context": {"user": {"id": 1, "name": "Ben Johnson"}, "http": {"method": "GET", "host": "timber.io", "path": "/path", "request_id": "abcd1234"}}, "event": {"http_server_response": {"status": 200, "time_ms": 45.2}}}
31
31
  ```
32
32
 
33
- Allowing you to run queries like:
33
+ Allowing you to run queries in the [Timber console](https://app.timber.io) like:
34
34
 
35
35
  1. `context.request_id:abcd1234` - View all logs generated for a specific request.
36
36
  2. `context.user.id:1` - View logs generated by a specific user.
@@ -52,6 +52,20 @@ Allowing you to run queries like:
52
52
  3. In your `shell`, run `bundle exec timber install`
53
53
 
54
54
 
55
+ ## Configuration
56
+
57
+ All configuration options can be seen in the
58
+ [`Timber::Config docs`](http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config).
59
+
60
+ Here's a few popular options:
61
+
62
+ 1. `config.timber.format =`
63
+ * `:default` - This is the default. It's the original, default, unchanged log messages.
64
+ * `:lograge` - Works exactly like [lograge](https://github.com/roidrage/lograge), except Timber's
65
+ additional context and metadata is also appended. Lograge++.
66
+
67
+
68
+
55
69
  ## Usage
56
70
 
57
71
  <details><summary><strong>Basic logging</strong></summary><p>
@@ -32,7 +32,7 @@ module Timber
32
32
  case ask_yes_no("Are the above details correct?")
33
33
  when :yes
34
34
  if app.heroku?
35
- create_initializer(:stdout)
35
+ update_environment_config("production", :stdout)
36
36
 
37
37
  puts ""
38
38
  puts Messages.separator
@@ -55,7 +55,7 @@ module Timber
55
55
 
56
56
  case ask("Enter your choice: (1/2) ")
57
57
  when "1"
58
- create_initializer(:http, :api_key_code => "ENV['TIMBER_API_KEY']")
58
+ update_environment_config("production", :http, :api_key_code => "ENV['TIMBER_API_KEY']")
59
59
 
60
60
  puts ""
61
61
  puts Messages.http_environment_variables(app.api_key)
@@ -65,7 +65,7 @@ module Timber
65
65
  puts ""
66
66
 
67
67
  when "2"
68
- create_initializer(:http, :api_key_code => "'#{app.api_key}'")
68
+ update_environment_config("production", :http, :api_key_code => "'#{app.api_key}'")
69
69
 
70
70
  end
71
71
 
@@ -107,53 +107,48 @@ module Timber
107
107
  end
108
108
 
109
109
  private
110
- def create_initializer(log_device_type, options = {})
110
+ def update_environment_config(name, log_device_type, options = {})
111
+ path = File.join("config", "environments", "#{name}.rb")
112
+
111
113
  puts ""
112
- write Messages.task_start("Creating config/initializers/timber.rb")
114
+ task_message = "Configuring Timber in #{path}"
115
+ write Messages.task_start(task_message)
113
116
 
114
117
  logger_code = \
115
118
  case log_device_type
116
119
  when :http
117
120
  api_key_code = options[:api_key_code] || raise(ArgumentError.new("the :api_key_code option is required"))
118
- "log_device = Timber::LogDevices::HTTP.new(#{api_key_code})\n" +
119
- " Timber::Logger.new(log_device)"
121
+
122
+ logger_code = defined?(::ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger"
123
+
124
+ code = <<-CODE
125
+ # Install the Timber.io logger, send logs over HTTP
126
+ log_device = Timber::LogDevices::HTTP.new(#{api_key_code})
127
+ logger = Timber::Logger.new(log_device)
128
+ logger.level = config.log_level
129
+ config.logger = #{logger_code}
130
+ CODE
131
+ code.rstrip
120
132
 
121
133
  when :stdout
122
- "Timber::Logger.new(STDOUT)"
134
+ code = <<-CODE
135
+ # Install the Timber.io logger, send logs to STDOUT
136
+ logger = Timber::Logger.new(STDOUT)
137
+ logger.level = config.log_level
138
+ config.logger = #{logger_code}
139
+ CODE
140
+ code.rstrip
123
141
  end
124
142
 
125
- body = <<-BODY
126
- # Timber.io Ruby Library
127
- #
128
- # ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^
129
- # /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
130
- # /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
131
- # /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
132
- #
133
- # Library: http://github.com/timberio/timber-ruby
134
- # Docs: http://www.rubydoc.info/github/timberio/timber-ruby
135
- # Support: support@timber.io
136
-
137
- logger = case Rails.env
138
- when "development"
139
- # Write logs to STDOUT in a simple message only format
140
- Timber::Logger.new(STDOUT).tap do |logger|
141
- logger.formatter = Timber::Logger::SimpleFormatter.new
142
- end
143
- when "production", "staging"
144
- #{logger_code}
145
- end
146
143
 
147
- if logger
148
- logger.level = Rails.application.config.log_level
149
- Timber::Frameworks::Rails.set_logger(logger)
150
- end
151
- BODY
144
+ current_contents = File.read(path)
152
145
 
153
- FileUtils.mkdir_p(File.join(Dir.pwd, "config", "initializers"))
154
- File.write(File.join(Dir.pwd, "config/initializers/timber.rb"), body)
146
+ if !current_contents.include?("Timber::Logger.new")
147
+ new_contents = current_contents.sub(/\nend/, "\n\n#{logger_code}\nend")
148
+ File.write(path, new_contents)
149
+ end
155
150
 
156
- puts colorize(Messages.task_complete("Creating config/initializers/timber.rb"), :green)
151
+ puts colorize(Messages.task_complete(task_message), :green)
157
152
  end
158
153
 
159
154
  def send_test_messages(api_key)
@@ -1,34 +1,48 @@
1
1
  require "singleton"
2
2
 
3
3
  module Timber
4
- # Interface for settings and reading Timber configuration.
4
+ # Interface for setting and reading Timber configuration.
5
5
  #
6
- # You can override any configuration supplied here by simply setting it:
6
+ # For Rails apps this is installed into `config.timber`. See examples below.
7
7
  #
8
- # # Rails
9
- # config.timber.api_key = "my api key"
10
- #
11
- # # Everything else
12
- # Timber::Config.instance.api_key = "my api key"
13
- #
14
- # If a value is not explicity set, the environment is checked for it's associated
15
- # environment variable. If that is not set, a reasonable default will be chosen. Each
16
- # method documents this.
8
+ # @example Rails example
9
+ # config.timber.append_metadata = false
10
+ # @example Everything else
11
+ # config = Timber::Config.instance
12
+ # config.append_metdata = false
17
13
  class Config
18
14
  class NoLoggerError < StandardError; end
19
15
 
16
+ PRODUCTION_NAME = "production".freeze
17
+ STAGING_NAME = "staging".freeze
18
+
20
19
  include Singleton
21
20
 
22
- attr_writer :debug_logger, :http_body_limit, :logger
21
+ attr_writer :append_metadata, :debug_logger, :http_body_limit, :logger
23
22
 
23
+ # @private
24
24
  def initialize
25
25
  @http_body_limit = 2000
26
26
  end
27
27
 
28
+ # The environment your app is running in. Defaults to `RACK_ENV` and `RAILS_ENV`.
29
+ #
30
+ # @example Rails
31
+ # config.timber.environment = "staging"
32
+ # @example Everything else
33
+ # Timber::Config.instance.environment = "staging"
34
+ def environment
35
+ @environment ||= ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
36
+ end
28
37
 
29
38
  # Set a debug_logger to view internal Timber library log message.
30
39
  # Useful for debugging. Defaults to `nil`. If set, debug messages will be
31
40
  # written to this logger.
41
+ #
42
+ # @example Rails
43
+ # config.timber.debug_logger = ::Logger.new(STDOUT)
44
+ # @example Everything else
45
+ # Timber::Config.instance.debug_logger = ::Logger.new(STDOUT)
32
46
  def debug_logger
33
47
  @debug_logger
34
48
  end
@@ -36,16 +50,54 @@ module Timber
36
50
  # Truncates captured HTTP bodies to this specified limit. The default is `2000`.
37
51
  # If you want to capture more data, you can raise this to a maximum of `5000`,
38
52
  # or lower this to be more efficient with data.
53
+ #
54
+ # @example Rails
55
+ # config.timber.http_body_limit = 500
56
+ # @example Everything else
57
+ # Timber::Config.instance.http_body_limit = 500
39
58
  def http_body_limit
40
59
  @http_body_limit
41
60
  end
42
61
 
43
- # This is the logger Timber writes to. It should be set to your global
44
- # logger to keep the logging destination consitent. Please see `delegate_logger_to`
45
- # to delegate this call to another method. This is set to `Rails.logger`
46
- # for rails.
62
+ # Should the logger append the Timber metadata. This is automatically turned on
63
+ # for production and staging environments. Other environments should be set manually.
64
+ # If set to `true` log messages will look like:
65
+ #
66
+ # log message @metadata {...}
67
+ #
68
+ # @example Rails
69
+ # config.timber.append_metadata = false
70
+ # @example Everything else
71
+ # Timber::Config.instance.append_metadata = false
72
+ def append_metadata?
73
+ if defined?(@append_metadata)
74
+ return @append_metadata == true
75
+ end
76
+
77
+ production? || staging?
78
+ end
79
+
80
+ # This is the logger Timber writes to. All of the Timber integrations write to
81
+ # this logger. It should be set to your global logger to keep the logging destination consitent.
82
+ #
83
+ # For Rails this is set automatically to `Rails.logger`.
84
+ #
85
+ # @example Rails
86
+ # Rails.logger = Timber::Logger.new(STDOUT)
87
+ # config.timber.logger = Rails.logger
88
+ # @example Everything else
89
+ # Timber::Config.instance.logger = Timber::Logger.new(STDOUT)
47
90
  def logger
48
- @logger || raise(NoLoggerError.new)
91
+ @logger || Logger.new(STDOUT)
49
92
  end
93
+
94
+ private
95
+ def production?
96
+ environment == PRODUCTION_NAME
97
+ end
98
+
99
+ def staging?
100
+ environment == STAGING_NAME
101
+ end
50
102
  end
51
103
  end
@@ -1,53 +1,57 @@
1
1
  module Timber
2
2
  module Frameworks
3
+ # Module for Rails specific code, such as the Railtie and any methods that assist
4
+ # with Rails setup.
3
5
  module Rails
4
6
  # Installs Timber into your Rails app automatically.
5
7
  class Railtie < ::Rails::Railtie
6
8
  config.timber = Config.instance
7
9
 
8
- initializer(:timber_silence_logger_complaints, before: :initialize_logger) do
9
- # We set a default logger because Rails tries to write to a file by default.
10
- # This causes errors on platforms with a read only file system (Heroku).
11
- # See this commit: https://github.com/heroku/rails_stdout_logging/commit/13d092650118bcfeb30f383d3274cee46cbf7b8f
12
- # Moreover, the Timber logger gets configured properly later in an initiailizer.
13
- # This is a hold over until we reach that file in the initialization process.
14
- is_heroku = !ENV['DYNO'].nil?
15
- if is_heroku
16
- logger = defined?(::ActiveSupport::Logger) ?
17
- ::ActiveSupport::Logger.new(STDOUT) : ::Logger.new(STDOUT)
18
- ::Rails.logger = config.logger = logger
19
- end
20
- end
21
-
22
10
  # Initialize Timber immediately after the logger in case anything uses the logger
23
11
  # during the initialization process.
24
- initializer(:timber, after: :initialize_logger) do
25
- # The goals here:
26
- # 1. Respect the default log device that rails sets in :initialize_logger
27
- # 2. Replace the logger with Timber::Logger so that users get our logger API
28
- # 3. Disable metadata so that the logger is essentially transparent until further
29
- # configuration in initializers/timber.rb. This allows them to essentially "turn on"
30
- # timber for production, staging, etc.
31
- log_device = ::Rails.logger.instance_variable_get(:@logdev).try(:dev)
32
- logger = Logger.new(log_device)
33
- logger.formatter = Logger::SimpleFormatter.new
34
- logger.level = ::Rails.logger.level
35
- ::Rails.logger = config.logger = logger
12
+ initializer(:timber, group: :all, after: :initialize_logger) do
13
+ logger = Rails.ensure_timber_logger(::Rails.logger)
14
+ Rails.set_logger(logger)
36
15
 
37
16
  Rails.configure_middlewares(config.app_middleware)
38
17
  Integrations.integrate!
39
18
  end
40
19
  end
41
20
 
21
+ # This builds a new Timber::Logger from an existing logger. This allows us to transparentl
22
+ # switch users onto the Timber::Logger since we support a more useful logging API.
23
+ def self.ensure_timber_logger(existing_logger)
24
+ if existing_logger.is_a?(Logger)
25
+ return existing_logger
26
+ end
27
+
28
+ log_device = existing_logger.instance_variable_get(:@logdev).try(:dev)
29
+ logger = Logger.new(log_device)
30
+ logger.level = existing_logger.try(:level) || Logger::DEBUG
31
+ if defined?(::ActiveSupport::TaggedLogging)
32
+ logger = ::ActiveSupport::TaggedLogging.new(logger)
33
+ end
34
+ logger
35
+ end
36
+
37
+ # Sets the Rails logger. Rails
42
38
  def self.set_logger(logger)
43
39
  if defined?(::ActiveSupport::TaggedLogging) && !logger.is_a?(::ActiveSupport::TaggedLogging)
44
40
  logger = ::ActiveSupport::TaggedLogging.new(logger)
45
41
  end
46
42
 
47
43
  Config.instance.logger = logger
48
- ::ActionController::Base.logger = logger
49
- ::ActionView::Base.logger = logger if ::ActionView::Base.respond_to?(:logger=)
50
- ::ActiveRecord::Base.logger = logger
44
+
45
+ # Set the various Rails framework loggers. We *have* to do this because Rails
46
+ # internally sets these with an ActiveSupport.onload(:active_record) { } callback.
47
+ # We don't have an opportunity to intercept this since the :initialize_logger
48
+ # initializer loads these modules. Moreover, earlier version of rails don't do this
49
+ # at all, hence the defined? checks. Yay for being implicit.
50
+ ::ActionCable::Server::Base.logger = logger if defined?(::ActionCable::Server::Base)
51
+ ::ActionController::Base.logger = logger if defined?(::ActionController::Base)
52
+ ::ActionMailer::Base.logger = logger if defined?(::ActionMailer::Base) && ::ActionMailer::Base.respond_to?(:logger=)
53
+ ::ActionView::Base.logger = logger if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:logger=)
54
+ ::ActiveRecord::Base.logger = logger if defined?(::ActiveRecord::Base)
51
55
  ::Rails.logger = logger
52
56
  end
53
57
 
@@ -119,24 +119,26 @@ module Timber
119
119
  end
120
120
  end
121
121
 
122
- # Structures your log messages into Timber's hybrid format, which makes
123
- # it easy to read while also appending the appropriate metadata.
122
+ # Structures your log messages as strings and appends metadata if
123
+ # `Timber::Config.instance.append_metadata?` is true.
124
124
  #
125
- # logger = Timber::Logger.new(STDOUT)
126
- # logger.formatter = Timber::JSONFormatter.new
127
- #
128
- # Example message:
125
+ # Example message with metdata:
129
126
  #
130
127
  # My log message @metadata {"level":"info","dt":"2016-09-01T07:00:00.000000-05:00"}
131
128
  #
132
- class HybridFormatter < Formatter
129
+ class StringFormatter < Formatter
133
130
  METADATA_CALLOUT = "@metadata".freeze
134
131
 
135
132
  def call(severity, time, progname, msg)
136
133
  log_entry = build_log_entry(severity, time, progname, msg)
137
- metadata = log_entry.to_json(:except => [:message])
138
- # use << for concatenation for performance reasons
139
- log_entry.message.gsub("\n", "\\n") << " " << METADATA_CALLOUT << " " << metadata << "\n"
134
+
135
+ if Config.instance.append_metadata?
136
+ metadata = log_entry.to_json(:except => [:message])
137
+ # use << for concatenation for performance reasons
138
+ log_entry.message.gsub("\n", "\\n") << " " << METADATA_CALLOUT << " " << metadata << "\n"
139
+ else
140
+ log_entry.message + "\n"
141
+ end
140
142
  end
141
143
  end
142
144
 
@@ -190,7 +192,7 @@ module Timber
190
192
  if args.size == 1 and args.first.is_a?(LogDevices::HTTP)
191
193
  self.formatter = PassThroughFormatter.new
192
194
  else
193
- self.formatter = HybridFormatter.new
195
+ self.formatter = StringFormatter.new
194
196
  end
195
197
 
196
198
  self.level = environment_level
@@ -0,0 +1 @@
1
+ metadata_methods.rb
@@ -1,5 +1,4 @@
1
1
  require "timber/overrides/lograge"
2
- require "timber/overrides/rails_server"
3
2
  require "timber/overrides/rails_stdout_logging"
4
3
 
5
4
  module Timber
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4"
3
3
  end
@@ -1,3 +1,5 @@
1
1
  require "timber"
2
2
 
3
- Timber::Config.instance.debug_logger = ::Logger.new(STDOUT)
3
+ config = Timber::Config.instance
4
+ config.append_metadata = true
5
+ config.debug_logger = ::Logger.new(STDOUT)
@@ -10,8 +10,8 @@ describe Timber::Logger, :rails_23 => true do
10
10
  Timecop.freeze(time) { example.run }
11
11
  end
12
12
 
13
- context "with the :hybrid format" do
14
- before(:each) { logger.formatter = Timber::Logger::HybridFormatter.new }
13
+ context "with the StringFormatter" do
14
+ before(:each) { logger.formatter = Timber::Logger::StringFormatter.new }
15
15
 
16
16
  it "should accept strings" do
17
17
  logger.info("this is a test")
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.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timber Technologies, Inc.
@@ -198,9 +198,9 @@ files:
198
198
  - lib/timber/log_devices/http.rb
199
199
  - lib/timber/log_entry.rb
200
200
  - lib/timber/logger.rb
201
+ - lib/timber/logger/metadata_methods.rb
201
202
  - lib/timber/overrides.rb
202
203
  - lib/timber/overrides/lograge.rb
203
- - lib/timber/overrides/rails_server.rb
204
204
  - lib/timber/overrides/rails_stdout_logging.rb
205
205
  - lib/timber/util.rb
206
206
  - lib/timber/util/active_support_log_subscriber.rb
@@ -1,10 +0,0 @@
1
- begin
2
- require "rails/commands/server"
3
-
4
- class ::Rails::Server < ::Rack::Server
5
- private
6
- def log_to_stdout
7
- end
8
- end
9
- rescue Exception
10
- end