Source code for mirage.mirage_irregular_unstable

"""
mirage_irregular_unstable.py
"""
import logging
import traceback

import numpy as np

import settings

from functions.timeseries.normalized_variance import normalized_variance
from functions.victoriametrics.get_victoriametrics_metric import get_victoriametrics_metric
from skyline_functions import get_graphite_metric

skyline_app = 'mirage'
skyline_app_logger = '%sLog' % skyline_app
logger = logging.getLogger(skyline_app_logger)

[docs] def mirage_irregular_unstable(base_name, timeseries): """ Determine if a timeseries is irregular and unstable and if it is, determine if it is also irregular and unstable at 30 days, if it is return the timeseries_30d :param base_name: the metric base_name. :param timeseries: the time series as a list e.g. ``[[1667608854, 1269121024.0], [1667609454, 1269174272.0], [1667610054, 1269174272.0]]`` :type base_name: str :type timeseries: list :return: timeseries_30d :rtype: tuple(boolean, float) """ logger.info('mirage_irregular_unstable :: checking %s' % base_name) results = { 'irregular_unstable': False, 'resolution_7d': None, 'skipped': None, 'normalised_var_7d': None, 'normalised_var_30d': None, 'timeseries_30d': [], } timeseries_30d = [] low_variance_7d = 0.009 # On 20230505 for Feature #4848: mirage - analyse.irregular.unstable.timeseries.at.30days # After analysing and assessing the variance values for 251 tN SNAB results and # 7 fN results and 1 unsure result, it was determined that at 30 days the # normalised_var should be < 0.0065. Of the 251 tN result only 7 of those were # >= 0.0065 (0.0065, 0.0065, 0.0066, 0.0066, 0.0081, 0.0096, 0.0104). These # were reassessed and found that they could be deemed either way. Further the # unsure metric was 0.0065, therefore for the sake of perhaps 2.5% fPs we ensure # less fNs or unsures (with current knowledge) low_variance_30d = 0.0065 try: timestamps = [int(item[0]) for item in timeseries] np_timestamps = np.array(timestamps) ts_diffs = np.diff(np_timestamps) resolution_counts = np.unique(ts_diffs, return_counts=True) resolution = resolution_counts[0][np.argmax(resolution_counts[1])] results['resolution_7d'] = resolution if resolution > 900: # Not suited to low resolution data results['skipped'] = 'Not suited to low resolution > 900' return results duration = timestamps[-1] - timestamps[0] results['duration'] = duration if duration < 446400: # Not suitable for less than 5.25 days worth of data results['skipped'] = 'Not suitable for less than 5.25 days worth of data' return results normalized_var = None try: normalized_var = normalized_variance(timeseries) except Exception as err: results['normalized_var execution error'] = err return results if not isinstance(normalized_var, float): results['normalized_var error'] = normalized_var['error'] return results results['normalised_var_7d'] = normalized_var if normalized_var > low_variance_7d: results['skipped'] = 'normalized_var > %s' % str(low_variance_7d) return results until_timestamp = timestamps[-1] from_timestamp = until_timestamp - (86400 * 30) try: if '_tenant_id=' not in base_name: timeseries_30d = get_graphite_metric(skyline_app, base_name, from_timestamp, until_timestamp, 'list', 'object') else: timeseries_30d = get_victoriametrics_metric(skyline_app, base_name, from_timestamp, until_timestamp, 'list', 'object') except Exception as err: logger.error('error :: no timeseries_30d fetched for %s - %s' % (base_name, err)) results['skipped'] = 'no timeseries_30d fetched - %s' % str(err) return results if len(timeseries_30d) == 0: results['skipped'] = 'no timeseries_30d returned' return results if len(timeseries_30d) <= len(timeseries): results['skipped'] = 'len(timeseries_30d) <= len(timeseries)' return results normalized_var_30d = None try: normalized_var_30d = normalized_variance(timeseries_30d) except Exception as err: results['normalized_var_30d execution error'] = err return results if not isinstance(normalized_var_30d, float): results['normalized_var_30d error'] = normalized_var_30d['error'] return results results['normalised_var_30d'] = normalized_var_30d if normalized_var_30d >= low_variance_30d: results['skipped'] = 'normalized_var_30d >= %s (low_variance_30d)' % str(low_variance_30d) return results results['irregular_unstable'] = True results['timeseries_30d'] = timeseries_30d except Exception as err: logger.error(traceback.format_exc()) logger.error('error :: mirage_irregular_unstable failed - %s' % err) results['error'] = err return results