appsignal 2.1.2 → 2.2.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +14 -0
  3. data/.rubocop_todo.yml +16 -171
  4. data/.travis.yml +14 -1
  5. data/.yardopts +8 -0
  6. data/CHANGELOG.md +21 -3
  7. data/README.md +20 -2
  8. data/Rakefile +60 -62
  9. data/appsignal.gemspec +24 -23
  10. data/ext/agent.yml +11 -11
  11. data/ext/appsignal_extension.c +43 -12
  12. data/ext/extconf.rb +9 -9
  13. data/gemfiles/padrino.gemfile +1 -1
  14. data/lib/appsignal.rb +403 -26
  15. data/lib/appsignal/auth_check.rb +28 -1
  16. data/lib/appsignal/cli.rb +1 -0
  17. data/lib/appsignal/cli/demo.rb +40 -0
  18. data/lib/appsignal/cli/diagnose.rb +345 -89
  19. data/lib/appsignal/cli/helpers.rb +9 -4
  20. data/lib/appsignal/cli/install.rb +6 -6
  21. data/lib/appsignal/cli/notify_of_deploy.rb +58 -0
  22. data/lib/appsignal/config.rb +40 -38
  23. data/lib/appsignal/demo.rb +20 -0
  24. data/lib/appsignal/event_formatter.rb +4 -0
  25. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +1 -0
  26. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +1 -0
  27. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +1 -0
  28. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +1 -0
  29. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +1 -0
  30. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +2 -1
  31. data/lib/appsignal/event_formatter/moped/query_formatter.rb +1 -0
  32. data/lib/appsignal/extension.rb +1 -0
  33. data/lib/appsignal/garbage_collection_profiler.rb +20 -19
  34. data/lib/appsignal/hooks.rb +1 -0
  35. data/lib/appsignal/hooks/active_support_notifications.rb +1 -0
  36. data/lib/appsignal/hooks/celluloid.rb +1 -0
  37. data/lib/appsignal/hooks/data_mapper.rb +1 -0
  38. data/lib/appsignal/hooks/delayed_job.rb +1 -0
  39. data/lib/appsignal/hooks/mongo_ruby_driver.rb +1 -0
  40. data/lib/appsignal/hooks/net_http.rb +1 -0
  41. data/lib/appsignal/hooks/passenger.rb +1 -0
  42. data/lib/appsignal/hooks/puma.rb +1 -0
  43. data/lib/appsignal/hooks/rake.rb +1 -0
  44. data/lib/appsignal/hooks/redis.rb +1 -0
  45. data/lib/appsignal/hooks/sequel.rb +1 -0
  46. data/lib/appsignal/hooks/shoryuken.rb +1 -0
  47. data/lib/appsignal/hooks/sidekiq.rb +1 -0
  48. data/lib/appsignal/hooks/unicorn.rb +1 -0
  49. data/lib/appsignal/hooks/webmachine.rb +1 -0
  50. data/lib/appsignal/integrations/capistrano/appsignal.cap +4 -4
  51. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +2 -0
  52. data/lib/appsignal/integrations/data_mapper.rb +1 -1
  53. data/lib/appsignal/integrations/delayed_job_plugin.rb +1 -0
  54. data/lib/appsignal/integrations/grape.rb +3 -1
  55. data/lib/appsignal/integrations/mongo_ruby_driver.rb +1 -0
  56. data/lib/appsignal/integrations/padrino.rb +36 -21
  57. data/lib/appsignal/integrations/railtie.rb +2 -2
  58. data/lib/appsignal/integrations/resque.rb +1 -0
  59. data/lib/appsignal/integrations/resque_active_job.rb +1 -0
  60. data/lib/appsignal/integrations/webmachine.rb +27 -24
  61. data/lib/appsignal/js_exception_transaction.rb +8 -8
  62. data/lib/appsignal/marker.rb +41 -4
  63. data/lib/appsignal/minutely.rb +1 -0
  64. data/lib/appsignal/rack/generic_instrumentation.rb +3 -2
  65. data/lib/appsignal/rack/js_exception_catcher.rb +55 -15
  66. data/lib/appsignal/rack/rails_instrumentation.rb +2 -1
  67. data/lib/appsignal/rack/sinatra_instrumentation.rb +4 -2
  68. data/lib/appsignal/rack/streaming_listener.rb +4 -2
  69. data/lib/appsignal/system.rb +5 -31
  70. data/lib/appsignal/transaction.rb +71 -6
  71. data/lib/appsignal/transmitter.rb +24 -13
  72. data/lib/appsignal/utils.rb +18 -11
  73. data/lib/appsignal/utils/params_sanitizer.rb +2 -1
  74. data/lib/appsignal/utils/query_params_sanitizer.rb +1 -0
  75. data/lib/appsignal/version.rb +1 -1
  76. data/resources/appsignal.yml.erb +1 -1
  77. data/spec/lib/appsignal/auth_check_spec.rb +64 -22
  78. data/spec/lib/appsignal/cli/diagnose_spec.rb +539 -81
  79. data/spec/lib/appsignal/cli/helpers_spec.rb +74 -2
  80. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  81. data/spec/lib/appsignal/config_spec.rb +38 -72
  82. data/spec/lib/appsignal/demo_spec.rb +2 -2
  83. data/spec/lib/appsignal/event_formatter_spec.rb +2 -2
  84. data/spec/lib/appsignal/extension_spec.rb +4 -0
  85. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +18 -21
  86. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +1 -1
  87. data/spec/lib/appsignal/hooks/redis_spec.rb +34 -44
  88. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +2 -2
  89. data/spec/lib/appsignal/integrations/grape_spec.rb +6 -6
  90. data/spec/lib/appsignal/integrations/padrino_spec.rb +241 -122
  91. data/spec/lib/appsignal/integrations/railtie_spec.rb +34 -16
  92. data/spec/lib/appsignal/integrations/resque_spec.rb +1 -1
  93. data/spec/lib/appsignal/integrations/sinatra_spec.rb +38 -10
  94. data/spec/lib/appsignal/integrations/webmachine_spec.rb +2 -2
  95. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +7 -6
  96. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +95 -58
  97. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +9 -6
  98. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +11 -10
  99. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +20 -13
  100. data/spec/lib/appsignal/system_spec.rb +2 -32
  101. data/spec/lib/appsignal/transaction_spec.rb +48 -7
  102. data/spec/lib/appsignal/transmitter_spec.rb +52 -33
  103. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +3 -1
  104. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +3 -3
  105. data/spec/lib/appsignal/utils_spec.rb +49 -6
  106. data/spec/lib/appsignal_spec.rb +60 -5
  107. data/spec/spec_helper.rb +4 -3
  108. data/spec/support/helpers/api_request_helper.rb +1 -4
  109. data/spec/support/helpers/dependency_helper.rb +4 -0
  110. data/spec/support/helpers/system_helpers.rb +1 -17
  111. data/spec/support/helpers/time_helpers.rb +1 -1
  112. metadata +19 -8
  113. data/spec/lib/appsignal/system/container_spec.rb +0 -67
  114. data/spec/lib/appsignal/utils/gzip_spec.rb +0 -10
