timber 1.1.14 → 2.0.0

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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -2
  3. data/.travis.yml +47 -0
  4. data/Gemfile +1 -28
  5. data/README.md +83 -298
  6. data/bin/timber +13 -0
  7. data/gemfiles/rails-3.0.gemfile +5 -0
  8. data/gemfiles/rails-3.1.gemfile +5 -0
  9. data/gemfiles/rails-3.2.gemfile +5 -0
  10. data/gemfiles/rails-4.0.gemfile +9 -0
  11. data/gemfiles/rails-4.1.gemfile +9 -0
  12. data/gemfiles/rails-4.2.gemfile +9 -0
  13. data/gemfiles/rails-5.0.gemfile +9 -0
  14. data/gemfiles/rails-edge.gemfile +7 -0
  15. data/lib/timber.rb +7 -7
  16. data/lib/timber/cli.rb +72 -0
  17. data/lib/timber/cli/api.rb +104 -0
  18. data/lib/timber/cli/application.rb +28 -0
  19. data/lib/timber/cli/install.rb +186 -0
  20. data/lib/timber/cli/io_helper.rb +58 -0
  21. data/lib/timber/cli/messages.rb +170 -0
  22. data/lib/timber/config.rb +47 -6
  23. data/lib/timber/contexts/http.rb +2 -2
  24. data/lib/timber/current_context.rb +1 -1
  25. data/lib/timber/event.rb +8 -0
  26. data/lib/timber/events.rb +2 -0
  27. data/lib/timber/events/controller_call.rb +12 -3
  28. data/lib/timber/events/exception.rb +4 -3
  29. data/lib/timber/events/http_client_request.rb +61 -0
  30. data/lib/timber/events/http_client_response.rb +47 -0
  31. data/lib/timber/events/http_server_request.rb +15 -23
  32. data/lib/timber/events/http_server_response.rb +9 -9
  33. data/lib/timber/events/sql_query.rb +2 -2
  34. data/lib/timber/events/template_render.rb +2 -2
  35. data/lib/timber/frameworks/rails.rb +31 -6
  36. data/lib/timber/integrations.rb +22 -0
  37. data/lib/timber/integrations/action_controller/log_subscriber.rb +25 -0
  38. data/lib/timber/integrations/action_controller/log_subscriber/timber_log_subscriber.rb +40 -0
  39. data/lib/timber/integrations/action_dispatch/debug_exceptions.rb +51 -0
  40. data/lib/timber/integrations/action_view/log_subscriber.rb +25 -0
  41. data/lib/timber/integrations/action_view/log_subscriber/timber_log_subscriber.rb +73 -0
  42. data/lib/timber/integrations/active_record/log_subscriber.rb +25 -0
  43. data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +39 -0
  44. data/lib/timber/integrations/active_support/tagged_logging.rb +71 -0
  45. data/lib/timber/integrations/rack.rb +16 -0
  46. data/lib/timber/integrations/rack/exception_event.rb +28 -0
  47. data/lib/timber/integrations/rack/http_context.rb +25 -0
  48. data/lib/timber/integrations/rack/http_events.rb +46 -0
  49. data/lib/timber/integrations/rack/user_context.rb +59 -0
  50. data/lib/timber/integrations/rails/rack_logger.rb +49 -0
  51. data/lib/timber/integrator.rb +24 -0
  52. data/lib/timber/log_devices/http.rb +14 -21
  53. data/lib/timber/log_entry.rb +1 -1
  54. data/lib/timber/logger.rb +38 -12
  55. data/lib/timber/overrides.rb +9 -0
  56. data/lib/timber/overrides/lograge.rb +14 -0
  57. data/lib/timber/overrides/rails_server.rb +10 -0
  58. data/lib/timber/util.rb +2 -0
  59. data/lib/timber/util/active_support_log_subscriber.rb +13 -9
  60. data/lib/timber/util/http_event.rb +54 -0
  61. data/lib/timber/util/request.rb +44 -0
  62. data/lib/timber/version.rb +1 -1
  63. data/spec/README.md +5 -9
  64. data/spec/spec_helper.rb +1 -4
  65. data/spec/support/action_controller.rb +7 -3
  66. data/spec/support/active_record.rb +23 -19
  67. data/spec/support/rails.rb +56 -32
  68. data/spec/support/timber.rb +2 -3
  69. data/spec/support/webmock.rb +1 -0
  70. data/spec/timber/integrations/action_controller/log_subscriber_spec.rb +55 -0
  71. data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +53 -0
  72. data/spec/timber/integrations/action_view/log_subscriber_spec.rb +115 -0
  73. data/spec/timber/integrations/active_record/log_subscriber_spec.rb +46 -0
  74. data/spec/timber/integrations/rack/http_context_spec.rb +60 -0
  75. data/spec/timber/integrations/rails/rack_logger_spec.rb +58 -0
  76. data/spec/timber/logger_spec.rb +45 -9
  77. data/timber.gemspec +29 -3
  78. metadata +143 -46
  79. data/Appraisals +0 -41
  80. data/circle.yml +0 -33
  81. data/lib/timber/overrides/logger_add.rb +0 -38
  82. data/lib/timber/probe.rb +0 -23
  83. data/lib/timber/probes.rb +0 -23
  84. data/lib/timber/probes/action_controller_log_subscriber.rb +0 -20
  85. data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +0 -64
  86. data/lib/timber/probes/action_controller_user_context.rb +0 -52
  87. data/lib/timber/probes/action_dispatch_debug_exceptions.rb +0 -80
  88. data/lib/timber/probes/action_view_log_subscriber.rb +0 -20
  89. data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +0 -69
  90. data/lib/timber/probes/active_record_log_subscriber.rb +0 -20
  91. data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +0 -31
  92. data/lib/timber/probes/active_support_tagged_logging.rb +0 -63
  93. data/lib/timber/probes/rails_rack_logger.rb +0 -77
  94. data/lib/timber/rack_middlewares.rb +0 -12
  95. data/lib/timber/rack_middlewares/http_context.rb +0 -30
  96. data/spec/support/action_view.rb +0 -4
  97. data/spec/support/coveralls.rb +0 -2
  98. data/spec/support/simplecov.rb +0 -9
  99. data/spec/timber/overrides/logger_add_spec.rb +0 -26
  100. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +0 -65
  101. data/spec/timber/probes/action_controller_user_context_spec.rb +0 -53
  102. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +0 -48
  103. data/spec/timber/probes/action_view_log_subscriber_spec.rb +0 -107
  104. data/spec/timber/probes/active_record_log_subscriber_spec.rb +0 -47
  105. data/spec/timber/probes/rails_rack_logger_spec.rb +0 -46
  106. data/spec/timber/rack_middlewares/http_context_spec.rb +0 -47
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
4
+ require "timber/cli"
5
+
6
+ begin
7
+ Timber::CLI.run
8
+ rescue => e
9
+ raise e if $DEBUG
10
+ STDERR.puts e.message
11
+ STDERR.puts e.backtrace.join("\n")
12
+ exit 1
13
+ end
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 3.0.0'
4
+
5
+ gemspec :path => '../'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 3.1.0'
4
+
5
+ gemspec :path => '../'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 3.2.0'
4
+
5
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.0.0'
4
+
5
+ if RUBY_PLATFORM == "java"
6
+ gem 'mime-types', '2.6.2'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.1.0'
4
+
5
+ if RUBY_PLATFORM == "java"
6
+ gem 'mime-types', '2.6.2'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.2.0'
4
+
5
+ if RUBY_PLATFORM == "java"
6
+ gem 'mime-types', '2.6.2'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 5.0.0'
4
+
5
+ if RUBY_PLATFORM == "java"
6
+ gem 'mime-types', '2.6.2'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack', github: 'rack/rack', branch: 'master'
4
+ gem 'arel', github: 'rails/arel', branch: 'master'
5
+ gem 'rails', github: 'rails/rails', branch: 'master'
6
+
7
+ gemspec :path => '../'
@@ -1,14 +1,12 @@
1
1
  # core classes
