def __run(self, controller):
        """Runs the Scalyr Agent 2.

        This method will not return until a TERM signal is received or a fatal error occurs.

        @param controller The controller that started this agent service.
        @type controller: PlatformController

        @return: the exit status code
        @rtype: int
        """

        self.__start_time = time.time()
        controller.register_for_termination(self.__handle_terminate)

        # Register handler for when we get an interrupt signal.  That indicates we should dump the status to
        # a file because a user has run the 'detailed_status' command.
        self.__controller.register_for_status_requests(self.__report_status_to_file)

        # The stats we track for the lifetime of the agent.  This variable tracks the accumulated stats since the
        # last stat reset (the stats get reset every time we read a new configuration).
        base_overall_stats = OverallStats()
        # We only emit the overall stats once ever ten minutes.  Track when we last reported it.
        last_overall_stats_report_time = time.time()
        # We only emit the bandwidth stats once every minute.  Track when we last reported it.
        last_bw_stats_report_time = last_overall_stats_report_time

        # The thread that runs the monitors and and the log copier.
        worker_thread = None

        try:
            # noinspection PyBroadException
            try:
                self.__run_state = RunState()
                self.__log_file_path = os.path.join(self.__config.agent_log_path, 'agent.log')
                scalyr_logging.set_log_destination(use_disk=True, logs_directory=self.__config.agent_log_path,
                                                   agent_log_file_path='agent.log')

                self.__update_debug_log_level(self.__config.debug_level)

                # We record where the log file currently is so that we can (in the worse case) start copying it
                # from this position.  That way we capture the first 'Starting scalyr agent' call.
                agent_log_position = self.__get_file_initial_position(self.__log_file_path)
                if agent_log_position is not None:
                    logs_initial_positions = {self.__log_file_path: agent_log_position}
                else:
                    logs_initial_positions = None

                log.info('Starting scalyr agent... (version=%s) %s' % (SCALYR_VERSION, scalyr_util.get_pid_tid()))
                log.log(scalyr_logging.DEBUG_LEVEL_1, 'Starting scalyr agent... (version=%s) %s' % (
                    SCALYR_VERSION, scalyr_util.get_pid_tid()))
                self.__controller.emit_init_log(log, self.__config.debug_init)

                self.__start_or_stop_unsafe_debugging()

                self.__scalyr_client = self.__create_client()
                worker_thread = self.__create_worker_thread(self.__config)
                worker_thread.start(self.__scalyr_client, logs_initial_positions)

                self.__copying_manager = worker_thread.copying_manager
                self.__monitors_manager = worker_thread.monitors_manager

                while not self.__run_state.sleep_but_awaken_if_stopped(30):
                    current_time = time.time()
                    self.__last_config_check_time = current_time

                    # Log the overall stats once every 10 mins.
                    if current_time > last_overall_stats_report_time + 600:
                        self.__log_overall_stats(self.__calculate_overall_stats(base_overall_stats))
                        last_overall_stats_report_time = current_time

                    # Log the bandwidth-related stats once every minute:
                    if current_time > last_bw_stats_report_time + 60:
                        self.__log_bandwidth_stats(self.__calculate_overall_stats(base_overall_stats))
                        last_bw_stats_report_time = current_time

                    log.log(scalyr_logging.DEBUG_LEVEL_1, 'Checking for any changes to config file')
                    new_config = None
                    try:
                        new_config = self.__read_config(self.__config_file_path)
                        # TODO:  By parsing the configuration file, we are doing a lot of work just to have it thrown
                        # out in a few seconds when we discover it is equivalent to the previous one.  Maybe we should
                        # rework the equivalence so that it can work on the raw files, but this is difficult since
                        # we need to parse the main configuration file to at least get the fragment directory.  For
                        # now, we will just wait this work.  We only do it once every 30 secs anyway.

                        self.__verify_config(new_config)

                        # Update the debug_level based on the new config.. we always update it.
                        self.__update_debug_log_level(new_config.debug_level)

                        if self.__current_bad_config is None and new_config.equivalent(self.__config,
                                                                                       exclude_debug_level=True):
                            log.log(scalyr_logging.DEBUG_LEVEL_1, 'Config was not different than previous')
                            continue

                        self.__verify_can_write_to_logs_and_data(new_config)

                    except Exception, e:
                        if self.__current_bad_config is None:
                            log.error(
                                'Bad configuration file seen.  Ignoring, using last known good configuration file.  '
                                'Exception was "%s"', str(e), error_code='badConfigFile')
                        self.__current_bad_config = new_config
                        log.log(scalyr_logging.DEBUG_LEVEL_1, 'Config could not be read or parsed')
                        continue

                    log.log(scalyr_logging.DEBUG_LEVEL_1, 'Config was different than previous.  Reloading.')
                    # We are about to reset the current workers and ScalyrClientSession, so we will lose their
                    # contribution to the stats, so recalculate the base.
                    base_overall_stats = self.__calculate_overall_stats(base_overall_stats)
                    log.info('New configuration file seen.')
                    log.info('Stopping copying and metrics threads.')
                    worker_thread.stop()

                    worker_thread = None

                    self.__config = new_config
                    self.__controller.consume_config(new_config, new_config.file_path)

                    self.__start_or_stop_unsafe_debugging()
                    self.__scalyr_client = self.__create_client()

                    log.info('Starting new copying and metrics threads')
                    worker_thread = self.__create_worker_thread(new_config)
                    worker_thread.start(self.__scalyr_client)

                    self.__copying_manager = worker_thread.copying_manager
                    self.__monitors_manager = worker_thread.monitors_manager

                    self.__current_bad_config = None

                # Log the stats one more time before we terminate.
                self.__log_overall_stats(self.__calculate_overall_stats(base_overall_stats))

            except Exception:
                log.exception('Main run method for agent failed due to exception', error_code='failedAgentMain')
        finally:
            if worker_thread is not None:
                worker_thread.stop()
dataset/ETHPy150Open scalyr/scalyr-agent-2/scalyr_agent/agent_main.py/ScalyrAgent.__run/original