@@ -1,5 +1,21 @@
1
1
  module Appsignal
2
+ # Class used to perform a Push API validation / authentication check against
3
+ # the AppSignal Push API.
4
+ #
5
+ # @example
6
+ # config = Appsignal::Config.new(Dir.pwd, "production")
7
+ # auth_check = Appsignal::AuthCheck.new(config)
8
+ # # Valid push_api_key
9
+ # auth_check.perform # => "200"
10
+ # # Invalid push_api_key
11
+ # auth_check.perform # => "401"
12
+ #
13
+ # @!attribute [r] config
14
+ # @return [Appsignal::Config] config to use in the authentication request.
15
+ # @api private
2
16
  class AuthCheck
17
+ # Path used on the AppSignal Push API
18
+ # https://push.appsignal.com/1/auth
3
19
  ACTION = "auth".freeze
4
20
 
5
21
  attr_reader :config, :logger
@@ -12,10 +28,21 @@ module Appsignal
12
28
  end
13
29
  end
14
30
 
31
+ # Perform push api validation request and return response status code.
32
+ #
33
+ # @return [String] response status code.
34
+ # @raise [StandardError] see {Appsignal::Transmitter#transmit}.
15
35
  def perform
16
- Appsignal::Transmitter.new(ACTION, config).transmit({})
36
+ Appsignal::Transmitter.new(ACTION, config).transmit({}).code
17
37
  end
