From 13258ae201be1d47ad9a72993b538079d2f8ac44 Mon Sep 17 00:00:00 2001 From: mellis Date: Wed, 17 Jan 2024 15:15:55 +0100 Subject: [PATCH] added debug decorator function and type hints --- .../check_mk/agents/special/agent_mailcow | 102 +++++++++++++++--- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/local/share/check_mk/agents/special/agent_mailcow b/local/share/check_mk/agents/special/agent_mailcow index 7738a27..b34f409 100755 --- a/local/share/check_mk/agents/special/agent_mailcow +++ b/local/share/check_mk/agents/special/agent_mailcow @@ -9,8 +9,11 @@ import os from pprint import pprint from requests.structures import CaseInsensitiveDict from requests.auth import HTTPBasicAuth +from time import ( + time, localtime, strftime, +) -def showUsage(): +def showUsage() -> None: sys.stderr.write("""CheckMK Mailcow Special Agent USAGE: agent_nextcloud -H [hostname] -k [apikey] @@ -47,8 +50,73 @@ long_options = [ domain_data = {} mailbox_data = {} +debugLogFilename = "" +SEP = "|" +#SEP = "\t" +TIMEFMT = "%Y-%m-%d %H:%M:%S" +FLOATFMT = "{:.4f}" -def getOptions(): +''' +Decorator function for debugging purposes + creates a file with many information regarding the function call, like: + timestamp + name of function + runtime + number of arguments + number of keyword arguments + return value of function call + type of return value + all parameters given to function +''' +def debugLog(function): + def wrapper(*args, **kwargs): + # execute function and measure runtime + start = time() + value = function(*args, **kwargs) + end = time() + # get number of args and kwargs + len_args = len(args) + len_kwargs = len(kwargs) + # format the output + seconds = FLOATFMT.format(end - start) + local_time = strftime(TIMEFMT,localtime(start)) + # get function name + fname = function.__name__ + # create output + # out1: Timestamp|Name of Function|Runtime|Num Args|Num Kwargs|Return Value|Return Value Type + out1 = f"{local_time}{SEP}{fname}{SEP}{seconds}{SEP}{len_args}{SEP}{len_kwargs}{SEP}{value}{SEP}{type(value)}" + # out2: all arguments + out2 = "" + for arg in args: + out2 = out2 + SEP + str(arg) + # out 3: all keyword arguments + out3 = "" + if len_kwargs > 0: + for key, val in kwargs.items(): + out3 = out3 + SEP + key + ":" + str(val) + # write output to file + if debugLogFilename != "": + try: + with open(debugLogFilename, "a+") as f: + f.write(f"{out1}{out2}{out3}\n") + except: + sys.stderr.write(f"Something went wrong when writing to file {debugLogFilename}\n") + sys.exit(1) + else: + sys.stderr.write(f"Debug activated, but no debug filename given.\n") + sys.exit(1) + return value + return wrapper + + +def getDebugFilename(hostname: str) -> str: + home_path = os.getenv("HOME") + tmp_path = f"{home_path}/tmp" + file_name = f"{tmp_path}/mailcow_{hostname}_debug.log" + return file_name + + +def getOptions() -> None: global opt_hostname global opt_apikey global opt_port @@ -84,7 +152,8 @@ def getOptions(): file.write(f"Number of Arguments: {len(sys.argv)}, Argument List: {str(sys.argv)}\n") -def showOptions(): +#@debugLog +def showOptions() -> None: print(f"Hostname: {opt_hostname}") print(f"Username: {opt_apikey}") print(f"Port: {opt_port}") @@ -96,8 +165,8 @@ def showOptions(): with open(help_file, "a") as file: file.write(f"Hostname: {opt_hostname}, Port: {opt_port}, No HTTPS: {opt_no_https}, No Cert Check: {opt_no_cert_check}\n") - -def getDomainInfo(headers, verify, base_url): +#@debugLog +def getDomainInfo(headers: str, verify: bool, base_url: str) -> int: url = f"{base_url}/domain/all" response = requests.get(url, headers=headers, verify=verify) if (response.status_code == 200): @@ -146,8 +215,8 @@ def getDomainInfo(headers, verify, base_url): sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n") sys.exit(1) - -def getMailboxInfo(headers, verify, base_url): +#@debugLog +def getMailboxInfo(headers: str, verify: bool, base_url: str) -> tuple: url = f"{base_url}/mailbox/all" response = requests.get(url, headers=headers, verify=verify) if (response.status_code == 200): @@ -202,8 +271,8 @@ def getMailboxInfo(headers, verify, base_url): sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n") sys.exit(1) - -def getMailcowInfo(headers, verify, base_url): +#@debugLog +def getMailcowInfo(headers: str, verify: bool, base_url: str) -> str: url = f"{base_url}/status/version" response = requests.get(url, headers=headers, verify=verify) if (response.status_code == 200): @@ -217,7 +286,8 @@ def getMailcowInfo(headers, verify, base_url): sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n") sys.exit(1) -def getSolrInfo(headers, verify, base_url): +#@debugLog +def getSolrInfo(headers: str, verify: bool, base_url: str) -> tuple: url = f"{base_url}/status/solr" response = requests.get(url, headers=headers, verify=verify) if (response.status_code == 200): @@ -255,7 +325,8 @@ user2@dom1.de;1;2022-04-29 14:38:33;2022-04-29 14:38:33;Tom;271;0;21474836480;25 user1@dom2.de;1;2022-04-30 09:55:37;2022-04-30 09:55:37;Melissa;53460;33;19964887040;6677677548;1692520066;0;1692510822 ''' -def doCmkOutputMailboxes(): +#@debugLog +def doCmkOutputMailboxes() -> None: print("<<>>") for mb in mailbox_data: active = mailbox_data[mb]["active"] @@ -273,8 +344,8 @@ def doCmkOutputMailboxes(): last_smtp_login = mailbox_data[mb]["last_smtp_login"] print(f"{mb};{active};{created};{modified};{name};{num_messages};{percent_in_use};{quota};{quota_used};{last_imap_login};{last_pop3_login};{last_smtp_login}") - -def doCmkOutputMailcow(version, num_domains, num_mailboxes, num_global_messages, solr_enabled, solr_size, solr_documents): +#@debugLog +def doCmkOutputMailcow(version: str, num_domains: int, num_mailboxes: int, num_global_messages: int, solr_enabled: bool, solr_size: float, solr_documents: int) -> None: print("<<>>") # strip semicolons, if present, since we use it as delimiter version = version.replace(";", "") @@ -301,7 +372,8 @@ dom2.de;1;2022-04-29 13:38:42;2023-08-19 17:21:04;10;0;400;2;0;0;10737418240 dom3.de;1;2022-04-29 13:36:08;2022-04-29 21:26:19;10;1;100;3;28132;12852485367;21474836480 ''' -def doCmkOutputDomains(): +#@debugLog +def doCmkOutputDomains() -> None: print("<<>>") for dom in domain_data: active = domain_data[dom]["active"] @@ -318,6 +390,7 @@ def doCmkOutputDomains(): def main(): + global debugLogFilename getOptions() # do some parameter checks if (opt_hostname == ""): @@ -363,6 +436,7 @@ def main(): # now "port" contains the port number to use # now "verify" signals whether certificate checking will be done (True) or not (False) # now "headers" contains the accepted format (JSON) and the API key to use + debugLogFilename = getDebugFilename(hostname) if DEBUG: showOptions() print(f"hostname: {hostname}, protocol: {protocol}, port: {port}, verify: {verify}")