2
2
  require "json" # brings to_json to the core classes
3
3
 
4
- require "timber/overrides/logger_add"
5
- require "timber/overrides/rails_stdout_logging"
6
-
7
4
  # Base (must come first, order matters)
5
+ require "timber/overrides"
8
6
  require "timber/config"
9
7
  require "timber/context"
10
8
  require "timber/event"
11
- require "timber/probe"
9
+ require "timber/integrator"
12
10
  require "timber/util"
13
11
  require "timber/version"
14
12
 
@@ -19,8 +17,10 @@ require "timber/events"
19
17
  require "timber/log_devices"
20
18
  require "timber/log_entry"
21
19
  require "timber/logger"
22
- require "timber/probes"
23
- require "timber/rack_middlewares"
20
+ require "timber/integrations"
24
21
 
25
22
  # Load frameworks
26
- require "timber/frameworks"
23
+ require "timber/frameworks"
24
+
25
+ module Timber
26
+ end
@@ -0,0 +1,72 @@
1
+ require "optparse"
2
+ require "yaml"
3
+ require "timber"
4
+
5
+
6
+ require "timber/cli/api"
7
+ require "timber/cli/application"
8
+ require "timber/cli/io_helper"
9
+ require "timber/cli/messages"
10
+
11
+ require "timber/cli/install"
12
+
13
+ module Timber
14
+ # @private
15
+ class CLI
16
+ AVAILABLE_COMMANDS = %w(install).freeze
17
+
18
+ class << self
19
+ attr_accessor :options
20
+
21
+ def run(argv = ARGV)
22
+ @options = {}
23
+ global = global_option_parser
24
+ commands = command_option_parser
25
+ global.order!(argv)
26
+ command = argv.shift
27
+ if command
28
+ if AVAILABLE_COMMANDS.include?(command)
29
+ commands[command].parse!(argv)
30
+ case command.to_sym
31
+ when :install
32
+ Timber::CLI::Install.run(argv.shift)
33
+ end
34
+ else
35
+ puts "Command '#{command}' does not exist, run timber -h to "\
36
+ "see the help"
37
+ exit(1)
38
+ end
39
+ else
40
+ # Print help
41
+ puts global
42
+ exit(0)
43
+ end
44
+ end
45
+
46
+ def global_option_parser
47
+ OptionParser.new do |o|
48
+ o.banner = "Usage: timber <command> [options]"
49
+
50
+ o.on "-v", "--version", "Print version and exit" do |_arg|
51
+ puts "Timber #{Timber::VERSION}"
52
+ exit(0)
53
+ end
54
+
55
+ o.on "-h", "--help", "Show help and exit" do
56
+ puts o
57
+ exit(0)
58
+ end
59
+
60
+ o.separator ""
61
+ o.separator "Available commands: #{AVAILABLE_COMMANDS.join(", ")}"
62
+ end
63
+ end
64
+
65
+ def command_option_parser
66
+ {
67
+ "install" => OptionParser.new
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,104 @@
1
+ require "base64"
2
+ require "json"
3
+ require "net/https"
4
+ require "securerandom"
5
+ require "uri"
6
+
7
+ module Timber
8
+ class CLI
9
+ class API
10
+ class APIKeyInvalidError < StandardError
11
+ def message
12
+ "Uh oh! The API key supplied is invalid. Please ensure that you copied the" \
13
+ " key properly.\n\n#{Messages.obtain_key_instructions}"
14
+ end
15
+ end
16
+
17
+ class NoAPIKeyError < StandardError
18
+ def message
19
+ "Uh oh! You didn't supply an API key.\n\n#{Messages.obtain_key_instructions}"
20
+ end
21
+ end
22
+
23
+ TIMBER_API_URI = URI.parse('https://api.timber.io')
24
+ APPLICATION_PATH = "/installer/application".freeze
25
+ EVENT_PATH = "/installer/events".freeze
26
+ HAS_LOGS_PATH = "/installer/has_logs".freeze
27
+ USER_AGENT = "Timber Ruby/#{Timber::VERSION} (HTTP)".freeze
28
+
29
+ def initialize(api_key)
30
+ @api_key = api_key
31
+ @session_id = SecureRandom.uuid
32
+ end
33
+
34
+ def application!
35
+ get!(APPLICATION_PATH)
36
+ end
37
+
38
+ def event!(name, data = {})
39
+ post!(EVENT_PATH, event: {name: name, data: data})
40
+ end
41
+
42
+ def wait_for_logs(iteration = 0, &block)
43
+ if block_given?
44
+ yield iteration
45
+ end
46
+
47
+ sleep 0.5
48
+
49
+ res = get!(HAS_LOGS_PATH)
50
+
51
+ case res.code
52
+ when "202"
53
+ wait_for_logs(iteration + 1, &block)
54
+
55
+ when "204"
56
+ true
57
+ end
58
+ end
59
+
60
+ private
61
+ def get!(path)
62
+ req = Net::HTTP::Get.new(path)
63
+ issue!(req)
64
+ end
65
+
66
+ def post!(path, body)
67
+ req = Net::HTTP::Post.new(path)
68
+ req.body = body.to_json
69
+ req['Content-Type'] = "application/json"
70
+ issue!(req)
71
+ end
72
+
73
+ def issue!(req)
74
+ req['Authorization'] = "Basic #{encoded_api_key}"
75
+ req['User-Agent'] = USER_AGENT
76
+ req['X-Installer-Session-Id'] = @session_id
77
+ res = http.start do |http|
78
+ http.request(req)
79
+ end
80
+
81
+ if res.code == "401"
82
+ raise NoAPIKeyError.new
83
+ elsif res.code == "403"
84
+ raise APIKeyInvalidError.new
85
+ else
86
+ res
87
+ end
88
+ end
89
+
90
+ def http
91
+ @http ||= begin
92
+ http = Net::HTTP.new(TIMBER_API_URI.host, TIMBER_API_URI.port)
93
+ http.use_ssl = true
94
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
95
+ http
96
+ end
97
+ end
98
+
99
+ def encoded_api_key
100
+ Base64.urlsafe_encode64(@api_key).chomp
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,28 @@
1
+ require "json"
2
+
3
+ module Timber
4
+ class CLI
5
+ class Application
6
+
7
+ attr_reader :api_key, :environment, :framework_type, :heroku_drain_url, :language_type,
8
+ :name, :platform_type
9
+
10
+ def initialize(api)
11
+ res = api.application!
12
+ parsed_body = JSON.parse(res.body)
13
+ application_data = parsed_body.fetch("data")
14
+ @api_key = application_data.fetch("api_key")
15
+ @environment = application_data.fetch("environment")
16
+ @framework_type = application_data.fetch("framework_type")
17
+ @heroku_drain_url = application_data.fetch("heroku_drain_url")
18
+ @language_type = application_data.fetch("language_type")
19
+ @name = application_data.fetch("name")
20
+ @platform_type = application_data.fetch("platform_type")
21
+ end
22
+
23
+ def heroku?
24
+ platform_type == "heroku"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,186 @@
1
+ require "fileutils"
2
+
3
+ module Timber
4
+ class CLI
5
+ class Install
6
+ EXCLUDED_ENVIRONMENTS = ["test"].freeze
7
+
8
+ class << self
9
+ include IOHelper
10
+
11
+ def run(api_key)
12
+ puts ""
13
+ puts colorize(Messages.header, :green)
14
+ puts colorize(Messages.separator, :green)
15
+ puts colorize(Messages.contact, :green)
16
+ puts colorize(Messages.separator, :green)
17
+ puts ""
18
+
19
+ if !api_key
20
+ puts colorize(Messages.no_api_key_provided, :red)
21
+ return
22
+ end
23
+
24
+ api = API.new(api_key)
25
+
26
+ api.event!(:started)
27
+
28
+ app = Application.new(api)
29
+
30
+ puts Messages.application_details(app)
31
+
32
+ case ask_yes_no("Are the above details correct?")
33
+ when :yes
34
+ if app.heroku?
35
+ create_initializer(:stdout)
36
+
37
+ puts ""
38
+ puts Messages.separator
39
+ puts ""
40
+ puts Messages.heroku_install(app)
41
+ puts ""
42
+
43
+ else
44
+ puts ""
45
+ puts Messages.separator
46
+ puts ""
47
+ puts "How would you like configure Timber?"
48
+ puts ""
49
+ puts "1) Using environment variables"
50
+ puts "2) Configuring in my app"
51
+ puts ""
52
+
53
+ case ask("Enter your choice: (1/2) ")
54
+ when "1"
55
+ create_initializer(:http, :api_key_code => "ENV['TIMBER_API_KEY']")
56
+
57
+ puts ""
58
+ puts Messages.http_environment_variables(app.api_key)
59
+ puts ""
60
+
61
+ when "2"
62
+ create_initializer(:http, :api_key_code => "'#{app.api_key}'")
63
+
64
+ puts ""
65
+ end
66
+
67
+ send_test_messages(api_key)
68
+ end
69
+
70
+ api.wait_for_logs do |iteration|
71
+ write Messages.task_start("Waiting for logs")
72
+ write Messages.spinner(iteration)
73
+ end
74
+
75
+ puts colorize(Messages.task_complete("Waiting for logs"), :green)
76
+
77
+ puts ""
78
+ puts Messages.separator
79
+ puts ""
80
+ puts Messages.free_data
81
+ puts ""
82
+ puts Messages.separator
83
+ puts ""
84
+ puts colorize(Messages.commit_and_deploy_reminder, :green)
85
+
86
+ api.event!(:success)
87
+
88
+ collect_feedback(api)
89
+
90
+ when :no
91
+ puts ""
92
+ puts "Bummer. Head to this URL to update the details:"
93
+ puts ""
94
+ puts " #{Messages.edit_app_url(app)}"
95
+ puts ""
96
+ puts "exiting..."
97
+ return false
98
+ end
99
+ end
100
+
101
+ private
102
+ def create_initializer(log_device_type, options = {})
103
+ puts ""
104
+ write Messages.task_start("Creating config/initializers/timber.rb")
105
+
106
+ logger_code = \
107
+ case log_device_type
108
+ when :http
109
+ api_key_code = options[:api_key_code] || raise(ArgumentError.new("the :api_key_code option is required"))
110
+ "log_device = Timber::LogDevices::HTTP.new(#{api_key_code})\n" +
111
+ "Timber::Logger.new(log_device)"
112
+
113
+ when :stdout
114
+ "Timber::Logger.new(STDOUT)"
115
+ end
116
+
117
+ body = <<-BODY
118
+ # Timber.io Ruby Library
119
+ #
120
+ # ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^
121
+ # /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
122
+ # /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
123
+ # /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
124
+ #
125
+ # Library: http://github.com/timberio/timber-ruby
126
+ # Docs: http://www.rubydoc.info/github/timberio/timber-ruby
127
+ # Support: support@timber.io
128
+
129
+ logger = case Rails.env
130
+ when "development", "test"
131
+ logger = Timber::Logger.new(STDOUT)
132
+ logger.formatter = Timber::Logger::SimpleFormatter.new
133
+ logger
134
+ else
135
+ #{logger_code}
136
+ end
137
+
138
+ Timber::Frameworks::Rails.set_logger(logger)
139
+ BODY
140
+
141
+ FileUtils.mkdir_p(File.join(Dir.pwd, "config", "initializers"))
142
+ File.write(File.join(Dir.pwd, "config/initializers/timber.rb"), body)
143
+
144
+ puts colorize(Messages.task_complete("Creating config/initializers/timber.rb"), :green)
145
+ end
146
+
147
+ def send_test_messages(api_key)
148
+ write Messages.task_start("Sending test logs")
149
+
150
+ http_device = LogDevices::HTTP.new(api_key)
151
+ logger = Logger.new(http_device)
152
+ logger.info("test")
153
+
154
+ puts colorize(Messages.task_complete("Sending test logs"), :green)
155
+ end
156
+
157
+ def collect_feedback(api)
158
+ puts ""
159
+ puts Messages.separator
160
+ puts ""
161
+ rating = ask("How would rate this install experience? 1 (bad) - 5 (perfect)")
162
+ case rating
163
+ when "4", "5"
164
+ api.event!(:feedback, rating: rating.to_i)
165
+ puts ""
166
+ puts Messages.we_love_you_too
167
+
168
+ when "1", "2", "3"
169
+ puts ""
170
+ puts Messages.bad_experience_message
171
+ puts ""
172
+
173
+ comments = ask("Type your comments (enter sends)")
174
+
175
+ api.event!(:feedback, rating: rating.to_i, comments: comments)
176
+
177
+ puts ""
178
+ puts "Thank you! We take feedback seriously and will work to improve this."
179
+ end
180
+
181
+ puts ""
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end