<commit_before>require 'adhearsion/punchblock_plugin'
require 'adhearsion/linux_proc_name'

module Adhearsion
  class Initializer

    extend ActiveSupport::Autoload

    autoload :Logging

    class << self
      def start(*args, &block)
        new(*args, &block).start
      end
    end

    attr_reader :path, :daemon, :pid_file

    # Creation of pid_files
    #
    #  - You may want to have Adhearsion create a process identification
    #    file when it boots so that a crash monitoring program such as
    #    Monit can reboot if necessary or so the init script can kill it
    #    for system shutdowns.
    #  - To have Adhearsion create a pid file in the default location (i.e.
    #    AHN_INSTALL_DIR/adhearsion.pid), supply :pid_file with 'true'. Otherwise
    #    one is not created UNLESS it is running in daemon mode, in which
    #    case one is created. You can force Adhearsion to not create one
    #    even in daemon mode by supplying "false".
    def initialize(options = {})
      @@started = true
      @path     = path
      @mode     = options[:mode]
      @pid_file = options[:pid_file].nil? ? ENV['PID_FILE'] : options[:pid_file]
      @loaded_init_files  = options[:loaded_init_files]
      Adhearsion.ahn_root = '.'
    end

    def start
      resolve_pid_file_path
      load_lib_folder
      load_config
      initialize_log_paths
      daemonize! if should_daemonize?
      launch_console if need_console?
      catch_termination_signal
      create_pid_file
      start_logging
      set_ahn_proc_name
      logger.info "Loaded config in <#{Adhearsion.config.platform.environment}> environment"
      initialize_exception_logger
      update_rails_env_var
      init_plugins

      logger.info "Adhearsion v#{Adhearsion::VERSION} initialized!"
      Adhearsion::Process.booted

      run_plugins
      trigger_after_initialized_hooks

      # This method will block until all important threads have finished.
      # When it does, the process will exit.
      join_important_threads
      self
    end

    def update_rails_env_var
      env = ENV['AHN_ENV']
      if env && Adhearsion.config.valid_environment?(env.to_sym)
        if ENV['RAILS_ENV'] == env
          logger.info "Using the configured value for RAILS_ENV : <#{env}>"
        else
          logger.warn "Updating AHN_RAILS variable to <#{env}>"
          ENV['RAILS_ENV'] = env
        end
      else
        env = ENV['RAILS_ENV']
        if env
          logger.info "Using the configured value for RAILS_ENV : <#{env}>"
        else
          env = Adhearsion.config.platform.environment.to_s
          logger.info "Defining AHN_RAILS variable to <#{env}>"
          ENV['RAILS_ENV'] = env
        end
      end
      env
    end

    def default_pid_path
      File.join Adhearsion.config.root, 'adhearsion.pid'
    end

    def resolve_pid_file_path
      @pid_file = if pid_file.equal?(true)
        default_pid_path
      elsif pid_file.equal?(false)
        nil
      elsif pid_file
        File.expand_path pid_file
      else
        should_daemonize? ? default_pid_path : nil
      end
    end

    def resolve_log_file_path
      _log_file = Adhearsion.config.platform.logging.outputters
      _log_file = _log_file[0] if _log_file.is_a?(Array)
      _log_file = File.expand_path(Adhearsion.config.root.dup.concat("/").concat(_log_file)) unless _log_file.start_with?("/")
      _log_file
    end

    def catch_termination_signal
      %w'INT TERM'.each do |process_signal|
        logger.info "Received #{process_signal} signal. Shutting down."
        trap process_signal do
          Adhearsion::Process.shutdown
        end
      end

      trap 'QUIT' do
        logger.info "Received QUIT signal. Hard shutting down."
        Adhearsion::Process.hard_shutdown
      end

      trap 'ABRT' do
        logger.info "Received ABRT signal. Forcing stop."
        Adhearsion::Process.force_stop
      end
    end

    ##
    # Loads files in application lib folder
    # @return [Boolean] if files have been loaded (lib folder is configured to not nil and actually exists)
    def load_lib_folder
      return false if Adhearsion.config.platform.lib.nil?

      lib_folder = [Adhearsion.config.platform.root, Adhearsion.config.platform.lib].join '/'
      return false unless File.directory? lib_folder

      Dir.chdir lib_folder do
        rbfiles = File.join "**", "*.rb"
        Dir.glob(rbfiles).each do |file|
          require "#{lib_folder}/#{file}"
        end
      end
      true
    end

    def load_config
      require "#{Adhearsion.config.root}/config/adhearsion.rb"
    end

    def init_get_logging_appenders
      @file_loggers ||= memoize_logging_appenders
    end

    def memoize_logging_appenders
      appenders = Array(Adhearsion.config.platform.logging.outputters.dup)
      # Any filename in the outputters array is mapped to a ::Logging::Appenders::File instance
      appenders.map! do |a|
        case a
        when String
          f = File.expand_path(Adhearsion.config.root.dup.concat("/").concat(a)) unless a.start_with?("/")
          ::Logging.appenders.file(f,
            :layout => ::Logging.layouts.pattern(
              :pattern => Adhearsion::Logging.adhearsion_pattern
            )
          )
        else
         a
        end
      end

      if should_daemonize?
        appenders
      else
        stdout = ::Logging.appenders.stdout(
                            'stdout',
                            :layout => ::Logging.layouts.pattern(
                              :pattern => Adhearsion::Logging.adhearsion_pattern,
                              :color_scheme => 'bright'
                            )
                          )
        appenders << stdout
      end
    end

    def init_plugins
      Plugin.init_plugins
    end

    def run_plugins
      Plugin.run_plugins
    end

    def should_daemonize?
      @mode == :daemon
    end

    def need_console?
      @mode == :console
    end

    def daemonize!
      logger.info "Daemonizing now!"
      logger.info "Creating PID file #{pid_file}"
      extend Adhearsion::CustomDaemonizer
      daemonize resolve_log_file_path
    end

    def launch_console
      Adhearsion::Process.important_threads << Thread.new do
        catching_standard_errors do
          Adhearsion::Console.run
          Adhearsion::Process.shutdown
        end
      end
    end

    # Creates the relative paths associated to log files
    # i.e.
    # - log_file = "log/adhearsion.log"      => creates 'log' folder
    # - log_file = "log/test/adhearsion.log" => creates 'log' and 'log/test' folders
    def initialize_log_paths
      outputters = Array(Adhearsion.config.platform.logging.outputters)
      outputters.select{|o| o.is_a?(String)}.each do |o|
        o = o.split("/")
        unless o[0].empty? # only if relative path
          o.pop # not consider filename
          o.inject("") do |path, folder|
            path = path.concat(folder).concat("/")
            Dir.mkdir(path) unless File.directory? path
            path
          end
        end
      end
    end

    def start_logging
      outputters = init_get_logging_appenders
      Logging.start outputters, Adhearsion.config.platform.logging.level, Adhearsion.config.platform.logging.formatter
    end

    def initialize_exception_logger
      Events.register_handler :exception do |e|
        logger.error e
      end
    end

    def create_pid_file
      return unless pid_file

      File.open pid_file, 'w' do |file|
        file.puts ::Process.pid
      end

      Events.register_callback :shutdown do
        File.delete(pid_file) if File.exists?(pid_file)
      end
    end

    def set_ahn_proc_name
      Adhearsion::LinuxProcName.set_proc_name Adhearsion.config.platform.process_name
    end

    def trigger_after_initialized_hooks
      Events.trigger_immediately :after_initialized
    end

    ##
    # This method will block Thread.main() until calling join() has returned for all Threads in Adhearsion::Process.important_threads.
    # Note: important_threads won't always contain Thread instances. It simply requires the objects respond to join().
    #
    def join_important_threads
      # Note: we're using this ugly accumulator to ensure that all threads have ended since IMPORTANT_THREADS will almost
      # certainly change sizes after this method is called.
      index = 0
      until index == Adhearsion::Process.important_threads.size
        begin
          Adhearsion::Process.important_threads[index].join
        rescue => e
          logger.error "Error after joining Thread #{Thread.inspect}. #{e.message}"
        ensure
          index = index + 1
        end
      end
    end

    InitializationFailedError = Class.new StandardError
  end
