#!/usr/bin/env python # coding=utf-8 __author__ = "TrackMe Limited" __copyright__ = "Copyright 2022-2026, TrackMe Limited, U.K." __credits__ = "TrackMe Limited, U.K." __license__ = "TrackMe Limited, all rights reserved" __version__ = "0.1.0" __maintainer__ = "TrackMe Limited, U.K." __email__ = "support@trackme-solutions.com" __status__ = "PRODUCTION" import os import sys import json import hashlib from collections import OrderedDict import time import logging from logging.handlers import RotatingFileHandler import urllib.parse import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # splunk home splunkhome = os.environ["SPLUNK_HOME"] # append lib sys.path.append(os.path.join(splunkhome, "etc", "apps", "trackme", "lib")) # import TrackMe libs from trackme_libs import JSONFormatter # import trackme libs utils from trackme_libs_utils import remove_leading_spaces # logging: # To avoid overriding logging destination of callers, the libs will not set on purpose any logging definition # and rely on callers themselves def trackme_ingest_version(index, source, sourcetype, event): try: # Create a dedicated logger for version events version_logger = logging.getLogger("trackme.wlk.version") version_logger.setLevel(logging.INFO) # Only add the handler if it doesn't exist yet if not version_logger.handlers: # Set up the file handler filehandler = RotatingFileHandler( f"{splunkhome}/var/log/splunk/trackme_wlk_version.log", mode="a", maxBytes=100000000, backupCount=1, ) formatter = JSONFormatter() logging.Formatter.converter = time.gmtime filehandler.setFormatter(formatter) version_logger.addHandler(filehandler) # Prevent propagation to root logger version_logger.propagate = False else: # Find the RotatingFileHandler among existing handlers filehandler = None for handler in version_logger.handlers: if isinstance(handler, RotatingFileHandler): filehandler = handler break # If no RotatingFileHandler found, create one if filehandler is None: filehandler = RotatingFileHandler( f"{splunkhome}/var/log/splunk/trackme_wlk_version.log", mode="a", maxBytes=100000000, backupCount=1, ) formatter = JSONFormatter() logging.Formatter.converter = time.gmtime filehandler.setFormatter(formatter) version_logger.addHandler(filehandler) version_logger.info( "TrackMe State Events", extra={ "target_index": index, "target_sourcetype": sourcetype, "target_source": source, "event": event, }, ) except Exception as e: raise Exception(str(e)) def trackme_wlk_gen_metrics( tenant_id, overgroup, group, app, user, account, savedsearch_name, object_value, object_id, version_id, metric_index, metrics_event, ): try: # Create a dedicated logger for WLK metrics wlk_logger = logging.getLogger("trackme.wlk.metrics") wlk_logger.setLevel(logging.INFO) # Only add the handler if it doesn't exist yet if not wlk_logger.handlers: # Set up the file handler filehandler = RotatingFileHandler( f"{splunkhome}/var/log/splunk/trackme_wlk_metrics.log", mode="a", maxBytes=100000000, backupCount=1, ) formatter = JSONFormatter() filehandler.setFormatter(formatter) wlk_logger.addHandler(filehandler) # Prevent propagation to root logger wlk_logger.propagate = False else: # Find the RotatingFileHandler among existing handlers filehandler = None for handler in wlk_logger.handlers: if isinstance(handler, RotatingFileHandler): filehandler = handler break # If no RotatingFileHandler found, create one if filehandler is None: filehandler = RotatingFileHandler( f"{splunkhome}/var/log/splunk/trackme_wlk_metrics.log", mode="a", maxBytes=100000000, backupCount=1, ) formatter = JSONFormatter() filehandler.setFormatter(formatter) wlk_logger.addHandler(filehandler) wlk_logger.info( "Metrics - group=wlk_metrics", extra={ "target_index": metric_index, "tenant_id": tenant_id, "overgroup": overgroup, "group": group, "app": app, "user": user, "account": account, "savedsearch_name": savedsearch_name, "object": object_value, "object_id": object_id, "object_category": "splk-wlk", "version_id": version_id, "metrics_event": json.dumps(metrics_event), }, ) except Exception as e: raise Exception(str(e)) # return main searches logics for that entity def splk_wlk_return_searches(tenant_id, entity_info): # log debug logging.debug( f'Starting function=splk_wlk_return_searches with entity_info="{json.dumps(entity_info, indent=2)}"' ) # define required searches dynamically based on the upstream entity information splk_wlk_mctalog_search = None splk_wlk_metrics_report = None splk_wlk_mpreview = None splk_wlk_metrics_populate_search = None splk_wlk_scheduler_skipping_search = None splk_wlk_scheduler_errors_search = None splk_wlk_scheduler_skipping_search_sample = None splk_wlk_scheduler_errors_search_sample = None splk_wlk_check_orphan = None splk_wlk_get_metadata = None # get the object_id object_id = hashlib.sha256(entity_info["object"].encode("utf-8")).hexdigest() object_name = entity_info["object"] try: ######## # mstats ######## # mcatalog splk_wlk_mctalog_search = f"| mcatalog values(metric_name) as metrics, values(_dims) as dims where `trackme_metrics_idx({tenant_id})` tenant_id=\"{tenant_id}\" object_category=\"splk-wlk\" object_id=\"{entity_info['object_id']}\" metric_name=* by index" # metrics report splk_wlk_metrics_report = remove_leading_spaces( f"""\ | mstats latest(_value) as latest_value, avg(_value) as avg_value, max(_value) as max_value, perc95(_value) as perc95_value, stdev(_value) as stdev_value where `trackme_metrics_idx({tenant_id})` metric_name=* tenant_id=\"{tenant_id}\" object_category=\"splk-wlk\" object_id=\"{entity_info['object_id']}\" by index, object, object_id, metric_name | foreach *_value [ eval <> = if(match(metric_name, \".status\"), round('<>', 0), round('<>', 3)) ] """ ) # mpreview splk_wlk_mpreview = f"| mpreview `trackme_metrics_idx({tenant_id})` filter=\"tenant_id={tenant_id} object_category=\"splk-wlk\" object_id=\\\"{entity_info['object_id']}\\\"\"" # metrics popuating search splk_wlk_metrics_populate_search = remove_leading_spaces( f""" | mcatalog values(metric_name) as metrics where `trackme_metrics_idx({tenant_id})` tenant_id="{tenant_id}" object_category="splk-wlk" object_id="{entity_info["object_id"]}" metric_name=* | mvexpand metrics | rename metrics as metric_name | rex field=metric_name "^trackme\\.splk.wlk\\.(?