<commit_before>require 'erb'
require 'yaml'
require 'appsignal/integrations/capistrano/careful_logger'

module Appsignal
  class Config
    include Appsignal::CarefulLogger

    DEFAULT_CONFIG = {
      :debug                          => false,
      :ignore_errors                  => [],
      :ignore_actions                 => [],
      :send_params                    => true,
      :endpoint                       => 'https://push.appsignal.com',
      :instrument_net_http            => true,
      :skip_session_data              => false,
      :enable_frontend_error_catching => false,
      :frontend_error_catching_path   => '/appsignal_error_catcher'
    }.freeze

    ENV_TO_KEY_MAPPING = {
      'APPSIGNAL_ACTIVE'                         => :active,
      'APPSIGNAL_PUSH_API_KEY'                   => :push_api_key,
      'APPSIGNAL_APP_NAME'                       => :name,
      'APPSIGNAL_PUSH_API_ENDPOINT'              => :endpoint,
      'APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH'   => :frontend_error_catching_path,
      'APPSIGNAL_DEBUG'                          => :debug,
      'APPSIGNAL_INSTRUMENT_NET_HTTP'            => :instrument_net_http,
      'APPSIGNAL_SKIP_SESSION_DATA'              => :skip_session_data,
      'APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING' => :enable_frontend_error_catching,
      'APPSIGNAL_IGNORE_ERRORS'                  => :ignore_errors,
      'APPSIGNAL_IGNORE_ACTIONS'                 => :ignore_actions,
      'APPSIGNAL_HTTP_PROXY'                     => :http_proxy
    }.freeze

    attr_reader :root_path, :env, :initial_config, :config_hash

    def initialize(root_path, env, initial_config={}, logger=Appsignal.logger)
      @root_path      = root_path
      @env            = env.to_s
      @initial_config = initial_config
      @logger         = logger
      @valid          = false

      # Initial config
      @config_hash = DEFAULT_CONFIG.merge(initial_config)

      # Load config from environment variables
      load_from_environment

      # Load the config file if it exists
      if File.exists?(config_file)
        load_from_disk
      end

      # Validate that we have a correct config
      validate
    end

    def [](key)
      config_hash[key]
    end

    def valid?
      @valid
    end

    def active?
      @valid && self[:active]
    end

    def write_to_environment
      ENV['APPSIGNAL_ACTIVE']            = active?.to_s
      ENV['APPSIGNAL_APP_PATH']          = root_path.to_s
      ENV['APPSIGNAL_AGENT_PATH']        = File.expand_path('../../../ext', __FILE__).to_s
      ENV['APPSIGNAL_LOG_PATH']          = File.join(root_path, 'log')
      ENV['APPSIGNAL_ENVIRONMENT']       = env
      ENV['APPSIGNAL_AGENT_VERSION']     = Appsignal::Extension.agent_version
      ENV['APPSIGNAL_DEBUG_LOGGING']     = config_hash[:debug].to_s
      ENV['APPSIGNAL_PUSH_API_ENDPOINT'] = config_hash[:endpoint]
      ENV['APPSIGNAL_PUSH_API_KEY']      = config_hash[:push_api_key]
      ENV['APPSIGNAL_APP_NAME']          = config_hash[:name]
      ENV['APPSIGNAL_HTTP_PROXY']        = config_hash[:http_proxy]
      ENV['APPSIGNAL_IGNORE_ACTIONS']    = config_hash[:ignore_actions].join(',')
    end

    protected

    def config_file
      @config_file ||= File.join(root_path, 'config', 'appsignal.yml')
    end

    def load_from_disk
      configurations = YAML.load(ERB.new(IO.read(config_file)).result)
      config_for_this_env = configurations[env]
      if config_for_this_env
        config_for_this_env = Hash[config_for_this_env.map do |key, value|
          [key.to_sym, value]
        end] # convert keys to symbols

        # Backwards compatibility with config files generated by earlier
        # versions of the gem
        if !config_for_this_env[:push_api_key] && config_for_this_env[:api_key]
          config_for_this_env[:push_api_key] = config_for_this_env[:api_key]
        end
        if !config_for_this_env[:ignore_errors] && config_for_this_env[:ignore_exceptions]
          config_for_this_env[:ignore_errors] = config_for_this_env[:ignore_exceptions]
        end

        merge(@config_hash, config_for_this_env)
      else
        carefully_log_error("Not loading from config file: config for '#{env}' not found")
      end
    end

    def load_from_environment
      config = {}

      # Make active by default if APPSIGNAL_PUSH_API_KEY is present
      if ENV['APPSIGNAL_PUSH_API_KEY']
        config[:active] = true
      end

      # Configuration with string type
      %w(APPSIGNAL_PUSH_API_KEY APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_ENDPOINT
         APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var
        end
      end

      # Configuration with boolean type
      %w(APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP
         APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var == 'true'
        end
      end

      # Configuration with array of strings type
      %w(APPSIGNAL_IGNORE_ERRORS APPSIGNAL_IGNORE_ACTIONS).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var.split(',')
        end
      end

      merge(@config_hash, config)
    end

    def merge(original_config, new_config)
      new_config.each do |key, value|
        unless original_config[key].nil?
          @logger.warn("Config key '#{key}' is being overwritten")
        end
        original_config[key] = value
      end
    end

    def validate
      if config_hash[:push_api_key]
        @valid = true
      else
        @valid = false
        carefully_log_error("Push api key not set after loading config")
      end
    end

    def load_default_config_with_push_api_key_and_name_from_env(key)
      # Get base config by doing the default merge and adding the push api key.
      @config_hash = merge_config(
        :push_api_key => key,
        :active => true
      )
      @config_hash[:name]   = ENV['APPSIGNAL_APP_NAME'] if ENV['APPSIGNAL_APP_NAME']
      @config_hash[:active] = ENV['APPSIGNAL_ACTIVE'] == 'true' if ENV['APPSIGNAL_ACTIVE']
    end
  end
end
<commit_msg>Use info instead of warn, cap2 logger doesn't have warn<commit_after>require 'erb'
require 'yaml'
require 'appsignal/integrations/capistrano/careful_logger'

module Appsignal
  class Config
    include Appsignal::CarefulLogger

    DEFAULT_CONFIG = {
      :debug                          => false,
      :ignore_errors                  => [],
      :ignore_actions                 => [],
      :send_params                    => true,
      :endpoint                       => 'https://push.appsignal.com',
      :instrument_net_http            => true,
      :skip_session_data              => false,
      :enable_frontend_error_catching => false,
      :frontend_error_catching_path   => '/appsignal_error_catcher'
    }.freeze

    ENV_TO_KEY_MAPPING = {
      'APPSIGNAL_ACTIVE'                         => :active,
      'APPSIGNAL_PUSH_API_KEY'                   => :push_api_key,
      'APPSIGNAL_APP_NAME'                       => :name,
      'APPSIGNAL_PUSH_API_ENDPOINT'              => :endpoint,
      'APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH'   => :frontend_error_catching_path,
      'APPSIGNAL_DEBUG'                          => :debug,
      'APPSIGNAL_INSTRUMENT_NET_HTTP'            => :instrument_net_http,
      'APPSIGNAL_SKIP_SESSION_DATA'              => :skip_session_data,
      'APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING' => :enable_frontend_error_catching,
      'APPSIGNAL_IGNORE_ERRORS'                  => :ignore_errors,
      'APPSIGNAL_IGNORE_ACTIONS'                 => :ignore_actions,
      'APPSIGNAL_HTTP_PROXY'                     => :http_proxy
    }.freeze

    attr_reader :root_path, :env, :initial_config, :config_hash

    def initialize(root_path, env, initial_config={}, logger=Appsignal.logger)
      @root_path      = root_path
      @env            = env.to_s
      @initial_config = initial_config
      @logger         = logger
      @valid          = false

      # Initial config
      @config_hash = DEFAULT_CONFIG.merge(initial_config)

      # Load config from environment variables
      load_from_environment

      # Load the config file if it exists
      if File.exists?(config_file)
        load_from_disk
      end

      # Validate that we have a correct config
      validate
    end

    def [](key)
      config_hash[key]
    end

    def valid?
      @valid
    end

    def active?
      @valid && self[:active]
    end

    def write_to_environment
      ENV['APPSIGNAL_ACTIVE']            = active?.to_s
      ENV['APPSIGNAL_APP_PATH']          = root_path.to_s
      ENV['APPSIGNAL_AGENT_PATH']        = File.expand_path('../../../ext', __FILE__).to_s
      ENV['APPSIGNAL_LOG_PATH']          = File.join(root_path, 'log')
      ENV['APPSIGNAL_ENVIRONMENT']       = env
      ENV['APPSIGNAL_AGENT_VERSION']     = Appsignal::Extension.agent_version
      ENV['APPSIGNAL_DEBUG_LOGGING']     = config_hash[:debug].to_s
      ENV['APPSIGNAL_PUSH_API_ENDPOINT'] = config_hash[:endpoint]
      ENV['APPSIGNAL_PUSH_API_KEY']      = config_hash[:push_api_key]
      ENV['APPSIGNAL_APP_NAME']          = config_hash[:name]
      ENV['APPSIGNAL_HTTP_PROXY']        = config_hash[:http_proxy]
      ENV['APPSIGNAL_IGNORE_ACTIONS']    = config_hash[:ignore_actions].join(',')
    end

    protected

    def config_file
      @config_file ||= File.join(root_path, 'config', 'appsignal.yml')
    end

    def load_from_disk
      configurations = YAML.load(ERB.new(IO.read(config_file)).result)
      config_for_this_env = configurations[env]
      if config_for_this_env
        config_for_this_env = Hash[config_for_this_env.map do |key, value|
          [key.to_sym, value]
        end] # convert keys to symbols

        # Backwards compatibility with config files generated by earlier
        # versions of the gem
        if !config_for_this_env[:push_api_key] && config_for_this_env[:api_key]
          config_for_this_env[:push_api_key] = config_for_this_env[:api_key]
        end
        if !config_for_this_env[:ignore_errors] && config_for_this_env[:ignore_exceptions]
          config_for_this_env[:ignore_errors] = config_for_this_env[:ignore_exceptions]
        end

        merge(@config_hash, config_for_this_env)
      else
        carefully_log_error("Not loading from config file: config for '#{env}' not found")
      end
    end

    def load_from_environment
      config = {}

      # Make active by default if APPSIGNAL_PUSH_API_KEY is present
      if ENV['APPSIGNAL_PUSH_API_KEY']
        config[:active] = true
      end

      # Configuration with string type
      %w(APPSIGNAL_PUSH_API_KEY APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_ENDPOINT
         APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var
        end
      end

      # Configuration with boolean type
      %w(APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP
         APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var == 'true'
        end
      end

      # Configuration with array of strings type
      %w(APPSIGNAL_IGNORE_ERRORS APPSIGNAL_IGNORE_ACTIONS).each do |var|
        if env_var = ENV[var]
          config[ENV_TO_KEY_MAPPING[var]] = env_var.split(',')
        end
      end

      merge(@config_hash, config)
    end

    def merge(original_config, new_config)
      new_config.each do |key, value|
        unless original_config[key].nil?
          @logger.info("Config key '#{key}' is being overwritten")
        end
        original_config[key] = value
      end
    end

    def validate
      if config_hash[:push_api_key]
        @valid = true
      else
        @valid = false
        carefully_log_error("Push api key not set after loading config")
      end
    end

    def load_default_config_with_push_api_key_and_name_from_env(key)
      # Get base config by doing the default merge and adding the push api key.
      @config_hash = merge_config(
        :push_api_key => key,
        :active => true
      )
      @config_hash[:name]   = ENV['APPSIGNAL_APP_NAME'] if ENV['APPSIGNAL_APP_NAME']
      @config_hash[:active] = ENV['APPSIGNAL_ACTIVE'] == 'true' if ENV['APPSIGNAL_ACTIVE']
    end
  end
end

{'fraction_non_alphanumeric': 0.08771651040839028, 'fraction_numerical': 7.94533608771651e-05, 'mean_word_length': 2.4259662493195426, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 49, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1967307', 'n_tokens_mistral': 4120, 'n_tokens_neox': 4022, 'n_words': 731}