appsignal 5.0.0.rc.1-java → 5.0.0.rc.2-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +140 -0
- data/README.md +2 -1
- data/Rakefile +110 -6
- data/appsignal.gemspec +7 -0
- data/build_matrix.yml +7 -2
- data/ext/agent.rb +27 -27
- data/lib/appsignal/cli/demo.rb +5 -0
- data/lib/appsignal/cli/diagnose.rb +8 -48
- data/lib/appsignal/cli/helpers.rb +45 -0
- data/lib/appsignal/config.rb +262 -37
- data/lib/appsignal/demo.rb +11 -9
- data/lib/appsignal/helpers/instrumentation.rb +88 -0
- data/lib/appsignal/hooks/action_cable.rb +8 -2
- data/lib/appsignal/hooks/active_job.rb +189 -1
- data/lib/appsignal/integrations/delayed_job_plugin.rb +172 -32
- data/lib/appsignal/integrations/que.rb +41 -9
- data/lib/appsignal/integrations/railtie.rb +4 -2
- data/lib/appsignal/integrations/resque.rb +26 -3
- data/lib/appsignal/integrations/shoryuken.rb +21 -2
- data/lib/appsignal/integrations/sidekiq.rb +23 -2
- data/lib/appsignal/integrations/webmachine.rb +13 -5
- data/lib/appsignal/opentelemetry/http_server_request.rb +35 -1
- data/lib/appsignal/opentelemetry/proxied_exporter.rb +83 -0
- data/lib/appsignal/opentelemetry.rb +182 -24
- data/lib/appsignal/rack/abstract_middleware.rb +4 -1
- data/lib/appsignal/rack/event_handler.rb +9 -2
- data/lib/appsignal/rack/grape_middleware.rb +37 -7
- data/lib/appsignal/rack.rb +29 -1
- data/lib/appsignal/transaction/base_backend.rb +21 -0
- data/lib/appsignal/transaction/extension_backend.rb +26 -0
- data/lib/appsignal/transaction/opentelemetry_backend.rb +90 -39
- data/lib/appsignal/transaction.rb +189 -32
- data/lib/appsignal/utils/request_headers.rb +78 -0
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/sig/appsignal.rbi +205 -1
- data/sig/appsignal.rbs +196 -0
- metadata +3 -1
|
@@ -189,13 +189,19 @@ module Appsignal
|
|
|
189
189
|
|
|
190
190
|
def configure_appsignal(options)
|
|
191
191
|
env_option = options.fetch(:environment, nil)
|
|
192
|
+
# Mark app as Rails app
|
|
193
|
+
data[:app][:rails] = true if rails_present?
|
|
192
194
|
# Try and load the Rails app, if any.
|
|
193
195
|
# This will configure AppSignal through the config file or an
|
|
194
196
|
# initializer.
|
|
195
|
-
require_rails_app_if_present(env_option)
|
|
197
|
+
require_rails_app_if_present(env_option) do |error|
|
|
198
|
+
data[:app][:load_error] =
|
|
199
|
+
"#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
|
|
200
|
+
end
|
|
196
201
|
|
|
197
202
|
# No config loaded yet, try loading as normal
|
|
198
203
|
Appsignal._load_config!(env_option) unless Appsignal.config
|
|
204
|
+
Appsignal.config.apply_overrides
|
|
199
205
|
Appsignal._start_logger
|
|
200
206
|
Appsignal.config.write_to_environment
|
|
201
207
|
Appsignal.internal_logger.info("Starting AppSignal diagnose")
|
|
@@ -467,16 +473,7 @@ module Appsignal
|
|
|
467
473
|
config = Appsignal.config
|
|
468
474
|
data[:config] = {
|
|
469
475
|
:options => config.config_hash.merge(:env => config.env),
|
|
470
|
-
:sources =>
|
|
471
|
-
:default => Appsignal::Config::DEFAULT_CONFIG,
|
|
472
|
-
:system => config.system_config,
|
|
473
|
-
:loaders => config.loaders_config,
|
|
474
|
-
:initial => config.initial_config,
|
|
475
|
-
:file => config.file_config,
|
|
476
|
-
:env => config.env_config,
|
|
477
|
-
:override => config.override_config,
|
|
478
|
-
:dsl => config.dsl_config
|
|
479
|
-
}
|
|
476
|
+
:sources => config.config_sources
|
|
480
477
|
}
|
|
481
478
|
print_config_options(config)
|
|
482
479
|
end
|
|
@@ -627,43 +624,6 @@ module Appsignal
|
|
|
627
624
|
puts " Read error: #{path[:read_error]}"
|
|
628
625
|
print_empty_line
|
|
629
626
|
end
|
|
630
|
-
|
|
631
|
-
def print_empty_line
|
|
632
|
-
puts "\n"
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
def require_rails_app_if_present(env_option)
|
|
636
|
-
return unless rails_present?
|
|
637
|
-
|
|
638
|
-
# Set the environment given as an option to the diagnose CLI so the
|
|
639
|
-
# Rails app uses it when loaded.
|
|
640
|
-
ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_option
|
|
641
|
-
# Mark app as Rails app
|
|
642
|
-
data[:app][:rails] = true
|
|
643
|
-
# Manually require the railtie, because it wasn't loaded when the CLI
|
|
644
|
-
# started and AppSignal loaded, because the `Rails` constant wasn't
|
|
645
|
-
# present.
|
|
646
|
-
require "appsignal/integrations/railtie"
|
|
647
|
-
# Start the Rails app, including railties and initializers.
|
|
648
|
-
require Appsignal::Utils::RailsHelper.environment_config_path
|
|
649
|
-
rescue LoadError, StandardError => error
|
|
650
|
-
print_empty_line
|
|
651
|
-
puts "ERROR: Error encountered while loading the Rails app"
|
|
652
|
-
puts "#{error.class}: #{error.message}"
|
|
653
|
-
puts error.backtrace
|
|
654
|
-
data[:app][:load_error] =
|
|
655
|
-
"#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
|
|
656
|
-
ensure
|
|
657
|
-
ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
def rails_present?
|
|
661
|
-
# Try and load the Rails gem
|
|
662
|
-
require "rails"
|
|
663
|
-
true
|
|
664
|
-
rescue LoadError
|
|
665
|
-
false
|
|
666
|
-
end
|
|
667
627
|
end
|
|
668
628
|
end
|
|
669
629
|
end
|
|
@@ -36,6 +36,51 @@ module Appsignal
|
|
|
36
36
|
"\e[#{color_code}m#{text}\e[#{reset_color_code}m"
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def print_empty_line
|
|
40
|
+
puts "\n"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def rails_present?
|
|
44
|
+
require "rails"
|
|
45
|
+
true
|
|
46
|
+
rescue LoadError
|
|
47
|
+
false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The Rails gem being loadable says nothing about the directory the
|
|
51
|
+
# command runs in, so check for the app itself as well.
|
|
52
|
+
def rails_app_present?
|
|
53
|
+
rails_present? &&
|
|
54
|
+
File.exist?(Appsignal::Utils::RailsHelper.environment_config_path)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def load_rails_app(environment)
|
|
58
|
+
# Pass the environment given as a command line option to the app, so
|
|
59
|
+
# that the AppSignal config file uses it when the app loads it.
|
|
60
|
+
ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = environment
|
|
61
|
+
# Require the railtie manually. It was not loaded when AppSignal
|
|
62
|
+
# loaded, because the `Rails` constant was not present at that point.
|
|
63
|
+
require "appsignal/integrations/railtie"
|
|
64
|
+
# Start the Rails app, including its railties and initializers.
|
|
65
|
+
require Appsignal::Utils::RailsHelper.environment_config_path
|
|
66
|
+
ensure
|
|
67
|
+
ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Yields the error when the app fails to load, so that a command can
|
|
71
|
+
# report it in its own way.
|
|
72
|
+
def require_rails_app_if_present(environment)
|
|
73
|
+
return unless rails_app_present?
|
|
74
|
+
|
|
75
|
+
load_rails_app(environment)
|
|
76
|
+
rescue LoadError, StandardError => error
|
|
77
|
+
print_empty_line
|
|
78
|
+
puts "ERROR: Error encountered while loading the Rails app"
|
|
79
|
+
puts "#{error.class}: #{error.message}"
|
|
80
|
+
puts error.backtrace
|
|
81
|
+
yield error if block_given?
|
|
82
|
+
end
|
|
83
|
+
|
|
39
84
|
def periods
|
|
40
85
|
3.times do
|
|
41
86
|
print "."
|
data/lib/appsignal/config.rb
CHANGED
|
@@ -134,6 +134,11 @@ module Appsignal
|
|
|
134
134
|
:instrument_sequel => true,
|
|
135
135
|
:instrument_shoryuken => true,
|
|
136
136
|
:instrument_sidekiq => true,
|
|
137
|
+
:keep_request_environment => [],
|
|
138
|
+
:keep_request_headers => %w[
|
|
139
|
+
accept accept-charset accept-encoding accept-language cache-control
|
|
140
|
+
connection content-length range
|
|
141
|
+
],
|
|
137
142
|
:log => "file",
|
|
138
143
|
:logging_endpoint => "https://appsignal-endpoint.net",
|
|
139
144
|
:ownership_set_namespace => false,
|
|
@@ -146,10 +151,10 @@ module Appsignal
|
|
|
146
151
|
],
|
|
147
152
|
:response_headers => [],
|
|
148
153
|
:send_environment_metadata => true,
|
|
149
|
-
:send_function_parameters =>
|
|
154
|
+
:send_function_parameters => true,
|
|
150
155
|
:send_params => true,
|
|
151
|
-
:send_request_payload =>
|
|
152
|
-
:send_request_query_parameters =>
|
|
156
|
+
:send_request_payload => true,
|
|
157
|
+
:send_request_query_parameters => true,
|
|
153
158
|
:send_session_data => true,
|
|
154
159
|
:service_name => nil,
|
|
155
160
|
:sidekiq_report_errors => "all",
|
|
@@ -171,6 +176,18 @@ module Appsignal
|
|
|
171
176
|
"trace" => ::Logger::DEBUG
|
|
172
177
|
}.freeze
|
|
173
178
|
|
|
179
|
+
# Environment variables set by deployment platforms that name the
|
|
180
|
+
# revision that is being deployed, in the order the agent reads them.
|
|
181
|
+
# The agent detects the revision this way as well, but only for the data
|
|
182
|
+
# it sends itself, so the gem has to do it for collector mode.
|
|
183
|
+
# @!visibility private
|
|
184
|
+
PLATFORM_REVISION_ENV_VARS = [
|
|
185
|
+
"HEROKU_SLUG_COMMIT",
|
|
186
|
+
"RENDER_GIT_COMMIT",
|
|
187
|
+
"KAMAL_VERSION",
|
|
188
|
+
"CONTAINER_VERSION" # Scalingo
|
|
189
|
+
].freeze
|
|
190
|
+
|
|
174
191
|
# @!visibility private
|
|
175
192
|
STRING_OPTIONS = {
|
|
176
193
|
:activejob_report_errors => "APPSIGNAL_ACTIVEJOB_REPORT_ERRORS",
|
|
@@ -254,6 +271,8 @@ module Appsignal
|
|
|
254
271
|
:ignore_errors => "APPSIGNAL_IGNORE_ERRORS",
|
|
255
272
|
:ignore_logs => "APPSIGNAL_IGNORE_LOGS",
|
|
256
273
|
:ignore_namespaces => "APPSIGNAL_IGNORE_NAMESPACES",
|
|
274
|
+
:keep_request_environment => "APPSIGNAL_KEEP_REQUEST_ENVIRONMENT",
|
|
275
|
+
:keep_request_headers => "APPSIGNAL_KEEP_REQUEST_HEADERS",
|
|
257
276
|
:request_headers => "APPSIGNAL_REQUEST_HEADERS",
|
|
258
277
|
:response_headers => "APPSIGNAL_RESPONSE_HEADERS"
|
|
259
278
|
}.freeze
|
|
@@ -275,15 +294,14 @@ module Appsignal
|
|
|
275
294
|
# @!visibility private
|
|
276
295
|
MIN_RUBY_VERSION_FOR_COLLECTOR_MODE = "3.1"
|
|
277
296
|
|
|
278
|
-
# Configuration options that only have an effect when the integration is
|
|
279
|
-
# in collector mode. When the agent is in use, setting any of these emits
|
|
280
|
-
# a warning at startup.
|
|
281
297
|
# @!visibility private
|
|
282
298
|
COLLECTOR_ONLY_OPTIONS = [
|
|
283
299
|
:filter_attributes,
|
|
284
300
|
:filter_function_parameters,
|
|
285
301
|
:filter_request_payload,
|
|
286
302
|
:filter_request_query_parameters,
|
|
303
|
+
:keep_request_environment,
|
|
304
|
+
:keep_request_headers,
|
|
287
305
|
:response_headers,
|
|
288
306
|
:send_function_parameters,
|
|
289
307
|
:send_request_payload,
|
|
@@ -291,16 +309,45 @@ module Appsignal
|
|
|
291
309
|
:service_name
|
|
292
310
|
].freeze
|
|
293
311
|
|
|
294
|
-
# Existing AppSignal options that only affect the agent's handling of
|
|
295
|
-
# trace data. In collector mode these don't filter anything; users need
|
|
296
|
-
# their collector-mode equivalents (see COLLECTOR_ONLY_OPTIONS).
|
|
297
312
|
# @!visibility private
|
|
298
|
-
|
|
299
|
-
:
|
|
300
|
-
:filter_parameters,
|
|
301
|
-
:
|
|
313
|
+
COLLECTOR_ONLY_REPLACED_OPTIONS = {
|
|
314
|
+
:filter_function_parameters => :filter_parameters,
|
|
315
|
+
:filter_request_payload => :filter_parameters,
|
|
316
|
+
:filter_request_query_parameters => :filter_parameters,
|
|
317
|
+
:keep_request_environment => :request_headers,
|
|
318
|
+
:keep_request_headers => :request_headers,
|
|
319
|
+
:send_function_parameters => :send_params,
|
|
320
|
+
:send_request_payload => :send_params,
|
|
321
|
+
:send_request_query_parameters => :send_params
|
|
322
|
+
}.freeze
|
|
323
|
+
|
|
324
|
+
# @!visibility private
|
|
325
|
+
DEPRECATED_COLLECTOR_OPTIONS = {
|
|
326
|
+
:filter_parameters => {
|
|
327
|
+
:filter_request_payload => :derived_as_is,
|
|
328
|
+
:filter_function_parameters => :derived_as_is,
|
|
329
|
+
:filter_request_query_parameters => :derived_as_is
|
|
330
|
+
},
|
|
331
|
+
:request_headers => {
|
|
332
|
+
:keep_request_headers => :derived_header_names,
|
|
333
|
+
:keep_request_environment => :derived_environment_keys
|
|
334
|
+
},
|
|
335
|
+
:send_params => {
|
|
336
|
+
:send_request_payload => :derived_as_is,
|
|
337
|
+
:send_request_query_parameters => :derived_as_is,
|
|
338
|
+
:send_function_parameters => :derived_as_is
|
|
339
|
+
}
|
|
340
|
+
}.freeze
|
|
341
|
+
|
|
342
|
+
# @!visibility private
|
|
343
|
+
SOURCE_ORDER = [
|
|
344
|
+
:default, :derived, :system, :loaders, :initial, :file, :env, :override,
|
|
345
|
+
:dsl
|
|
302
346
|
].freeze
|
|
303
347
|
|
|
348
|
+
# @!visibility private
|
|
349
|
+
APPLICATION_SOURCES = [:initial, :file, :env, :dsl].freeze
|
|
350
|
+
|
|
304
351
|
# @!visibility private
|
|
305
352
|
attr_reader :root_path, :env, :config_hash
|
|
306
353
|
|
|
@@ -312,8 +359,23 @@ module Appsignal
|
|
|
312
359
|
#
|
|
313
360
|
# Used by the diagnose report to list which value was read from which source.
|
|
314
361
|
# @!visibility private
|
|
315
|
-
attr_reader :
|
|
316
|
-
:env_config, :override_config, :dsl_config
|
|
362
|
+
attr_reader :derived_config, :system_config, :loaders_config,
|
|
363
|
+
:initial_config, :file_config, :env_config, :override_config, :dsl_config
|
|
364
|
+
|
|
365
|
+
# @!visibility private
|
|
366
|
+
def config_sources
|
|
367
|
+
{
|
|
368
|
+
:default => DEFAULT_CONFIG,
|
|
369
|
+
:derived => derived_config,
|
|
370
|
+
:system => system_config,
|
|
371
|
+
:loaders => loaders_config,
|
|
372
|
+
:initial => initial_config,
|
|
373
|
+
:file => file_config,
|
|
374
|
+
:env => env_config,
|
|
375
|
+
:override => override_config,
|
|
376
|
+
:dsl => dsl_config
|
|
377
|
+
}
|
|
378
|
+
end
|
|
317
379
|
|
|
318
380
|
# Initialize a new AppSignal configuration object.
|
|
319
381
|
#
|
|
@@ -349,6 +411,7 @@ module Appsignal
|
|
|
349
411
|
@initial_config = {}
|
|
350
412
|
@file_config = {}
|
|
351
413
|
@env_config = {}
|
|
414
|
+
@derived_config = {}
|
|
352
415
|
@override_config = {}
|
|
353
416
|
@dsl_config = {} # Can be set using `Appsignal.configure`
|
|
354
417
|
|
|
@@ -569,6 +632,10 @@ module Appsignal
|
|
|
569
632
|
ENV["_APPSIGNAL_ENABLE_HOST_METRICS"] = config_hash[:enable_host_metrics].to_s
|
|
570
633
|
ENV["_APPSIGNAL_ENABLE_STATSD"] = config_hash[:enable_statsd].to_s
|
|
571
634
|
ENV["_APPSIGNAL_ENABLE_NGINX_METRICS"] = config_hash[:enable_nginx_metrics].to_s
|
|
635
|
+
# The gem never sends OpenTelemetry data to the agent, so it has no
|
|
636
|
+
# reason to listen for it. Written out rather than left to the agent's
|
|
637
|
+
# own default, so a value set in the environment cannot turn it on.
|
|
638
|
+
ENV["_APPSIGNAL_ENABLE_OPENTELEMETRY_HTTP"] = "false"
|
|
572
639
|
ENV["_APPSIGNAL_APP_ENV"] = env
|
|
573
640
|
ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = config_hash[:files_world_accessible].to_s
|
|
574
641
|
ENV["_APPSIGNAL_FILTER_PARAMETERS"] = config_hash[:filter_parameters].join(",")
|
|
@@ -585,6 +652,7 @@ module Appsignal
|
|
|
585
652
|
ENV["_APPSIGNAL_LOG_LEVEL"] = config_hash[:log_level]
|
|
586
653
|
ENV["_APPSIGNAL_LOG_FILE_PATH"] = log_file_path.to_s if log_file_path
|
|
587
654
|
ENV["_APPSIGNAL_LOGGING_ENDPOINT"] = config_hash[:logging_endpoint]
|
|
655
|
+
ENV["_APPSIGNAL_PLATFORM"] = config_hash[:platform].to_s
|
|
588
656
|
ENV["_APPSIGNAL_PROCESS_NAME"] = $PROGRAM_NAME
|
|
589
657
|
ENV["_APPSIGNAL_PUSH_API_ENDPOINT"] = config_hash[:endpoint]
|
|
590
658
|
ENV["_APPSIGNAL_PUSH_API_KEY"] = config_hash[:push_api_key]
|
|
@@ -604,9 +672,11 @@ module Appsignal
|
|
|
604
672
|
merge(options)
|
|
605
673
|
end
|
|
606
674
|
|
|
607
|
-
# Apply any overrides for invalid settings.
|
|
608
675
|
# @!visibility private
|
|
609
676
|
def apply_overrides
|
|
677
|
+
@derived_config = determine_derived
|
|
678
|
+
merge(derived_config)
|
|
679
|
+
|
|
610
680
|
@override_config = determine_overrides
|
|
611
681
|
merge(override_config)
|
|
612
682
|
end
|
|
@@ -645,16 +715,11 @@ module Appsignal
|
|
|
645
715
|
# @!visibility private
|
|
646
716
|
def warn_for_mode_mismatch
|
|
647
717
|
if collector_mode_configured?
|
|
648
|
-
warn_user_modified(
|
|
649
|
-
|
|
650
|
-
"only used by the agent for trace data and will be ignored."
|
|
718
|
+
warn_user_modified(DEPRECATED_COLLECTOR_OPTIONS.keys) do |option|
|
|
719
|
+
deprecated_collector_option_message(option)
|
|
651
720
|
end
|
|
652
721
|
else
|
|
653
|
-
|
|
654
|
-
"The agent is in use. The '#{option}' configuration option is " \
|
|
655
|
-
"only used by the collector and will be ignored. Set " \
|
|
656
|
-
"'collector_endpoint' to use the collector."
|
|
657
|
-
end
|
|
722
|
+
warn_collector_only_options
|
|
658
723
|
end
|
|
659
724
|
end
|
|
660
725
|
|
|
@@ -679,12 +744,49 @@ module Appsignal
|
|
|
679
744
|
|
|
680
745
|
private
|
|
681
746
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
747
|
+
def deprecated_collector_option_message(option)
|
|
748
|
+
replacements = DEPRECATED_COLLECTOR_OPTIONS.fetch(option).keys
|
|
749
|
+
message = "The collector is in use. The '#{option}' configuration " \
|
|
750
|
+
"option is deprecated in collector mode. It is replaced by " \
|
|
751
|
+
"#{quoted_option_list(replacements)}."
|
|
752
|
+
|
|
753
|
+
derived = replacements.select { |name| derived_config.key?(name) }
|
|
754
|
+
return message if derived.empty?
|
|
755
|
+
|
|
756
|
+
values = derived.map { |name| "\n #{name}: #{derived_config[name].inspect}" }
|
|
757
|
+
"#{message} Set these options to keep reporting what this application " \
|
|
758
|
+
"reports now:#{values.join}"
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
def quoted_option_list(names)
|
|
762
|
+
names = names.map { |name| "'#{name}'" }
|
|
763
|
+
return names.first if names.length == 1
|
|
764
|
+
|
|
765
|
+
"#{names[0..-2].join(", ")} and #{names.last}"
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
def warn_collector_only_options
|
|
769
|
+
options = COLLECTOR_ONLY_OPTIONS.select { |option| configured?(option) }
|
|
770
|
+
return if options.empty?
|
|
771
|
+
|
|
772
|
+
options.each do |option|
|
|
773
|
+
logger.warn(
|
|
774
|
+
"The agent is in use. The '#{option}' configuration option is " \
|
|
775
|
+
"only used by the collector and will be ignored."
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
replacement = COLLECTOR_ONLY_REPLACED_OPTIONS[option]
|
|
779
|
+
logger.warn("Use the '#{replacement}' option instead.") if replacement
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
logger.info(
|
|
783
|
+
"To use the collector, set the 'collector_endpoint' configuration option."
|
|
784
|
+
)
|
|
785
|
+
end
|
|
786
|
+
|
|
685
787
|
def warn_user_modified(options)
|
|
686
788
|
options.each do |option|
|
|
687
|
-
next
|
|
789
|
+
next unless configured?(option)
|
|
688
790
|
|
|
689
791
|
logger.warn(yield(option))
|
|
690
792
|
end
|
|
@@ -710,13 +812,57 @@ module Appsignal
|
|
|
710
812
|
|
|
711
813
|
hash[:enable_at_exit_hook] = "always" if Appsignal::Extension.running_in_container?
|
|
712
814
|
|
|
713
|
-
# Set revision from REVISION file
|
|
714
|
-
#
|
|
715
|
-
|
|
716
|
-
|
|
815
|
+
# Set the revision from a REVISION file in the project root, which
|
|
816
|
+
# helps with Capistrano and Hatchbox.io deployments, or from the
|
|
817
|
+
# environment variable the deployment platform sets.
|
|
818
|
+
revision = detect_revision_from_file || detect_revision_from_platform
|
|
819
|
+
hash[:revision] = revision if revision
|
|
820
|
+
|
|
821
|
+
hostname = detect_hostname
|
|
822
|
+
hash[:hostname] = hostname if hostname
|
|
823
|
+
|
|
824
|
+
platform = detect_platform
|
|
825
|
+
hash[:platform] = platform if platform
|
|
717
826
|
end
|
|
718
827
|
end
|
|
719
828
|
|
|
829
|
+
# Detect the platform the application is deployed on, the way the agent
|
|
830
|
+
# does. The agent only detects it for the data it reports itself, so the
|
|
831
|
+
# gem has to do it for collector mode. There is no config option for it,
|
|
832
|
+
# because these are the only two platforms that can be recognized.
|
|
833
|
+
def detect_platform
|
|
834
|
+
return "dokku" unless ENV.fetch("DOKKU_ROOT", nil).to_s.empty?
|
|
835
|
+
return "heroku" unless ENV.fetch("DYNO", nil).to_s.empty?
|
|
836
|
+
|
|
837
|
+
nil
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
# Detect the hostname the way the agent does: the Heroku dyno name first,
|
|
841
|
+
# then the name the host reports for itself. The agent only detects it for
|
|
842
|
+
# the data it reports itself, so the gem has to do it for collector mode.
|
|
843
|
+
def detect_hostname
|
|
844
|
+
dyno = ENV.fetch("DYNO", nil)
|
|
845
|
+
return dyno unless dyno.to_s.empty?
|
|
846
|
+
|
|
847
|
+
hostname = Socket.gethostname
|
|
848
|
+
hostname unless hostname.to_s.empty?
|
|
849
|
+
rescue SystemCallError => e
|
|
850
|
+
logger.debug "Unable to detect the hostname: #{e.class}: #{e.message}"
|
|
851
|
+
nil
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
def detect_revision_from_platform
|
|
855
|
+
PLATFORM_REVISION_ENV_VARS.each do |env_var|
|
|
856
|
+
revision = ENV.fetch(env_var, nil)
|
|
857
|
+
next if revision.to_s.empty?
|
|
858
|
+
|
|
859
|
+
logger.debug "Detected revision from the #{env_var} environment variable"
|
|
860
|
+
return revision
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
nil
|
|
864
|
+
end
|
|
865
|
+
|
|
720
866
|
def detect_revision_from_file
|
|
721
867
|
return unless root_path
|
|
722
868
|
|
|
@@ -854,9 +1000,68 @@ module Appsignal
|
|
|
854
1000
|
config[:sidekiq_report_errors] = "all"
|
|
855
1001
|
end
|
|
856
1002
|
|
|
1003
|
+
# A config file holding a YAML null gives an array option a `nil`, which
|
|
1004
|
+
# nothing downstream expects. Correct it to the empty list the option means.
|
|
1005
|
+
ARRAY_OPTIONS.each_key do |option|
|
|
1006
|
+
config[option] = [] if config_hash[option].nil?
|
|
1007
|
+
end
|
|
1008
|
+
|
|
857
1009
|
config
|
|
858
1010
|
end
|
|
859
1011
|
|
|
1012
|
+
def determine_derived
|
|
1013
|
+
derived = {}
|
|
1014
|
+
|
|
1015
|
+
DEPRECATED_COLLECTOR_OPTIONS.each do |option, replacements|
|
|
1016
|
+
next unless configured?(option)
|
|
1017
|
+
|
|
1018
|
+
replacements.each do |replacement, derivation|
|
|
1019
|
+
next if set_above_derived?(replacement)
|
|
1020
|
+
|
|
1021
|
+
derived[replacement] = send(derivation, config_hash[option])
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
derived
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
def derived_as_is(value)
|
|
1029
|
+
value
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
def derived_header_names(value)
|
|
1033
|
+
Array(value).filter_map do |key|
|
|
1034
|
+
Appsignal::Utils::RequestHeaders.header_name(key)
|
|
1035
|
+
end
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
def derived_environment_keys(value)
|
|
1039
|
+
Array(value).reject do |key|
|
|
1040
|
+
Appsignal::Utils::RequestHeaders.header_name(key) ||
|
|
1041
|
+
Appsignal::Utils::RequestHeaders::TRANSLATED_ENV_KEYS.include?(key)
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
def configured?(option)
|
|
1046
|
+
config_hash[option] != DEFAULT_CONFIG[option] && user_set?(option)
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
def user_set?(option)
|
|
1050
|
+
set_by_any?(APPLICATION_SOURCES, option)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
def set_above_derived?(option)
|
|
1054
|
+
set_by_any?(sources_above_derived, option)
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
def sources_above_derived
|
|
1058
|
+
SOURCE_ORDER[(SOURCE_ORDER.index(:derived) + 1)..] - [:override]
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
def set_by_any?(sources, option)
|
|
1062
|
+
sources.any? { |source| config_sources.fetch(source).key?(option) }
|
|
1063
|
+
end
|
|
1064
|
+
|
|
860
1065
|
def merge(new_config)
|
|
861
1066
|
new_config.each do |key, value|
|
|
862
1067
|
logger.debug("Config key '#{key}' is being overwritten") unless config_hash[key].nil?
|
|
@@ -881,14 +1086,19 @@ module Appsignal
|
|
|
881
1086
|
# @see AppSignal Ruby gem configuration
|
|
882
1087
|
# https://docs.appsignal.com/ruby/configuration.html
|
|
883
1088
|
class ConfigDSL
|
|
884
|
-
# @!visibility private
|
|
885
|
-
# @return [Hash] Hash containing the DSL option values
|
|
886
|
-
attr_reader :dsl_options
|
|
887
|
-
|
|
888
1089
|
# @!visibility private
|
|
889
1090
|
def initialize(config)
|
|
890
1091
|
@config = config
|
|
891
1092
|
@dsl_options = {}
|
|
1093
|
+
@assigned_options = Set.new
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
# @!visibility private
|
|
1097
|
+
# @return [Hash] Hash containing the DSL option values
|
|
1098
|
+
def dsl_options
|
|
1099
|
+
@dsl_options.reject do |key, value|
|
|
1100
|
+
!@assigned_options.include?(key) && unchanged_option?(key, value)
|
|
1101
|
+
end
|
|
892
1102
|
end
|
|
893
1103
|
|
|
894
1104
|
# Returns the application's root path.
|
|
@@ -1074,6 +1284,12 @@ module Appsignal
|
|
|
1074
1284
|
# @return [Array<String>] Ignore log messages by substrings
|
|
1075
1285
|
# @!attribute [rw] ignore_namespaces
|
|
1076
1286
|
# @return [Array<String>] Ignore traces by namespaces
|
|
1287
|
+
# @!attribute [rw] keep_request_environment
|
|
1288
|
+
# @return [Array<String>] Rack environment keys to report in collector
|
|
1289
|
+
# mode, named the way Rack names them
|
|
1290
|
+
# @!attribute [rw] keep_request_headers
|
|
1291
|
+
# @return [Array<String>] HTTP request headers to report in collector
|
|
1292
|
+
# mode, named the way OpenTelemetry names them
|
|
1077
1293
|
# @!attribute [rw] request_headers
|
|
1078
1294
|
# @return [Array<String>] HTTP request headers to include in error reports
|
|
1079
1295
|
|
|
@@ -1128,14 +1344,23 @@ module Appsignal
|
|
|
1128
1344
|
if @dsl_options.key?(key)
|
|
1129
1345
|
@dsl_options[key]
|
|
1130
1346
|
else
|
|
1131
|
-
@dsl_options[key] =
|
|
1347
|
+
@dsl_options[key] = initial_option_value(key)
|
|
1132
1348
|
end
|
|
1133
1349
|
end
|
|
1134
1350
|
|
|
1135
1351
|
def update_option(key, value)
|
|
1352
|
+
@assigned_options << key
|
|
1136
1353
|
@dsl_options[key] = value
|
|
1137
1354
|
end
|
|
1138
1355
|
|
|
1356
|
+
def initial_option_value(key)
|
|
1357
|
+
@config[key].dup
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
def unchanged_option?(key, value)
|
|
1361
|
+
value == initial_option_value(key)
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1139
1364
|
# Parse tags from various input formats and validate values
|
|
1140
1365
|
# @param value [Hash, nil] input tags
|
|
1141
1366
|
# @return [Hash] validated tags with string keys
|
data/lib/appsignal/demo.rb
CHANGED
|
@@ -77,21 +77,23 @@ module Appsignal
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def add_headers_to(transaction)
|
|
80
|
-
transaction.
|
|
80
|
+
transaction.add_request_headers(
|
|
81
|
+
"accept" => "text/html,application/xhtml+xml",
|
|
82
|
+
"accept-encoding" => "gzip, deflate, sdch",
|
|
83
|
+
"accept-language" => "en-US,en;q=0.8,nl;q=0.6",
|
|
84
|
+
"cache-control" => "max-age=0",
|
|
85
|
+
"connection" => "keep-alive",
|
|
86
|
+
"user-agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)",
|
|
87
|
+
"referer" => "http://appsignal.com/accounts"
|
|
88
|
+
)
|
|
89
|
+
transaction.add_request_environment(
|
|
81
90
|
"REMOTE_ADDR" => "127.0.0.1",
|
|
82
91
|
"REQUEST_METHOD" => "GET",
|
|
83
92
|
"SERVER_NAME" => "localhost",
|
|
84
93
|
"SERVER_PORT" => "80",
|
|
85
94
|
"SERVER_PROTOCOL" => "HTTP/1.1",
|
|
86
95
|
"REQUEST_PATH" => "/hello",
|
|
87
|
-
"PATH_INFO" => "/hello"
|
|
88
|
-
"HTTP_ACCEPT" => "text/html,application/xhtml+xml",
|
|
89
|
-
"HTTP_ACCEPT_ENCODING" => "gzip, deflate, sdch",
|
|
90
|
-
"HTTP_ACCEPT_LANGUAGE" => "en-US,en;q=0.8,nl;q=0.6",
|
|
91
|
-
"HTTP_CACHE_CONTROL" => "max-age=0",
|
|
92
|
-
"HTTP_CONNECTION" => "keep-alive",
|
|
93
|
-
"HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)",
|
|
94
|
-
"HTTP_REFERER" => "http://appsignal.com/accounts"
|
|
96
|
+
"PATH_INFO" => "/hello"
|
|
95
97
|
)
|
|
96
98
|
end
|
|
97
99
|
end
|