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 +4 -4
- data/README.md +15 -1
- data/lib/timber/cli/install.rb +32 -37
- data/lib/timber/config.rb +69 -17
- data/lib/timber/frameworks/rails.rb +33 -29
- data/lib/timber/logger.rb +13 -11
- data/lib/timber/logger/metadata_methods.rb +1 -0
- data/lib/timber/overrides.rb +0 -1
- data/lib/timber/version.rb +1 -1
- data/spec/support/timber.rb +3 -1
- data/spec/timber/logger_spec.rb +2 -2
- metadata +2 -2
- data/lib/timber/overrides/rails_server.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0432ed485c5f9ddbe423ae464cabe9365ac1eefc
|
4
|
+
data.tar.gz: 2051b18db981d2542497cb6b26813ce272625833
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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>
|
data/lib/timber/cli/install.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
110
|
+
def update_environment_config(name, log_device_type, options = {})
|
111
|
+
path = File.join("config", "environments", "#{name}.rb")
|
112
|
+
|
111
113
|
puts ""
|
112
|
-
|
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
|
-
|
119
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
154
|
-
|
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(
|
151
|
+
puts colorize(Messages.task_complete(task_message), :green)
|
157
152
|
end
|
158
153
|
|
159
154
|
def send_test_messages(api_key)
|
data/lib/timber/config.rb
CHANGED
@@ -1,34 +1,48 @@
|
|
1
1
|
require "singleton"
|
2
2
|
|
3
3
|
module Timber
|
4
|
-
# Interface for
|
4
|
+
# Interface for setting and reading Timber configuration.
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# For Rails apps this is installed into `config.timber`. See examples below.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
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
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
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 ||
|
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
|
-
|
26
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
|
data/lib/timber/logger.rb
CHANGED
@@ -119,24 +119,26 @@ module Timber
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
# Structures your log messages
|
123
|
-
#
|
122
|
+
# Structures your log messages as strings and appends metadata if
|
123
|
+
# `Timber::Config.instance.append_metadata?` is true.
|
124
124
|
#
|
125
|
-
#
|
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
|
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
|
-
|
138
|
-
|
139
|
-
|
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 =
|
195
|
+
self.formatter = StringFormatter.new
|
194
196
|
end
|
195
197
|
|
196
198
|
self.level = environment_level
|
@@ -0,0 +1 @@
|
|
1
|
+
metadata_methods.rb
|
data/lib/timber/overrides.rb
CHANGED
data/lib/timber/version.rb
CHANGED
data/spec/support/timber.rb
CHANGED
data/spec/timber/logger_spec.rb
CHANGED
@@ -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
|
14
|
-
before(:each) { logger.formatter = Timber::Logger::
|
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.
|
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
|