appsignal 2.5.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +66 -0
  5. data/.rubocop_todo.yml +124 -0
  6. data/.travis.yml +72 -0
  7. data/.yardopts +8 -0
  8. data/CHANGELOG.md +639 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE +20 -0
  11. data/README.md +264 -0
  12. data/Rakefile +214 -0
  13. data/appsignal.gemspec +42 -0
  14. data/benchmark.rake +77 -0
  15. data/bin/appsignal +13 -0
  16. data/ext/Rakefile +27 -0
  17. data/ext/agent.yml +64 -0
  18. data/ext/appsignal_extension.c +692 -0
  19. data/ext/base.rb +79 -0
  20. data/ext/extconf.rb +35 -0
  21. data/gemfiles/capistrano2.gemfile +7 -0
  22. data/gemfiles/capistrano3.gemfile +7 -0
  23. data/gemfiles/grape.gemfile +7 -0
  24. data/gemfiles/no_dependencies.gemfile +5 -0
  25. data/gemfiles/padrino.gemfile +7 -0
  26. data/gemfiles/que.gemfile +5 -0
  27. data/gemfiles/rails-3.2.gemfile +6 -0
  28. data/gemfiles/rails-4.0.gemfile +6 -0
  29. data/gemfiles/rails-4.1.gemfile +6 -0
  30. data/gemfiles/rails-4.2.gemfile +10 -0
  31. data/gemfiles/rails-5.0.gemfile +5 -0
  32. data/gemfiles/rails-5.1.gemfile +5 -0
  33. data/gemfiles/resque.gemfile +12 -0
  34. data/gemfiles/sequel-435.gemfile +11 -0
  35. data/gemfiles/sequel.gemfile +11 -0
  36. data/gemfiles/sinatra.gemfile +6 -0
  37. data/gemfiles/webmachine.gemfile +5 -0
  38. data/lib/appsignal.rb +804 -0
  39. data/lib/appsignal/auth_check.rb +65 -0
  40. data/lib/appsignal/capistrano.rb +10 -0
  41. data/lib/appsignal/cli.rb +108 -0
  42. data/lib/appsignal/cli/demo.rb +63 -0
  43. data/lib/appsignal/cli/diagnose.rb +500 -0
  44. data/lib/appsignal/cli/helpers.rb +72 -0
  45. data/lib/appsignal/cli/install.rb +277 -0
  46. data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
  47. data/lib/appsignal/config.rb +287 -0
  48. data/lib/appsignal/demo.rb +107 -0
  49. data/lib/appsignal/event_formatter.rb +74 -0
  50. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
  51. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
  52. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
  53. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
  54. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
  55. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
  56. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  57. data/lib/appsignal/extension.rb +63 -0
  58. data/lib/appsignal/extension/jruby.rb +460 -0
  59. data/lib/appsignal/garbage_collection_profiler.rb +48 -0
  60. data/lib/appsignal/hooks.rb +105 -0
  61. data/lib/appsignal/hooks/action_cable.rb +113 -0
  62. data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
  63. data/lib/appsignal/hooks/celluloid.rb +30 -0
  64. data/lib/appsignal/hooks/data_mapper.rb +18 -0
  65. data/lib/appsignal/hooks/delayed_job.rb +19 -0
  66. data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
  67. data/lib/appsignal/hooks/net_http.rb +29 -0
  68. data/lib/appsignal/hooks/passenger.rb +22 -0
  69. data/lib/appsignal/hooks/puma.rb +35 -0
  70. data/lib/appsignal/hooks/que.rb +21 -0
  71. data/lib/appsignal/hooks/rake.rb +39 -0
  72. data/lib/appsignal/hooks/redis.rb +30 -0
  73. data/lib/appsignal/hooks/sequel.rb +60 -0
  74. data/lib/appsignal/hooks/shoryuken.rb +43 -0
  75. data/lib/appsignal/hooks/sidekiq.rb +144 -0
  76. data/lib/appsignal/hooks/unicorn.rb +40 -0
  77. data/lib/appsignal/hooks/webmachine.rb +23 -0
  78. data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
  79. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
  80. data/lib/appsignal/integrations/data_mapper.rb +33 -0
  81. data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
  82. data/lib/appsignal/integrations/grape.rb +53 -0
  83. data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
  84. data/lib/appsignal/integrations/object.rb +35 -0
  85. data/lib/appsignal/integrations/padrino.rb +84 -0
  86. data/lib/appsignal/integrations/que.rb +43 -0
  87. data/lib/appsignal/integrations/railtie.rb +41 -0
  88. data/lib/appsignal/integrations/rake.rb +2 -0
  89. data/lib/appsignal/integrations/resque.rb +20 -0
  90. data/lib/appsignal/integrations/resque_active_job.rb +30 -0
  91. data/lib/appsignal/integrations/sinatra.rb +17 -0
  92. data/lib/appsignal/integrations/webmachine.rb +38 -0
  93. data/lib/appsignal/js_exception_transaction.rb +54 -0
  94. data/lib/appsignal/marker.rb +63 -0
  95. data/lib/appsignal/minutely.rb +42 -0
  96. data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
  97. data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
  98. data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
  99. data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
  100. data/lib/appsignal/rack/streaming_listener.rb +73 -0
  101. data/lib/appsignal/system.rb +81 -0
  102. data/lib/appsignal/transaction.rb +498 -0
  103. data/lib/appsignal/transmitter.rb +107 -0
  104. data/lib/appsignal/utils.rb +127 -0
  105. data/lib/appsignal/utils/params_sanitizer.rb +59 -0
  106. data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
  107. data/lib/appsignal/version.rb +3 -0
  108. data/lib/sequel/extensions/appsignal_integration.rb +3 -0
  109. data/resources/appsignal.yml.erb +39 -0
  110. data/resources/cacert.pem +3866 -0
  111. data/spec/.rubocop.yml +7 -0
  112. data/spec/lib/appsignal/auth_check_spec.rb +80 -0
  113. data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
  114. data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
  115. data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
  116. data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
  117. data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
  118. data/spec/lib/appsignal/cli/install_spec.rb +632 -0
  119. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
  120. data/spec/lib/appsignal/cli_spec.rb +56 -0
  121. data/spec/lib/appsignal/config_spec.rb +637 -0
  122. data/spec/lib/appsignal/demo_spec.rb +87 -0
  123. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
  124. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
  125. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
  126. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
  127. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
  128. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
  129. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
  130. data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
  131. data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
  132. data/spec/lib/appsignal/extension_spec.rb +137 -0
  133. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
  134. data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
  135. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
  136. data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
  137. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
  138. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
  139. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
  140. data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
  141. data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
  142. data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
  143. data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
  144. data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
  145. data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
  146. data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
  147. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
  148. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
  149. data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
  150. data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
  151. data/spec/lib/appsignal/hooks_spec.rb +195 -0
  152. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
  153. data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
  154. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
  155. data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
  156. data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
  157. data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
  158. data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
  159. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
  160. data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
  161. data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
  162. data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
  163. data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
  164. data/spec/lib/appsignal/marker_spec.rb +51 -0
  165. data/spec/lib/appsignal/minutely_spec.rb +50 -0
  166. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
  167. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
  168. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
  169. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
  170. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
  171. data/spec/lib/appsignal/system_spec.rb +131 -0
  172. data/spec/lib/appsignal/transaction_spec.rb +1146 -0
  173. data/spec/lib/appsignal/transmitter_spec.rb +152 -0
  174. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
  175. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
  176. data/spec/lib/appsignal/utils_spec.rb +150 -0
  177. data/spec/lib/appsignal_spec.rb +1049 -0
  178. data/spec/spec_helper.rb +116 -0
  179. data/spec/support/fixtures/containers/cgroups/docker +14 -0
  180. data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
  181. data/spec/support/fixtures/containers/cgroups/lxc +10 -0
  182. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  183. data/spec/support/fixtures/containers/cgroups/none +1 -0
  184. data/spec/support/fixtures/generated_config.yml +24 -0
  185. data/spec/support/fixtures/uploaded_file.txt +0 -0
  186. data/spec/support/helpers/api_request_helper.rb +19 -0
  187. data/spec/support/helpers/cli_helpers.rb +26 -0
  188. data/spec/support/helpers/config_helpers.rb +21 -0
  189. data/spec/support/helpers/dependency_helper.rb +73 -0
  190. data/spec/support/helpers/directory_helper.rb +27 -0
  191. data/spec/support/helpers/env_helpers.rb +33 -0
  192. data/spec/support/helpers/example_exception.rb +13 -0
  193. data/spec/support/helpers/example_standard_error.rb +13 -0
  194. data/spec/support/helpers/log_helpers.rb +22 -0
  195. data/spec/support/helpers/std_streams_helper.rb +66 -0
  196. data/spec/support/helpers/system_helpers.rb +8 -0
  197. data/spec/support/helpers/time_helpers.rb +11 -0
  198. data/spec/support/helpers/transaction_helpers.rb +37 -0
  199. data/spec/support/matchers/contains_log.rb +7 -0
  200. data/spec/support/mocks/fake_gc_profiler.rb +19 -0
  201. data/spec/support/mocks/mock_extension.rb +6 -0
  202. data/spec/support/project_fixture/config/application.rb +0 -0
  203. data/spec/support/project_fixture/config/appsignal.yml +32 -0
  204. data/spec/support/project_fixture/config/environments/development.rb +0 -0
  205. data/spec/support/project_fixture/config/environments/production.rb +0 -0
  206. data/spec/support/project_fixture/config/environments/test.rb +0 -0
  207. data/spec/support/project_fixture/log/.gitkeep +0 -0
  208. data/spec/support/rails/my_app.rb +6 -0
  209. data/spec/support/shared_examples/instrument.rb +43 -0
  210. data/spec/support/stubs/delayed_job.rb +0 -0
  211. metadata +483 -0
