module Appsignal
def _load_config!(env_param = nil, &block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
-
(void)-
Parameters:
-
block(Proc) -- Optional block to configure the config object. -
env_param(String, nil) -- Used by diagnose CLI to pass through
def _load_config!(env_param = nil, &block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity # Ensure it's not an empty string if it's a value proper_env_param = env_param&.to_s&.strip # Unset it if it's an empty string proper_env_param = nil if proper_env_param&.empty? context = Appsignal::Config::Context.new( :env => Config.determine_env(env_param), :root_path => Config.determine_root_path ) # If there's a config/appsignal.rb file if context.dsl_config_file? if config # When calling `Appsignal.configure` from an app, not the # `config/appsignal.rb` file, with also a Ruby config file present. message = "The `Appsignal.configure` helper is called from within an " \ "app while a `#{context.dsl_config_file}` file is present. " \ "The `config/appsignal.rb` file is ignored when the " \ "config is loaded with `Appsignal.configure` from within an app. " \ "We recommend moving all config to the `config/appsignal.rb` file " \ "or the `Appsignal.configure` helper in the app." Appsignal::Utils::StdoutAndLoggerMessage.warning(message) else # Load it when no config is present # # We don't pass the `env_var` or `context.env` here so that the # `Appsignal.configure` or `Appsignal.start` can figure out the # environment themselves if it was not explicitly set. # This way we prevent forcing an environment that's auto loaded on # the to-be-loaded config file. # # The `(proper)_env_param` is only set when it's explicitly set, # which means it needs to override any auto detected environment. load_dsl_config_file(context.dsl_config_file, proper_env_param) end else # Load config if no config file was found and no config is present yet # This will load the config/appsignal.yml file automatically @config ||= Config.new(context.root_path, context.env) end # Allow a block to be given to customize the config and override any # loaded config before it's validated. block.call(config) if block_given? # Apply any config overrides after the user config has been merged config&.apply_overrides # Skip validation if not configured as active for this environment return unless config.active_for_env? # Validate the config, if present config&.validate end
def _start_logger
-
(void)-
def _start_logger if config && config[:log] == "file" && config.log_file_path start_internal_file_logger(config.log_file_path) else start_internal_stdout_logger end internal_logger.level = if config config.log_level else Appsignal::Config::DEFAULT_LOG_LEVEL end return unless @in_memory_logger messages = @in_memory_logger.messages_for_level(internal_logger.level) internal_logger << messages.join @in_memory_logger = nil end
def active?
- Since: - 0.2.7
Returns:
-
(Boolean)-
Other tags:
- Example: Don't do this -
Example: Do this -
def active? config&.active? && extension_loaded? end
def check_if_started!
-
(void)-
Raises:
-
(Appsignal::NotStartedError)-
def check_if_started! return if started? begin raise config_error if config_error? rescue # Raise the NotStartedError and make the config error the error cause raise NotStartedError, config_error end # Raise the NotStartedError as normal raise NotStartedError end
def collect_environment_metadata
def collect_environment_metadata Appsignal::Environment.report("ruby_version") do "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" end Appsignal::Environment.report("ruby_engine") { RUBY_ENGINE } if defined?(RUBY_ENGINE_VERSION) Appsignal::Environment.report("ruby_engine_version") do RUBY_ENGINE_VERSION end end Appsignal::Environment.report_supported_gems end
def config_file_context?
Returns true if we're currently in the `config/appsignal.rb` file
def config_file_context? ENV.fetch("_APPSIGNAL_CONFIG_FILE_CONTEXT", nil) == "true" end
def configure(env_param = nil, root_path: nil)
- See: https://docs.appsignal.com/ruby/configuration/options.html - Configuration options
See: https://docs.appsignal.com/ruby/configuration.html - Configuration guide
See: Config -
See: config -
Returns:
-
(void)-
Other tags:
- Yieldparam: config_dsl - The configuration DSL object
Other tags:
- Yield: - Gives the configuration DSL instance to the block.
Parameters:
-
root_path(String) -- The path to look the `config/appsignal.yml` config file in. -
env_param(String, Symbol) -- The environment to load.
Other tags:
- Example: Load config without a block -
Example: Calling configure multiple times for different environments resets the configuration -
Example: Automatically detects the app environment -
Example: Configure AppSignal for the application and select the environment -
Example: Configure AppSignal for the application -
def configure(env_param = nil, root_path: nil) if Appsignal.started? Appsignal.internal_logger .warn("AppSignal is already started. Ignoring `Appsignal.configure` call.") return end root_path_param = root_path if params_match_loaded_config?(env_param, root_path_param) config else @config = Config.new( root_path_param || Config.determine_root_path, Config.determine_env(env_param), # If in the context of an `config/appsignal.rb` config file, do not # load the `config/appsignal.yml` file. # The `.rb` file is a replacement for the `.yml` file so it shouldn't # load both. :load_yaml_file => !config_file_context? ) end # When calling `Appsignal.configure` from a Rails initializer and a YAML # file is present. We will not load the YAML file in the future. if !config_file_context? && config.yml_config_file? message = "The `Appsignal.configure` helper is called while a " \ "`config/appsignal.yml` file is present. In future versions the " \ "`config/appsignal.yml` file will be ignored when loading the " \ "config. We recommend moving all config to the " \ "`config/appsignal.rb` file, or the `Appsignal.configure` helper " \ "in Rails initializer file, and remove the " \ "`config/appsignal.yml` file." Appsignal::Utils::StdoutAndLoggerMessage.warning(message) end config_dsl = Appsignal::Config::ConfigDSL.new(config) return unless block_given? yield config_dsl config.merge_dsl_options(config_dsl.dsl_options) nil end
def dsl_config_file_loaded?
def dsl_config_file_loaded? defined?(@dsl_config_file_loaded) ? true : false end
def extension_loaded?
- Since: - 1.0.0
Other tags:
- See: Extension -
Returns:
-
(Boolean)-
def extension_loaded? !!extension_loaded end
def forked
-
(void)-
def forked return unless active? Appsignal._start_logger internal_logger.debug("Forked process, resubscribing and restarting extension") Appsignal::Extension.start nil end
def get_server_state(key)
def get_server_state(key) Appsignal::Extension.get_server_state(key) end
def in_memory_logger
def in_memory_logger @in_memory_logger ||= Appsignal::Utils::IntegrationMemoryLogger.new.tap do |l| l.formatter = log_formatter("appsignal") end end
def internal_logger
def internal_logger @internal_logger ||= in_memory_logger end
def load(integration_name)
- Since: - 3.12.0
Returns:
-
(void)-
Parameters:
-
integration_name(String, Symbol) -- Name of the integration to load.
Other tags:
- Example: Load Sinatra integrations and define custom config -
Example: Load Sinatra integrations -
def load(integration_name) Loaders.load(integration_name) nil end
def load_dsl_config_file(path, env_param = nil)
loaded more than once, which should never happen, it will not do
If the config file has already been loaded once and it's trying to be
Load the `config/appsignal.rb` config file, if present.
def load_dsl_config_file(path, env_param = nil) return if defined?(@dsl_config_file_loaded) begin ENV["_APPSIGNAL_CONFIG_FILE_CONTEXT"] = "true" ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_param if env_param @dsl_config_file_loaded = true require path rescue => error @config_error = error message = "Not starting AppSignal because an error occurred while " \ "loading the AppSignal config file.\n" \ "File: #{path.inspect}\n" \ "#{error.class.name}: #{error}" Kernel.warn "appsignal ERROR: #{message}" internal_logger.error "#{message}\n#{error.backtrace.join("\n")}" ensure unless Appsignal.config # Ensure _a config object_ is present, even if something went wrong # loading it or the file is empty. In this config file context, see # the context env vars, it will intentionally not load the YAML file. Appsignal.configure # Disable if no config was loaded from the file but it is present config[:active] = false end # Disable on config file error config[:active] = false if defined?(@config_error) ENV.delete("_APPSIGNAL_CONFIG_FILE_CONTEXT") ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV") end end
def log_formatter(prefix = nil)
def log_formatter(prefix = nil) pre = "#{prefix}: " if prefix proc do |severity, datetime, _progname, msg| "[#{datetime.strftime("%Y-%m-%dT%H:%M:%S")} (process) " \ "##{Process.pid}][#{severity}] #{pre}#{msg}\n" end end
def params_match_loaded_config?(env_param, root_path_param)
def params_match_loaded_config?(env_param, root_path_param) # No config present: can't match any config return false unless config # Check if the params, if present, match the loaded config (env_param.nil? || config.env == env_param.to_s) && (root_path_param.nil? || config.root_path == root_path_param) end
def start # rubocop:disable Metrics/AbcSize
- Since: - 0.7.0
Returns:
-
(void)-
Other tags:
- Example: with custom loaded configuration -
def start # rubocop:disable Metrics/AbcSize if ENV.fetch("_APPSIGNAL_DIAGNOSE", false) internal_logger.info("Skipping start in diagnose context") return end if started? internal_logger.warn("Ignoring call to Appsignal.start after AppSignal has started") return end if config_file_context? internal_logger.warn( "Ignoring call to Appsignal.start in config file context." ) return end unless extension_loaded? internal_logger.info("Not starting AppSignal, extension is not loaded") return end internal_logger.debug("Loading AppSignal gem") _load_config! _start_logger if config.active_for_env? if config.valid? @started = true internal_logger.info "Starting AppSignal #{Appsignal::VERSION} " \ "(#{$PROGRAM_NAME}, Ruby #{RUBY_VERSION}, #{RUBY_PLATFORM})" config.write_to_environment Appsignal::Extension.start Appsignal::Hooks.load_hooks Appsignal::Loaders.start if config[:enable_allocation_tracking] && !Appsignal::System.jruby? Appsignal::Extension.install_allocation_event_hook Appsignal::Environment.report_enabled("allocation_tracking") end Appsignal::Probes.start if config[:enable_minutely_probes] collect_environment_metadata @config.freeze else internal_logger.info("Not starting, no valid config for this environment") end else internal_logger.info("Not starting, not active for #{config.env}") end nil end
def start_internal_file_logger(path)
def start_internal_file_logger(path) @internal_logger = Appsignal::Utils::IntegrationLogger.new(path) internal_logger.formatter = log_formatter rescue SystemCallError => error start_internal_stdout_logger internal_logger.warn "Unable to start internal logger with log path '#{path}'." internal_logger.warn error end
def start_internal_stdout_logger
def start_internal_stdout_logger @internal_logger = Appsignal::Utils::IntegrationLogger.new($stdout) internal_logger.formatter = log_formatter("appsignal") end
def started?
- Since: - 3.12.0
Other tags:
- See: Extension -
Returns:
-
(Boolean)-
def started? defined?(@started) ? @started : false end
def stop(called_by = nil)
- Since: - 1.0.0
Returns:
-
(void)-
Parameters:
-
called_by(String) -- Name of the thing that requested the agent to
def stop(called_by = nil) Thread.new do if called_by internal_logger.info("Stopping AppSignal (#{called_by})") else internal_logger.info("Stopping AppSignal") end Appsignal::Extension.stop Appsignal::Probes.stop Appsignal::CheckIn.stop end.join nil end
def testing?
def testing? false end