appsignal 3.10.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +197 -0
  4. data/Gemfile +1 -0
  5. data/Rakefile +1 -1
  6. data/benchmark.rake +99 -42
  7. data/lib/appsignal/cli/demo.rb +0 -1
  8. data/lib/appsignal/cli/diagnose.rb +1 -1
  9. data/lib/appsignal/config.rb +204 -130
  10. data/lib/appsignal/demo.rb +16 -26
  11. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  12. data/lib/appsignal/event_formatter.rb +3 -2
  13. data/lib/appsignal/helpers/instrumentation.rb +331 -19
  14. data/lib/appsignal/hooks/action_cable.rb +21 -16
  15. data/lib/appsignal/hooks/active_job.rb +14 -8
  16. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  17. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  18. data/lib/appsignal/integrations/action_cable.rb +5 -7
  19. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  20. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  21. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  22. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  23. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  24. data/lib/appsignal/integrations/excon.rb +1 -0
  25. data/lib/appsignal/integrations/grape.rb +7 -0
  26. data/lib/appsignal/integrations/hanami.rb +8 -43
  27. data/lib/appsignal/integrations/http.rb +1 -0
  28. data/lib/appsignal/integrations/net_http.rb +1 -0
  29. data/lib/appsignal/integrations/object.rb +6 -0
  30. data/lib/appsignal/integrations/padrino.rb +8 -73
  31. data/lib/appsignal/integrations/que.rb +13 -20
  32. data/lib/appsignal/integrations/railtie.rb +36 -14
  33. data/lib/appsignal/integrations/rake.rb +1 -5
  34. data/lib/appsignal/integrations/redis.rb +1 -0
  35. data/lib/appsignal/integrations/redis_client.rb +1 -0
  36. data/lib/appsignal/integrations/resque.rb +2 -5
  37. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  38. data/lib/appsignal/integrations/sidekiq.rb +7 -15
  39. data/lib/appsignal/integrations/sinatra.rb +8 -19
  40. data/lib/appsignal/integrations/unicorn.rb +1 -0
  41. data/lib/appsignal/integrations/webmachine.rb +2 -5
  42. data/lib/appsignal/loaders/grape.rb +13 -0
  43. data/lib/appsignal/loaders/hanami.rb +40 -0
  44. data/lib/appsignal/loaders/padrino.rb +68 -0
  45. data/lib/appsignal/loaders/sinatra.rb +24 -0
  46. data/lib/appsignal/loaders.rb +92 -0
  47. data/lib/appsignal/logger.rb +7 -3
  48. data/lib/appsignal/probes/helpers.rb +1 -0
  49. data/lib/appsignal/probes/mri.rb +1 -0
  50. data/lib/appsignal/probes/sidekiq.rb +1 -0
  51. data/lib/appsignal/probes.rb +3 -0
  52. data/lib/appsignal/rack/abstract_middleware.rb +20 -13
  53. data/lib/appsignal/rack/event_handler.rb +44 -13
  54. data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
  55. data/lib/appsignal/rack/grape_middleware.rb +2 -1
  56. data/lib/appsignal/rack/streaming_listener.rb +1 -0
  57. data/lib/appsignal/rack.rb +35 -0
  58. data/lib/appsignal/span.rb +1 -0
  59. data/lib/appsignal/transaction.rb +308 -101
  60. data/lib/appsignal/utils/data.rb +0 -1
  61. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  62. data/lib/appsignal/utils/integration_logger.rb +0 -13
  63. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  64. data/lib/appsignal/utils/json.rb +0 -1
  65. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  66. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  67. data/lib/appsignal/utils.rb +6 -0
  68. data/lib/appsignal/version.rb +1 -1
  69. data/lib/appsignal.rb +169 -14
  70. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  71. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  72. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  73. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  74. data/spec/lib/appsignal/config_spec.rb +291 -44
  75. data/spec/lib/appsignal/demo_spec.rb +1 -2
  76. data/spec/lib/appsignal/environment_spec.rb +4 -2
  77. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  78. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  79. data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
  80. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  81. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  82. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  83. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  84. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  85. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  86. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  87. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  88. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  89. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  90. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  91. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  92. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  93. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  94. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  95. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  96. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  97. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  98. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  99. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  100. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  101. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  102. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  103. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  104. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
  105. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  106. data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
  107. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  108. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  109. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  110. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  111. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  112. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  113. data/spec/lib/appsignal/probes_spec.rb +6 -5
  114. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
  115. data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
  116. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  117. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  118. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  119. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  120. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  121. data/spec/lib/appsignal/rack_spec.rb +63 -0
  122. data/spec/lib/appsignal/span_spec.rb +1 -3
  123. data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
  124. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  125. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  126. data/spec/lib/appsignal_spec.rb +601 -36
  127. data/spec/lib/puma/appsignal_spec.rb +0 -3
  128. data/spec/spec_helper.rb +5 -4
  129. data/spec/support/helpers/config_helpers.rb +2 -1
  130. data/spec/support/helpers/loader_helper.rb +21 -0
  131. data/spec/support/helpers/transaction_helpers.rb +44 -20
  132. data/spec/support/matchers/transaction.rb +15 -1
  133. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  134. data/spec/support/testing.rb +47 -1
  135. metadata +19 -2
