diff --git a/docs/source/Reference/sr3_options.7.rst b/docs/source/Reference/sr3_options.7.rst index f25fad40e..3300ac9d0 100644 --- a/docs/source/Reference/sr3_options.7.rst +++ b/docs/source/Reference/sr3_options.7.rst @@ -238,7 +238,7 @@ flag an option that has only True or False values (aka: a boolean value) float - a floating point number. + a floating point number (3 decimal places max, numbers > 1000 are integers) list a list of string values, each succeeding occurrence catenates to the total. diff --git a/docs/source/fr/Reference/sr3_options.7.rst b/docs/source/fr/Reference/sr3_options.7.rst index 1afcdcdae..efdd53fe4 100644 --- a/docs/source/fr/Reference/sr3_options.7.rst +++ b/docs/source/fr/Reference/sr3_options.7.rst @@ -237,6 +237,7 @@ flag float un nombre à virgule flottante, (séparateur de décimale étant un point.) + max de trois chiffres après le décimal, alors plus grand que 1000 devient des nombre entiers. list une liste de chaîne de caractères, chaque occurrence successive se rajoute au total. diff --git a/sarracenia/config.py b/sarracenia/config.py index 6bc0d6983..e1e663bf5 100755 --- a/sarracenia/config.py +++ b/sarracenia/config.py @@ -135,8 +135,8 @@ def __repr__(self) -> str: count_options = [ 'batch', 'count', 'exchangeSplit', 'instances', 'logRotateCount', 'no', - 'post_exchangeSplit', 'prefetch', 'messageCountMax', 'messageRateMax', - 'messageRateMin', 'runStateThreshold_cpuSlow', 'runStateThreshold_reject', 'runStateThreshold_retry', 'runStateThreshold_slow', + 'post_exchangeSplit', 'prefetch', 'messageCountMax', 'runStateThreshold_cpuSlow', + 'runStateThreshold_reject', 'runStateThreshold_retry', 'runStateThreshold_slow', ] @@ -151,7 +151,7 @@ def __repr__(self) -> str: 'statehost', 'users', 'v2compatRenameDoublePost', 'wololo' ] -float_options = [ ] +float_options = [ 'messageRateMax', 'messageRateMin' ] duration_options = [ 'expire', 'housekeeping', 'logRotateInterval', 'message_ttl', 'fileAgeMax', 'fileAgeMin', 'metrics_writeInterval', \ @@ -337,12 +337,58 @@ def isTrue(S): return S.lower() in ['true', 'yes', 'on', '1'] def parse_count(cstr): + """ + number argument accepts k,m,g suffix with i and b to use base 2 ) and +- + return value is integer. + """ if cstr[0] == '-': offset=1 else: offset=0 - count=humanfriendly.parse_size(cstr[offset:], binary=cstr[-1].lower() in ['i','b'] ) - return -count if offset else count + try: + count=humanfriendly.parse_size(cstr[offset:], binary=cstr[-1].lower() in ['i','b'] ) + return -count if offset else count + except Exception as Ex: + logger.error( f"failed to parse: {cstr} as a count value" ) + logger.debug('Exception details: ', exc_info=True) + return 0 + +def parse_float(cstr): + """ + like parse_count, numeric argument accepts k,m,g suffix and +-. + below 1000, return a decimal number with 3 digits max. + """ + if type(cstr) is not str: + return cstr + + try: + fa = parse_count(cstr) + if abs(fa) < 1000: + if cstr[-1] in [ 'b', 'i' ]: + if cstr[-2] in [ 'k' ]: + fa=float(cstr[0:-2])*1024 + else: + fa=float(cstr[0:-1]) + elif cstr[-1] in [ 'k' ]: + fa=float(cstr[0:-1])*1000 + else: + fa=float(cstr) + + # apply 3 sig figs. + if abs(fa) > 1000: + fa=int(fa) + elif abs(fa) > 100: + fa=round(fa,1) + elif abs(fa) > 10: + fa=round(fa,2) + else: + fa=round(fa,3) + + return fa + except Exception as Ex: + logger.error( f"failed to parse: {cstr} as a float value" ) + logger.debug('Exception details: ', exc_info=True) + return 0.0 def get_package_lib_dir(): return os.path.dirname(inspect.getfile(Config)) @@ -1113,7 +1159,7 @@ def add_option(self, option, kind='list', default_value=None, all_values=None ): elif kind == 'float' or kind == float : float_options.append(option) if type(v) is not float: - setattr(self, option, float(v)) + setattr(self, option, parse_float(v)) elif kind == 'list' or kind == list: list_options.append( option ) if type(v) is not list: @@ -1620,7 +1666,7 @@ def parse_line(self, component, cfg, cfname, lineno, l ): setattr(self, k, durationToSeconds(v)) elif k in float_options: try: - setattr(self, k, float(v)) + setattr(self, k, parse_float(v)) except (ValueError, TypeError) as e: logger.error(f"{','.join(self.files)}:{self.lineno} Ignored '{i}': {e}") elif k in perm_options: @@ -1670,7 +1716,7 @@ def parse_line(self, component, cfg, cfname, lineno, l ): v = ' '.join(line[1:]) if hasattr(self, k): if type(getattr(self, k)) is float: - setattr(self, k, float(v)) + setattr(self, k, parse_float(v)) elif type(getattr(self, k)) is int: # the only integers that have units are durations. # integers without units will come out unchanged. @@ -1852,7 +1898,7 @@ def finalize(self, component=None, config=None): for f in float_options: if hasattr(self, f) and (type(getattr(self, f)) is str): - setattr(self, f, float(getattr(self, f))) + setattr(self, f, parse_float(getattr(self, f))) if ( (len(self.logEvents) > 0 ) or self.log_flowcb_needed) : if ('sarracenia.flowcb.log.Log' not in self.plugins_late) and \ @@ -2025,7 +2071,7 @@ def check_undeclared_options(self): setattr(self,u,isTrue(getattr(self,u))) elif u in float_options: if type( getattr(self,u) ) is not float: - setattr(self,u,float(getattr(self,u))) + setattr(self,u,parse_float(getattr(self,u))) elif u in set_options: if type( getattr(self,u) ) is not set: setattr(self,u,self._parse_set_string(getattr(self,u),set())) diff --git a/tests/sarracenia/config_test.py b/tests/sarracenia/config_test.py index b368dfbb8..085bb143d 100644 --- a/tests/sarracenia/config_test.py +++ b/tests/sarracenia/config_test.py @@ -154,6 +154,22 @@ def test_read_line_counts(): options.parse_line( "subscribe", "ex1", "subscribe/ex1", 1, "batch 1.9" ) assert( options.batch == 1 ) +def test_read_line_floats(): + + options = sarracenia.config.default_config() + + options.parse_line( "subscribe", "ex1", "subscribe/ex1", 1, "messageRateMax 1.5mb" ) + assert( options.messageRateMax == 1572864 ) + + options.parse_line( "subscribe", "ex1", "subscribe/ex1", 1, "messageRateMax 0.5k" ) + assert( options.messageRateMax == 500 ) + + options.parse_line( "subscribe", "ex1", "subscribe/ex1", 1, "messageRateMax 0.5kb" ) + assert( options.messageRateMax == 512 ) + + options.parse_line( "subscribe", "ex1", "subscribe/ex1", 1, "messageRateMax 0.5b" ) + assert( options.messageRateMax == 0.5 ) + def test_read_line_sets():