timber 2.1.0.rc3 → 2.1.0.rc4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f1b00e64f1666ef47d33c347cea42bcc4d7b262
4
- data.tar.gz: cbde1d3d51a40c4e08eb3357f8d1fa72beae5d19
3
+ metadata.gz: 6c4de508448203aa02a9dba6eec487ed04d0ffcf
4
+ data.tar.gz: 8c7e69aad8ab879841ca7d31910e09e86e5c7658
5
5
  SHA512:
6
- metadata.gz: 374705c1b1a8f0e0091d92a4ee0186246af3126a8c4e5e5358591deac6a1f2174052347350d42d1c8d1e79548a9a159438e39bdcbc95a2753182d5b52f18b921
7
- data.tar.gz: baa0ba4b26cc7157710213635f12750da54ee3bde50e7b1fdac74a06da5ba2b1314c66db5aa258cfd8a170d4299b4f866520ba9a63a31a6ee39f200f95c9331e
6
+ metadata.gz: e91f93d4548d7459c5ecdda73917a1cf188301feaab95de3bcd319e8b779a9f250507046010688c459bbfc1a06de058df9caf3329e834d0f6e49d31fe9099c22
7
+ data.tar.gz: d944798f07d4b1bb0ee0d07b34ce321b75918aa5c5b23107ca6e6f62ba532837d474f2f625092f513c977fe7362fbfd4831506383945e28419c68c8fe44950a1
data/README.md CHANGED
@@ -26,8 +26,9 @@ focusing on logging.
26
26
  3. **Seamlessly integrates with popular libraries and frameworks.** - Rails, Rack, Devise,
