def test_transform_time_string(self): transform_result_1 = utils.transform_time_string('10S', mode='to_second') transform_result_2 = utils.transform_time_string('2M', mode='to_second') transform_result_3 = utils.transform_time_string('3H', mode='to_second') transform_result_4 = utils.transform_time_string('1D', mode='to_second') transform_result_5 = utils.transform_time_string('2W', mode='to_second') transform_result_6 = utils.transform_time_string('10S', mode='timedelta') transform_result_7 = utils.transform_time_string('2M', mode='timedelta') transform_result_8 = utils.transform_time_string('3H', mode='timedelta') transform_result_9 = utils.transform_time_string('1D', mode='timedelta') transform_result_10 = utils.transform_time_string('2W', mode='timedelta') self.assertEqual(transform_result_1, 10) self.assertEqual(transform_result_2, 2 * 60) self.assertEqual(transform_result_3, 3 * 60 * 60) self.assertEqual(transform_result_4, 1 * 24 * 60 * 60) self.assertEqual(transform_result_5, 2 * 7 * 24 * 60 * 60) self.assertEqual(transform_result_6, timedelta(seconds=10)) self.assertEqual(transform_result_7, timedelta(minutes=2)) self.assertEqual(transform_result_8, timedelta(hours=3)) self.assertEqual(transform_result_9, timedelta(days=1)) self.assertEqual(transform_result_10, timedelta(weeks=2))
def select_timeseries_by_timestamp(self, period): timeseries = [] times = 0 times_limit = 5 while times < times_limit: try: get_last_timestamp_sql = "select timestamp from {table} order by timestamp desc limit 1" self._cur.execute( get_last_timestamp_sql.format(table=self._table)) last_timestamp = self._cur.fetchall()[0][0] time_interval = transform_time_string(period, mode='to_second') select_timestamp = last_timestamp - time_interval get_timeseries_sql = "select timestamp, value from {table} where timestamp >= '{select_timestamp}'" self._cur.execute( get_timeseries_sql.format( table=self._table, select_timestamp=select_timestamp)) timeseries = self._cur.fetchall() if not timeseries: logger.warn( "get no timeseries from {table}', retry...".format( table=self._table)) else: return timeseries except Exception as e: logger.exception( 'exception occur when get timeseries: {error}, retry...'. format(error=str(e)), exc_info=True) times += 1 time.sleep(0.11) return timeseries
def apply(self, instance, args=None, kwargs=None): if instance in self._tasks: return False logger.info('add [{task}] in Monitor task......'.format(task=getattr(instance, 'metric_name'))) interval = getattr(instance, 'forecast_interval') try: interval = transform_time_string(interval, mode='to_second') except ValueError as e: logger.error(e, exc_info=True) return timer = RepeatTimer(interval=interval, function=instance.run, args=args, kwargs=kwargs) self._tasks[instance] = timer return True
def check_agent_parameter(config): """ Check if the agent parameter is valid, if the parameter is valid, then return parameters dict, otherwise exit process. :param config: config handler for config file. :return: agent parameters dict. """ agent_parameters = {} url = "" try: host = config.get('server', 'host') listen_port = config.get('server', 'listen_port') except (NoOptionError, NoSectionError) as e: logger.error(e) sys.exit(0) else: agent_parameters['host'] = host agent_parameters['listen_port'] = listen_port default_agent_parameter_dicts = { 'sink_timer_interval': '10S', 'source_timer_interval': '10S', 'channel_capacity': 1000 } for parameter, default_value in default_agent_parameter_dicts.items(): try: if parameter == 'channel_capacity': agent_parameter_value = config.getint('agent', parameter) agent_parameters[parameter] = agent_parameter_value else: agent_parameter_value = config.get('agent', parameter) agent_parameters[parameter] = transform_time_string( agent_parameter_value, mode='to_second') except Exception as e: logger.error( "error occur when acquire {parameter}: {error}, use default_value: {default_value}" .format(parameter=parameter, error=str(e), default_value=default_value)) agent_parameters[parameter] = default_agent_parameter_dicts[ parameter] return agent_parameters
def select_timeseries_by_timestamp(self, table, period): """ Acquire all timeseries in a timedelta from the present. :param table: string, table name from database. :param period: string, name of timedelta from now, like '100S', '1H'. :return: list, timeseries dataset. """ timeseries = [] times = 0 times_limit = 5 while times < times_limit: try: get_last_timestamp_sql = "select timestamp from {table} order by timestamp desc limit 1" self._cur.execute(get_last_timestamp_sql.format(table=table)) last_timestamp = self._cur.fetchall()[0][0] time_interval = transform_time_string(period, mode='to_second') select_timestamp = last_timestamp - time_interval get_timeseries_sql = "select timestamp, value from {table} where timestamp >= '{select_timestamp}'" self._cur.execute( get_timeseries_sql.format( table=table, select_timestamp=select_timestamp)) timeseries = self._cur.fetchall() if not timeseries: logger.warn( "get no timeseries from {table}', retry...".format( table=table)) else: return timeseries except Exception as e: logger.exception( 'exception occur when get timeseries: {error}, retry...'. format(error=str(e)), exc_info=True) times += 1 time.sleep(0.11) return timeseries
def start_agent(config_path): if not os.path.exists(config_path): logger.error( '{config_path} is not exist..'.format(config_path=config_path)) return config = ConfigParser() config.read(config_path) if not config.has_section('agent') or not config.has_section('server'): logger.error( "do not has 'agent' or 'server' section in config file...") return if not config.has_option('server', 'host') or not config.has_option( 'server', 'listen_port'): logger.error( "do not has 'host' or 'listen_port' in 'server' section...") return else: context = None if config.has_option('security', 'tls') and config.getboolean( 'security', 'tls'): url = 'https://' + config.get('server', 'host') + ':' + config.get( 'server', 'listen_port') + '/sink' try: agent_cert = os.path.realpath( config.get('security', 'agent_cert')) agent_key = os.path.realpath( config.get('security', 'agent_key')) ca = os.path.realpath(config.get('security', 'ca')) except NoOptionError as e: logger.error(e) return else: logger.info(agent_cert) logger.info(agent_key) logger.info(ca) ssl_certificate_status = check_certificate(agent_cert) ca_certificate_status = check_certificate(ca) if ssl_certificate_status['status'] == 'fail': logger.error( "error occur when check '{certificate}'.".format( certificate=agent_cert)) else: if ssl_certificate_status['level'] == 'info': logger.info(ssl_certificate_status['info']) elif ssl_certificate_status['level'] == 'warn': logger.warn(ssl_certificate_status['info']) else: logger.error(ssl_certificate_status['info']) return if ca_certificate_status['status'] == 'fail': logger.error( "error occur when check '{certificate}'.".format( certificate=ca)) else: if ca_certificate_status['level'] == 'info': logger.info(ca_certificate_status['info']) elif ca_certificate_status['level'] == 'warn': logger.warn(ca_certificate_status['info']) else: logger.error(ca_certificate_status['info']) return pw_file = os.path.join(os.path.dirname(config_path), 'certificate/pwf') with open(pw_file, mode='r') as f: pw = f.read().strip() context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca) context.check_hostname = False context.load_cert_chain(certfile=agent_cert, keyfile=agent_key, password=pw) else: logger.warn( "detect not config 'ssl certificate', use 'http' instead.[advise use 'https']" ) url = 'http://' + config.get('server', 'host') + ':' + config.get( 'server', 'listen_port') + '/sink' default_agent_parameter_dicts = { 'sink_timer_interval': '10S', 'source_timer_interval': '10S', 'channel_capacity': 1000 } for parameter, default_value in default_agent_parameter_dicts.items(): if not config.has_option('agent', parameter): logger.warn( "do not provide '{parameter}' in 'agent' section, use default '{default_value}'." .format(parameter=parameter, default_value=default_agent_parameter_dicts[ 'sink_timer_interval'])) value = default_value else: value = config.get('agent', parameter) try: if parameter in ('sink_timer_interval', 'source_timer_interval'): globals()[parameter] = transform_time_string(value, mode='to_second') if parameter == 'channel_capacity': globals()[parameter] = int(value) except Exception as e: logger.error(e) return chan = ChannelManager() source = DBSource() http_sink = HttpSink(interval=globals()['sink_timer_interval'], url=url, context=context) source.channel_manager = chan http_sink.channel_manager = chan for task_name, task_func in get_funcs(metric_task): source.add_task(name=task_name, interval=globals()['source_timer_interval'], task=task_func, maxsize=globals()['channel_capacity']) source.start() http_sink.start()
def forecast(args): from detector.timeseries_algorithms import forecast_algorithm from detector.monitor import data_handler from utils import transform_time_string, SuppressStreamObject config = ConfigParser() config.read(config_path) display_table = PrettyTable() display_table.field_names = [ 'Metric name', 'Date range', 'Minimum', 'Maximum', 'Average' ] try: database_path = config.get('database', 'database_path') max_rows = int(config.get('database', 'max_rows')) except (NoSectionError, NoOptionError) as e: print("FATAL: {error}.".format(error=str(e))) return -1 if not args.forecast_method: forecast_alg = forecast_algorithm('auto_arima')() else: forecast_alg = forecast_algorithm(args.forecast_method)() forecast_periods = str( transform_time_string(args.forecast_periods, mode='to_second')) + 'S' if not args.metric_name: with data_handler.DataHandler(database_path) as db: tables = db.get_all_tables() for table in tables: timeseries = db.get_timeseries(table=table, period=max_rows) with SuppressStreamObject(): forecast_alg.fit(timeseries=timeseries) future_date, future_value = forecast_alg.forecast( forecast_periods=forecast_periods) date_range = "{start_date}~{end_date}".format( start_date=future_date[0], end_date=future_date[-1]) minimum_forecast_value = min(future_value) maximum_forecast_value = max(future_value) average_value = sum(future_value) / len(future_value) display_table.add_row([ table, date_range, minimum_forecast_value, maximum_forecast_value, average_value ]) else: with data_handler.DataHandler(database_path) as db: timeseries = db.get_timeseries(table=args.metric_name, period=max_rows) with SuppressStreamObject(): forecast_alg.fit(timeseries=timeseries) future_date, future_value = forecast_alg.forecast( forecast_periods=forecast_periods) date_range = "{start_date}~{end_date}".format( start_date=future_date[0], end_date=future_date[-1]) minimum_forecast_value = min(future_value) maximum_forecast_value = max(future_value) average_value = sum(future_value) / len(future_value) display_table.add_row([ args.metric_name, date_range, minimum_forecast_value, maximum_forecast_value, average_value ]) if args.save_path: if not os.path.exists(os.path.dirname(args.save_path)): os.makedirs(os.path.dirname(args.save_path)) with open(args.save_path, mode='w') as f: for date, value in zip(future_date, future_value): f.write(date + ',' + str(value) + '\n') print(display_table.get_string())