timber 2.1.0.rc3 → 2.1.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
@@ -92,11 +92,10 @@ MESSAGE
92
92
 
93
93
  def free_data
94
94
  message = <<-MESSAGE
95
- Because you're awesome, we've credited your account with ✨ 50mb✨. Get more:
95
+ Because you're awesome, we've credited your account with ✨ 100mb✨.
96
96
 
97
- * Get ✨ 250mb✨ for tweeting your experience to #{TWITTER_HANDLE}
98
- * Get ✨ 100mb for starring our repo: #{REPO_URL}
99
- * Get ✨ 100mb✨ for following #{TWITTER_HANDLE} on twitter
97
+ * Get ✨ 250mb✨ for starring our repo: #{IO::ANSI.colorize(REPO_URL, :blue)}
98
+ * Get ✨ 250mb for tweeting your experience to #{IO::ANSI.colorize(TWITTER_HANDLE, :blue)}
100
99
  MESSAGE
101
100
  message.rstrip
102
101
  end
@@ -1,5 +1,8 @@
1
+ require "socket"
2
+
1
3
  require "timber/config"
2
4
  require "timber/contexts/release"
5
+ require "timber/contexts/system"
3
6
 
4
7
  module Timber
5
8
  # Holds the current context in a thread safe memory storage. This context is
@@ -81,7 +84,7 @@ module Timber
81
84
  # to only neccessary data.
82
85
  def add(*objects)
83
86
  objects.each do |object|
84
- add_to(hash, object)
87
+ add_to!(hash, object)
85
88
  end
86
89
  expire_cache!
87
90
  self
@@ -142,14 +145,23 @@ module Timber
142
145
  # it's hash properly.
143
146
  def build_initial_hash
144
147
  new_hash = {}
148
+
149
+ # Release context
145
150
  release_context = Contexts::Release.from_env
146
151
  if release_context
147
- add_to(new_hash, release_context)
152
+ add_to!(new_hash, release_context)
148
153
  end
154
+
155
+ # System context
156
+ hostname = Socket.gethostname
157
+ pid = Process.pid
158
+ system_context = Contexts::System.new(hostname: hostname, pid: pid)
159
+ add_to!(new_hash, system_context)
160
+
149
161
  new_hash
150
162
  end
151
163
 
152
- def add_to(hash, object)
164
+ def add_to!(hash, object)
153
165
  context = Contexts.build(object) # Normalizes objects into a Timber::Context descendant.
154
166
  key = context.keyspace
155
167
  json = context.as_json # Convert to json now so that we aren't doing it for every line
@@ -33,16 +33,6 @@ module Timber
33
33
  @message = message.is_a?(String) ? message : message.inspect
34
34
  @tags = options[:tags]
35
35
  @time_ms = options[:time_ms]
36
-
37
- context_snapshot = {} if context_snapshot.nil?
38
-
39
- # Set the system context for each log entry since processes can be forked
40
- # and the process ID could change.
41
- hostname = Socket.gethostname
42
- pid = Process.pid
43
- system_context = Contexts::System.new(hostname: hostname, pid: pid)
44
- context_snapshot[system_context.keyspace] = system_context.as_json
45
-
46
36
  @context_snapshot = context_snapshot
47
37
  @event = event
48
38
  end
@@ -92,8 +92,8 @@ module Timber
92
92
  elsif logged_obj.is_a?(Hash)
93
93
  # Extract the tags
94
94
  tags = tags.clone
95
- tags << logged_obj.delete(:tag) if logged_obj.key?(:tag)
96
- tags += logged_obj.delete(:tags) if logged_obj.key?(:tags)
95
+ tags.push(logged_obj.delete(:tag)) if logged_obj.key?(:tag)
96
+ tags.concat(logged_obj.delete(:tags)) if logged_obj.key?(:tags)
97
97
  tags.uniq!
98
98
 
99
99
  # Extract the time_ms
@@ -113,9 +113,13 @@ module Timber
113
113
  # Because of all the crazy ways Rails has attempted tags, we need this crazy method.
114
114
  def extract_active_support_tagged_logging_tags
115
115
  Thread.current[:activesupport_tagged_logging_tags] ||
116
- Thread.current["activesupport_tagged_logging_tags:#{object_id}"] ||
116
+ Thread.current[tagged_logging_object_key_name] ||
117
117
  EMPTY_ARRAY