@@ -10,6 +10,17 @@ module Appsignal
10
10
  class Config
11
11
  include Appsignal::Utils::StdoutAndLoggerMessage
12
12
 
13
+ # @api private
14
+ def self.loader_defaults
15
+ @loader_defaults ||= []
16
+ end
17
+
18
+ # @api private
19
+ def self.add_loader_defaults(name, options)
20
+ loader_defaults << [name, options]
21
+ end
22
+
23
+ # @api private
13
24
  DEFAULT_CONFIG = {
14
25
  :activejob_report_errors => "all",
15
26
  :ca_file_path => File.expand_path(File.join("../../../resources/cacert.pem"), __FILE__),
@@ -67,15 +78,31 @@ module Appsignal
67
78
  "trace" => ::Logger::DEBUG
68
79
  }.freeze
69
80
 
70
- ENV_TO_KEY_MAPPING = {
71
- "APPSIGNAL_ACTIVE" => :active,
81
+ # @api private
82
+ ENV_STRING_KEYS = {
72
83
  "APPSIGNAL_ACTIVEJOB_REPORT_ERRORS" => :activejob_report_errors,
73
84
  "APPSIGNAL_APP_NAME" => :name,
74
85
  "APPSIGNAL_BIND_ADDRESS" => :bind_address,
75
86
  "APPSIGNAL_CA_FILE_PATH" => :ca_file_path,
76
- "APPSIGNAL_CPU_COUNT" => :cpu_count,
87
+ "APPSIGNAL_HOSTNAME" => :hostname,
88
+ "APPSIGNAL_HOST_ROLE" => :host_role,
89
+ "APPSIGNAL_HTTP_PROXY" => :http_proxy,
90
+ "APPSIGNAL_LOG" => :log,
91
+ "APPSIGNAL_LOG_LEVEL" => :log_level,
92
+ "APPSIGNAL_LOG_PATH" => :log_path,
93
+ "APPSIGNAL_LOGGING_ENDPOINT" => :logging_endpoint,
94
+ "APPSIGNAL_PUSH_API_ENDPOINT" => :endpoint,
95
+ "APPSIGNAL_PUSH_API_KEY" => :push_api_key,
96
+ "APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => :sidekiq_report_errors,
97
+ "APPSIGNAL_STATSD_PORT" => :statsd_port,
98
+ "APPSIGNAL_WORKING_DIRECTORY_PATH" => :working_directory_path,
99
+ "APPSIGNAL_WORKING_DIR_PATH" => :working_dir_path,
100
+ "APP_REVISION" => :revision
101
+ }.freeze
102
+ # @api private
103
+ ENV_BOOLEAN_KEYS = {
104
+ "APPSIGNAL_ACTIVE" => :active,
77
105
  "APPSIGNAL_DEBUG" => :debug,
78
- "APPSIGNAL_DNS_SERVERS" => :dns_servers,
79
106
  "APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => :enable_allocation_tracking,
80
107
  "APPSIGNAL_ENABLE_HOST_METRICS" => :enable_host_metrics,
81
108
  "APPSIGNAL_ENABLE_MINUTELY_PROBES" => :enable_minutely_probes,
@@ -87,100 +114,33 @@ module Appsignal
87
114
  "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION" =>
88
115
  :enable_rake_performance_instrumentation,
89
116
  "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => :files_world_accessible,
90
- "APPSIGNAL_FILTER_METADATA" => :filter_metadata,
91
- "APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
92
- "APPSIGNAL_FILTER_SESSION_DATA" => :filter_session_data,
93
- "APPSIGNAL_HOSTNAME" => :hostname,
94
- "APPSIGNAL_HOST_ROLE" => :host_role,
95
- "APPSIGNAL_HTTP_PROXY" => :http_proxy,
96
- "APPSIGNAL_IGNORE_ACTIONS" => :ignore_actions,
97
- "APPSIGNAL_IGNORE_ERRORS" => :ignore_errors,
98
- "APPSIGNAL_IGNORE_LOGS" => :ignore_logs,
99
- "APPSIGNAL_IGNORE_NAMESPACES" => :ignore_namespaces,
100
117
  "APPSIGNAL_INSTRUMENT_HTTP_RB" => :instrument_http_rb,
101
118
  "APPSIGNAL_INSTRUMENT_NET_HTTP" => :instrument_net_http,
102
119
  "APPSIGNAL_INSTRUMENT_REDIS" => :instrument_redis,
103
120
  "APPSIGNAL_INSTRUMENT_SEQUEL" => :instrument_sequel,
104
- "APPSIGNAL_LOG" => :log,
105
- "APPSIGNAL_LOG_LEVEL" => :log_level,
106
- "APPSIGNAL_LOG_PATH" => :log_path,
107
- "APPSIGNAL_LOGGING_ENDPOINT" => :logging_endpoint,
108
- "APPSIGNAL_PUSH_API_ENDPOINT" => :endpoint,
109
- "APPSIGNAL_PUSH_API_KEY" => :push_api_key,
110
- "APPSIGNAL_REQUEST_HEADERS" => :request_headers,
111
121
  "APPSIGNAL_RUNNING_IN_CONTAINER" => :running_in_container,
112
122
  "APPSIGNAL_SEND_ENVIRONMENT_METADATA" => :send_environment_metadata,
113
123
  "APPSIGNAL_SEND_PARAMS" => :send_params,
114
124
  "APPSIGNAL_SEND_SESSION_DATA" => :send_session_data,
115
- "APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => :sidekiq_report_errors,
116
125
  "APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data,
117
- "APPSIGNAL_STATSD_PORT" => :statsd_port,
118
- "APPSIGNAL_TRANSACTION_DEBUG_MODE" => :transaction_debug_mode,
119
- "APPSIGNAL_WORKING_DIRECTORY_PATH" => :working_directory_path,
120
- "APPSIGNAL_WORKING_DIR_PATH" => :working_dir_path,
121
- "APP_REVISION" => :revision
126
+ "APPSIGNAL_TRANSACTION_DEBUG_MODE" => :transaction_debug_mode
122
127
  }.freeze
123
128
  # @api private
124
- ENV_STRING_KEYS = %w[
125
- APPSIGNAL_ACTIVEJOB_REPORT_ERRORS
126
- APPSIGNAL_APP_NAME
127
- APPSIGNAL_BIND_ADDRESS
128
- APPSIGNAL_CA_FILE_PATH
129
- APPSIGNAL_HOSTNAME
130
- APPSIGNAL_HOST_ROLE
131
- APPSIGNAL_HTTP_PROXY
132
- APPSIGNAL_LOG
133
- APPSIGNAL_LOG_LEVEL
134
- APPSIGNAL_LOG_PATH
135
- APPSIGNAL_LOGGING_ENDPOINT
136
- APPSIGNAL_PUSH_API_ENDPOINT
137
- APPSIGNAL_PUSH_API_KEY
138
- APPSIGNAL_SIDEKIQ_REPORT_ERRORS
139
- APPSIGNAL_STATSD_PORT
140
- APPSIGNAL_WORKING_DIRECTORY_PATH
141
- APPSIGNAL_WORKING_DIR_PATH
142
- APP_REVISION
143
- ].freeze
144
- # @api private
145
- ENV_BOOLEAN_KEYS = %w[
146
- APPSIGNAL_ACTIVE
147
- APPSIGNAL_DEBUG
148
- APPSIGNAL_ENABLE_ALLOCATION_TRACKING
149
- APPSIGNAL_ENABLE_HOST_METRICS
150
- APPSIGNAL_ENABLE_MINUTELY_PROBES
151
- APPSIGNAL_ENABLE_STATSD
152
- APPSIGNAL_ENABLE_NGINX_METRICS
153
- APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER
154
- APPSIGNAL_ENABLE_GVL_WAITING_THREADS
155
- APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER
156
- APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION
157
- APPSIGNAL_FILES_WORLD_ACCESSIBLE
158
- APPSIGNAL_INSTRUMENT_HTTP_RB
159
- APPSIGNAL_INSTRUMENT_NET_HTTP
160
- APPSIGNAL_INSTRUMENT_REDIS
161
- APPSIGNAL_INSTRUMENT_SEQUEL
162
- APPSIGNAL_RUNNING_IN_CONTAINER
163
- APPSIGNAL_SEND_ENVIRONMENT_METADATA
164
- APPSIGNAL_SEND_PARAMS
165
- APPSIGNAL_SEND_SESSION_DATA
166
- APPSIGNAL_SKIP_SESSION_DATA
167
- APPSIGNAL_TRANSACTION_DEBUG_MODE
168
- ].freeze
129
+ ENV_ARRAY_KEYS = {
130
+ "APPSIGNAL_DNS_SERVERS" => :dns_servers,
131
+ "APPSIGNAL_FILTER_METADATA" => :filter_metadata,
132
+ "APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
133
+ "APPSIGNAL_FILTER_SESSION_DATA" => :filter_session_data,
134
+ "APPSIGNAL_IGNORE_ACTIONS" => :ignore_actions,
135
+ "APPSIGNAL_IGNORE_ERRORS" => :ignore_errors,
136
+ "APPSIGNAL_IGNORE_LOGS" => :ignore_logs,
137
+ "APPSIGNAL_IGNORE_NAMESPACES" => :ignore_namespaces,
138
+ "APPSIGNAL_REQUEST_HEADERS" => :request_headers
139
+ }.freeze
169
140
  # @api private
170
- ENV_ARRAY_KEYS = %w[
171
- APPSIGNAL_DNS_SERVERS
172
- APPSIGNAL_FILTER_METADATA
173
- APPSIGNAL_FILTER_PARAMETERS
174
- APPSIGNAL_FILTER_SESSION_DATA
175
- APPSIGNAL_IGNORE_ACTIONS
176
- APPSIGNAL_IGNORE_ERRORS
177
- APPSIGNAL_IGNORE_LOGS
178
- APPSIGNAL_IGNORE_NAMESPACES
179
- APPSIGNAL_REQUEST_HEADERS
180
- ].freeze
181
- ENV_FLOAT_KEYS = %w[
182
- APPSIGNAL_CPU_COUNT
183
- ].freeze
141
+ ENV_FLOAT_KEYS = {
142
+ "APPSIGNAL_CPU_COUNT" => :cpu_count
143
+ }.freeze
184
144
 
185
145
  # @attribute [r] system_config
186
146
  # Config detected on the system level.
@@ -211,23 +171,15 @@ module Appsignal
211
171
  # @api private
212
172
  # @return [Hash]
213
173
 
214
- attr_reader :root_path, :env, :config_hash, :system_config,
215
- :initial_config, :file_config, :env_config, :override_config
174
+ # @api private
175
+ attr_accessor :root_path, :env, :config_hash
176
+ attr_reader :system_config, :initial_config, :file_config, :env_config,
177
+ :override_config, :dsl_config
178
+ # @api private
216
179
  attr_accessor :logger
217
180
 
218
181
  # Initialize a new configuration object for AppSignal.
219
182
  #
220
- # If this is manually initialized, and not by {Appsignal.start}, it needs
221
- # to be assigned to the {Appsignal.config} attribute.
222
- #
223
- # @example
224
- # require "appsignal"
225
- # Appsignal.config = Appsignal::Config.new(
226
- # app_path,
227
- # "production"
228
- # )
229
- # Appsignal.start
230
- #
231
183
  # @param root_path [String] Root path of the app.
232
184
  # @param env [String] The environment to load when AppSignal is started. It
233
185
  # will look for an environment with this name in the `config/appsignal.yml`
@@ -241,55 +193,90 @@ module Appsignal
241
193
  # @param config_file [String] Custom config file location. Default
242
194
  # `config/appsignal.yml`.
243
195
  #
196
+ # @api private
244
197
  # @see https://docs.appsignal.com/ruby/configuration/
245
198
  # Configuration documentation
246
199
  # @see https://docs.appsignal.com/ruby/configuration/load-order.html
247
200
  # Configuration load order
248
201
  # @see https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html
249
202
  # How to integrate AppSignal manually
250
- def initialize(
203
+ def initialize( # rubocop:disable Metrics/ParameterLists
251
204
  root_path,
252
- env,
205
+ initial_env,
253
206
  initial_config = {},
254
207
  logger = Appsignal.internal_logger,
255
- config_file = nil
208
+ config_file = nil,
209
+ load_on_new = true # rubocop:disable Style/OptionalBooleanParameter
256
210
  )
257
- @config_file_error = false
258
211
  @root_path = root_path
212
+ @config_file_error = false
259
213
  @config_file = config_file
260
214
  @logger = logger
261
215
  @valid = false
262
- @config_hash = DEFAULT_CONFIG.dup
263
- env_loaded_from_initial = env.to_s
264
- @env =
265
- if ENV.key?("APPSIGNAL_APP_ENV")
266
- env_loaded_from_env = ENV["APPSIGNAL_APP_ENV"]
267
- else
268
- env_loaded_from_initial
269
- end
216
+
217
+ @initial_env = initial_env
218
+ @env = initial_env.to_s
219
+ @config_hash = {}
220
+ @system_config = {}
221
+ @initial_config = initial_config
222
+ @file_config = {}
223
+ @env_config = {}
224
+ @override_config = {}
225
+ @dsl_config = {} # Can be set using `Appsignal.configure`
226
+
227
+ return unless load_on_new
228
+
229
+ # Determine starting environment
230
+ @env = ENV["APPSIGNAL_APP_ENV"] if ENV.key?("APPSIGNAL_APP_ENV")
231
+ load_config
232
+ validate
233
+ end
234
+
235
+ # @api private
236
+ def load_config
237
+ # Set defaults
238
+ # Deep duplicate each frozen default value
239
+ merge(DEFAULT_CONFIG.transform_values(&:dup))
270
240
 
271
241
  # Set config based on the system
272
242
  @system_config = detect_from_system
273
243
  merge(system_config)
274
- # Initial config
275
- @initial_config = initial_config
244
+
245
+ # Set defaults from loaders in reverse order so the first register
246
+ # loader's defaults overwrite all others
247
+ self.class.loader_defaults.reverse.each do |(_loader_name, loader_defaults)|
248
+ defaults = loader_defaults.compact.dup
249
+ # Overwrite root path
250
+ loader_path = defaults.delete(:root_path)
251
+ @root_path = loader_path if loader_path
252
+ # Overwrite env
253
+ loader_env = defaults.delete(:env)
254
+ @env = loader_env.to_s if loader_env
255
+ # Merge with the config loaded so far
256
+ merge(defaults)
257
+ end
258
+
276
259
  merge(initial_config)
260
+ # Track origin of env
261
+ @initial_config[:env] = @initial_env.to_s
262
+
277
263
  # Load the config file if it exists
278
264
  @file_config = load_from_disk || {}
279
265
  merge(file_config)
266
+
280
267
  # Load config from environment variables
281
268
  @env_config = load_from_environment
282
269
  merge(env_config)
270
+ # Track origin of env
271
+ env_loaded_from_env = ENV.fetch("APPSIGNAL_APP_ENV", nil)
272
+ @env_config[:env] = env_loaded_from_env if env_loaded_from_env
273
+
283
274
  # Load config overrides
284
275
  @override_config = determine_overrides
285
276
  merge(override_config)
277
+
286
278
  # Handle deprecated config options
287
279
  maintain_backwards_compatibility
288
- # Validate that we have a correct config
289
- validate
290
- # Track origin of env
291
- @initial_config[:env] = env_loaded_from_initial if env_loaded_from_initial
292
- @env_config[:env] = env_loaded_from_env if env_loaded_from_env
293
280
  end
294
281
 
295
282
  # @api private
@@ -302,6 +289,7 @@ module Appsignal
302
289
  end
303
290
  end
304
291
 
292
+ # @api private
305
293
  def [](key)
306
294
  config_hash[key]
307
295
  end
@@ -316,6 +304,7 @@ module Appsignal
316
304
  config_hash[key] = value
317
305
  end
318
306
 
307
+ # @api private
319
308
  def log_level
320
309
  level = ::Logger::DEBUG if config_hash[:debug] || config_hash[:transaction_debug_mode]
321
310
  option = config_hash[:log_level]
@@ -326,6 +315,7 @@ module Appsignal
326
315
  level.nil? ? Appsignal::Config::DEFAULT_LOG_LEVEL : level
327
316
  end
328
317
 
318
+ # @api private
329
319
  def log_file_path
330
320
  return @log_file_path if defined? @log_file_path
331
321
 
@@ -360,6 +350,7 @@ module Appsignal
360
350
  @valid && config_hash[:active]
361
351
  end
362
352
 
353
+ # @api private
363
354
  def write_to_environment # rubocop:disable Metrics/AbcSize
364
355
  ENV["_APPSIGNAL_ACTIVE"] = active?.to_s
365
356
  ENV["_APPSIGNAL_AGENT_PATH"] = File.expand_path("../../ext", __dir__).to_s
@@ -405,6 +396,13 @@ module Appsignal
405
396
  ENV["_APP_REVISION"] = config_hash[:revision].to_s
406
397
  end
407
398
 
399
+ # @api private
400
+ def merge_dsl_options(options)
401
+ @dsl_options = options
402
+ merge(options)
403
+ end
404
+
405
+ # @api private
408
406
  def validate
409
407
  # Strip path from endpoint so we're backwards compatible with
410
408
  # earlier versions of the gem.
@@ -503,35 +501,35 @@ module Appsignal
503
501
  config = {}
504
502
 
505
503
  # Configuration with string type
506
- ENV_STRING_KEYS.each do |var|
507
- env_var = ENV.fetch(var, nil)
504
+ ENV_STRING_KEYS.each do |env_key, option|
505
+ env_var = ENV.fetch(env_key, nil)
508
506
  next unless env_var
509
507
 
510
- config[ENV_TO_KEY_MAPPING[var]] = env_var
508
+ config[option] = env_var
511
509
  end
512
510
 
513
511
  # Configuration with boolean type
514
- ENV_BOOLEAN_KEYS.each do |var|
515
- env_var = ENV.fetch(var, nil)
512
+ ENV_BOOLEAN_KEYS.each do |env_key, option|
513
+ env_var = ENV.fetch(env_key, nil)
516
514
  next unless env_var
517
515
 
518
- config[ENV_TO_KEY_MAPPING[var]] = env_var.casecmp("true").zero?
516
+ config[option] = env_var.casecmp("true").zero?
519
517
  end
520
518
 
521
519
  # Configuration with array of strings type
522
- ENV_ARRAY_KEYS.each do |var|
523
- env_var = ENV.fetch(var, nil)
520
+ ENV_ARRAY_KEYS.each do |env_key, option|
521
+ env_var = ENV.fetch(env_key, nil)
524
522
  next unless env_var
525
523
 
526
- config[ENV_TO_KEY_MAPPING[var]] = env_var.split(",")
524
+ config[option] = env_var.split(",")
527
525
  end
528
526
 
529
527
  # Configuration with float type
530
- ENV_FLOAT_KEYS.each do |var|
531
- env_var = ENV.fetch(var, nil)
528
+ ENV_FLOAT_KEYS.each do |env_key, option|
529
+ env_var = ENV.fetch(env_key, nil)
532
530
  next unless env_var
533
531
 
534
- config[ENV_TO_KEY_MAPPING[var]] = env_var.to_f
532
+ config[option] = env_var.to_f
535
533
  end
536
534
 
537
535
  config
@@ -590,5 +588,81 @@ module Appsignal
590
588
  value = ENV.fetch("APPSIGNAL_INACTIVE_ON_CONFIG_FILE_ERROR", false)
591
589
  ["1", "true"].include?(value)
592
590
  end
591
+
592
+ # @api private
593
+ class ConfigDSL
594
+ attr_reader :dsl_options
595
+
596
+ def initialize(config)
597
+ @config = config
598
+ @dsl_options = {}
599
+ end
600
+
601
+ def app_path
602
+ @config.root_path
603
+ end
604
+
605
+ def app_path=(path)
606
+ @config.root_path = path
607
+ end
608
+
609
+ def env
610
+ @config.env
611
+ end
612
+
613
+ Appsignal::Config::ENV_STRING_KEYS.each_value do |option|
614
+ define_method(option) do
615
+ fetch_option(option)
616
+ end
617
+
618
+ define_method("#{option}=") do |value|
619
+ update_option(option, value.to_s)
620
+ end
621
+ end
622
+
623
+ Appsignal::Config::ENV_BOOLEAN_KEYS.each_value do |option|
624
+ define_method(option) do
625
+ fetch_option(option)
626
+ end
627
+
628
+ define_method("#{option}=") do |value|
629
+ update_option(option, !!value)
630
+ end
631
+ end
632
+
633
+ Appsignal::Config::ENV_ARRAY_KEYS.each_value do |option|
634
+ define_method(option) do
635
+ fetch_option(option)
636
+ end
637
+
638
+ define_method("#{option}=") do |value|
639
+ update_option(option, value.to_a)
640
+ end
641
+ end
642
+
643
+ Appsignal::Config::ENV_FLOAT_KEYS.each_value do |option|
644
+ define_method(option) do
645
+ fetch_option(option)
646
+ end
647
+
648
+ define_method("#{option}=") do |value|
649
+ update_option(option, value.to_f)
650
+ end
651
+ end
652
+
653
+ private
654
+
655
+ def fetch_option(key)
656
+ if @dsl_options.key?(key)
657
+ @dsl_options[key]
658
+ else
659
+ @dsl_options[key] = @config[key].dup
660
+ end
661
+ end
662
+
663
+ def update_option(key, value)
664
+ @dsl_options[key] = value
665
+ end
666
+ end
593
667
  end
594
668
  end
@@ -6,12 +6,7 @@ module Appsignal
6
6
  # {Appsignal::Demo} is a way to send demonstration / test samples for a
7
7
  # exception and a performance issue.
8
8
  #
9
- # @example Loading config automatically
10
- # Appsignal::Demo.transmit
11
- #
12
- # @example With custom config
13
- # # If another configuration should be used, set it beforehand.
14
- # Appsignal.config = Appsignal::Config.new(Dir.pwd, "production")
9
+ # @example Send example transactions
15
10
  # Appsignal::Demo.transmit
16
11
  #
17
12
  # @since 2.0.0
@@ -39,18 +34,15 @@ module Appsignal
39
34
  private
40
35
 
41
36
  def create_example_error_request
42
- transaction = Appsignal::Transaction.create(
43
- SecureRandom.uuid,
44
- Appsignal::Transaction::HTTP_REQUEST,
45
- rack_request
46
- )
37
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::HTTP_REQUEST)
47
38
  begin
48
39
  raise TestError,
49
40
  "Hello world! This is an error used for demonstration purposes."
50
41
  rescue => error
51
42
  Appsignal.set_error(error)
52
43
  end
53
- transaction.set_http_or_background_queue_start
44
+ add_params_to(transaction)
45
+ add_headers_to(transaction)
54
46
  transaction.set_metadata("path", "/hello")
55
47
  transaction.set_metadata("method", "GET")
56
48
  transaction.set_action("DemoController#hello")
@@ -59,16 +51,13 @@ module Appsignal
59
51
  end
60
52
 
61
53
  def create_example_performance_request
62
- transaction = Appsignal::Transaction.create(
63
- SecureRandom.uuid,
64
- Appsignal::Transaction::HTTP_REQUEST,
65
- rack_request
66
- )
54
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::HTTP_REQUEST)
67
55
  Appsignal.instrument "action_view.render", "Render hello.html.erb",
