appsignal 2.5.0.alpha.1-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 +7 -0
- data/.gitignore +33 -0
- data/.rspec +4 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +124 -0
- data/.travis.yml +72 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +639 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +264 -0
- data/Rakefile +214 -0
- data/appsignal.gemspec +42 -0
- data/benchmark.rake +77 -0
- data/bin/appsignal +13 -0
- data/ext/Rakefile +27 -0
- data/ext/agent.yml +64 -0
- data/ext/appsignal_extension.c +692 -0
- data/ext/base.rb +79 -0
- data/ext/extconf.rb +35 -0
- data/gemfiles/capistrano2.gemfile +7 -0
- data/gemfiles/capistrano3.gemfile +7 -0
- data/gemfiles/grape.gemfile +7 -0
- data/gemfiles/no_dependencies.gemfile +5 -0
- data/gemfiles/padrino.gemfile +7 -0
- data/gemfiles/que.gemfile +5 -0
- data/gemfiles/rails-3.2.gemfile +6 -0
- data/gemfiles/rails-4.0.gemfile +6 -0
- data/gemfiles/rails-4.1.gemfile +6 -0
- data/gemfiles/rails-4.2.gemfile +10 -0
- data/gemfiles/rails-5.0.gemfile +5 -0
- data/gemfiles/rails-5.1.gemfile +5 -0
- data/gemfiles/resque.gemfile +12 -0
- data/gemfiles/sequel-435.gemfile +11 -0
- data/gemfiles/sequel.gemfile +11 -0
- data/gemfiles/sinatra.gemfile +6 -0
- data/gemfiles/webmachine.gemfile +5 -0
- data/lib/appsignal.rb +804 -0
- data/lib/appsignal/auth_check.rb +65 -0
- data/lib/appsignal/capistrano.rb +10 -0
- data/lib/appsignal/cli.rb +108 -0
- data/lib/appsignal/cli/demo.rb +63 -0
- data/lib/appsignal/cli/diagnose.rb +500 -0
- data/lib/appsignal/cli/helpers.rb +72 -0
- data/lib/appsignal/cli/install.rb +277 -0
- data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
- data/lib/appsignal/config.rb +287 -0
- data/lib/appsignal/demo.rb +107 -0
- data/lib/appsignal/event_formatter.rb +74 -0
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
- data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
- data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
- data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
- data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
- data/lib/appsignal/extension.rb +63 -0
- data/lib/appsignal/extension/jruby.rb +460 -0
- data/lib/appsignal/garbage_collection_profiler.rb +48 -0
- data/lib/appsignal/hooks.rb +105 -0
- data/lib/appsignal/hooks/action_cable.rb +113 -0
- data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
- data/lib/appsignal/hooks/celluloid.rb +30 -0
- data/lib/appsignal/hooks/data_mapper.rb +18 -0
- data/lib/appsignal/hooks/delayed_job.rb +19 -0
- data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
- data/lib/appsignal/hooks/net_http.rb +29 -0
- data/lib/appsignal/hooks/passenger.rb +22 -0
- data/lib/appsignal/hooks/puma.rb +35 -0
- data/lib/appsignal/hooks/que.rb +21 -0
- data/lib/appsignal/hooks/rake.rb +39 -0
- data/lib/appsignal/hooks/redis.rb +30 -0
- data/lib/appsignal/hooks/sequel.rb +60 -0
- data/lib/appsignal/hooks/shoryuken.rb +43 -0
- data/lib/appsignal/hooks/sidekiq.rb +144 -0
- data/lib/appsignal/hooks/unicorn.rb +40 -0
- data/lib/appsignal/hooks/webmachine.rb +23 -0
- data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
- data/lib/appsignal/integrations/data_mapper.rb +33 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
- data/lib/appsignal/integrations/grape.rb +53 -0
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
- data/lib/appsignal/integrations/object.rb +35 -0
- data/lib/appsignal/integrations/padrino.rb +84 -0
- data/lib/appsignal/integrations/que.rb +43 -0
- data/lib/appsignal/integrations/railtie.rb +41 -0
- data/lib/appsignal/integrations/rake.rb +2 -0
- data/lib/appsignal/integrations/resque.rb +20 -0
- data/lib/appsignal/integrations/resque_active_job.rb +30 -0
- data/lib/appsignal/integrations/sinatra.rb +17 -0
- data/lib/appsignal/integrations/webmachine.rb +38 -0
- data/lib/appsignal/js_exception_transaction.rb +54 -0
- data/lib/appsignal/marker.rb +63 -0
- data/lib/appsignal/minutely.rb +42 -0
- data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
- data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
- data/lib/appsignal/rack/streaming_listener.rb +73 -0
- data/lib/appsignal/system.rb +81 -0
- data/lib/appsignal/transaction.rb +498 -0
- data/lib/appsignal/transmitter.rb +107 -0
- data/lib/appsignal/utils.rb +127 -0
- data/lib/appsignal/utils/params_sanitizer.rb +59 -0
- data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
- data/lib/appsignal/version.rb +3 -0
- data/lib/sequel/extensions/appsignal_integration.rb +3 -0
- data/resources/appsignal.yml.erb +39 -0
- data/resources/cacert.pem +3866 -0
- data/spec/.rubocop.yml +7 -0
- data/spec/lib/appsignal/auth_check_spec.rb +80 -0
- data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
- data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
- data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
- data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
- data/spec/lib/appsignal/cli/install_spec.rb +632 -0
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
- data/spec/lib/appsignal/cli_spec.rb +56 -0
- data/spec/lib/appsignal/config_spec.rb +637 -0
- data/spec/lib/appsignal/demo_spec.rb +87 -0
- data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
- data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
- data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
- data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
- data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
- data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
- data/spec/lib/appsignal/extension_spec.rb +137 -0
- data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
- data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
- data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
- data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
- data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
- data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
- data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
- data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
- data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
- data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
- data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
- data/spec/lib/appsignal/hooks_spec.rb +195 -0
- data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
- data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
- data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
- data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
- data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
- data/spec/lib/appsignal/marker_spec.rb +51 -0
- data/spec/lib/appsignal/minutely_spec.rb +50 -0
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
- data/spec/lib/appsignal/system_spec.rb +131 -0
- data/spec/lib/appsignal/transaction_spec.rb +1146 -0
- data/spec/lib/appsignal/transmitter_spec.rb +152 -0
- data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
- data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
- data/spec/lib/appsignal/utils_spec.rb +150 -0
- data/spec/lib/appsignal_spec.rb +1049 -0
- data/spec/spec_helper.rb +116 -0
- data/spec/support/fixtures/containers/cgroups/docker +14 -0
- data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
- data/spec/support/fixtures/containers/cgroups/lxc +10 -0
- data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
- data/spec/support/fixtures/containers/cgroups/none +1 -0
- data/spec/support/fixtures/generated_config.yml +24 -0
- data/spec/support/fixtures/uploaded_file.txt +0 -0
- data/spec/support/helpers/api_request_helper.rb +19 -0
- data/spec/support/helpers/cli_helpers.rb +26 -0
- data/spec/support/helpers/config_helpers.rb +21 -0
- data/spec/support/helpers/dependency_helper.rb +73 -0
- data/spec/support/helpers/directory_helper.rb +27 -0
- data/spec/support/helpers/env_helpers.rb +33 -0
- data/spec/support/helpers/example_exception.rb +13 -0
- data/spec/support/helpers/example_standard_error.rb +13 -0
- data/spec/support/helpers/log_helpers.rb +22 -0
- data/spec/support/helpers/std_streams_helper.rb +66 -0
- data/spec/support/helpers/system_helpers.rb +8 -0
- data/spec/support/helpers/time_helpers.rb +11 -0
- data/spec/support/helpers/transaction_helpers.rb +37 -0
- data/spec/support/matchers/contains_log.rb +7 -0
- data/spec/support/mocks/fake_gc_profiler.rb +19 -0
- data/spec/support/mocks/mock_extension.rb +6 -0
- data/spec/support/project_fixture/config/application.rb +0 -0
- data/spec/support/project_fixture/config/appsignal.yml +32 -0
- data/spec/support/project_fixture/config/environments/development.rb +0 -0
- data/spec/support/project_fixture/config/environments/production.rb +0 -0
- data/spec/support/project_fixture/config/environments/test.rb +0 -0
- data/spec/support/project_fixture/log/.gitkeep +0 -0
- data/spec/support/rails/my_app.rb +6 -0
- data/spec/support/shared_examples/instrument.rb +43 -0
- data/spec/support/stubs/delayed_job.rb +0 -0
- metadata +483 -0
data/ext/base.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require "digest"
|
|
2
|
+
require "logger"
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "open-uri"
|
|
5
|
+
require "zlib"
|
|
6
|
+
require "yaml"
|
|
7
|
+
require "rubygems/package"
|
|
8
|
+
require File.expand_path("../../lib/appsignal/system.rb", __FILE__)
|
|
9
|
+
|
|
10
|
+
EXT_PATH = File.expand_path("..", __FILE__).freeze
|
|
11
|
+
AGENT_CONFIG = YAML.load(File.read(File.join(EXT_PATH, "agent.yml"))).freeze
|
|
12
|
+
|
|
13
|
+
PLATFORM = Appsignal::System.agent_platform
|
|
14
|
+
ARCH = "#{RbConfig::CONFIG["host_cpu"]}-#{PLATFORM}".freeze
|
|
15
|
+
CA_CERT_PATH = File.join(EXT_PATH, "../resources/cacert.pem").freeze
|
|
16
|
+
|
|
17
|
+
def ext_path(path)
|
|
18
|
+
File.join(EXT_PATH, path)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def logger
|
|
22
|
+
@logger ||= Logger.new(File.join(EXT_PATH, "install.log"))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def installation_failed(reason)
|
|
26
|
+
logger.error "Installation failed: #{reason}"
|
|
27
|
+
File.open(File.join(EXT_PATH, "Makefile"), "w") do |file|
|
|
28
|
+
file.write "default:\nclean:\ninstall:"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def write_agent_architecture
|
|
33
|
+
File.open(File.join(EXT_PATH, "appsignal.architecture"), "w") do |file|
|
|
34
|
+
file.write ARCH
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def check_architecture
|
|
39
|
+
if AGENT_CONFIG["triples"].keys.include?(ARCH)
|
|
40
|
+
true
|
|
41
|
+
else
|
|
42
|
+
installation_failed(
|
|
43
|
+
"AppSignal currently does not support your system architecture (#{ARCH})." \
|
|
44
|
+
"Please let us know at support@appsignal.com, we aim to support everything our customers run."
|
|
45
|
+
)
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def download_archive(arch_config, type)
|
|
51
|
+
logger.info "Downloading agent release from #{arch_config[type]["download_url"]}"
|
|
52
|
+
open(arch_config[type]["download_url"], :ssl_ca_cert => CA_CERT_PATH)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def verify_archive(archive, arch_config, type)
|
|
56
|
+
if Digest::SHA256.hexdigest(archive.read) == arch_config[type]["checksum"]
|
|
57
|
+
logger.info "Checksum of downloaded archive verified, extracting archive"
|
|
58
|
+
true
|
|
59
|
+
else
|
|
60
|
+
installation_failed(
|
|
61
|
+
"Aborting installation, checksum of downloaded archive could not be verified: " \
|
|
62
|
+
"Expected '#{arch_config[type]["checksum"]}', got '#{checksum}'."
|
|
63
|
+
)
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def unarchive(archive)
|
|
69
|
+
Gem::Package::TarReader.new(Zlib::GzipReader.open(archive)) do |tar|
|
|
70
|
+
tar.each do |entry|
|
|
71
|
+
next unless entry.file?
|
|
72
|
+
|
|
73
|
+
File.open(ext_path(entry.full_name), "wb") do |f|
|
|
74
|
+
f.write(entry.read)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
FileUtils.chmod(0o755, ext_path("appsignal-agent"))
|
|
79
|
+
end
|
data/ext/extconf.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require File.expand_path("../../lib/appsignal/version.rb", __FILE__)
|
|
2
|
+
require File.expand_path("../base.rb", __FILE__)
|
|
3
|
+
|
|
4
|
+
def install
|
|
5
|
+
logger.info "Installing appsignal agent #{Appsignal::VERSION} for Ruby #{RUBY_VERSION} on #{RUBY_PLATFORM}"
|
|
6
|
+
write_agent_architecture
|
|
7
|
+
return unless check_architecture
|
|
8
|
+
arch_config = AGENT_CONFIG["triples"][ARCH]
|
|
9
|
+
|
|
10
|
+
unless File.exist?(ext_path("appsignal-agent")) &&
|
|
11
|
+
File.exist?(ext_path("libappsignal.a")) &&
|
|
12
|
+
File.exist?(ext_path("appsignal.h"))
|
|
13
|
+
archive = download_archive(arch_config, "static")
|
|
14
|
+
return unless verify_archive(archive, arch_config, "static")
|
|
15
|
+
unarchive(archive)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
logger.info "Creating makefile"
|
|
19
|
+
require "mkmf"
|
|
20
|
+
if !have_library("appsignal", "appsignal_start", "appsignal.h")
|
|
21
|
+
installation_failed "Aborting installation, libappsignal.a or appsignal.h not found"
|
|
22
|
+
elsif !find_executable("appsignal-agent", EXT_PATH)
|
|
23
|
+
installation_failed "Aborting installation, appsignal-agent not found"
|
|
24
|
+
else
|
|
25
|
+
create_makefile "appsignal_extension"
|
|
26
|
+
logger.info "Successfully created Makefile for appsignal extension"
|
|
27
|
+
end
|
|
28
|
+
rescue => ex
|
|
29
|
+
installation_failed "Exception while installing: #{ex}"
|
|
30
|
+
ex.backtrace.each do |line|
|
|
31
|
+
logger.error line
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
install
|
data/lib/appsignal.rb
ADDED
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "logger"
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
# AppSignal for Ruby gem's main module.
|
|
6
|
+
#
|
|
7
|
+
# Provides method to control the AppSignal instrumentation and the system agent.
|
|
8
|
+
# Also provides instrumentation helpers for ease of use.
|
|
9
|
+
module Appsignal
|
|
10
|
+
class << self
|
|
11
|
+
extend Gem::Deprecate
|
|
12
|
+
|
|
13
|
+
# Accessor for the AppSignal configuration.
|
|
14
|
+
# Return the current AppSignal configuration.
|
|
15
|
+
#
|
|
16
|
+
# Can return `nil` if no configuration has been set or automatically loaded
|
|
17
|
+
# by an automatic integration or by calling {.start}.
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# Appsignal.config
|
|
21
|
+
#
|
|
22
|
+
# @example Setting the configuration
|
|
23
|
+
# Appsignal.config = Appsignal::Config.new(Dir.pwd, "production")
|
|
24
|
+
#
|
|
25
|
+
# @return [Config, nil]
|
|
26
|
+
# @see Config
|
|
27
|
+
attr_accessor :config
|
|
28
|
+
# Accessor for toggle if the AppSignal C-extension is loaded.
|
|
29
|
+
#
|
|
30
|
+
# Can be `nil` if extension has not been loaded yet. See
|
|
31
|
+
# {.extension_loaded?} for a boolean return value.
|
|
32
|
+
#
|
|
33
|
+
# @api private
|
|
34
|
+
# @return [Boolean, nil]
|
|
35
|
+
# @see Extension
|
|
36
|
+
# @see extension_loaded?
|
|
37
|
+
attr_accessor :extension_loaded
|
|
38
|
+
# @!attribute [rw] logger
|
|
39
|
+
# Accessor for the AppSignal logger.
|
|
40
|
+
#
|
|
41
|
+
# If no logger has been set, it will return a "in memory logger", using
|
|
42
|
+
# `in_memory_log`. Once AppSignal is started (using {.start}) the
|
|
43
|
+
# contents of the "in memory logger" is written to the new logger.
|
|
44
|
+
#
|
|
45
|
+
# @note some classes may have options to set custom loggers. Their
|
|
46
|
+
# defaults are pointed to this attribute.
|
|
47
|
+
# @api private
|
|
48
|
+
# @return [Logger]
|
|
49
|
+
# @see start_logger
|
|
50
|
+
attr_writer :logger
|
|
51
|
+
|
|
52
|
+
# @api private
|
|
53
|
+
def extensions
|
|
54
|
+
@extensions ||= []
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @api private
|
|
58
|
+
def initialize_extensions
|
|
59
|
+
Appsignal.logger.debug("Initializing extensions")
|
|
60
|
+
extensions.each do |extension|
|
|
61
|
+
Appsignal.logger.debug("Initializing #{extension}")
|
|
62
|
+
extension.initializer
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
def testing?
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Start the AppSignal integration.
|
|
72
|
+
#
|
|
73
|
+
# Starts AppSignal with the given configuration. If no configuration is set
|
|
74
|
+
# yet it will try to automatically load the configuration using the
|
|
75
|
+
# environment loaded from environment variables and the currently working
|
|
76
|
+
# directory.
|
|
77
|
+
#
|
|
78
|
+
# This is not required for the automatic integrations AppSignal offers, but
|
|
79
|
+
# this is required for all non-automatic integrations and pure Ruby
|
|
80
|
+
# applications. For more information, see our [integrations
|
|
81
|
+
# list](http://docs.appsignal.com/ruby/integrations/) and our [Integrating
|
|
82
|
+
# AppSignal](http://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html)
|
|
83
|
+
# guide.
|
|
84
|
+
#
|
|
85
|
+
# To start the logger see {.start_logger}.
|
|
86
|
+
#
|
|
87
|
+
# @example
|
|
88
|
+
# Appsignal.start
|
|
89
|
+
#
|
|
90
|
+
# @example with custom loaded configuration
|
|
91
|
+
# Appsignal.config = Appsignal::Config.new(Dir.pwd, "production")
|
|
92
|
+
# Appsignal.start
|
|
93
|
+
#
|
|
94
|
+
# @return [void]
|
|
95
|
+
# @since 0.7.0
|
|
96
|
+
def start # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
97
|
+
unless extension_loaded?
|
|
98
|
+
logger.info("Not starting appsignal, extension is not loaded")
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
logger.debug("Starting appsignal")
|
|
103
|
+
|
|
104
|
+
unless @config
|
|
105
|
+
@config = Config.new(
|
|
106
|
+
Dir.pwd,
|
|
107
|
+
ENV["APPSIGNAL_APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"]
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
if config.valid?
|
|
112
|
+
logger.level =
|
|
113
|
+
if config[:debug]
|
|
114
|
+
Logger::DEBUG
|
|
115
|
+
else
|
|
116
|
+
Logger::INFO
|
|
117
|
+
end
|
|
118
|
+
if config.active?
|
|
119
|
+
logger.info "Starting AppSignal #{Appsignal::VERSION} "\
|
|
120
|
+
"(#{$PROGRAM_NAME}, Ruby #{RUBY_VERSION}, #{RUBY_PLATFORM})"
|
|
121
|
+
config.write_to_environment
|
|
122
|
+
Appsignal::Extension.start
|
|
123
|
+
Appsignal::Hooks.load_hooks
|
|
124
|
+
Appsignal::EventFormatter.initialize_formatters
|
|
125
|
+
initialize_extensions
|
|
126
|
+
|
|
127
|
+
if config[:enable_allocation_tracking] && !Appsignal::System.jruby?
|
|
128
|
+
Appsignal::Extension.install_allocation_event_hook
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
if config[:enable_gc_instrumentation]
|
|
132
|
+
GC::Profiler.enable
|
|
133
|
+
Appsignal::Minutely.add_gc_probe
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
Appsignal::Minutely.start if config[:enable_minutely_probes]
|
|
137
|
+
else
|
|
138
|
+
logger.info("Not starting, not active for #{config.env}")
|
|
139
|
+
end
|
|
140
|
+
else
|
|
141
|
+
logger.error("Not starting, no valid config for this environment")
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Stop AppSignal's agent.
|
|
146
|
+
#
|
|
147
|
+
# Stops the AppSignal agent. Call this before the end of your program to
|
|
148
|
+
# make sure the agent is stopped as well.
|
|
149
|
+
#
|
|
150
|
+
# @example
|
|
151
|
+
# Appsignal.start
|
|
152
|
+
# # Run your application
|
|
153
|
+
# Appsignal.stop
|
|
154
|
+
#
|
|
155
|
+
# @param called_by [String] Name of the thing that requested the agent to
|
|
156
|
+
# be stopped. Will be used in the AppSignal log file.
|
|
157
|
+
# @return [void]
|
|
158
|
+
# @since 1.0.0
|
|
159
|
+
def stop(called_by = nil)
|
|
160
|
+
if called_by
|
|
161
|
+
logger.debug("Stopping appsignal (#{called_by})")
|
|
162
|
+
else
|
|
163
|
+
logger.debug("Stopping appsignal")
|
|
164
|
+
end
|
|
165
|
+
Appsignal::Extension.stop
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def forked
|
|
169
|
+
return unless active?
|
|
170
|
+
Appsignal.start_logger
|
|
171
|
+
logger.debug("Forked process, resubscribing and restarting extension")
|
|
172
|
+
Appsignal::Extension.start
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def get_server_state(key)
|
|
176
|
+
Appsignal::Extension.get_server_state(key)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Creates an AppSignal transaction for the given block.
|
|
180
|
+
#
|
|
181
|
+
# If AppSignal is not {.active?} it will still execute the block, but not
|
|
182
|
+
# create a transaction for it.
|
|
183
|
+
#
|
|
184
|
+
# A event is created for this transaction with the name given in the `name`
|
|
185
|
+
# argument. The event name must start with either `perform_job` or
|
|
186
|
+
# `process_action` to differentiate between the "web" and "background"
|
|
187
|
+
# namespace. Custom namespaces are not supported by this helper method.
|
|
188
|
+
#
|
|
189
|
+
# This helper method also captures any exception that occurs in the given
|
|
190
|
+
# block.
|
|
191
|
+
#
|
|
192
|
+
# The other (request) `env` argument hash keys, not listed here, can be
|
|
193
|
+
# found on the {Appsignal::Transaction::ENV_METHODS} array.
|
|
194
|
+
# Each of these keys are available as keys in the `env` hash argument.
|
|
195
|
+
#
|
|
196
|
+
# @example
|
|
197
|
+
# Appsignal.monitor_transaction("perform_job.nightly_update") do
|
|
198
|
+
# # your code
|
|
199
|
+
# end
|
|
200
|
+
#
|
|
201
|
+
# @example with an environment
|
|
202
|
+
# Appsignal.monitor_transaction(
|
|
203
|
+
# "perform_job.nightly_update",
|
|
204
|
+
# :metadata => { "user_id" => 1 }
|
|
205
|
+
# ) do
|
|
206
|
+
# # your code
|
|
207
|
+
# end
|
|
208
|
+
#
|
|
209
|
+
# @param name [String] main event name.
|
|
210
|
+
# @param env [Hash<Symbol, Object>]
|
|
211
|
+
# @option env [Hash<Symbol/String, Object>] :params Params for the
|
|
212
|
+
# monitored request/job, see {Appsignal::Transaction#params=} for more
|
|
213
|
+
# information.
|
|
214
|
+
# @option env [String] :controller name of the controller in which the
|
|
215
|
+
# transaction was recorded.
|
|
216
|
+
# @option env [String] :class name of the Ruby class in which the
|
|
217
|
+
# transaction was recorded. If `:controller` is also given, `:controller`
|
|
218
|
+
# is used instead.
|
|
219
|
+
# @option env [String] :action name of the controller action in which the
|
|
220
|
+
# transaction was recorded.
|
|
221
|
+
# @option env [String] :method name of the Ruby method in which the
|
|
222
|
+
# transaction was recorded. If `:action` is also given, `:action`
|
|
223
|
+
# is used instead.
|
|
224
|
+
# @option env [Integer] :queue_start the moment the request/job was queued.
|
|
225
|
+
# Used to track how long requests/jobs were queued before being executed.
|
|
226
|
+
# @option env [Hash<Symbol/String, String/Fixnum>] :metadata Additional
|
|
227
|
+
# metadata for the transaction, see {Appsignal::Transaction#set_metadata}
|
|
228
|
+
# for more information.
|
|
229
|
+
# @yield the block to monitor.
|
|
230
|
+
# @raise [Exception] any exception that occurs within the given block is re-raised by
|
|
231
|
+
# this method.
|
|
232
|
+
# @return [Object] the value of the given block is returned.
|
|
233
|
+
# @since 0.10.0
|
|
234
|
+
def monitor_transaction(name, env = {})
|
|
235
|
+
unless active?
|
|
236
|
+
return yield
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
if name.start_with?("perform_job".freeze)
|
|
240
|
+
namespace = Appsignal::Transaction::BACKGROUND_JOB
|
|
241
|
+
request = Appsignal::Transaction::GenericRequest.new(env)
|
|
242
|
+
elsif name.start_with?("process_action".freeze)
|
|
243
|
+
namespace = Appsignal::Transaction::HTTP_REQUEST
|
|
244
|
+
request = ::Rack::Request.new(env)
|
|
245
|
+
else
|
|
246
|
+
logger.error("Unrecognized name '#{name}'")
|
|
247
|
+
return
|
|
248
|
+
end
|
|
249
|
+
transaction = Appsignal::Transaction.create(
|
|
250
|
+
SecureRandom.uuid,
|
|
251
|
+
namespace,
|
|
252
|
+
request
|
|
253
|
+
)
|
|
254
|
+
begin
|
|
255
|
+
Appsignal.instrument(name) do
|
|
256
|
+
yield
|
|
257
|
+
end
|
|
258
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
259
|
+
transaction.set_error(error)
|
|
260
|
+
raise error
|
|
261
|
+
ensure
|
|
262
|
+
transaction.set_http_or_background_action(request.env)
|
|
263
|
+
transaction.set_http_or_background_queue_start
|
|
264
|
+
Appsignal::Transaction.complete_current!
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Monitor a transaction, stop AppSignal and wait for this single
|
|
269
|
+
# transaction to be flushed.
|
|
270
|
+
#
|
|
271
|
+
# Useful for cases such as Rake tasks and Resque-like systems where a
|
|
272
|
+
# process is forked and immediately exits after the transaction finishes.
|
|
273
|
+
#
|
|
274
|
+
# @see monitor_transaction
|
|
275
|
+
def monitor_single_transaction(name, env = {}, &block)
|
|
276
|
+
monitor_transaction(name, env, &block)
|
|
277
|
+
ensure
|
|
278
|
+
stop("monitor_single_transaction")
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Listen for an error to occur and send it to AppSignal.
|
|
282
|
+
#
|
|
283
|
+
# Uses {.send_error} to directly send the error in a separate transaction.
|
|
284
|
+
# Does not add the error to the current transaction.
|
|
285
|
+
#
|
|
286
|
+
# Make sure that AppSignal is integrated in your application beforehand.
|
|
287
|
+
# AppSignal won't record errors unless {Config#active?} is `true`.
|
|
288
|
+
#
|
|
289
|
+
# @example
|
|
290
|
+
# # my_app.rb
|
|
291
|
+
# # setup AppSignal beforehand
|
|
292
|
+
#
|
|
293
|
+
# Appsignal.listen_for_error do
|
|
294
|
+
# # my code
|
|
295
|
+
# raise "foo"
|
|
296
|
+
# end
|
|
297
|
+
#
|
|
298
|
+
# @see Transaction.set_tags
|
|
299
|
+
# @see Transaction.set_namespace
|
|
300
|
+
# @see .send_error
|
|
301
|
+
# @see https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html
|
|
302
|
+
# AppSignal integration guide
|
|
303
|
+
#
|
|
304
|
+
# @param tags [Hash, nil]
|
|
305
|
+
# @param namespace [String] the namespace for this error.
|
|
306
|
+
# @yield yields the given block.
|
|
307
|
+
# @return [Object] returns the return value of the given block.
|
|
308
|
+
def listen_for_error(tags = nil, namespace = Appsignal::Transaction::HTTP_REQUEST)
|
|
309
|
+
yield
|
|
310
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
311
|
+
send_error(error, tags, namespace)
|
|
312
|
+
raise error
|
|
313
|
+
end
|
|
314
|
+
alias :listen_for_exception :listen_for_error
|
|
315
|
+
|
|
316
|
+
# Send an error to AppSignal regardless of the context.
|
|
317
|
+
#
|
|
318
|
+
# Records and send the exception to AppSignal.
|
|
319
|
+
#
|
|
320
|
+
# This instrumentation helper does not require a transaction to be active,
|
|
321
|
+
# it starts a new transaction by itself.
|
|
322
|
+
#
|
|
323
|
+
# Use {.set_error} if your want to add an exception to the current
|
|
324
|
+
# transaction.
|
|
325
|
+
#
|
|
326
|
+
# **Note**: Does not do anything if AppSignal is not active or when the
|
|
327
|
+
# "error" is not a class extended from Ruby's Exception class.
|
|
328
|
+
#
|
|
329
|
+
# @example Send an exception
|
|
330
|
+
# begin
|
|
331
|
+
# raise "oh no!"
|
|
332
|
+
# rescue => e
|
|
333
|
+
# Appsignal.send_error(e)
|
|
334
|
+
# end
|
|
335
|
+
#
|
|
336
|
+
# @example Send an exception with tags
|
|
337
|
+
# begin
|
|
338
|
+
# raise "oh no!"
|
|
339
|
+
# rescue => e
|
|
340
|
+
# Appsignal.send_error(e, :key => "value")
|
|
341
|
+
# end
|
|
342
|
+
#
|
|
343
|
+
# @param error [Exception] The error to send to AppSignal.
|
|
344
|
+
# @param tags [Hash{String, Symbol => String, Symbol, Integer}] Additional
|
|
345
|
+
# tags to add to the error. See also {.tag_request}.
|
|
346
|
+
# @param namespace [String] The namespace in which the error occurred.
|
|
347
|
+
# See also {.set_namespace}.
|
|
348
|
+
# @return [void]
|
|
349
|
+
#
|
|
350
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/exception-handling.html
|
|
351
|
+
# Exception handling guide
|
|
352
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/tagging.html
|
|
353
|
+
# Tagging guide
|
|
354
|
+
# @since 0.6.0
|
|
355
|
+
def send_error(error, tags = nil, namespace = Appsignal::Transaction::HTTP_REQUEST)
|
|
356
|
+
return unless active?
|
|
357
|
+
unless error.is_a?(Exception)
|
|
358
|
+
logger.error("Can't send error, given value is not an exception")
|
|
359
|
+
return
|
|
360
|
+
end
|
|
361
|
+
transaction = Appsignal::Transaction.new(
|
|
362
|
+
SecureRandom.uuid,
|
|
363
|
+
namespace,
|
|
364
|
+
Appsignal::Transaction::GenericRequest.new({})
|
|
365
|
+
)
|
|
366
|
+
transaction.set_tags(tags) if tags
|
|
367
|
+
transaction.set_error(error)
|
|
368
|
+
transaction.complete
|
|
369
|
+
end
|
|
370
|
+
alias :send_exception :send_error
|
|
371
|
+
|
|
372
|
+
# Set an error on the current transaction.
|
|
373
|
+
#
|
|
374
|
+
# **Note**: Does not do anything if AppSignal is not active, no transaction
|
|
375
|
+
# is currently active or when the "error" is not a class extended from
|
|
376
|
+
# Ruby's Exception class.
|
|
377
|
+
#
|
|
378
|
+
# @example Manual instrumentation of set_error.
|
|
379
|
+
# # Manually starting AppSignal here
|
|
380
|
+
# # Manually starting a transaction here.
|
|
381
|
+
# begin
|
|
382
|
+
# raise "oh no!"
|
|
383
|
+
# rescue => e
|
|
384
|
+
# Appsignal.set_error(error)
|
|
385
|
+
# end
|
|
386
|
+
# # Manually completing the transaction here.
|
|
387
|
+
# # Manually stopping AppSignal here
|
|
388
|
+
#
|
|
389
|
+
# @example In a Rails application
|
|
390
|
+
# class SomeController < ApplicationController
|
|
391
|
+
# # The AppSignal transaction is created by our integration for you.
|
|
392
|
+
# def create
|
|
393
|
+
# # Do something that breaks
|
|
394
|
+
# rescue => e
|
|
395
|
+
# Appsignal.set_error(e)
|
|
396
|
+
# end
|
|
397
|
+
# end
|
|
398
|
+
#
|
|
399
|
+
# @param exception [Exception] The error to add to the current transaction.
|
|
400
|
+
# @param tags [Hash{String, Symbol => String, Symbol, Integer}] Additional
|
|
401
|
+
# tags to add to the error. See also {.tag_request}.
|
|
402
|
+
# @param namespace [String] The namespace in which the error occurred.
|
|
403
|
+
# See also {.set_namespace}.
|
|
404
|
+
# @return [void]
|
|
405
|
+
#
|
|
406
|
+
# @see Transaction#set_error
|
|
407
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/exception-handling.html
|
|
408
|
+
# Exception handling guide
|
|
409
|
+
# @since 0.6.6
|
|
410
|
+
def set_error(exception, tags = nil, namespace = nil)
|
|
411
|
+
return if !active? ||
|
|
412
|
+
Appsignal::Transaction.current.nil? ||
|
|
413
|
+
exception.nil?
|
|
414
|
+
transaction = Appsignal::Transaction.current
|
|
415
|
+
transaction.set_error(exception)
|
|
416
|
+
transaction.set_tags(tags) if tags
|
|
417
|
+
transaction.set_namespace(namespace) if namespace
|
|
418
|
+
end
|
|
419
|
+
alias :set_exception :set_error
|
|
420
|
+
alias :add_exception :set_error
|
|
421
|
+
|
|
422
|
+
# Set a custom action name for the current transaction.
|
|
423
|
+
#
|
|
424
|
+
# When using an integration such as the Rails or Sinatra AppSignal will try
|
|
425
|
+
# to find the action name from the controller or endpoint for you.
|
|
426
|
+
#
|
|
427
|
+
# If you want to customize the action name as it appears on AppSignal.com
|
|
428
|
+
# you can use this method. This overrides the action name AppSignal
|
|
429
|
+
# generates in an integration.
|
|
430
|
+
#
|
|
431
|
+
# @example in a Rails controller
|
|
432
|
+
# class SomeController < ApplicationController
|
|
433
|
+
# before_action :set_appsignal_action
|
|
434
|
+
#
|
|
435
|
+
# def set_appsignal_action
|
|
436
|
+
# Appsignal.set_action("DynamicController#dynamic_method")
|
|
437
|
+
# end
|
|
438
|
+
# end
|
|
439
|
+
#
|
|
440
|
+
# @param action [String]
|
|
441
|
+
# @return [void]
|
|
442
|
+
# @see Transaction#set_action
|
|
443
|
+
# @since 2.2.0
|
|
444
|
+
def set_action(action)
|
|
445
|
+
return if !active? ||
|
|
446
|
+
Appsignal::Transaction.current.nil? ||
|
|
447
|
+
action.nil?
|
|
448
|
+
Appsignal::Transaction.current.set_action(action)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# Set a custom namespace for the current transaction.
|
|
452
|
+
#
|
|
453
|
+
# When using an integration such as Rails or Sidekiq AppSignal will try to
|
|
454
|
+
# find a appropriate namespace for the transaction.
|
|
455
|
+
#
|
|
456
|
+
# A Rails controller will be automatically put in the "http_request"
|
|
457
|
+
# namespace, while a Sidekiq background job is put in the "background_job"
|
|
458
|
+
# namespace.
|
|
459
|
+
#
|
|
460
|
+
# Note: The "http_request" namespace gets transformed on AppSignal.com to
|
|
461
|
+
# "Web" and "background_job" gets transformed to "Background".
|
|
462
|
+
#
|
|
463
|
+
# If you want to customize the namespace in which transactions appear you
|
|
464
|
+
# can use this method. This overrides the namespace AppSignal uses by
|
|
465
|
+
# default.
|
|
466
|
+
#
|
|
467
|
+
# A common request we've seen is to split the administration panel from the
|
|
468
|
+
# main application.
|
|
469
|
+
#
|
|
470
|
+
# @example create a custom admin namespace
|
|
471
|
+
# class AdminController < ApplicationController
|
|
472
|
+
# before_action :set_appsignal_namespace
|
|
473
|
+
#
|
|
474
|
+
# def set_appsignal_namespace
|
|
475
|
+
# Appsignal.set_namespace("admin")
|
|
476
|
+
# end
|
|
477
|
+
# end
|
|
478
|
+
#
|
|
479
|
+
# @param namespace [String]
|
|
480
|
+
# @return [void]
|
|
481
|
+
# @see Transaction#set_namespace
|
|
482
|
+
# @since 2.2.0
|
|
483
|
+
def set_namespace(namespace)
|
|
484
|
+
return if !active? ||
|
|
485
|
+
Appsignal::Transaction.current.nil? ||
|
|
486
|
+
namespace.nil?
|
|
487
|
+
Appsignal::Transaction.current.set_namespace(namespace)
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Set tags on the current transaction.
|
|
491
|
+
#
|
|
492
|
+
# Tags are extra bits of information that are added to transaction and
|
|
493
|
+
# appear on sample details pages on AppSignal.com.
|
|
494
|
+
#
|
|
495
|
+
# @example
|
|
496
|
+
# Appsignal.tag_request(:locale => "en")
|
|
497
|
+
# Appsignal.tag_request("locale" => "en")
|
|
498
|
+
# Appsignal.tag_request("user_id" => 1)
|
|
499
|
+
#
|
|
500
|
+
# @example Nested hashes are not supported
|
|
501
|
+
# # Bad
|
|
502
|
+
# Appsignal.tag_request(:user => { :locale => "en" })
|
|
503
|
+
#
|
|
504
|
+
# @example in a Rails controller
|
|
505
|
+
# class SomeController < ApplicationController
|
|
506
|
+
# before_action :set_appsignal_tags
|
|
507
|
+
#
|
|
508
|
+
# def set_appsignal_tags
|
|
509
|
+
# Appsignal.tag_request(:locale => I18n.locale)
|
|
510
|
+
# end
|
|
511
|
+
# end
|
|
512
|
+
#
|
|
513
|
+
# @param tags [Hash] Collection of tags.
|
|
514
|
+
# @option tags [String, Symbol, Integer] :any
|
|
515
|
+
# The name of the tag as a Symbol.
|
|
516
|
+
# @option tags [String, Symbol, Integer] "any"
|
|
517
|
+
# The name of the tag as a String.
|
|
518
|
+
# @return [void]
|
|
519
|
+
#
|
|
520
|
+
# @see Transaction.set_tags
|
|
521
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/tagging.html
|
|
522
|
+
# Tagging guide
|
|
523
|
+
def tag_request(tags = {})
|
|
524
|
+
return unless active?
|
|
525
|
+
transaction = Appsignal::Transaction.current
|
|
526
|
+
return false unless transaction
|
|
527
|
+
transaction.set_tags(tags)
|
|
528
|
+
end
|
|
529
|
+
alias :tag_job :tag_request
|
|
530
|
+
|
|
531
|
+
# Instrument helper for AppSignal.
|
|
532
|
+
#
|
|
533
|
+
# For more help, read our custom instrumentation guide, listed under "See
|
|
534
|
+
# also".
|
|
535
|
+
#
|
|
536
|
+
# @example Simple instrumentation
|
|
537
|
+
# Appsignal.instrument("fetch.issue_fetcher") do
|
|
538
|
+
# # To be instrumented code
|
|
539
|
+
# end
|
|
540
|
+
#
|
|
541
|
+
# @example Instrumentation with title and body
|
|
542
|
+
# Appsignal.instrument(
|
|
543
|
+
# "fetch.issue_fetcher",
|
|
544
|
+
# "Fetching issue",
|
|
545
|
+
# "GitHub API"
|
|
546
|
+
# ) do
|
|
547
|
+
# # To be instrumented code
|
|
548
|
+
# end
|
|
549
|
+
#
|
|
550
|
+
# @param name [String] Name of the instrumented event. Read our event
|
|
551
|
+
# naming guide listed under "See also".
|
|
552
|
+
# @param title [String, nil] Human readable name of the event.
|
|
553
|
+
# @param body [String, nil] Value of importance for the event, such as the
|
|
554
|
+
# server against an API call is made.
|
|
555
|
+
# @param body_format [Integer] Enum for the type of event that is
|
|
556
|
+
# instrumented. Accepted values are {EventFormatter::DEFAULT} and
|
|
557
|
+
# {EventFormatter::SQL_BODY_FORMAT}, but we recommend you use
|
|
558
|
+
# {.instrument_sql} instead of {EventFormatter::SQL_BODY_FORMAT}.
|
|
559
|
+
# @yield yields the given block of code instrumented in an AppSignal
|
|
560
|
+
# event.
|
|
561
|
+
# @return [Object] Returns the block's return value.
|
|
562
|
+
#
|
|
563
|
+
# @see Appsignal::Transaction#instrument
|
|
564
|
+
# @see .instrument_sql
|
|
565
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/instrumentation.html
|
|
566
|
+
# AppSignal custom instrumentation guide
|
|
567
|
+
# @see http://docs.appsignal.com/api/event-names.html
|
|
568
|
+
# AppSignal event naming guide
|
|
569
|
+
# @since 1.3.0
|
|
570
|
+
def instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT)
|
|
571
|
+
Appsignal::Transaction.current.start_event
|
|
572
|
+
yield if block_given?
|
|
573
|
+
ensure
|
|
574
|
+
Appsignal::Transaction.current.finish_event(name, title, body, body_format)
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# Instrumentation helper for SQL queries.
|
|
578
|
+
#
|
|
579
|
+
# This helper filters out values from SQL queries so you don't have to.
|
|
580
|
+
#
|
|
581
|
+
# @example SQL query instrumentation
|
|
582
|
+
# Appsignal.instrument_sql("perform.query", nil, "SELECT * FROM ...") do
|
|
583
|
+
# # To be instrumented code
|
|
584
|
+
# end
|
|
585
|
+
#
|
|
586
|
+
# @example SQL query instrumentation
|
|
587
|
+
# Appsignal.instrument_sql("perform.query", nil, "WHERE email = 'foo@..'") do
|
|
588
|
+
# # query value will replace 'foo..' with a question mark `?`.
|
|
589
|
+
# end
|
|
590
|
+
#
|
|
591
|
+
# @param name [String] Name of the instrumented event. Read our event
|
|
592
|
+
# naming guide listed under "See also".
|
|
593
|
+
# @param title [String, nil] Human readable name of the event.
|
|
594
|
+
# @param body [String, nil] SQL query that's being executed.
|
|
595
|
+
# @yield yields the given block of code instrumented in an AppSignal event.
|
|
596
|
+
# @return [Object] Returns the block's return value.
|
|
597
|
+
#
|
|
598
|
+
# @see .instrument
|
|
599
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/instrumentation.html
|
|
600
|
+
# AppSignal custom instrumentation guide
|
|
601
|
+
# @see http://docs.appsignal.com/api/event-names.html
|
|
602
|
+
# AppSignal event naming guide
|
|
603
|
+
# @since 2.0.0
|
|
604
|
+
def instrument_sql(name, title = nil, body = nil, &block)
|
|
605
|
+
instrument(name, title, body, Appsignal::EventFormatter::SQL_BODY_FORMAT, &block)
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
def set_gauge(key, value)
|
|
609
|
+
Appsignal::Extension.set_gauge(key.to_s, value.to_f)
|
|
610
|
+
rescue RangeError
|
|
611
|
+
Appsignal.logger.warn("Gauge value #{value} for key '#{key}' is too big")
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def set_host_gauge(key, value)
|
|
615
|
+
Appsignal::Extension.set_host_gauge(key.to_s, value.to_f)
|
|
616
|
+
rescue RangeError
|
|
617
|
+
Appsignal.logger.warn("Host gauge value #{value} for key '#{key}' is too big")
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
def set_process_gauge(key, value)
|
|
621
|
+
Appsignal::Extension.set_process_gauge(key.to_s, value.to_f)
|
|
622
|
+
rescue RangeError
|
|
623
|
+
Appsignal.logger.warn("Process gauge value #{value} for key '#{key}' is too big")
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
def increment_counter(key, value = 1)
|
|
627
|
+
Appsignal::Extension.increment_counter(key.to_s, value)
|
|
628
|
+
rescue RangeError
|
|
629
|
+
Appsignal.logger.warn("Counter value #{value} for key '#{key}' is too big")
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
def add_distribution_value(key, value)
|
|
633
|
+
Appsignal::Extension.add_distribution_value(key.to_s, value.to_f)
|
|
634
|
+
rescue RangeError
|
|
635
|
+
Appsignal.logger.warn("Distribution value #{value} for key '#{key}' is too big")
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# In memory logger used before any logger is started with {.start_logger}.
|
|
639
|
+
#
|
|
640
|
+
# The contents of this logger are flushed to the logger in {.start_logger}.
|
|
641
|
+
#
|
|
642
|
+
# @api private
|
|
643
|
+
# @return [StringIO]
|
|
644
|
+
def in_memory_log
|
|
645
|
+
if defined?(@in_memory_log) && @in_memory_log
|
|
646
|
+
@in_memory_log
|
|
647
|
+
else
|
|
648
|
+
@in_memory_log = StringIO.new
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def logger
|
|
653
|
+
@logger ||= Logger.new(in_memory_log).tap do |l|
|
|
654
|
+
l.level = Logger::INFO
|
|
655
|
+
l.formatter = log_formatter("appsignal")
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
# @api private
|
|
660
|
+
def log_formatter(prefix = nil)
|
|
661
|
+
pre = "#{prefix}: " if prefix
|
|
662
|
+
proc do |severity, datetime, _progname, msg|
|
|
663
|
+
"[#{datetime.strftime("%Y-%m-%dT%H:%M:%S")} (process) "\
|
|
664
|
+
"##{Process.pid}][#{severity}] #{pre}#{msg}\n"
|
|
665
|
+
end
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# Start the AppSignal logger.
|
|
669
|
+
#
|
|
670
|
+
# Sets the log level and sets the logger. Uses a file-based logger or the
|
|
671
|
+
# STDOUT-based logger. See the `:log` configuration option.
|
|
672
|
+
#
|
|
673
|
+
# @param path_arg [nil] Deprecated param. Use the `:log_path`
|
|
674
|
+
# configuration option instead.
|
|
675
|
+
# @return [void]
|
|
676
|
+
# @since 0.7.0
|
|
677
|
+
def start_logger(path_arg = nil)
|
|
678
|
+
if config && config[:log] == "file" && config.log_file_path
|
|
679
|
+
start_file_logger(config.log_file_path)
|
|
680
|
+
else
|
|
681
|
+
start_stdout_logger
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
logger.level =
|
|
685
|
+
if config && config[:debug]
|
|
686
|
+
Logger::DEBUG
|
|
687
|
+
else
|
|
688
|
+
Logger::INFO
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
if in_memory_log
|
|
692
|
+
logger << in_memory_log.string
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
if path_arg
|
|
696
|
+
logger.info("Setting the path in start_logger has no effect anymore, set it in the config instead")
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
# Returns if the C-extension was loaded properly.
|
|
701
|
+
#
|
|
702
|
+
# @return [Boolean]
|
|
703
|
+
# @see Extension
|
|
704
|
+
# @since 1.0.0
|
|
705
|
+
def extension_loaded?
|
|
706
|
+
!!extension_loaded
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
# Returns the active state of the AppSignal integration.
|
|
710
|
+
#
|
|
711
|
+
# Conditions apply for AppSignal to be marked as active:
|
|
712
|
+
#
|
|
713
|
+
# - There is a config set on the {.config} attribute.
|
|
714
|
+
# - The set config is active {Config.active?}.
|
|
715
|
+
# - The AppSignal Extension is loaded {.extension_loaded?}.
|
|
716
|
+
#
|
|
717
|
+
# This logic is used within instrument helper such as {.instrument} so it's
|
|
718
|
+
# not necessary to wrap {.instrument} calls with this method.
|
|
719
|
+
#
|
|
720
|
+
# @example Do this
|
|
721
|
+
# Appsignal.instrument(..) do
|
|
722
|
+
# # Do this
|
|
723
|
+
# end
|
|
724
|
+
#
|
|
725
|
+
# @example Don't do this
|
|
726
|
+
# if Appsignal.active?
|
|
727
|
+
# Appsignal.instrument(..) do
|
|
728
|
+
# # Don't do this
|
|
729
|
+
# end
|
|
730
|
+
# end
|
|
731
|
+
#
|
|
732
|
+
# @return [Boolean]
|
|
733
|
+
# @since 0.2.7
|
|
734
|
+
def active?
|
|
735
|
+
config && config.active? && extension_loaded?
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
# @deprecated No replacement
|
|
739
|
+
def is_ignored_error?(error) # rubocop:disable Style/PredicateName
|
|
740
|
+
Appsignal.config[:ignore_errors].include?(error.class.name)
|
|
741
|
+
end
|
|
742
|
+
alias :is_ignored_exception? :is_ignored_error?
|
|
743
|
+
deprecate :is_ignored_error?, :none, 2017, 3
|
|
744
|
+
|
|
745
|
+
# @deprecated No replacement
|
|
746
|
+
def is_ignored_action?(action) # rubocop:disable Style/PredicateName
|
|
747
|
+
Appsignal.config[:ignore_actions].include?(action)
|
|
748
|
+
end
|
|
749
|
+
deprecate :is_ignored_action?, :none, 2017, 3
|
|
750
|
+
|
|
751
|
+
# Convenience method for skipping instrumentations around a block of code.
|
|
752
|
+
#
|
|
753
|
+
# @example
|
|
754
|
+
# Appsignal.without_instrumentation do
|
|
755
|
+
# # Complex code here
|
|
756
|
+
# end
|
|
757
|
+
#
|
|
758
|
+
# @yield block of code that shouldn't be instrumented.
|
|
759
|
+
# @return [Object] Returns the return value of the block.
|
|
760
|
+
# @since 0.8.7
|
|
761
|
+
def without_instrumentation
|
|
762
|
+
Appsignal::Transaction.current.pause! if Appsignal::Transaction.current
|
|
763
|
+
yield
|
|
764
|
+
ensure
|
|
765
|
+
Appsignal::Transaction.current.resume! if Appsignal::Transaction.current
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
private
|
|
769
|
+
|
|
770
|
+
def start_stdout_logger
|
|
771
|
+
@logger = Logger.new($stdout)
|
|
772
|
+
logger.formatter = log_formatter("appsignal")
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
def start_file_logger(path)
|
|
776
|
+
@logger = Logger.new(path)
|
|
777
|
+
logger.formatter = log_formatter
|
|
778
|
+
rescue SystemCallError => error
|
|
779
|
+
start_stdout_logger
|
|
780
|
+
logger.warn "Unable to start logger with log path '#{path}'."
|
|
781
|
+
logger.warn error
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
require "appsignal/system"
|
|
787
|
+
require "appsignal/utils"
|
|
788
|
+
require "appsignal/extension"
|
|
789
|
+
require "appsignal/auth_check"
|
|
790
|
+
require "appsignal/config"
|
|
791
|
+
require "appsignal/event_formatter"
|
|
792
|
+
require "appsignal/hooks"
|
|
793
|
+
require "appsignal/marker"
|
|
794
|
+
require "appsignal/minutely"
|
|
795
|
+
require "appsignal/garbage_collection_profiler"
|
|
796
|
+
require "appsignal/integrations/railtie" if defined?(::Rails)
|
|
797
|
+
require "appsignal/integrations/resque"
|
|
798
|
+
require "appsignal/integrations/resque_active_job"
|
|
799
|
+
require "appsignal/transaction"
|
|
800
|
+
require "appsignal/version"
|
|
801
|
+
require "appsignal/rack/generic_instrumentation"
|
|
802
|
+
require "appsignal/rack/js_exception_catcher"
|
|
803
|
+
require "appsignal/js_exception_transaction"
|
|
804
|
+
require "appsignal/transmitter"
|