118
118
  end
119
+
120
+ def tagged_logging_object_key_name
121
+ @tagged_logging_object_key_name ||= "activesupport_tagged_logging_tags:#{object_id}"
122
+ end
119
123
  end
120
124
 
121
125
  # For use in development and test environments where you do not want metadata
@@ -3,7 +3,6 @@ require "timber/util/hash"
3
3
  require "timber/util/http_event"
4
4
  require "timber/util/object"
5
5
  require "timber/util/request"
6
- require "timber/util/string"
7
6
  require "timber/util/struct"
8
7
 
9
8
  module Timber
@@ -33,28 +33,16 @@ module Timber
33
33
 
34
34
  # Normalizes headers to:
35
35
  #
36
- # 1. Ensure the value is UTF8, this will otherwise throw errors upon capturing.
36
+ # 1. Only select values that are UTF8, otherwise they will throw errors when serializing.
37
37
  # 2. Sanitize sensitive headers such as `Authorization` or custom headers specified in
38
38
  def normalize_headers(headers)
39
39
  if headers.is_a?(::Hash)
40
40
  h = headers.each_with_object({}) do |(k, v), h|
41
- # Force the header into a valid UTF-8 string, otherwise we will encounter
42
- # encoding issues when we serialize this data. Moreoever, if the
43
- # data is already valid UTF-8 we don't pay a penalty.
44
- #
45
- # Note: we compare the class name because...
46
- #
47
- # string = 'my string'.force_encoding('ASCII-8BIT')
48
- # string.is_a?(String) => false
49
- # string.class => String
50
- # string.class == String => false
51
- # string.class.name == "String" => true
52
- #
53
- # ¯\_(ツ)_/¯
54
- if v.class.name == STRING_CLASS_NAME
55
- h[k] = Timber::Util::String.normalize_to_utf8(v)
56
- else
57
- h[k] = v
41
+ if v
42
+ v = v.to_s
43
+ if [Encoding::UTF_8, Encoding::US_ASCII].include?(v.encoding)
44
+ h[k] = v
45
+ end
58
46
  end
59
47
  end
60
48
 
@@ -8,8 +8,17 @@ if defined?(::Rack::Request)
8
8
  module Util
9
9
  # @private
10
10
  class Request < ::Rack::Request
11
+ # We store strings as constants since they are reused on a per request basis.
12
+ # This avoids string allocations.
13
+ HTTP_HEADER_ORIGINAL_DELIMITER = '_'.freeze
14
+ HTTP_HEADER_NEW_DELIMITER = '_'.freeze
11
15
  HTTP_PREFIX = 'HTTP_'.freeze
12
16
 
17
+ REMOTE_IP_KEY_NAME = 'action_dispatch.remote_ip'.freeze
18
+ REQUEST_ID_KEY_NAME1 = 'action_dispatch.request_id'.freeze
19
+ REQUEST_ID_KEY_NAME2 = 'X-Request-ID'.freeze
20
+ REQUEST_ID_KEY_NAME3 = 'X-Request-Id'.freeze
21
+
13
22
  def body_content
14
23
  content = body.read
15
24
  body.rewind
@@ -18,19 +27,30 @@ if defined?(::Rack::Request)
18
27
 
19
28
  # Returns a list of request headers. The rack env contains a lot of data, this function
20
29
  # identifies those that were the actual request headers.
30
+ #
31
+ # This was extracted from: https://github.com/ruby-grape/grape/blob/91c6c78ae3d3f3ffabaf57ffc4dc35ab7cfc7b5f/lib/grape/request.rb#L30
21
32
  def headers