end
<commit_msg>[BUGFIX] Log SIGINT/SIGTERM when they are actually received<commit_after>require 'adhearsion/punchblock_plugin'
require 'adhearsion/linux_proc_name'

module Adhearsion
  class Initializer

    extend ActiveSupport::Autoload

    autoload :Logging

    class << self
      def start(*args, &block)
        new(*args, &block).start
      end
    end

    attr_reader :path, :daemon, :pid_file

    # Creation of pid_files
    #
    #  - You may want to have Adhearsion create a process identification
    #    file when it boots so that a crash monitoring program such as
    #    Monit can reboot if necessary or so the init script can kill it
    #    for system shutdowns.
    #  - To have Adhearsion create a pid file in the default location (i.e.
    #    AHN_INSTALL_DIR/adhearsion.pid), supply :pid_file with 'true'. Otherwise
    #    one is not created UNLESS it is running in daemon mode, in which
    #    case one is created. You can force Adhearsion to not create one
    #    even in daemon mode by supplying "false".
    def initialize(options = {})
      @@started = true
      @path     = path
      @mode     = options[:mode]
      @pid_file = options[:pid_file].nil? ? ENV['PID_FILE'] : options[:pid_file]
      @loaded_init_files  = options[:loaded_init_files]
      Adhearsion.ahn_root = '.'
    end

    def start
      resolve_pid_file_path
      load_lib_folder
      load_config
      initialize_log_paths
      daemonize! if should_daemonize?
      launch_console if need_console?
      catch_termination_signal
      create_pid_file
      start_logging
      set_ahn_proc_name
      logger.info "Loaded config in <#{Adhearsion.config.platform.environment}> environment"
      initialize_exception_logger
      update_rails_env_var
      init_plugins

      logger.info "Adhearsion v#{Adhearsion::VERSION} initialized!"
      Adhearsion::Process.booted

      run_plugins
      trigger_after_initialized_hooks

      # This method will block until all important threads have finished.
      # When it does, the process will exit.
      join_important_threads
      self
    end

    def update_rails_env_var
      env = ENV['AHN_ENV']
      if env && Adhearsion.config.valid_environment?(env.to_sym)
        if ENV['RAILS_ENV'] == env
          logger.info "Using the configured value for RAILS_ENV : <#{env}>"
        else
          logger.warn "Updating AHN_RAILS variable to <#{env}>"
          ENV['RAILS_ENV'] = env
        end
      else
        env = ENV['RAILS_ENV']
        if env
          logger.info "Using the configured value for RAILS_ENV : <#{env}>"
        else
          env = Adhearsion.config.platform.environment.to_s
          logger.info "Defining AHN_RAILS variable to <#{env}>"
          ENV['RAILS_ENV'] = env
        end
      end
      env
    end

    def default_pid_path
      File.join Adhearsion.config.root, 'adhearsion.pid'
    end

    def resolve_pid_file_path
      @pid_file = if pid_file.equal?(true)
        default_pid_path
      elsif pid_file.equal?(false)
        nil
      elsif pid_file
        File.expand_path pid_file
      else
        should_daemonize? ? default_pid_path : nil
      end
    end

    def resolve_log_file_path
      _log_file = Adhearsion.config.platform.logging.outputters
      _log_file = _log_file[0] if _log_file.is_a?(Array)
      _log_file = File.expand_path(Adhearsion.config.root.dup.concat("/").concat(_log_file)) unless _log_file.start_with?("/")
      _log_file
    end

    def catch_termination_signal
      %w'INT TERM'.each do |process_signal|
        trap process_signal do
          logger.info "Received #{process_signal} signal. Shutting down."
          Adhearsion::Process.shutdown
        end
      end

      trap 'QUIT' do
        logger.info "Received QUIT signal. Hard shutting down."
        Adhearsion::Process.hard_shutdown
      end

      trap 'ABRT' do
        logger.info "Received ABRT signal. Forcing stop."
        Adhearsion::Process.force_stop
      end
    end

    ##
    # Loads files in application lib folder
    # @return [Boolean] if files have been loaded (lib folder is configured to not nil and actually exists)
    def load_lib_folder
      return false if Adhearsion.config.platform.lib.nil?

      lib_folder = [Adhearsion.config.platform.root, Adhearsion.config.platform.lib].join '/'
      return false unless File.directory? lib_folder

      Dir.chdir lib_folder do
        rbfiles = File.join "**", "*.rb"
        Dir.glob(rbfiles).each do |file|
          require "#{lib_folder}/#{file}"
        end
      end
      true
    end

    def load_config
      require "#{Adhearsion.config.root}/config/adhearsion.rb"
    end

    def init_get_logging_appenders
      @file_loggers ||= memoize_logging_appenders
    end

    def memoize_logging_appenders
      appenders = Array(Adhearsion.config.platform.logging.outputters.dup)
      # Any filename in the outputters array is mapped to a ::Logging::Appenders::File instance
      appenders.map! do |a|
        case a
        when String
          f = File.expand_path(Adhearsion.config.root.dup.concat("/").concat(a)) unless a.start_with?("/")
          ::Logging.appenders.file(f,
            :layout => ::Logging.layouts.pattern(
              :pattern => Adhearsion::Logging.adhearsion_pattern
            )
          )
        else
         a
        end
      end

      if should_daemonize?
        appenders
      else
        stdout = ::Logging.appenders.stdout(
                            'stdout',
                            :layout => ::Logging.layouts.pattern(
                              :pattern => Adhearsion::Logging.adhearsion_pattern,
                              :color_scheme => 'bright'
                            )
                          )
        appenders << stdout
      end
    end

    def init_plugins
      Plugin.init_plugins
    end

    def run_plugins
      Plugin.run_plugins
    end

    def should_daemonize?
      @mode == :daemon
    end

    def need_console?
      @mode == :console
    end

    def daemonize!
      logger.info "Daemonizing now!"
      logger.info "Creating PID file #{pid_file}"
      extend Adhearsion::CustomDaemonizer
      daemonize resolve_log_file_path
    end

    def launch_console
      Adhearsion::Process.important_threads << Thread.new do
        catching_standard_errors do
          Adhearsion::Console.run
          Adhearsion::Process.shutdown
        end
      end
    end

    # Creates the relative paths associated to log files
    # i.e.
    # - log_file = "log/adhearsion.log"      => creates 'log' folder
    # - log_file = "log/test/adhearsion.log" => creates 'log' and 'log/test' folders
    def initialize_log_paths
      outputters = Array(Adhearsion.config.platform.logging.outputters)
      outputters.select{|o| o.is_a?(String)}.each do |o|
        o = o.split("/")
        unless o[0].empty? # only if relative path
          o.pop # not consider filename
          o.inject("") do |path, folder|
            path = path.concat(folder).concat("/")
            Dir.mkdir(path) unless File.directory? path
            path
          end
        end
      end
    end

    def start_logging
      outputters = init_get_logging_appenders
      Logging.start outputters, Adhearsion.config.platform.logging.level, Adhearsion.config.platform.logging.formatter
    end

    def initialize_exception_logger
      Events.register_handler :exception do |e|
        logger.error e
      end
    end

    def create_pid_file
      return unless pid_file

      File.open pid_file, 'w' do |file|
        file.puts ::Process.pid
      end

      Events.register_callback :shutdown do
        File.delete(pid_file) if File.exists?(pid_file)
      end
    end

    def set_ahn_proc_name
      Adhearsion::LinuxProcName.set_proc_name Adhearsion.config.platform.process_name
    end

    def trigger_after_initialized_hooks
      Events.trigger_immediately :after_initialized
    end

    ##
    # This method will block Thread.main() until calling join() has returned for all Threads in Adhearsion::Process.important_threads.
    # Note: important_threads won't always contain Thread instances. It simply requires the objects respond to join().
    #
    def join_important_threads
      # Note: we're using this ugly accumulator to ensure that all threads have ended since IMPORTANT_THREADS will almost
      # certainly change sizes after this method is called.
      index = 0
      until index == Adhearsion::Process.important_threads.size
        begin
          Adhearsion::Process.important_threads[index].join
        rescue => e
          logger.error "Error after joining Thread #{Thread.inspect}. #{e.message}"
        ensure
          index = index + 1
        end
      end
    end

    InitializationFailedError = Class.new StandardError
  end
end

{'fraction_non_alphanumeric': 0.07841914266273531, 'fraction_numerical': 0.0004536176003628941, 'mean_word_length': 2.2679266259032795, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, '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': '6174980', 'n_tokens_mistral': 5310, 'n_tokens_neox': 5209, 'n_words': 1351}