def create_config_matcher(self, conf): """ Create a function that will return a log configuration when passed in data that matches that config. Intended to be overwritten by users of LogConfigManager to match their own use case. If passed an empty dictionary in `conf` this should create a catchall matcher with default configuration. @param conf: Logger configuration in the form of a dictionary or JsonObject, that a matcher should be created for. @return: Logger configuration in the form of a dictionary or JsonObject if this matcher matches the passed in data, None otherwise """ config = copy.deepcopy(conf) if "journald_unit" not in config: config["journald_unit"] = ".*" file_template = Template("journald_${ID}.log") regex = re.compile(config["journald_unit"]) match_hash = six.text_type(hash(config["journald_unit"])) if config["journald_unit"] == ".*": match_hash = "monitor" full_path = os.path.join( self._global_config.agent_log_path, file_template.safe_substitute({"ID": match_hash}), ) matched_config = JsonObject({"parser": "journald", "path": full_path}) matched_config.update(config) def config_matcher(unit): if regex.match(unit) is not None: return matched_config return None return config_matcher
def create_config_matcher(self, conf): """Create a function that will return a log configuration when passed in data that matches that config. Intended to be overwritten by users of LogConfigManager to match their own use case. If passed an empty dictionary in `conf` this should create a catchall matcher with default configuration. @param conf: Logger configuration in the form of a dictionary or JsonObject, that a matcher should be created for. @return: Logger configuration in the form of a dictionary or JsonObject if this matcher matches the passed in data, None otherwise """ config = copy.deepcopy(conf) journald_unit = config.get("journald_unit", None, none_if_missing=True) journald_globs = config.get("journald_globs", None, none_if_missing=True) # User shouldn't be able to specify both `journald_unit` and # `journald_globs` if journald_unit is not None and journald_globs is not None: raise BadConfiguration( "Cannot specify both journald_unit and journald_globs", "journald_unit", "invalidConfigError", ) # If neither is specified, default to journald_unit matching # everything if journald_unit is None and journald_globs is None: journald_unit = ".*" config["journald_unit"] = journald_unit match_hash = "monitor" regex = None if journald_unit is not None: match_hash = six.text_type(hash(journald_unit)) if journald_unit == ".*": match_hash = "monitor" regex = re.compile(journald_unit) elif journald_globs is not None: items = sorted(six.iteritems(journald_globs), key=operator.itemgetter(0)) match_hash = six.text_type(hash("%s" % items)) file_template = Template("journald_${ID}.log") full_path = os.path.join( self._global_config.agent_log_path, file_template.safe_substitute({"ID": match_hash}), ) matched_config = JsonObject({"parser": "journald", "path": full_path}) matched_config.update(config) def regex_matcher(fields): if regex is None: return None # Special case where we bail out early if regex is .* aka match all if journald_unit == ".*": return matched_config unit = None if isinstance(fields, six.string_types): unit = fields else: # regex only matches on unit unit = fields.get("unit", "") if unit is not None: if regex.match(unit) is not None: return matched_config return None def glob_matcher(fields): if journald_globs is None: return None # journald_globs requires all fields # to match for key, glob in six.iteritems(journald_globs): if key not in fields: return None if not fnmatch.fnmatch(fields[key], glob): return None return matched_config if journald_globs is not None: return glob_matcher return regex_matcher