ok
Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/lvestats/plugins/generic/ |
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/lvestats/plugins/generic/dbsaver_x60.py |
# coding=utf-8 # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT from __future__ import print_function from __future__ import absolute_import from __future__ import division from builtins import range import sys import logging import time from lvestats.core.plugin import LveStatsPlugin, LveStatsPluginTerminated from sqlalchemy import insert from lvestats.orm.history import history, history_x60 from sqlalchemy.sql.expression import func from sqlalchemy.sql import select from sqlalchemy.exc import OperationalError from lvestats.lib.commons.func import get_chunks, reboot_lock from lvestats.lib.lveinfolib import HistoryShow, FIELD_TO_TABLE_COLUMN from lvestats.lib.commons.progress import ProgressCallback from lvestats.lib import dbengine AGGREGATE_PERIOD = 60*60 # one hour class DBSaverX60(LveStatsPlugin): FIELDS = [ 'ID', 'aCPU', 'lCPU', 'CPUf', 'aEP', 'lEP', 'EPf', 'aVMem', 'lVMem', 'VMemF', 'aPMem', 'lPMem', 'PMemF', 'aNproc', 'lNproc', 'NprocF', 'aIO', 'lIO', 'IOf', 'IOPSf', 'lIOPS', 'aIOPS' ] def __init__(self): self.log = logging.getLogger('plugin.DBSaverX60') self.now = 0 # This changes in MainLoop self.config = None self.period = AGGREGATE_PERIOD # once an hour self.server_id = 'localhost' self.verbose_ = False self.execute_timeout = 20 self.progress = ProgressCallback(time_change_step=0.1) def set_config(self, _config): self.config = _config def aggregate_db_data_by_hours(self, utc_from, utc_to): if self.verbose_: self.progress(0) utc_from_ = int(utc_from) // int(AGGREGATE_PERIOD)*int(AGGREGATE_PERIOD) if utc_from_ != utc_from: utc_from_ += AGGREGATE_PERIOD if utc_to - utc_from_ > AGGREGATE_PERIOD: self.log.debug("Data aggregation from %s to %s started.", utc_from_, utc_to) for aggr_cycle, hour_from in enumerate(range(utc_from_, int(utc_to), AGGREGATE_PERIOD), 1): hour_to = hour_from + AGGREGATE_PERIOD if hour_to > utc_to: break history_show = HistoryShow( dbengine=self.engine, period_from=hour_from + 1, # "+1" for exclude "hour_from" timestamp period_to=hour_to, show_columns=self.FIELDS, server_id=self.server_id, log=self.log) rows = history_show.proceed() mass_insert_values = list() for row in rows: one_insert_values = { 'server_id': self.server_id, 'time': history_show.time_count, 'created': hour_to} one_insert_values.update( {FIELD_TO_TABLE_COLUMN[field_]: row[indx_] for indx_, field_ in enumerate(self.FIELDS)}) # correct cpu one_insert_values['cpu'] *= 100 one_insert_values['cpu_limit'] *= 100 mass_insert_values.append(one_insert_values) with reboot_lock(): conn_ = self.engine.connect() trans = conn_.begin() try: if mass_insert_values: for chunk in get_chunks(mass_insert_values): conn_.execute(insert(history_x60), chunk) else: conn_.execute(insert(history_x60), {'server_id': self.server_id, 'created': hour_to, 'id': 0}) if self.verbose_: # show progress progress_ = 100 - (utc_to-hour_from)*100 // (utc_to-utc_from_) self.progress(progress_) except OperationalError as oe: trans.rollback() self.log.error('Can not write aggregated data to database: %s', str(oe)) if self.verbose_: print(' Warning: {}'.format(str(oe)[:255] + '...')) except LveStatsPluginTerminated: trans.rollback() conn_.close() self.log.debug("Plugin is terminated.") raise LveStatsPluginTerminated() except TypeError as oe: trans.rollback() conn_.close() msg = str(oe) # try fix incorrect database records after migration if "*=: 'NoneType' and 'int'" not in msg: raise self.log.warning(msg) from lvestats.lib.dbengine import fix_db fix_db(self.engine, self.config, from_timestmp=hour_from, to_timestamp=hour_to, log_=self.log) return else: trans.commit() conn_.close() work_time = time.time() - self.now # calculate plugin working time if (self.execute_timeout > 0 and self.execute_timeout - work_time < work_time/aggr_cycle + 1): # continue if can't finish in time self.log.debug('Data was aggregated from %s to %s in %s seconds', utc_from_, hour_to, work_time) return self.log.debug("Data aggregation done.") else: self.log.debug("Nothing to aggregate.") if self.verbose_: self.progress(100, force=True) self.progress.stop() def execute(self, lve_data): self.log.debug("Plugin executed") self.server_id = self.config.get('server_id', 'localhost') dt_x1_max, dt_x1_min, dt_x60_max, dt_x60_min = self.get_max_min_ts() self.aggregate_new(dt_x1_max, dt_x1_min, dt_x60_max) self.aggregate_migrated(dt_x1_min, dt_x60_min) def aggregate_migrated(self, dt_x1_min, dt_x60_min): self.log.debug("Aggregating migrated") if dt_x1_min is not None and dt_x60_min is not None and dt_x1_min + AGGREGATE_PERIOD < dt_x60_min: self.aggregate_db_data_by_hours(dt_x60_min - AGGREGATE_PERIOD, dt_x60_min) def aggregate_new(self, dt_x1_max, dt_x1_min, dt_x60_max): if dt_x1_max: if not dt_x60_max: dt_x60_max = dt_x1_min # from minimum timestamp if self.verbose_: print('[lve-stats]: Start aggregating data from "{}" to "{}"; to skip press Ctrl+C ...'.format( dt_x60_max, dt_x1_max)) # correct execute period if dt_x1_max - dt_x60_max > AGGREGATE_PERIOD * 2: # run plugin often if need aggregate more than one hour self.period = 60 # FIXME: This looks like mistake? else: self.period = AGGREGATE_PERIOD self.aggregate_db_data_by_hours(dt_x60_max, dt_x1_max) def get_max_min_ts(self): conn_ = self.engine.connect() try: # get last created query = select( [func.max(history.created), func.min(history.created)]).where( self.server_id == history.server_id) time_start = time.time() row = conn_.execute(query) dt_x1_max, dt_x1_min = row.fetchone() self.log.debug( '%s; query time: %s' % (str(query.compile(compile_kwargs={"literal_binds": True})).replace('\n', ' '), time.time() - time_start)) # get last created_max query = select( [func.max(history_x60.created), func.min(history_x60.created)]).where( self.server_id == history_x60.server_id) row = conn_.execute(query) dt_x60_max, dt_x60_min = row.fetchone() self.log.debug( '%s; query time: %s' % (str(query.compile(compile_kwargs={"literal_binds": True})).replace('\n', ' '), time.time() - time_start)) except LveStatsPluginTerminated: conn_.close() self.log.debug("Plugin is terminated.") raise LveStatsPluginTerminated() else: conn_.close() return dt_x1_max, dt_x1_min, dt_x60_max, dt_x60_min def main(argv_, config_, db_engine=None): lve_data = dict() verbose_ = '--verbose' in argv_ if db_engine is None: db_engine = dbengine.make_db_engine(config_, debug=False) if 'init' in argv_: if verbose_: print('[lve-stats]: creating table "{}"...'.format(history_x60.__tablename__)) with db_engine.begin() as conn_: history_x60.__table__.create(bind=conn_, checkfirst=True) # create table if exist if 'aggregate' in argv_: # configure plugin plugin_instance = DBSaverX60() plugin_instance.config = config_ # use specific config plugin_instance.set_db_engine(db_engine) plugin_instance.execute_timeout = 2*60*60 # two hours plugin_instance.verbose_ = verbose_ plugin_instance.now = time.time() plugin_instance.execute(lve_data) # generate aggregate data # for initial from command line # create table if exist and generate aggregate data if __name__ == '__main__' and len(sys.argv) >= 2: import lvestats.lib.config as config try: cnf = config.read_plugin_config(config.read_config(), plugin=DBSaverX60.__name__) main(argv_=sys.argv[1:], config_=cnf) except KeyboardInterrupt: print('Stopped') except dbengine.MakeDbException as e: print(str(e)) except config.ConfigError as ce: ce.log_and_exit()