27
27
  Omniauth, etc. [Automatically captures user context, HTTP context, and event data.](#third-party-integrations)
28
28
 
29
- 4. **Pairs with a modern console.** - Designed specifically for this librariy, hosted, instantly
30
- usable, zero configuration. [Checkout the docs](https://timber.io/docs/app/overview/).
29
+ 4. **Pairs with a modern structured-logging console.** - Designed specifically for structured data,
30
+ hosted, instantly usable, tail users, trace requests.
31
+ [Checkout the docs](https://timber.io/docs/app/tutorials/).
31
32
 
32
33
 
33
34
  ## Installation
@@ -45,16 +46,16 @@ focusing on logging.
45
46
 
46
47
  ## How it works
47
48
 
48
- Let's start with an example. Timber turns this:
49
+ Let's start with an example. Timber turns this production log line:
49
50
 
50
51
  ```
51
- Sent 200 in 45.2ms
52
+ I, [2017-06-04T18:04:53.653812 #42348] INFO -- : [my.host.com] [df88dbaa-50fd-4178-85d7-d66279ea33b6] [192.32.23.12] [bfa8242cd9733bf0211e334be203f0d0] Sent 200 in 45.2ms
52
53
  ```
53
54
 
54
- Into a rich [`http_server_response` event](https://timber.io/docs/ruby/events-and-context/http-server-response-event/).
55
+ Into a structured [`http_server_response` event](https://timber.io/docs/ruby/events-and-context/http-server-response-event/).
55
56
 
56
57
  ```
57
- Sent 200 in 45.2ms @metadata {"dt": "2017-02-02T01:33:21.154345Z", "level": "info", "context": {"http": {"method": "GET", "path": "/path", "remote_addr": "192.32.23.12", "request_id": "abcd1234"}, "system": {"hostname": "1.server.com", "pid": "254354"}, "user": {"id": 1, "name": "Ben Johnson", "email": "bens@email.com"}}, "event": {"http_server_response": {"status": 200, "time_ms": 45.2}}}
58
+ Sent 200 in 45.2ms @metadata {"dt": "2017-02-02T01:33:21.154345Z", "level": "info", "context": {"http": {"method": "GET", "path": "/path", "remote_addr": "192.32.23.12", "request_id": "df88dbaa-50fd-4178-85d7-d66279ea33b6"}, "session": {"id": "bfa8242cd9733bf0211e334be203f0d0"}, "system": {"hostname": "my.host.com", "pid": "254354"}, "user": {"id": 1, "name": "Ben Johnson", "email": "bens@email.com"}}, "event": {"http_server_response": {"status": 200, "time_ms": 45.2}}}
58
59
  ```
59
60
 
60
61
  Notice that instead of completely replacing your log messages,
@@ -72,7 +73,7 @@ logger.info("Sent 200 in 45.2ms")
72
73
 
73
74
  Here's a better look at the metadata:
74
75
 
75
- ```json
76
+ ```js
76
77
  {
77
78
  "dt": "2017-02-02T01:33:21.154345Z",
78
79
  "level": "info",
@@ -83,11 +84,14 @@ Here's a better look at the metadata:
83
84
  "remote_addr": "192.32.23.12",
84
85
  "request_id": "abcd1234"
85
86
  },
87
+ "session": {
88
+ "id": "bfa8242cd9733bf0211e334be203f0d0"
89
+ },
86
90
  "system": {
87
91
  "hostname": "1.server.com",
88
92
  "pid": "254354"
89
93
  },
90
- "user": {
94
+ "user": { // user identifiable logs :O
91
95
  "id": 1,
92
96
  "name": "Ben Johnson",
93
97
  "email": "bens@email.com"
@@ -418,15 +422,18 @@ Lastly, you can checkout how we capture these events in
418
422
 
419
423
  <details><summary><strong>Won't this increase the size of my log data?</strong></summary><p>
420
424
 
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.
425
+ Yes, but it's no different than adding any other useful data to your logs, such as
426
+ [tags](http://api.rubyonrails.org/classes/ActiveSupport/TaggedLogging.html). A few
427
+ of things to note:
428
+
429
+ 1. Timber generally _reduces_ the amount of logs your app generates, trading quality for quantity.
430
+ It does so by providing options to consolidate request / response logs, template logs, and
431
+ even silence logs that are not of value to you. (see [configuration](#configuration) for examples).
432
+ 2. Timber lets you pick exactly which events and contexts you want.
433
+ (see [configuration](#configuration) for examples)
434
+ 3. Your logging provider should be compressing your data and charging you accordingly. Log data
435
+ is notoriously repetitive, and the context Timber generates is repetitive.
436
+ Because of compression we've seen somes apps only incur a ~15% increase in data size.
430
437
 
431
438
  Finally, log what is useful to you. Quality over quantity certainly applies to logging.
432
439
 
@@ -64,7 +64,7 @@ module Timber
64
64
  HAS_LOGS_PATH = "/installer/has_logs".freeze
65
65
  USER_AGENT = "Timber Ruby/#{Timber::VERSION} (HTTP)".freeze
66
66
 
67
- attr_reader :api_key
67
+ attr_accessor :api_key
68
68
 
69
69
  def initialize(api_key)
70
70
  @api_key = api_key
@@ -103,7 +103,7 @@ module Timber
103
103
  when 0
104
104
  event(:waiting_for_logs)
105
105
  when 20
106
- event(:excessively_waiting_for_logs)
106
+ event(:excessive_log_waiting)
107
107
  when 60
108
108
  raise LogsNotReceivedError.new
109
109
  end
@@ -142,7 +142,10 @@ module Timber
142
142
  end
143
143
 
144
144
  def issue!(req)
145
- req['Authorization'] = "Basic #{encoded_api_key}"
145
+ if api_key
146
+ req['Authorization'] = "Basic #{encoded_api_key}"
147
+ end
148
+
146
149
  req['User-Agent'] = USER_AGENT
147
150
  req['X-Installer-Session-Id'] = @session_id
148
151
  res = http.start do |http|
@@ -2,7 +2,8 @@ module Timber
2
2
  class CLI
3
3
  class API
4
4
  class Application
5
- DEVELOPMENT = "development".freeze
5
+ DEVELOPMENT_ENVIRONMENT = "development".freeze
6
+ TEST_ENVIRONMENT = "test".freeze
6
7
  HEROKU = "heroku".freeze
7
8
 
8
9
  attr_accessor :api_key, :environment, :framework_type, :heroku_drain_url,
@@ -18,7 +19,11 @@ module Timber
18
19
  end
19
20
 
20
21
  def development?
21
- environment == DEVELOPMENT
22
+ environment == DEVELOPMENT_ENVIRONMENT
23
+ end
24
+
25
+ def test?
26
+ environment == TEST_ENVIRONMENT
22
27
  end
23
28
 
24
29
  def heroku?
@@ -7,27 +7,24 @@ module Timber
7
7
 
8
8
  def initialize(path)
9
9
  @path = path
10
- FileHelper.read_or_create(path, initial_content)
10
+ end
11
+
12
+ def create!
13
+ FileHelper.write(path, content)
14
+ end
15
+
16
+ def exists?
17
+ File.exists?(path)
11
18
  end
12
19
 
13
20
  def logrageify!
14
- append("config.logrageify!")
21
+ append!("config.logrageify!")
15
22
  end
16
23
 
17
24
  private
18
- def get_content
19
- FileHelper.read(path)
20
- end
21
-
22
- def append(code)
23
- current_content = get_content
24
- if !current_content.include?(code)
25
- if current_content.include?(insert_hook)
26
- new_content = current_content.gsub(insert_hook, "#{code}\n\n#{insert_hook}")
27
- FileHelper.write(path, new_content)
28
- else
29
- FileHelper.append(path, new_content)
30
- end
25
+ def append!(code)
26
+ if !content.include?(code)
27
+ content.gsub!(insert_hook, "#{code}\n\n#{insert_hook}")
31
28
  end
32
29
 
33
30
  true
@@ -39,8 +36,8 @@ module Timber
39
36
 
40
37
  # We provide this as an instance method so that the string is only defined when needed.
41
38
  # This avoids allocating this string during normal app runtime.
42
- def initial_content
43
- <<-CONTENT
39
+ def content
40
+ @content ||= <<-CONTENT
44
41
  # Timber.io Ruby Configuration - Simple Structured Logging
45
42
  #
46
43
  # ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^
@@ -1,32 +1,44 @@
1
1
  module Timber
2
2
  class CLI
3
- module FileHelper
4
- def self.append(path, contents)
3
+ class FileHelper
4
+ attr_reader :api
5
+
6
+ def initialize(api)
7
+ @api = api
8
+ end
9
+
10
+ def append(path, contents)
5
11
  File.open(path, "a") do |f|
6
12
  f.write(contents)
7
13
  end
8
14
  end
9
15
 
10
- def self.read_or_create(path, contents)
11
- if !File.exists?(path)
16
+ def exists?(path)
17
+ File.exists?(path)
18
+ end
19
+
20
+ def read_or_create(path, contents)
21
+ if !exists?(path)
12
22
  write(path, contents)
13
23
  end
14
24
 
15
- File.read(path)
25
+ read(path)
16
26
  end
17
27
 
18
- def self.read(path)
28
+ def read(path)
19
29
  File.read(path)
20
30
  end
21
31
 
22
- def self.write(path, contents)
32
+ def write(path, contents)
23
33
  File.open(path, "w") do |f|
24
34
  f.write(contents)
25
35
  end
36
+
37
+ api.event(:file_written, path: path)
26
38
  end
27
39
 
28
- def self.verify(path, io)
29
- if !File.exists?(path)
40
+ def verify(path, io)
41
+ if !exists?(path)
30
42
  io.puts ""
31
43
  io.puts "Uh oh! It looks like we couldn't locate the #{path} file. "
32
44
  io.puts "Please enter the correct path:"
@@ -1,13 +1,15 @@
1
+ require "timber/cli/file_helper"
1
2
  require "timber/cli/io/messages"
2
3
 
3
4
  module Timber
4
5
  class CLI
5
6
  class Installer
6
- attr_reader :io, :api
7
+ attr_reader :io, :api, :file_helper
7
8
 
8
9
  def initialize(io, api)
9
10
  @io = io
10
11
  @api = api
12
+ @file_helper = FileHelper.new(api)
11
13
  end
12
14
 
13
15
  def run(app)
@@ -9,57 +9,65 @@ module Timber
9
9
  class CLI
10
10
  module Installers
11
11
  def self.run(api_key, io)
12
- io.puts IO::Messages.header, :green
13
- io.puts IO::Messages.separator, :green
14
- io.puts IO::Messages.contact, :green
15
- io.puts IO::Messages.separator, :green
16
- io.puts ""
12
+ api = API.new(api_key)
13
+ api.event(:started)
17
14
 
18
- if !api_key
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."
15
+ begin
16
+ io.puts IO::Messages.header, :green
17
+ io.puts IO::Messages.separator, :green
18
+ io.puts IO::Messages.contact, :green
19
+ io.puts IO::Messages.separator, :green
25
20
  io.puts ""
26
21
 
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)
22
+ if !api_key
23
+ api.event(:no_api_key)
24
+
25
+ app_url = IO::Messages::APP_URL
26
+
27
+ io.puts "Hey there! Welcome to Timber. In order to proceed, you'll need an API key."
28
+ io.puts "You can grab one by registering at #{IO::ANSI.colorize(app_url, :blue)}."
29
+ io.puts ""
30
+ io.puts "It takes less than a minute, with one click Google and Github registration."
31
+ io.puts ""
32
+
33
+ if OSHelper.can_open?
34
+ case io.ask_yes_no("Open #{app_url}?")
35
+ when :yes
36
+ puts ""
37
+ io.task("Opening #{app_url}") do
38
+ OSHelper.open(app_url)
39
+ end
40
+ when :no
41
+ io.puts ""
42
+ io.puts "No problem, navigate to the following URL:"
43
+ io.puts ""
44
+ io.puts " #{IO::ANSI.colorize(app_url, :blue)}"
33
45
  end
34
- when :no
46
+ else
35
47
  io.puts ""
36
- io.puts "No problem, navigate to the following URL:"
48
+ io.puts "Please navigate to:"
37
49
  io.puts ""
38
50
  io.puts " #{IO::ANSI.colorize(app_url, :blue)}"
39
51
  end
40
- else
52
+
41
53
  io.puts ""
42
- io.puts "Please navigate to:"
54
+ io.puts "Once you obtain your API key, you can run the installer like"
43
55
  io.puts ""
44
- io.puts " #{IO::ANSI.colorize(app_url, :blue)}"
45
- end
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 ""
54
- else
55
- api = API.new(api_key)
56
- api.event(:started)
57
-
58
- io.api = api
56
+ io.puts " #{IO::ANSI.colorize("bundle exec timber my-api-key", :blue)}"
57
+ io.puts ""
58
+ io.puts "See you soon! 🎈"
59
+ io.puts ""
60
+ else
61
+ api.event(:api_key_provided)
62
+ io.api = api
59
63
 
60
- app = api.application!
64
+ app = api.application!
61
65
 
62
- Root.new(io, api).run(app)
66
+ Root.new(io, api).run(app)
67
+ end
68
+ rescue Exception => e
69
+ api.event(:exception, message: e.message, stacktrace: e.backtrace)
70
+ raise e
63
71
  end
64
72
  end
65
73
  end
@@ -0,0 +1,60 @@
1
+ begin
2
+ require "lograge"
3
+ rescue Exception
4
+ end
5
+
6
+ require "timber/cli/config_file"
7
+ require "timber/cli/installer"
8
+ require "timber/cli/io/messages"
9
+
10
+ module Timber
11
+ class CLI
12
+ module Installers
13
+ class ConfigFile < Installer
14
+ def run(app, path)
15
+ config_file = Timber::CLI::ConfigFile.new(path)
16
+
17
+ if config_file.exists?
18
+ io.puts ""
19
+ io.task_complete("#{config_file.path} already created")
20
+ return true
21
+ end
22
+
23
+ if logrageify?
24
+ config_file.logrageify!
25
+ end
26
+
27
+ io.puts ""
28
+ task_message = "Creating #{config_file.path}"
29
+ io.task(task_message) { config_file.create! }
30
+ end
31
+
32
+ private
33
+ def logrageify?
34
+ if defined?(::Lograge)
35
+ io.puts ""
36
+ io.puts IO::Messages.separator
37
+ io.puts ""
38
+ io.puts "We noticed you have lograge installed. Would you like to configure "
39
+ io.puts "Timber to function similarly?"
40
+ io.puts "(This silences template renders, sql queries, and controller calls."
41
+ io.puts "You can always do this later in config/initialzers/timber.rb)"
42
+ io.puts ""
43
+ io.puts "y) Yes, configure Timber like lograge", :blue
44
+ io.puts "n) No, use the Rails logging defaults", :blue
45
+ io.puts ""
46
+
47
+ case io.ask_yes_no("Enter your choice:", event_prompt: "Logrageify?")
48
+ when :yes
49
+ true
50
+ when :no
51
+ false
52
+ end
53
+ else
54
+ false
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -14,13 +14,7 @@ module Timber
14
14
  install_http(api_key_code)
15
15
  end
16
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 ""
17
+ ask_to_proceed
24
18
  end
25
19
 
26
20
  private
@@ -48,6 +42,16 @@ module Timber
48
42
  io.puts ""
49
43
  io.ask_to_proceed
50
44
  end
45
+
46
+ def ask_to_proceed
47
+ io.puts ""
48
+ io.puts IO::Messages.separator
49
+ io.puts ""
50
+ io.puts "We're going to send a few test messages to ensure communication is working."
51
+ io.puts ""
52
+ io.ask_to_proceed
53
+ io.puts ""
54
+ end
51
55
  end
52
56
  end
53
57
  end