18
38
 
39
+ # Perform push api validation request and return a descriptive response
40
+ # tuple.
41
+ #
42
+ # @return [Array<String/nil, String>] response tuple.
43
+ # - First value is the response status code.
44
+ # - Second value is a description of the response and the exception error
45
+ # message if an exception occured.
19
46
  def perform_with_result
20
47
  status = perform
21
48
  result =
@@ -9,6 +9,7 @@ require "appsignal/cli/install"
9
9
  require "appsignal/cli/notify_of_deploy"
10
10
 
11
11
  module Appsignal
12
+ # @api private
12
13
  class CLI
13
14
  AVAILABLE_COMMANDS = %w(demo diagnose install notify_of_deploy).freeze
14
15
 
@@ -2,8 +2,48 @@ require "appsignal/demo"
2
2
 
3
3
  module Appsignal
4
4
  class CLI
5
+ # Command line tool for sending demonstration samples to AppSignal.com
6
+ #
7
+ # This command line tool is useful when testing AppSignal on a system and
8
+ # validating the local configuration. It tests if the installation of
9
+ # AppSignal has succeeded and if the AppSignal agent is able to run on the
10
+ # machine's architecture and communicate with the AppSignal servers.
11
+ #
12
+ # The same test is also run during installation with
13
+ # {Appsignal::CLI::Install}.
14
+ #
15
+ # ## Exit codes
16
+ #
17
+ # - Exits with status code `0` if the demo command has finished.
18
+ # - Exits with status code `1` if the demo command failed to finished.
19
+ #
20
+ # @example On the command line in your project
21
+ # appsignal demo
22
+ #
23
+ # @example With a specific environment
24
+ # appsignal demo --environment=production
25
+ #
26
+ # @example Standalone run
27
+ # gem install appsignal
28
+ # export APPSIGNAL_APP_NAME="My test app"
29
+ # export APPSIGNAL_APP_ENV="test"
30
+ # export APPSIGNAL_PUSH_API_KEY="xxxx-xxxx-xxxx-xxxx"
31
+ # appsignal demo
32
+ #
33
+ # @since 2.0.0
34
+ # @see Appsignal::Demo
35
+ # @see Appsignal::CLI::Install
36
+ # @see http://docs.appsignal.com/ruby/command-line/demo.html
37
+ # AppSignal demo documentation
38
+ # @see http://docs.appsignal.com/support/debugging.html
39
+ # Debugging AppSignal guide
40
+ # @api private
5
41
  class Demo
6
42
  class << self
43
+ # @param options [Hash]
44
+ # @option options :environment [String] environment to load
45
+ # configuration for.
46
+ # @return [void]
7
47
  def run(options = {})
8
48
  ENV["APPSIGNAL_APP_ENV"] = options[:environment] if options[:environment]
9
49
 
@@ -5,19 +5,82 @@ require "etc"
5
5
 
6
6
  module Appsignal
7
7
  class CLI
8
+ # Command line tool to run diagnostics on your project.
9
+ #
10
+ # This command line tool is useful when testing AppSignal on a system and
11
+ # validating the local configuration. It outputs useful information to
12
+ # debug issues and it checks if AppSignal agent is able to run on the
13
+ # machine's architecture and communicate with the AppSignal servers.
14
+ #
15
+ # This diagnostic tool outputs the following:
16
+ # - if AppSignal can run on the host system.
17
+ # - if the configuration is valid and active.
18
+ # - if the Push API key is present and valid (internet connection required).
19
+ # - if the required system paths exist and are writable.
20
+ # - outputs AppSignal version information.
21
+ # - outputs information about the host system and Ruby.
22
+ # - outputs last lines from the available log files.
23
+ #
24
+ # ## Exit codes
25
+ #
26
+ # - Exits with status code `0` if the diagnose command has finished.
27
+ # - Exits with status code `1` if the diagnose command failed to finished.
28
+ #
29
+ # @example On the command line in your project
30
+ # appsignal diagnose
31
+ #
32
+ # @example With a specific environment
33
+ # appsignal diagnose --environment=production
34
+ #
35
+ # @see http://docs.appsignal.com/support/debugging.html Debugging AppSignal
36
+ # @see http://docs.appsignal.com/ruby/command-line/diagnose.html
37
+ # AppSignal diagnose documentation
38
+ # @since 1.1.0
8
39
  class Diagnose