68
56
  "<h1>Hello world!</h1>" do
69
57
  sleep 2
70
58
  end
71
- transaction.set_http_or_background_queue_start
59
+ add_params_to(transaction)
60
+ add_headers_to(transaction)
72
61
  transaction.set_metadata("path", "/hello")
73
62
  transaction.set_metadata("method", "GET")
74
63
  transaction.set_action("DemoController#hello")
@@ -80,13 +69,15 @@ module Appsignal
80
69
  transaction.set_metadata("demo_sample", "true")
81
70
  end
82
71
 
83
- def rack_request
84
- env = ::Rack::MockRequest.env_for(
85
- "/demo",
86
- :params => {
87
- "controller" => "demo",
88
- "action" => "hello"
89
- },
72
+ def add_params_to(transaction)
73
+ transaction.set_params(
74
+ "controller" => "demo",
75
+ "action" => "hello"
76
+ )
77
+ end
78
+
79
+ def add_headers_to(transaction)
80
+ transaction.set_headers(
90
81
  "REMOTE_ADDR" => "127.0.0.1",
91
82
  "REQUEST_METHOD" => "GET",
92
83
  "SERVER_NAME" => "localhost",
@@ -102,7 +93,6 @@ module Appsignal
102
93
  "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)",
103
94
  "HTTP_REFERER" => "http://appsignal.com/accounts"
104
95
  )
105
- ::Rack::Request.new(env)
106
96
  end
107
97
  end
108
98
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  class EventFormatter
5
+ # @api private
5
6
  module Rom
6
7
  class SqlFormatter
7
8
  def format(payload)
@@ -10,14 +10,14 @@ module Appsignal
10
10
  # event, the same object will be called intermittently in a threaded environment.
11
11
  # So only keep global configuration as state and pass the payload around as an
12
12
  # argument if you need to use helper methods.
13
- #
14
- # @api private
15
13
  class EventFormatter
16
14
  class << self
15
+ # @api private
17
16
  def formatters
18
17
  @formatters ||= {}
19
18
  end
20
19
 
20
+ # @api private
21
21
  def formatter_classes
22
22
  @formatter_classes ||= {}
23
23
  end
@@ -49,6 +49,7 @@ module Appsignal
49
49
  end
50
50
  end
51
51
 
52
+ # @api private
52
53
  def format(name, payload)
53
54
  formatter = formatters[name]
54
55
  formatter&.format(payload)