22
- @headers ||= ::Hash[
23
- *@env.select { |k,v| k.is_a?(String) && k.start_with?(HTTP_PREFIX) }
24
- .collect { |k,v| [k.sub(/^#{HTTP_PREFIX}/, ''), v] }
25
- .collect { |k,v| [k.split('_').collect(&:capitalize).join('-'), v] }
26
- .sort
27
- .flatten
28
- ]
33
+ @headers ||= begin
34
+ headers = {}
35
+
36
+ @env.each_pair do |k, v|
37
+ next unless k.is_a?(String) && k.to_s.start_with?(HTTP_PREFIX)
38
+
39
+ k = k[5..-1].
40
+ split(HTTP_HEADER_ORIGINAL_DELIMITER).
41
+ each(&:capitalize!).
42
+ join(HTTP_HEADER_NEW_DELIMITER)
43
+
44
+ headers[k] = v
45
+ end
46
+
47
+ headers
48
+ end
29
49
  end
30
50
 
31
51
  def ip
32
- @ip ||= if @env["action_dispatch.remote_ip"]
33
- @env["action_dispatch.remote_ip"].to_s || super
52
+ @ip ||= if @env[REMOTE_IP_KEY_NAME]
53
+ @env[REMOTE_IP_KEY_NAME].to_s || super
34
54
  else
35
55
  super
36
56
  end
@@ -42,8 +62,9 @@ if defined?(::Rack::Request)
42
62
  end
43
63
 
44
64
  def request_id
45
- @request_id ||= @env["action_dispatch.request_id"] || @env["X-Request-ID"] ||
46
- @env["X-Request-Id"]
65
+ @request_id ||= @env[REQUEST_ID_KEY_NAME1] ||
66
+ @env[REQUEST_ID_KEY_NAME12] ||
67
+ @env[REQUEST_ID_KEY_NAME3]
47
68
  end
48
69
  end
49
70
  end
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "2.1.0.rc3"
2
+ VERSION = "2.1.0.rc4"
3
3
  end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::CLI::ConfigFile, :rails_23 => true do
4
+ let(:path) { "config/initializers/timber.rb" }
5
+ let(:config_file) { described_class.new(path) }
6
+ let(:initial_contents) { "# Timber.io Ruby Configuration - Simple Structured Logging\n#\n# ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^\n# /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# -------------------------------------------------------------------\n# Website: https://timber.io\n# Documentation: https://timber.io/docs\n# Support: support@timber.io\n# -------------------------------------------------------------------\n\nconfig = Timber::Config.instance\n\n# Add additional configuration here.\n# For a full list of configuration options and their explanations see:\n# http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config\n\n" }
7
+ let(:contents_hook) { "# Add additional configuration here." }
8
+
9
+ describe ".create!" do
10
+ it "should create" do
11
+ expect(Timber::CLI::FileHelper).to receive(:write).with(path, initial_contents).exactly(1).times
12
+ config_file.create!
13
+ end
14
+ end
15
+
16
+ describe ".logrageify!" do
17
+ it "should set the option in the config file" do
18
+ config_file.logrageify!
19
+ new_contents = initial_contents.gsub(contents_hook, "config.logrageify!\n\n#{contents_hook}")
20
+ expect(config_file.send(:content)).to eq(new_contents)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe Timber::CLI::Installers::ConfigFile, :rails_23 => true do
4
+ let(:api_key) { "abcd1234" }
5
+ let(:app) do
6
+ attributes = {
7
+ "api_key" => api_key,
8
+ "environment" => "development",
9
+ "framework_type" => "rails",
10
+ "heroku_drain_url" => "http://drain.heroku.com",
11
+ "name" => "My Rails App",
12
+ "platform_type" => "other"
13
+ }
14
+ Timber::CLI::API::Application.new(attributes)
15
+ end
16
+ let(:api) { Timber::CLI::API.new(api_key) }
17
+ let(:input) { StringIO.new }
18
+ let(:output) { StringIO.new }
19
+ let(:io) { Timber::CLI::IO.new(io_out: output, io_in: input) }
20
+ let(:installer) { described_class.new(io, api) }
21
+ let(:initial_config_contents) { "# Timber.io Ruby Configuration - Simple Structured Logging\n#\n# ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^\n# /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# -------------------------------------------------------------------\n# Website: https://timber.io\n# Documentation: https://timber.io/docs\n# Support: support@timber.io\n# -------------------------------------------------------------------\n\nconfig = Timber::Config.instance\n\n# Add additional configuration here.\n# For a full list of configuration options and their explanations see:\n# http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config\n\n" }
22
+
23
+ describe ".run" do
24
+ it "should run properly" do
25
+ path = "/path/to/file"
26
+ config_file = Timber::CLI::ConfigFile.new(path)
27
+
28
+ expect(Timber::CLI::ConfigFile).to receive(:new).with(path).and_return(config_file)
29
+ expect(config_file).to receive(:exists?).exactly(1).times.and_return(false)
30
+ expect(installer).to receive(:logrageify?).exactly(1).times.and_return(true)
31
+ expect(config_file).to receive(:logrageify!).exactly(1).times
32
+ expect(config_file).to receive(:create!).exactly(1).times
33
+
34
+ installer.run(app, path)
35
+ end
36
+ end
37
+
38
+ describe ".logrageify?" do
39
+ it "should do nothing if Lograge is not detected" do
40
+ expect(installer.send(:logrageify?)).to eq(false)
41
+ expect(output.string).to eq("")
42
+ end
43
+
44
+ context "with a Lograge constant" do
45
+ around(:each) do |example|
46
+ Lograge = 1
47
+ example.run
48
+ Object.send(:remove_const, :Lograge)
49
+ end
50
+
51
+ it "should prompt for Lograge configuration and return true for y" do
52
+ input.string = "y\n"
53
+ expect(installer.send(:logrageify?)).to eq(true)
54
+ expect(output.string).to eq("\n--------------------------------------------------------------------------------\n\nWe noticed you have lograge installed. Would you like to configure \nTimber to function similarly?\n(This silences template renders, sql queries, and controller calls.\nYou can always do this later in config/initialzers/timber.rb)\n\n\e[34my) Yes, configure Timber like lograge\e[0m\n\e[34mn) No, use the Rails logging defaults\e[0m\n\nEnter your choice: (y/n) ")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Timber::CLI::Installers::Other, :rails_23 => true do
6
+ let(:api_key) { "abcd1234" }
7
+ let(:app) do
8
+ attributes = {
9
+ "api_key" => api_key,
10
+ "environment" => "development",
11
+ "framework_type" => "rails",
12
+ "heroku_drain_url" => "http://drain.heroku.com",
13
+ "name" => "My Rails App",
14
+ "platform_type" => "other"
15
+ }
16
+ Timber::CLI::API::Application.new(attributes)
17
+ end
18
+ let(:api) { Timber::CLI::API.new(api_key) }
19
+ let(:input) { StringIO.new }
20
+ let(:output) { StringIO.new }
21
+ let(:io) { Timber::CLI::IO.new(io_out: output, io_in: input) }
22
+ let(:installer) { described_class.new(io, api) }
23
+
24
+ describe ".run" do
25
+ context "heroku" do
26
+ before(:each) do
27
+ app.platform_type = "heroku"
28
+ end
29
+
30
+ it "should run properly" do
31
+ expect(installer).to receive(:install_stdout).exactly(1).times
32
+ expect(installer).to receive(:ask_to_proceed).exactly(1).times
33
+
34
+ installer.run(app)
35
+ end
36
+ end
37
+
38
+ context "non-heroku" do
39
+ it "should run properly" do
40
+ api_key_code = "'#{api_key}'"
41
+ expect(installer).to receive(:get_api_key_storage_preference).exactly(1).times.and_return(:inline)
42
+ expect(installer).to receive(:get_api_key_code).with(:inline).exactly(1).times.and_return(api_key_code)
43
+ expect(installer).to receive(:install_http).with(api_key_code).exactly(1).times
44
+ expect(installer).to receive(:ask_to_proceed).exactly(1).times
45
+
46
+ installer.run(app)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -18,143 +18,338 @@ describe Timber::CLI::Installers::Rails, :rails_23 => true do
18
18
  let(:output) { StringIO.new }
19
19
  let(:io) { Timber::CLI::IO.new(io_out: output, io_in: input) }
20
20
  let(:installer) { described_class.new(io, api) }
21
- let(:initial_config_contents) { "# Timber.io Ruby Configuration - Simple Structured Logging\n#\n# ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^\n# /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# -------------------------------------------------------------------\n# Website: https://timber.io\n# Documentation: https://timber.io/docs\n# Support: support@timber.io\n# -------------------------------------------------------------------\n\nconfig = Timber::Config.instance\n\n# Add additional configuration here.\n# For a full list of configuration options and their explanations see:\n# http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config\n\n" }
21
+ let(:logger_code) { defined?(ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger" }
22
22
 
23
23
  describe ".run" do
24
- it "should execute properly" do
25
- expect(installer).to receive(:get_development_preference).exactly(1).times.and_return(:send)
26
- expect(installer).to receive(:get_api_key_storage_preference).exactly(1).times.and_return(:environment)
27
- expect(installer).to receive(:logrageify?).exactly(1).times.and_return(true)
28
- expect(installer).to receive(:initializer).exactly(1).times.and_return(true)
29
- expect(installer).to receive(:logrageify!).exactly(1).times.and_return(true)
30
- expect(installer).to receive(:environment_file_paths).exactly(1).times.and_return(["config/environments/development.rb", "config/environments/production.rb", "config/environments/test.rb"])
31
- expect(installer).to receive(:setup_development_environment).with("config/environments/development.rb", :send).and_return(true)
32
- expect(installer).to receive(:setup_other_environment).with(app, "config/environments/production.rb", :environment).and_return(true)
33
- expect(installer).to receive(:setup_test_environment).with("config/environments/test.rb").and_return(true)
34
-
35
- installer.run(app)
24
+ context "development" do
25
+ it "should execute properly" do
26
+ expect(installer).to receive(:install_initializer).with(app).exactly(1).times
27
+ expect(installer).to receive(:install_development_environment).with(app).exactly(1).times
28
+ expect(installer).to receive(:install_test_environment).with(app).exactly(1).times
29
+ expect(installer).to_not receive(:install_app_environment)
30
+
31
+ installer.run(app)
32
+ end
36
33
  end
37
- end
38
-
39
- describe ".initializer" do
40
- it "should create a config file" do
41
- config_file_path = "config/initializers/timber.rb"
42
34
 
43
- expect(Timber::CLI::FileHelper).to receive(:read_or_create).
44
- with(config_file_path, initial_config_contents).
45
- and_return(initial_config_contents)
35
+ context "staging" do
36
+ before(:each) do
37
+ app.environment = "staging"
38
+ end
46
39
 
47
- config_file = installer.send(:initializer)
48
- expect(config_file.path).to eq(config_file_path)
49
- end
50
- end
40
+ it "should execute properly" do
41
+ expect(installer).to receive(:install_initializer).with(app).exactly(1).times
42
+ expect(installer).to receive(:install_development_environment).with(app).exactly(1).times
43
+ expect(installer).to receive(:install_test_environment).with(app).exactly(1).times
44
+ expect(installer).to receive(:install_app_environment).with(app).exactly(1).times
51
45
 
52
- describe ".logrageify?" do
53
- it "should do nothing if Lograge is not detected" do
54
- expect(installer.send(:logrageify?)).to eq(false)
55
- expect(output.string).to eq("")
46
+ installer.run(app)
47
+ end
56
48
  end
57
49
 
58
- context "with a Lograge constant" do
59
- around(:each) do |example|
60
- Lograge = 1
61
- example.run
62
- Object.send(:remove_const, :Lograge)
50
+ context "production" do
51
+ before(:each) do
52
+ app.environment = "production"
63
53
  end
64
54
 
65
- it "should prompt for Lograge configuration and return true for y" do
66
- input.string = "y\n"
67
- expect(installer.send(:logrageify?)).to eq(true)
68
- expect(output.string).to eq("\n--------------------------------------------------------------------------------\n\nWe noticed you have lograge installed. Would you like to configure \nTimber to function similarly?\n(This silences template renders, sql queries, and controller calls.\nYou can always do this later in config/initialzers/timber.rb)\n\n\e[34my) Yes, configure Timber like lograge\e[0m\n\e[34mn) No, use the Rails logging defaults\e[0m\n\nEnter your choice: (y/n) ")
55
+ it "should execute properly" do
56
+ expect(installer).to receive(:install_initializer).with(app).exactly(1).times
57
+ expect(installer).to receive(:install_development_environment).with(app).exactly(1).times
58
+ expect(installer).to receive(:install_test_environment).with(app).exactly(1).times
59
+ expect(installer).to receive(:install_app_environment).with(app).exactly(1).times
60
+
61
+ installer.run(app)
69
62
  end
70
63
  end
71
64
  end
72
65
 
73
- describe ".logrageify!" do
74
- it "should set the option in the config file" do
66
+ describe ".install_initializer" do
67
+ it "should create a config file" do
75
68
  config_file_path = "config/initializers/timber.rb"
69
+ expect_any_instance_of(Timber::CLI::Installers::ConfigFile).to receive(:run).with(app, config_file_path).exactly(1).times
76
70
 
77
- expect(Timber::CLI::FileHelper).to receive(:read_or_create).
78
- with(config_file_path, initial_config_contents).
79
- and_return(initial_config_contents)
71
+ installer.send(:install_initializer, app)
72
+ end
73
+ end
80
74
 
81
- expect(Timber::CLI::FileHelper).to receive(:read).
82
- with(config_file_path).
83
- and_return(initial_config_contents)
75
+ describe ".install_development_environment" do
76
+ let(:env_file_path) { "config/environments/development.rb" }
77
+
78
+ context "env file exists" do
79
+ context "not installed" do
80
+ context "send logs" do
81
+ it "should setup properly" do
82
+ expect(installer).to receive(:get_environment_file_path).
83
+ with("development").
84
+ exactly(1).times.
85
+ and_return(env_file_path)
86
+
87
+ expect(installer).to receive(:already_installed?).
88
+ with(env_file_path).
89
+ exactly(1).times.
90
+ and_return(false)
91
+
92
+ expect(installer).to receive(:get_development_preference).
93
+ with(app).
94
+ exactly(1).times.
95
+ and_return(:send)
96
+
97
+ expected_code = <<-CODE
98
+ # Install the Timber.io logger
99
+ send_logs_to_timber = true # <---- set to false to stop sending dev logs to Timber.io
100
+
101
+ log_device = send_logs_to_timber ? Timber::LogDevices::HTTP.new('#{app.api_key}') : STDOUT
102
+ logger = Timber::Logger.new(log_device)
103
+ logger.level = config.log_level
104
+ config.logger = #{logger_code}
105
+ CODE
106
+
107
+ expect(installer).to receive(:install_logger).
108
+ with(env_file_path, expected_code).
109
+ exactly(1).times
110
+
111
+ result = installer.send(:install_development_environment, app)
112
+ expect(result).to eq(:http)
113
+ end
114
+ end
115
+
116
+ context "dont send" do
117
+ it "should setup properly" do
118
+ expect(installer).to receive(:get_environment_file_path).
119
+ with("development").
120
+ exactly(1).times.
121
+ and_return(env_file_path)
122
+
123
+ expect(installer).to receive(:already_installed?).
124
+ with(env_file_path).
125
+ exactly(1).times.
126
+ and_return(false)
127
+
128
+ expect(installer).to receive(:get_development_preference).
129
+ with(app).
130
+ exactly(1).times.
131
+ and_return(:dont_send)
132
+
133
+ expect(installer).to receive(:install_stdout).
134
+ with(env_file_path).
135
+ exactly(1).times
136
+
137
+ result = installer.send(:install_development_environment, app)
138
+ expect(result).to eq(:stdout)
139
+ end
140
+ end
141
+ end
84
142
 
85
- new_config_contents = "# Timber.io Ruby Configuration - Simple Structured Logging\n#\n# ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^\n# /|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# /|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\\n# -------------------------------------------------------------------\n# Website: https://timber.io\n# Documentation: https://timber.io/docs\n# Support: support@timber.io\n# -------------------------------------------------------------------\n\nconfig = Timber::Config.instance\n\nconfig.logrageify!\n\n# Add additional configuration here.\n# For a full list of configuration options and their explanations see:\n# http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config\n\n"
143
+ context "installed" do
144
+ it "should skip" do
145
+ expect(installer).to receive(:get_environment_file_path).
146
+ with("development").
147
+ exactly(1).times.
148
+ and_return(env_file_path)
149
+
150
+ expect(installer).to receive(:already_installed?).
151
+ with(env_file_path).
152
+ exactly(1).times.
153
+ and_return(true)
154
+
155
+ result = installer.send(:install_development_environment, app)
156
+ expect(result).to eq(:already_installed)
157
+ end
158
+ end
159
+ end
160
+ end
86
161
 
87
- expect(Timber::CLI::FileHelper).to receive(:write).
88
- with(config_file_path, new_config_contents).
89
- and_return(true)
162
+ describe ".install_test_environment" do
163
+ let(:env_file_path) { "config/environments/test.rb" }
164
+
165
+ context "env file exists" do
166
+ context "not installed" do
167
+ it "should setup properly" do
168
+ expect(installer).to receive(:get_environment_file_path).
169
+ with("test").
170
+ exactly(1).times.
171
+ and_return(env_file_path)
172
+
173
+ expect(installer).to receive(:already_installed?).
174
+ with(env_file_path).
175
+ exactly(1).times.
176
+ and_return(false)
177
+
178
+ expect(installer).to receive(:install_nil).
179
+ with(env_file_path).
180
+ exactly(1).times
181
+
182
+ result = installer.send(:install_test_environment, app)
183
+ expect(result).to eq(:nil)
184
+ end
185
+ end
90
186
 
91
- expect(installer.send(:logrageify!)).to eq(true)
187
+ context "installed" do
188
+ it "should skip" do
189
+ expect(installer).to receive(:get_environment_file_path).
190
+ with("test").
191
+ exactly(1).times.
192
+ and_return(env_file_path)
193
+
194
+ expect(installer).to receive(:already_installed?).
195
+ with(env_file_path).
196
+ exactly(1).times.
197
+ and_return(true)
198
+
199
+ result = installer.send(:install_test_environment, app)
200
+ expect(result).to eq(:already_installed)
201
+ end
202
+ end
92
203
  end
93
204
  end
94
205
 
95
- describe ".setup_development_environment" do
96
- it "should setup properly" do
97
- env_file_path = "config/environments/development.rb"
206
+ describe ".install_app_environment" do
207
+ context "production" do
208
+ before(:each) do
209
+ app.environment = "production"
210
+ end
98
211
 
99
- expect(Timber::CLI::FileHelper).to receive(:read).
100
- with(env_file_path).
101
- exactly(2).times.
102
- and_return("\nend")
212
+ let(:env_file_path) { "config/environments/production.rb" }
213
+
214
+ context "env file exists" do
215
+ context "not installed" do
216
+ context "http" do
217
+ it "should setup properly" do
218
+ expect(installer).to receive(:get_environment_file_path).
219
+ with("production").
220
+ exactly(1).times.
221
+ and_return(env_file_path)
222
+
223
+ expect(installer).to receive(:already_installed?).
224
+ with(env_file_path).
225
+ exactly(1).times.
226
+ and_return(false)
227
+
228
+ expect(installer).to receive(:get_delivery_strategy).
229
+ with(app).
230
+ exactly(1).times.
231
+ and_return(:http)
232
+
233
+ expect(installer).to receive(:get_api_key_storage_preference).
234
+ exactly(1).times.
235
+ and_return(:inline)
236
+
237
+ expect(installer).to receive(:install_http).
238
+ with(env_file_path, :inline).
239
+ exactly(1).times
240
+
241
+ result = installer.send(:install_app_environment, app)
242
+ expect(result).to eq(:http)
243
+ end
244
+ end
245
+
246
+ context "stdout" do
247
+ it "should setup properly" do
248
+ expect(installer).to receive(:get_environment_file_path).
249
+ with("production").
250
+ exactly(1).times.
251
+ and_return(env_file_path)
252
+
253
+ expect(installer).to receive(:already_installed?).
254
+ with(env_file_path).
255
+ exactly(1).times.
256
+ and_return(false)
257
+
258
+ expect(installer).to receive(:get_delivery_strategy).
259
+ with(app).
260
+ exactly(1).times.
261
+ and_return(:stdout)
262
+
263
+ expect(installer).to receive(:install_stdout).
264
+ with(env_file_path).
265
+ exactly(1).times
266
+
267
+ result = installer.send(:install_app_environment, app)
268
+ expect(result).to eq(:stdout)
269
+ end
270
+ end
271
+ end
272
+
273
+ context "installed" do
274
+ it "should skip" do
275
+ expect(installer).to receive(:get_environment_file_path).
276
+ with("production").
277
+ exactly(1).times.
278
+ and_return(env_file_path)
279
+
280
+ expect(installer).to receive(:already_installed?).
281
+ with(env_file_path).
282
+ exactly(1).times.
283
+ and_return(true)
284
+
285
+ result = installer.send(:install_app_environment, app)
286
+ expect(result).to eq(:already_installed)
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
103
292
 
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"
293
+ describe ".get_environment_file_path" do
294
+ it "should return the file if it exists" do
295
+ env_file_path = "config/environments/development.rb"
296
+ expect(installer.file_helper).to receive(:exists?).with(env_file_path).exactly(1).times.and_return(true)
106
297
 
107
- expect(Timber::CLI::FileHelper).to receive(:write).
108
- with(env_file_path, new_contents).
109
- and_return(true)
298
+ result = installer.send(:get_environment_file_path, "development")
299
+ expect(result).to eq(env_file_path)
300
+ end
110
301
 
111
- expect(api).to receive(:event).with(:file_written, path: env_file_path)
302
+ it "should return nil if it does not exist" do
303
+ env_file_path = "config/environments/production.rb"
304
+ expect(installer.file_helper).to receive(:exists?).with(env_file_path).exactly(1).times.and_return(false)
112
305
 
113
- expect(installer.send(:setup_development_environment, env_file_path, :send)).to eq(true)
306
+ result = installer.send(:get_environment_file_path, "production")
307
+ expect(result).to eq(nil)
114
308
  end
115
309
  end
116
310
 
117
- describe ".setup_test_environment" do
118
- it "should setup properly" do
119
- env_file_path = "config/environments/test.rb"
120
-
121
- expect(Timber::CLI::FileHelper).to receive(:read).
122
- with(env_file_path).
123
- exactly(2).times.
124
- and_return("\nend")
125
-
126
- logger_code = defined?(ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger"
127
- new_contents = "\n\n # Install the Timber.io logger but silence all logs (log to nil). We install the\n # logger to ensure the Rails.logger object exposes the proper API.\n logger = Timber::Logger.new(nil)\n logger.level = config.log_level\n config.logger = #{logger_code}\n\nend"
311
+ describe ".install_nil" do
312
+ it "should pass the proper code" do
313
+ env_file_path = "config/environments/development.rb"
128
314
 
129
- expect(Timber::CLI::FileHelper).to receive(:write).
130
- with(env_file_path, new_contents).
131
- and_return(true)
315
+ expected_code = <<-CODE
316
+ # Install the Timber.io logger, but do not send logs.
317
+ logger = Timber::Logger.new(nil)
318
+ logger.level = config.log_level
319
+ config.logger = #{logger_code}
320
+ CODE
132
321
 
133
- expect(api).to receive(:event).with(:file_written, path: env_file_path)
322
+ expect(installer).to receive(:install_logger).
323
+ with(env_file_path, expected_code).
324
+ exactly(1).times
134
325
 
135
- expect(installer.send(:setup_test_environment, env_file_path)).to eq(true)
326
+ installer.send(:install_nil, env_file_path)
136
327
  end
137
328
  end
138
329
 
139
- describe ".setup_other_environment" do
140
- it "should setup properly" do
141
- env_file_path = "config/environments/production.rb"
330
+ describe ".install_logger" do
331
+ context "not installed" do
332
+ it "should pass the proper code" do
333
+ env_file_path = "config/environments/development.rb"
142
334
 
143
- expect(Timber::CLI::FileHelper).to receive(:read).
144
- with(env_file_path).
145
- exactly(2).times.
146
- and_return("\nend")
335
+ logger_code = "my code"
147
336
 
148
- logger_code = defined?(ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger"
149
- new_contents = "\n\n # Install the Timber.io logger, send logs over HTTP.\n log_device = Timber::LogDevices::HTTP.new(ENV['TIMBER_API_KEY'])\n logger = Timber::Logger.new(log_device)\n logger.level = config.log_level\n config.logger = #{logger_code}\n\nend"
337
+ current_contents = "\nend"
150
338
 
151
- expect(Timber::CLI::FileHelper).to receive(:write).
152
- with(env_file_path, new_contents).
153
- and_return(true)
339
+ expect(installer.file_helper).to receive(:read).
340
+ with(env_file_path).
341
+ exactly(1).times.
342
+ and_return(current_contents)
154
343
 
155
- expect(api).to receive(:event).with(:file_written, path: env_file_path).exactly(1).times
344
+ new_contents = "\n\nmy code\nend"
156
345
 
157
- expect(installer.send(:setup_other_environment, app, env_file_path, :environment)).to eq(true)
346
+ expect(installer.file_helper).to receive(:write).
347
+ with(env_file_path, new_contents).
348
+ exactly(1).times.
349
+ and_return("\nend")
350
+
351
+ installer.send(:install_logger, env_file_path, logger_code)
352
+ end
158
353
  end
159
354
  end
160
355
  end