40
+ extend CLI::Helpers
41
+
42
+ DIAGNOSE_ENDPOINT = "https://appsignal.com/diag".freeze
43
+
44
+ module Data
45
+ def data
46
+ @data ||= Hash.new { |hash, key| hash[key] = {} }
47
+ end
48
+
49
+ def data_section(key)
50
+ @section = key
51
+ yield
52
+ @section = nil
53
+ end
54
+
55
+ def current_section
56
+ @section
57
+ end
58
+
59
+ def save(key, value)
60
+ data[current_section][key] = value
61
+ end
62
+ end
63
+ extend Data
64
+
9
65
  class << self
66
+ # @param options [Hash]
67
+ # @option options :environment [String] environment to load
68
+ # configuration for.
69
+ # @return [void]
70
+ # @api private
10
71
  def run(options = {})
11
72
  header
12
73
  empty_line
13
74
 
14
- agent_version
75
+ library_information
15
76
  empty_line
16
77
 
17
78
  host_information
18
79
  empty_line
19
80
 
20
- start_appsignal(options)
81
+ configure_appsignal(options)
82
+ run_agent_diagnose_mode
83
+ empty_line
21
84
 
22
85
  config
23
86
  empty_line
@@ -25,30 +88,178 @@ module Appsignal
25
88
  check_api_key
26
89
  empty_line
27
90
 
28
- paths_writable
91
+ paths_section
29
92
  empty_line
30
93
 
31
94
  log_files
95
+
96
+ transmit_report_to_appsignal if send_report_to_appsignal?
32
97
  end
33
98
 
34
99
  private
35
100
 
36
- def start_appsignal(options)
101
+ def send_report_to_appsignal?
102
+ puts "\nDiagnostics report"
103
+ puts " Do you want to send this diagnostics report to AppSignal?"
104
+ puts " If you share this diagnostics report you will be given\n" \
105
+ " a support token you can use to refer to your diagnotics \n" \
106
+ " report when you contact us at support@appsignal.com\n\n"
107
+ send_diagnostics = yes_or_no(
108
+ " Send diagnostics report to AppSignal? (Y/n): ",
109
+ :default => "y"
110
+ )
111
+ unless send_diagnostics
112
+ puts " Not sending diagnostics information to AppSignal."
113
+ return false
114
+ end
115
+ true
116
+ end
117
+
118
+ def transmit_report_to_appsignal
119
+ puts "\n Transmitting diagnostics report"
120
+ transmitter = Transmitter.new(
121
+ DIAGNOSE_ENDPOINT,
122
+ Appsignal.config
123
+ )
124
+ response = transmitter.transmit(:diagnose => data)
125
+
126
+ unless response.code == "200"
127
+ puts " Error: Something went wrong while submitting the report "\
128
+ "to AppSignal."
129
+ puts " Response code: #{response.code}"
130
+ puts " Response body:\n#{response.body}"
131
+ return
132
+ end
133
+
134
+ puts " Your diagnostics report has been sent to AppSignal."
135
+ begin
136
+ response_data = JSON.parse(response.body)
137
+ puts " Your support token: #{response_data["token"]}"
138
+ rescue JSON::ParserError
139
+ puts " Error: Couldn't decode server response."
140
+ puts " #{response.body}"
141
+ end
142
+ end
143
+
144
+ def puts_and_save(key, label, value)
145
+ save key, value
146
+ puts_value label, value
147
+ end
148
+
149
+ def puts_value(label, value, options = {})
150
+ options[:level] ||= 1
151
+ puts "#{" " * options[:level]}#{label}: #{value}"
152
+ end
153
+
154
+ def configure_appsignal(options)
37
155
  current_path = Dir.pwd
38
156
  initial_config = {}
39
157
  if rails_app?
158
+ data[:app][:rails] = true
40
159
  current_path = Rails.root
41
160
  initial_config[:name] = Rails.application.class.parent_name
42
- initial_config[:log_path] = Rails.root.join("log")
161
+ initial_config[:log_path] = current_path.join("log")
43
162
  end
44
163
 
45
- ENV["APPSIGNAL_DIAGNOSE"] = "true"
46
164
  Appsignal.config = Appsignal::Config.new(
47
165
  current_path,
48
166
  options[:environment],
49
167
  initial_config
50
168
  )