@@ -0,0 +1,287 @@
1
+ require "erb"
2
+ require "yaml"
3
+ require "uri"
4
+ require "socket"
5
+ require "tmpdir"
6
+
7
+ module Appsignal
8
+ class Config
9
+ DEFAULT_CONFIG = {
10
+ :debug => false,
11
+ :log => "file",
12
+ :ignore_actions => [],
13
+ :ignore_errors => [],
14
+ :ignore_namespaces => [],
15
+ :filter_parameters => [],
16
+ :send_params => true,
17
+ :endpoint => "https://push.appsignal.com",
18
+ :instrument_net_http => true,
19
+ :instrument_redis => true,
20
+ :instrument_sequel => true,
21
+ :skip_session_data => false,
22
+ :enable_frontend_error_catching => false,
23
+ :frontend_error_catching_path => "/appsignal_error_catcher",
24
+ :enable_allocation_tracking => true,
25
+ :enable_gc_instrumentation => false,
26
+ :enable_host_metrics => true,
27
+ :enable_minutely_probes => false,
28
+ :hostname => ::Socket.gethostname,
29
+ :ca_file_path => File.expand_path(File.join("../../../resources/cacert.pem"), __FILE__),
30
+ :dns_servers => [],
31
+ :files_world_accessible => true
32
+ }.freeze
33
+
34
+ ENV_TO_KEY_MAPPING = {
35
+ "APPSIGNAL_ACTIVE" => :active,
36
+ "APPSIGNAL_PUSH_API_KEY" => :push_api_key,
37
+ "APPSIGNAL_APP_NAME" => :name,
38
+ "APPSIGNAL_PUSH_API_ENDPOINT" => :endpoint,
39
+ "APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH" => :frontend_error_catching_path,
40
+ "APPSIGNAL_DEBUG" => :debug,
41
+ "APPSIGNAL_LOG" => :log,
42
+ "APPSIGNAL_LOG_PATH" => :log_path,
43
+ "APPSIGNAL_INSTRUMENT_NET_HTTP" => :instrument_net_http,
44
+ "APPSIGNAL_INSTRUMENT_REDIS" => :instrument_redis,
45
+ "APPSIGNAL_INSTRUMENT_SEQUEL" => :instrument_sequel,
46
+ "APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data,
47
+ "APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING" => :enable_frontend_error_catching,
48
+ "APPSIGNAL_IGNORE_ACTIONS" => :ignore_actions,
49
+ "APPSIGNAL_IGNORE_ERRORS" => :ignore_errors,
50
+ "APPSIGNAL_IGNORE_NAMESPACES" => :ignore_namespaces,
51
+ "APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
52
+ "APPSIGNAL_SEND_PARAMS" => :send_params,
53
+ "APPSIGNAL_HTTP_PROXY" => :http_proxy,
54
+ "APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => :enable_allocation_tracking,
55
+ "APPSIGNAL_ENABLE_GC_INSTRUMENTATION" => :enable_gc_instrumentation,
56
+ "APPSIGNAL_RUNNING_IN_CONTAINER" => :running_in_container,
57
+ "APPSIGNAL_WORKING_DIR_PATH" => :working_dir_path,
58
+ "APPSIGNAL_ENABLE_HOST_METRICS" => :enable_host_metrics,
59
+ "APPSIGNAL_ENABLE_MINUTELY_PROBES" => :enable_minutely_probes,
60
+ "APPSIGNAL_HOSTNAME" => :hostname,
61
+ "APPSIGNAL_CA_FILE_PATH" => :ca_file_path,
62
+ "APPSIGNAL_DNS_SERVERS" => :dns_servers,
63
+ "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => :files_world_accessible
64
+ }.freeze
65
+
66
+ # Mapping of old and deprecated AppSignal configuration keys
67
+ DEPRECATED_CONFIG_KEY_MAPPING = {
68
+ :api_key => :push_api_key,
69
+ :ignore_exceptions => :ignore_errors
70
+ }.freeze
71
+
72
+ attr_reader :root_path, :env, :initial_config, :config_hash
73
+ attr_accessor :logger
74
+
75
+ def initialize(root_path, env, initial_config = {}, logger = Appsignal.logger)
76
+ @root_path = root_path
77
+ @env = ENV.fetch("APPSIGNAL_APP_ENV".freeze, env.to_s)
78
+ @initial_config = initial_config
79
+ @logger = logger
80
+ @valid = false
81
+ @config_hash = Hash[DEFAULT_CONFIG]
82
+
83
+ # Set config based on the system
84
+ detect_from_system
85
+ # Initial config
86
+ merge(@config_hash, initial_config)
87
+ # Load the config file if it exists
88
+ load_from_disk
89
+ # Load config from environment variables
90
+ load_from_environment
91
+ # Validate that we have a correct config
92
+ validate
93
+ end
94
+
95
+ # @api private
96
+ # @return [String] System's tmp directory.
97
+ def self.system_tmp_dir
98
+ if Gem.win_platform?
99
+ Dir.tmpdir
100
+ else
101
+ File.realpath("/tmp")
102
+ end
103
+ end
104
+
105
+ def [](key)
106
+ config_hash[key]
107
+ end
108
+
109
+ def []=(key, value)
110
+ config_hash[key] = value
111
+ end
112
+
113
+ def log_file_path
114
+ path = config_hash[:log_path] || root_path && File.join(root_path, "log")
115
+ if path && File.writable?(path)
116
+ return File.join(File.realpath(path), "appsignal.log")
117
+ end
118
+
119
+ system_tmp_dir = self.class.system_tmp_dir
120
+ if File.writable? system_tmp_dir
121
+ $stdout.puts "appsignal: Unable to log to '#{path}'. Logging to "\
122
+ "'#{system_tmp_dir}' instead. Please check the "\
123
+ "permissions for the application's (log) directory."
124
+ File.join(system_tmp_dir, "appsignal.log")
125
+ else
126
+ $stdout.puts "appsignal: Unable to log to '#{path}' or the "\
127
+ "'#{system_tmp_dir}' fallback. Please check the permissions "\
128
+ "for the application's (log) directory."
129
+ end
130
+ end
131
+
132
+ def valid?
133
+ @valid
134
+ end
135
+
136
+ def active?
137
+ @valid && config_hash[:active]
138
+ end
139
+
140
+ def write_to_environment # rubocop:disable Metrics/AbcSize
141
+ ENV["_APPSIGNAL_ACTIVE"] = active?.to_s
142
+ ENV["_APPSIGNAL_APP_PATH"] = root_path.to_s
143
+ ENV["_APPSIGNAL_AGENT_PATH"] = File.expand_path("../../../ext", __FILE__).to_s
144
+ ENV["_APPSIGNAL_ENVIRONMENT"] = env
145
+ ENV["_APPSIGNAL_AGENT_VERSION"] = Appsignal::Extension.agent_version
146
+ ENV["_APPSIGNAL_LANGUAGE_INTEGRATION_VERSION"] = "ruby-#{Appsignal::VERSION}"
147
+ ENV["_APPSIGNAL_DEBUG_LOGGING"] = config_hash[:debug].to_s
148
+ ENV["_APPSIGNAL_LOG"] = config_hash[:log]
149
+ ENV["_APPSIGNAL_LOG_FILE_PATH"] = log_file_path.to_s if log_file_path
150
+ ENV["_APPSIGNAL_PUSH_API_ENDPOINT"] = config_hash[:endpoint]
151
+ ENV["_APPSIGNAL_PUSH_API_KEY"] = config_hash[:push_api_key]
152
+ ENV["_APPSIGNAL_APP_NAME"] = config_hash[:name]
153
+ ENV["_APPSIGNAL_HTTP_PROXY"] = config_hash[:http_proxy]
154
+ ENV["_APPSIGNAL_IGNORE_ACTIONS"] = config_hash[:ignore_actions].join(",")
155
+ ENV["_APPSIGNAL_IGNORE_ERRORS"] = config_hash[:ignore_errors].join(",")
156
+ ENV["_APPSIGNAL_IGNORE_NAMESPACES"] = config_hash[:ignore_namespaces].join(",")
157
+ ENV["_APPSIGNAL_FILTER_PARAMETERS"] = config_hash[:filter_parameters].join(",")
158
+ ENV["_APPSIGNAL_SEND_PARAMS"] = config_hash[:send_params].to_s
159
+ ENV["_APPSIGNAL_RUNNING_IN_CONTAINER"] = config_hash[:running_in_container].to_s
160
+ ENV["_APPSIGNAL_WORKING_DIR_PATH"] = config_hash[:working_dir_path] if config_hash[:working_dir_path]
161
+ ENV["_APPSIGNAL_ENABLE_HOST_METRICS"] = config_hash[:enable_host_metrics].to_s
162
+ ENV["_APPSIGNAL_ENABLE_MINUTELY_PROBES"] = config_hash[:enable_minutely_probes].to_s
163
+ ENV["_APPSIGNAL_HOSTNAME"] = config_hash[:hostname].to_s
164
+ ENV["_APPSIGNAL_PROCESS_NAME"] = $PROGRAM_NAME
165
+ ENV["_APPSIGNAL_CA_FILE_PATH"] = config_hash[:ca_file_path].to_s
166
+ ENV["_APPSIGNAL_DNS_SERVERS"] = config_hash[:dns_servers].join(",")
167
+ ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = config_hash[:files_world_accessible].to_s
168
+ end
169
+
170
+ def validate
171
+ # Strip path from endpoint so we're backwards compatible with
172
+ # earlier versions of the gem.
173
+ # TODO: Move to its own method, maybe in `#[]=`?
174
+ endpoint_uri = URI(config_hash[:endpoint])
175
+ config_hash[:endpoint] =
176
+ if endpoint_uri.port == 443
177
+ "#{endpoint_uri.scheme}://#{endpoint_uri.host}"
178
+ else
179
+ "#{endpoint_uri.scheme}://#{endpoint_uri.host}:#{endpoint_uri.port}"
180
+ end
181
+
182
+ if config_hash[:push_api_key]
183
+ @valid = true
184
+ else
185
+ @valid = false
186
+ @logger.error "Push api key not set after loading config"
187
+ end
188
+ end
189
+
190
+ private
191
+
192
+ def config_file
193
+ @config_file ||=
194
+ root_path.nil? ? nil : File.join(root_path, "config", "appsignal.yml")
195
+ end
196
+
197
+ def detect_from_system
198
+ config_hash[:log] = "stdout" if Appsignal::System.heroku?
199
+
200
+ # Make active by default if APPSIGNAL_PUSH_API_KEY is present
201
+ config_hash[:active] = true if ENV["APPSIGNAL_PUSH_API_KEY"]
202
+ end
203
+
204
+ def load_from_disk
205
+ return if !config_file || !File.exist?(config_file)
206
+
207
+ configurations = YAML.load(ERB.new(IO.read(config_file)).result)
208
+ config_for_this_env = configurations[env]
209
+ if config_for_this_env
210
+ config_for_this_env =
211
+ config_for_this_env.each_with_object({}) do |(key, value), hash|
212
+ hash[key.to_sym] = value # convert keys to symbols
213
+ end
214
+
215
+ config_for_this_env = maintain_backwards_compatibility(config_for_this_env)
216
+
217
+ merge(@config_hash, config_for_this_env)
218
+ else
219
+ @logger.error "Not loading from config file: config for '#{env}' not found"
220
+ end
221
+ end
222
+
223
+ # Maintain backwards compatibility with config files generated by earlier
224
+ # versions of the gem
225
+ #
226
+ # Used by {#load_from_disk}. No compatibility for env variables or initial config currently.
227
+ def maintain_backwards_compatibility(configuration)
228
+ configuration.tap do |config|
229
+ DEPRECATED_CONFIG_KEY_MAPPING.each do |old_key, new_key|
230
+ old_config_value = config.delete(old_key)
231
+ next unless old_config_value
232
+ logger.warn "Old configuration key found. Please update the "\
233
+ "'#{old_key}' to '#{new_key}'."
234
+
235
+ next if config[new_key] # Skip if new key is already in use
236
+ config[new_key] = old_config_value
237
+ end
238
+ end
239
+ end
240
+
241
+ def load_from_environment
242
+ config = {}
243
+
244
+ # Configuration with string type
245
+ %w[APPSIGNAL_PUSH_API_KEY APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_ENDPOINT
246
+ APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY
247
+ APPSIGNAL_LOG APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH
248
+ APPSIGNAL_HOSTNAME APPSIGNAL_CA_FILE_PATH].each do |var|
249
+ env_var = ENV[var]
250
+ next unless env_var
251
+ config[ENV_TO_KEY_MAPPING[var]] = env_var
252
+ end
253
+
254
+ # Configuration with boolean type
255
+ %w[APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP
256
+ APPSIGNAL_INSTRUMENT_REDIS APPSIGNAL_INSTRUMENT_SEQUEL
257
+ APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING
258
+ APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
259
+ APPSIGNAL_RUNNING_IN_CONTAINER APPSIGNAL_ENABLE_HOST_METRICS
260
+ APPSIGNAL_SEND_PARAMS APPSIGNAL_ENABLE_MINUTELY_PROBES
261
+ APPSIGNAL_FILES_WORLD_ACCESSIBLE].each do |var|
262
+ env_var = ENV[var]
263
+ next unless env_var
264
+ config[ENV_TO_KEY_MAPPING[var]] = env_var.casecmp("true").zero?
265
+ end
266
+
267
+ # Configuration with array of strings type
268
+ %w[APPSIGNAL_IGNORE_ACTIONS APPSIGNAL_IGNORE_ERRORS
269
+ APPSIGNAL_IGNORE_NAMESPACES APPSIGNAL_FILTER_PARAMETERS].each do |var|
270
+ env_var = ENV[var]
271
+ next unless env_var
272
+ config[ENV_TO_KEY_MAPPING[var]] = env_var.split(",")
273
+ end
274
+
275
+ merge(@config_hash, config)
276
+ end
277
+
278
+ def merge(original_config, new_config)
279
+ new_config.each do |key, value|
280
+ unless original_config[key].nil?
281
+ @logger.debug("Config key '#{key}' is being overwritten")
282
+ end
283
+ original_config[key] = value
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,107 @@
1
+ require "rack/mock"
2
+
3
+ module Appsignal
4
+ # {Appsignal::Demo} is a way to send demonstration / test samples for a
5
+ # exception and a performance issue.
6
+ #
7
+ # @example Loading config automatically
8
+ # Appsignal::Demo.transmit
9
+ #
10
+ # @example With custom config
11
+ # # If another configuration should be used, set it beforehand.
12
+ # Appsignal.config = Appsignal::Config.new(Dir.pwd, "production")
13
+ # Appsignal::Demo.transmit
14
+ #
15
+ # @since 2.0.0
16
+ # @see Appsignal::CLI::Demo
17
+ # @api private
18
+ class Demo
19
+ # Error type used to create demonstration exception.
20
+ class TestError < StandardError; end
21
+
22
+ class << self
23
+ # Starts AppSignal and transmits the demonstration samples to AppSignal
24
+ # using the loaded configuration.
25
+ #
26
+ # @return [Boolean]
27
+ # - returns `false` if Appsignal is not active.
28
+ def transmit
29
+ Appsignal.start
30
+ Appsignal.start_logger
31
+ return false unless Appsignal.active?
32
+
33
+ create_example_error_request
34
+ create_example_performance_request
35
+ true
36
+ end
37
+
38
+ private
39
+
40
+ def create_example_error_request
41
+ transaction = Appsignal::Transaction.create(
42
+ SecureRandom.uuid,
43
+ Appsignal::Transaction::HTTP_REQUEST,
44
+ rack_request
45
+ )
46
+ begin
47
+ raise TestError,
48
+ "Hello world! This is an error used for demonstration purposes."
49
+ rescue => error
50
+ Appsignal.set_error(error)
51
+ end
52
+ transaction.set_http_or_background_queue_start
53
+ transaction.set_metadata("path", "/hello")
54
+ transaction.set_metadata("method", "GET")
55
+ transaction.set_action("DemoController#hello")
56
+ add_demo_metadata_to transaction
57
+ Appsignal::Transaction.complete_current!
58
+ end
59
+
60
+ def create_example_performance_request
61
+ transaction = Appsignal::Transaction.create(
62
+ SecureRandom.uuid,
63
+ Appsignal::Transaction::HTTP_REQUEST,
64
+ rack_request
65
+ )
66
+ Appsignal.instrument "action_view.render", "Render hello.html.erb", "<h1>Hello world!</h1>" do
67
+ sleep 2
68
+ end
69
+ transaction.set_http_or_background_queue_start
70
+ transaction.set_metadata("path", "/hello")
71
+ transaction.set_metadata("method", "GET")
72
+ transaction.set_action("DemoController#hello")
73
+ add_demo_metadata_to transaction
74
+ Appsignal::Transaction.complete_current!
75
+ end
76
+
77
+ def add_demo_metadata_to(transaction)
78
+ transaction.set_metadata("demo_sample", "true")
79
+ end
80
+
81
+ def rack_request
82
+ env = ::Rack::MockRequest.env_for(
83
+ "/demo",
84
+ :params => {
85
+ "controller" => "demo",
86
+ "action" => "hello"
87
+ },
88
+ "REMOTE_ADDR" => "127.0.0.1",
89
+ "REQUEST_METHOD" => "GET",
90
+ "SERVER_NAME" => "localhost",
91
+ "SERVER_PORT" => "80",
92
+ "SERVER_PROTOCOL" => "HTTP/1.1",
93
+ "REQUEST_URI" => "/hello",
94
+ "PATH_INFO" => "/hello",
95
+ "HTTP_ACCEPT" => "text/html,application/xhtml+xml",
96
+ "HTTP_ACCEPT_ENCODING" => "gzip, deflate, sdch",
97
+ "HTTP_ACCEPT_LANGUAGE" => "en-US,en;q=0.8,nl;q=0.6",
98
+ "HTTP_CACHE_CONTROL" => "max-age=0",
99
+ "HTTP_CONNECTION" => "keep-alive",
100
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)",
101
+ "HTTP_REFERER" => "http://appsignal.com/accounts"
102
+ )
103
+ ::Rack::Request.new(env)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,74 @@
1
+ module Appsignal
2
+ # Keeps track of formatters for types event that we can use to get
3
+ # the title and body of an event. Formatters should inherit from this class
4
+ # and implement a format(payload) method which returns an array with the title
5
+ # and body.
6
+ #
7
+ # When implementing a formatter remember that it cannot keep separate state per
8
+ # event, the same object will be called intermittently in a threaded environment.
9
+ # So only keep global configuration as state and pass the payload around as an
10
+ # argument if you need to use helper methods.
11
+ #
12
+ # @api private
13
+ class EventFormatter
14
+ class << self
15
+ def formatters
16
+ @@formatters ||= {}
17
+ end
18
+
19
+ def formatter_classes
20
+ @@formatter_classes ||= {}
21
+ end
22
+
23
+ def register(name, formatter = self)
24
+ formatter_classes[name] = formatter
25
+ end
26
+
27
+ def unregister(name, formatter = self)
28
+ return unless formatter_classes[name] == formatter
29
+
30
+ formatter_classes.delete(name)
31
+ formatters.delete(name)
32
+ end
33
+
34
+ def registered?(name, klass = nil)
35
+ if klass
36
+ formatter_classes[name] == klass
37
+ else
38
+ formatter_classes.include?(name)
39
+ end
40
+ end
41
+
42
+ def initialize_formatters
43
+ formatter_classes.each do |name, formatter|
44
+ begin
45
+ format_method = formatter.instance_method(:format)
46
+ if format_method && format_method.arity == 1
47
+ formatters[name] = formatter.new
48
+ else
49
+ raise "#{f} does not have a format(payload) method"
50
+ end
51
+ rescue => ex
52
+ formatter_classes.delete(name)
53
+ formatters.delete(name)
54
+ Appsignal.logger.debug("'#{ex.message}' when initializing #{name} event formatter")
55
+ end
56
+ end
57
+ end
58
+
59
+ def format(name, payload)
60
+ formatter = formatters[name]
61
+ formatter.format(payload) unless formatter.nil?
62
+ end
63
+ end
64
+
65
+ # @api public
66
+ DEFAULT = 0
67
+ # @api public
68
+ SQL_BODY_FORMAT = 1
69
+ end
70
+ end
71
+
72
+ Dir.glob(File.expand_path("../event_formatter/**/*.rb", __FILE__)).each do |file|
73
+ require file
74
+ end