51
- Appsignal.start
169
+ Appsignal.config.write_to_environment
170
+ end
171
+
172
+ def run_agent_diagnose_mode
173
+ puts "Agent diagnostics"
174
+ ENV["_APPSIGNAL_DIAGNOSE"] = "true"
175
+ diagnostics_report_string = Appsignal::Extension.diagnose
176
+ ENV.delete("_APPSIGNAL_DIAGNOSE")
177
+
178
+ begin
179
+ report = JSON.parse(diagnostics_report_string)
180
+ data[:agent] = report
181
+ print_agent_report(report)
182
+ rescue JSON::ParserError => error
183
+ puts " Error while parsing agent diagnostics report:"
184
+ puts " Error: #{error}"
185
+ puts " Output: #{diagnostics_report_string}"
186
+ data[:agent] = {
187
+ :error => error,
188
+ :output => diagnostics_report_string.split("\n")
189
+ }
190
+ end
191
+ end
192
+
193
+ def print_agent_report(report)
194
+ if report["error"]
195
+ puts " Error: #{report["error"]}"
196
+ return
197
+ end
198
+
199
+ agent_diagnostic_test_definition.each do |part, categories|
200
+ categories.each do |category, tests|
201
+ tests.each do |test_name, test_definition|
202
+ test_report = report
203
+ .fetch(part, {})
204
+ .fetch(category, {})
205
+ .fetch(test_name, {})
206
+
207
+ print_agent_test(test_definition, test_report)
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ def print_agent_test(definition, test)
214
+ value = test["result"]
215
+ error = test["error"]
216
+ output = test["output"]
217
+
218
+ print " #{definition[:label]}: "
219
+ display_value = definition[:values][value]
220
+ print display_value.nil? ? "-" : display_value
221
+ print "\n Error: #{error}" if error
222
+ print "\n Output: #{output}" if output
223
+ print "\n"
224
+ end
225
+
226
+ def agent_diagnostic_test_definition
227
+ {
228
+ "extension" => {
229
+ "config" => {
230
+ "valid" => {
231
+ :label => "Extension config",
232
+ :values => { true => "valid", false => "invalid" }
233
+ }
234
+ }
235
+ },
236
+ "agent" => {
237
+ "boot" => {
238
+ "started" => {
239
+ :label => "Agent started",
240
+ :values => { true => "started", false => "not started" }
241
+ }
242
+ },
243
+ "config" => {
244
+ "valid" => {
245
+ :label => "Agent config",
246
+ :values => { true => "valid", false => "invalid" }
247
+ }
248
+ },
249
+ "logger" => {
250
+ "started" => {
251
+ :label => "Agent logger",
252
+ :values => { true => "started", false => "not started" }
253
+ }
254
+ },
255
+ "lock_path" => {
256
+ "created" => {
257
+ :label => "Agent lock path",
258
+ :values => { true => "writable", false => "not writable" }
259
+ }
260
+ }
261
+ }
262
+ }
52
263
  end
53
264
 
54
265
  def header
@@ -61,41 +272,51 @@ module Appsignal
61
272
  puts "=" * 80
62
273
  end
63
274
 
64
- def agent_version
65
- puts "AppSignal agent"
66
- puts " Gem version: #{Appsignal::VERSION}"
67
- puts " Agent version: #{Appsignal::Extension.agent_version}"
68
- puts " Gem install path: #{gem_path}"
69
- print " Extension loaded: "
70
- puts Appsignal.extension_loaded ? "yes" : "no"
275
+ def library_information
276
+ puts "AppSignal library"
277
+ data_section :library do
278
+ save :language, "ruby"
279
+ puts_and_save :package_version, "Gem version", Appsignal::VERSION
280
+ puts_and_save :agent_version, "Agent version", Appsignal::Extension.agent_version
281
+ puts_and_save :package_install_path, "Gem install path", gem_path
282
+ puts_and_save :extension_loaded, "Extension loaded", Appsignal.extension_loaded
283
+ end
71
284
  end
72
285
 
73
286
  def host_information
74
287
  rbconfig = RbConfig::CONFIG
75
288
  puts "Host information"
76
- puts " Architecture: #{rbconfig["host_cpu"]}"
77
- puts " Operating System: #{rbconfig["host_os"]}"
78
- puts " Ruby version: #{rbconfig["RUBY_VERSION_NAME"]}"
79
- puts " Heroku: true" if Appsignal::System.heroku?
80
- print " root user: "
81
- puts Process.uid == 0 ? "yes (not recommended)" : "no"
82
-
83
- return unless Appsignal::System.container?
84
- puts " Container id: #{Appsignal::System::Container.id}"
289
+ data_section :host do
290
+ puts_and_save :architecture, "Architecture", rbconfig["host_cpu"]
291
+ puts_and_save :os, "Operating System", rbconfig["host_os"]
292
+ puts_and_save :language_version, "Ruby version",
293
+ "#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"
294
+
295
+ puts_value "Heroku", "true" if Appsignal::System.heroku?
296
+ save :heroku, Appsignal::System.heroku?
297
+
298
+ save :root, Process.uid.zero?
299
+ puts_value "root user",
300
+ Process.uid.zero? ? "true (not recommended)" : "false"
301
+ puts_and_save :running_in_container, "Running in container",
302
+ Appsignal::Extension.running_in_container?
303
+ end
85
304
  end
86
305
 
87
306
  def config
88
307
  puts "Configuration"
89
- environment
308
+ data_section :config do
309
+ puts_environment
90
310
 
91
- Appsignal.config.config_hash.each do |key, value|
92
- puts " #{key}: #{value}"
311
+ Appsignal.config.config_hash.each do |key, value|
312
+ puts_and_save key, key, value
313
+ end
93
314
  end
94
315
  end
95
316
 
96
- def environment
317
+ def puts_environment
97
318
  env = Appsignal.config.env
98
- puts " Environment: #{env}"
319
+ puts_and_save :env, "Environment", env
99
320
 
100
321
  return unless env == ""
101
322
  puts " Warning: No environment set, no config loaded!"
@@ -104,46 +325,62 @@ module Appsignal
104
325
  puts " appsignal diagnose --environment=production"
105
326
  end
106
327
 
107
- def paths_writable
108
- puts "Required paths"
109
-
110
- appsignal_paths.each do |name, path|
111
- puts " #{name}: #{path.to_s.inspect}"
112
- unless path
113
- puts " - Configured?: no"
114
- next
115
- end
116
- unless File.exist? path
117
- puts " - Exists?: no"
118
- next
328
+ def paths_section
329
+ puts "Paths"
330
+ data[:process] = process_user
331
+ data_section :paths do
332
+ appsignal_paths.each do |name, path|
333
+ path_info = {
334
+ :path => path,
335
+ :configured => !path.nil?,
336
+ :exists => false,
337
+ :writable => false
338
+ }
339
+ save name, path_info
340
+
341
+ puts_value name, path.to_s.inspect
342
+
343
+ unless path_info[:configured]
344
+ puts_value "Configured?", "false", :level => 2
345
+ next
346
+ end
347
+ unless File.exist?(path)
348
+ puts_value "Exists?", "false", :level => 2
349
+ next
350
+ end
351
+
352
+ path_info[:exists] = true
353
+ path_info[:writable] = File.writable?(path)
354
+ puts_value "Writable?", path_info[:writable], :level => 2
355
+
356
+ file_owner = path_ownership(path)
357
+ path_info[:ownership] = file_owner
358
+ save name, path_info
359
+
360
+ owned = process_user[:uid] == file_owner[:uid]
361
+ owner = "#{owned} " \
362
+ "(file: #{file_owner[:user]}:#{file_owner[:uid]}, " \
363
+ "process: #{process_user[:user]}:#{process_user[:uid]})"
364
+ puts_value "Ownership?", owner, :level => 2
119
365
  end
120
-
121
- print " - Writable?: "
122
- puts File.writable?(path) ? "yes" : "no"
123
-
124
- ownership = path_ownership(path)
125
- process_owner = ownership[:process]
126
- file_owner = ownership[:file]
127
- print " - Ownership?: "
128
- owned = process_owner[:uid] == file_owner[:uid]
129
- print owned ? "yes" : "no"
130
- print " (file: #{file_owner[:name]}:#{file_owner[:uid]}, "
131
- puts "process: #{process_owner[:name]}:#{process_owner[:uid]})"
132
366
  end
133
367
  end
134
368
 
135
369
  def path_ownership(path)
136
- process_uid = Process.uid
137
370
  file_uid = File.stat(path).uid
138
371
  {
139
- :process => {
140
- :uid => process_uid,
141
- :name => Etc.getpwuid(process_uid).name
142
- },
143
- :file => {
144
- :uid => file_uid,
145
- :name => Etc.getpwuid(file_uid).name
146
- }
372
+ :uid => file_uid,
373
+ :user => Etc.getpwuid(file_uid).name
374
+ }
375
+ end
376
+
377
+ def process_user
378
+ return @process_user if defined?(@process_user)
379
+
380
+ process_uid = Process.uid
381
+ @process_user = {
382
+ :uid => process_uid,
383
+ :user => Etc.getpwuid(process_uid).name
147
384
  }
148
385
  end
149
386
 
@@ -151,7 +388,7 @@ module Appsignal
151
388
  config = Appsignal.config
152
389
  log_file_path = config.log_file_path
153
390
  {
154
- :current_path => Dir.pwd,
391
+ :working_dir => Dir.pwd,
155
392
  :root_path => config.root_path,
156
393
  :log_dir_path => log_file_path ? File.dirname(log_file_path) : "",
157
394
  :log_file_path => log_file_path
@@ -159,46 +396,65 @@ module Appsignal
159
396
  end
160
397
 
161
398
  def check_api_key
162
- auth_check = ::Appsignal::AuthCheck.new(Appsignal.config)
163
- print "Validating API key: "
164
- status, error = auth_check.perform_with_result
165
- case status
166
- when "200"
167
- print "Valid"
168
- when "401"
169
- print "Invalid"
170
- else
171
- print "Failed with status #{status}\n"
172
- puts error if error
399
+ puts "Validation"
400
+ data_section :validation do
401
+ auth_check = ::Appsignal::AuthCheck.new(Appsignal.config)
402
+ status, error = auth_check.perform_with_result
403
+ result =
404
+ case status
405
+ when "200"
406
+ "valid"
407
+ when "401"
408
+ "invalid"
409
+ else
410
+ "Failed with status #{status}\n#{error.inspect}"
411
+ end
412
+ puts_and_save :push_api_key, "Validating Push API key", result
173
413
  end
174
- empty_line
175
414
  end
176
415
 
177
416
  def log_files
178
- install_log
179
- empty_line
180
- mkmf_log
417
+ puts "Log files"
418
+ data_section :logs do
419
+ install_log
420
+ empty_line
421
+ mkmf_log
422
+ end
181
423
  end
182
424
 
183
425
  def install_log
184
- install_log_path = File.join(gem_path, "ext", "install.log")
185
- puts "Extension install log"
186
- output_log_file install_log_path
426
+ puts " Extension install log"
427
+ filename = File.join("ext", "install.log")
428
+ log_info = log_file_info(File.join(gem_path, filename))
429
+ save filename, log_info
430
+ puts_log_file log_info
187
431
  end
188
432
 
189
433
  def mkmf_log
190
- mkmf_log_path = File.join(gem_path, "ext", "mkmf.log")
191
- puts "Makefile install log"
192
- output_log_file mkmf_log_path
434
+ puts " Makefile install log"
435
+ filename = File.join("ext", "mkmf.log")
436
+ log_info = log_file_info(File.join(gem_path, filename))
437
+ save filename, log_info
438
+ puts_log_file log_info
439
+ end
440
+
441
+ def log_file_info(log_file)
442
+ {
443
+ :path => log_file,
444
+ :exists => File.exist?(log_file)
445
+ }.tap do |info|
446
+ next unless info[:exists]
447
+ info[:content] = File.read(log_file).split("\n")
448
+ end
193
449
  end
194
450
 
195
- def output_log_file(log_file)
196
- puts " Path: #{log_file.to_s.inspect}"
197
- if File.exist? log_file
198
- puts " Contents:"
199
- puts File.read(log_file)
451
+ def puts_log_file(log_info)
452
+ puts_value "Path", log_info[:path].to_s.inspect, :level => 2
453
+ if log_info[:exists]
454
+ puts " Contents:"
455
+ puts log_info[:content].join("\n")
200
456
  else
201
- puts " File not found."
457
+ puts " File not found."
202
458
  end
203
459
  end
204
460