diff --git a/cctv-scheduler.py b/cctv-scheduler.py index d19f22d..12665d9 100644 --- a/cctv-scheduler.py +++ b/cctv-scheduler.py @@ -7,6 +7,7 @@ import calendar import base64 import datetime +import inspect import json import logging from random import choice @@ -204,7 +205,7 @@ class Proc: ], stdout=PIPE, stderr=PIPE - ).communicate() + ).communicate() for line in out.split(separate + separate): execpid, exename, exepath, cmdline = None, None, None, None for subline in line.split(separate): @@ -224,7 +225,7 @@ class Proc: 'exepath': exepath, 'cmdline': cmdline } - ) + ) return execlist @classmethod @@ -242,7 +243,7 @@ class Proc: ], stdout=PIPE, stderr=PIPE - ).communicate() + ).communicate() for line in out.splitlines(): execpid = line.split()[0].decode('utf-8') exepath = line.split()[1].decode('utf-8') @@ -256,7 +257,7 @@ class Proc: 'exepath': exepath, 'cmdline': cmdline } - ) + ) return execlist @classmethod @@ -275,16 +276,23 @@ class Proc: @classmethod # pylint: disable=W0150 - def search(cls, find: str, exclude: str = None) -> list: + def search( + cls, + find: str, + exclude: str = None, + logger_alias: str = inspect.stack()[0].function + ) -> list: """Find specified processes. Args: find (str): find process pid, name or arguments. exclude (str, optional): exclude process pid, name or arguments. Defaults to None. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: list: dictionaries with descriptions of found processes. """ + local_logger = logging.getLogger(logger_alias) proc_found = [] try: for proc in cls.list_all(): @@ -293,17 +301,17 @@ class Proc: exclude in proc['exename'] or exclude in proc['exepath'] or exclude in proc['cmdline'] - ): + ): pass elif ( find in proc['execpid'] or find in proc['exename'] or find in proc['exepath'] or find in proc['cmdline'] - ): + ): proc_found.append(proc) - except TypeError as ex: - print('ON', platform, 'PLATFORM', 'search ERROR:', ex) + except TypeError as error: + local_logger.warning(msg='ON ' + platform + ' PLATFORM search ERROR: ' + error) finally: if len(proc_found) == 0: return None @@ -337,7 +345,8 @@ class FFmpeg: ffpath: str = None, watchdog: bool = False, watchsec: int = None, - onlyonce: bool = False + onlyonce: bool = False, + logger_alias: str = inspect.stack()[0].function ) -> int: """Running the installed ffmpeg. @@ -352,10 +361,12 @@ class FFmpeg: watchdog (bool, optional): detect ffmpeg freeze and terminate. Defaults to False. watchsec (int, optional): seconds to wait before watchdog terminates. Defaults to None. onlyonce (bool, optional): detect ffmpeg running copy and terminate. Defaults to False. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: int: ffmpeg return code """ + local_logger = logging.getLogger(logger_alias) if not raw: process = ([] + cls._bin(ffpath).split() @@ -367,10 +378,10 @@ class FFmpeg: process = cls._bin(ffpath).split() + raw.split() if onlyonce and Proc.search(' '.join(process)): - logging.info(msg='ffmpeg process already exist') + local_logger.info(msg='ffmpeg process already exist') return 0 else: - logging.info(msg='Starting ' + ' '.join(process)) + local_logger.info(msg='Starting ' + ' '.join(process)) with Popen(process, stdout=PIPE, stderr=STDOUT) as proc: que = None if watchdog: @@ -382,22 +393,29 @@ class FFmpeg: ).start() for line in proc.stdout: if not que: - logging.debug(msg=line) + local_logger.debug(msg=line) else: que.put(line) return proc.returncode @classmethod - def _bin(cls, ffpath: str, tool: str = 'ffmpeg') -> str: + def _bin( + cls, + ffpath: str, + tool: str = 'ffmpeg', + logger_alias: str = inspect.stack()[0].function + ) -> str: """Returns the path to the bin depending on the OS. Args: ffpath (str): custom path to bin. tool (str, optional): 'ffmpeg', 'ffprobe'. Defaults to 'ffmpeg'. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: str: path to bin or None, if path does not exist. """ + local_logger = logging.getLogger(logger_alias) faq = ( '\n' 'Main download page: https://ffmpeg.org/download.html\n' @@ -428,7 +446,7 @@ class FFmpeg: if path.exists(ffpath): return ffpath else: - print('ON', platform, 'PLATFORM', 'not found', tool, faq) + local_logger.warning(msg='ON ' + platform + ' PLATFORM not found ' + tool + faq) return None @classmethod @@ -490,13 +508,13 @@ class FFmpeg: str(width), ':', str(height), ',setsar=1:1' ] - ) + ) video = ' '.join( [ video, '-c:v libx264 -pix_fmt yuv420p -preset ultrafast' ] - ) + ) if fps: video = ' '.join([video, '-r', str(fps), '-g', str(fps * 2)]) video = ' '.join([video, '-b:v', str(kbps) + 'k']) @@ -524,24 +542,32 @@ class FFmpeg: return ' '.join([container, destination, stdout]) @classmethod - def _watchdog(cls, pid: int, sec: int, que: Queue = None) -> None: + def _watchdog( + cls, + pid: int, + sec: int, + que: Queue = None, + logger_alias: str = inspect.stack()[0].function + ) -> None: """If no data arrives in the queue, kill the process. Args: pid (int): process ID. sec (int): seconds to wait for data. que (Queue, optional): queue pointer. Defaults to None. + logger_alias (str, optional): sublogger name. Defaults to function or method name. """ + local_logger = logging.getLogger(logger_alias) if not sec: sec = 5 if que: while True: while not que.empty(): - print(que.get()) + local_logger.debug(msg=que.get()) sleep(sec) if que.empty(): Proc.kill(pid) - print('exit by watchdog') + local_logger.debug(msg='exit by watchdog') break exit() @@ -595,7 +621,8 @@ class Connect: authtype: (str, type(None)) = None, contenttype: str = 'text/plain', contentdata: (str, bytes) = '', - headers: dict = {} + headers: dict = {}, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Handling HTTP request. @@ -608,10 +635,12 @@ class Connect: contenttype (str, optional): 'Content-Type' header. Defaults to 'text/plain'. contentdata (str, bytes, optional): content data. Defaults to ''. headers (dict, optional): additional headers. Defaults to {}. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'success':bool,'result':HTTP response or 'ERROR'}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), Connect.http.__annotations__): if contentdata != '': headers['Content-Type'] = contenttype @@ -635,29 +664,29 @@ class Connect: url=url, data=contentdata, method=method - ) + ) for key, val in headers.items(): request.add_header(key, val) if len(contentdata) > 128: contentdata = contentdata[:64] + b' ... ' + contentdata[-64:] - logging.debug(msg='' - + '\n' + 'uri: ' + url - + '\n' + 'method: ' + method - + '\n' + 'username: ' + username - + '\n' + 'password: ' + password - + '\n' + 'authtype: ' + str(authtype) - + '\n' + 'headers: ' + json.dumps(headers, indent=2) - + '\n' + 'content-data: ' + str(contentdata) - ) # Response + local_logger.debug(msg='' + + '\n' + 'uri: ' + url + + '\n' + 'method: ' + method + + '\n' + 'username: ' + username + + '\n' + 'password: ' + password + + '\n' + 'authtype: ' + str(authtype) + + '\n' + 'headers: ' + json.dumps(headers, indent=2) + + '\n' + 'content-data: ' + str(contentdata) + ) try: response = urllib.request.urlopen(request).read() if not response.startswith(b'\xff\xd8'): response = str(response.decode('utf-8')) return {"success": True, "result": response} except Exception as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) return {"success": False, "result": "ERROR"} @staticmethod @@ -667,7 +696,8 @@ class Connect: hostname: str, username: str, password: str, - port: int = 22 + port: int = 22, + logger_alias: str = inspect.stack()[0].function ) -> str: """Handling SSH command executing. @@ -677,12 +707,20 @@ class Connect: username (str): remote host username. password (str): remote host password. port (int, optional): remote host connection port. Defaults to 22. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: str: terminal response or 'ERROR'. """ + local_logger = logging.getLogger(logger_alias) client = SSHClient() client.set_missing_host_key_policy(AutoAddPolicy()) + local_logger.debug(msg='' + + '\n' + 'host: ' + hostname + ':' + str(port) + + '\n' + 'user: ' + username + + '\n' + 'pass: ' + password + + '\n' + 'command: ' + command + ) try: client.connect(hostname=hostname, username=username, password=password, port=port) stdin, stdout, stderr = client.exec_command(command=command, get_pty=True) @@ -694,14 +732,7 @@ class Connect: client.close() return data.decode('utf-8') except Exception as error: - logging.debug( - msg='' - + '\n' + 'host: ' + hostname + ':' + str(port) - + '\n' + 'user: ' + username - + '\n' + 'pass: ' + password - + '\n' + 'command: ' + command - + '\n' + 'error: ' + str(error) - ) + local_logger.debug(msg='error: ' + '\n' + str(error)) return 'ERROR' @staticmethod @@ -712,7 +743,8 @@ class Connect: hostname: str, username: str, password: str, - port: int = 22 + port: int = 22, + logger_alias: str = inspect.stack()[0].function ) -> str: """Handling SFTP upload file. @@ -723,12 +755,21 @@ class Connect: username (str): remote host username. password (str): remote host password. port (int, optional): remote host connection port. Defaults to 22. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: str: '/remote/path/to/file' or 'ERROR'. """ + local_logger = logging.getLogger(logger_alias) client = SSHClient() client.set_missing_host_key_policy(AutoAddPolicy()) + local_logger.debug(msg='' + + '\n' + 'src_file: ' + src_file + + '\n' + 'dst_file: ' + dst_file + + '\n' + 'host: ' + hostname + ':' + str(port) + + '\n' + 'user: ' + username + + '\n' + 'pass: ' + password + ) try: client.connect(hostname=hostname, username=username, password=password, port=port) client.exec_command('mkdir -p ' + path.dirname(dst_file)) @@ -737,60 +778,14 @@ class Connect: sftp.put(localpath=src_file, remotepath=dst_file) sftp.stat(dst_file) sftp.close() + local_logger.info(msg=dst_file + ' saved') return dst_file except Exception as error: - logging.debug( - msg='' - + '\n' + 'dst_file: ' + dst_file - + '\n' + 'error: ' + str(error) - ) + local_logger.debug(msg='error: ' + '\n' + str(error)) return 'ERROR' except Exception as error: - logging.debug( - msg='' - + '\n' + 'host: ' + hostname + ':' + str(port) - + '\n' + 'user: ' + username - + '\n' + 'pass: ' + password - + '\n' + 'src_file: ' + src_file - + '\n' + 'dst_file: ' + dst_file - + '\n' + 'error: ' + str(error) - ) + local_logger.debug(msg='error: ' + '\n' + str(error)) return 'ERROR' - ''' - @staticmethod - def ssh_get_file(src_file: str, dst_file: str, hostname: str, username: str, password: str, port: int = 22) -> str: - """Handling SFTP download file. - - Args: - src_file (str): /remote/path/to/file. - dst_file (str): /local/path/to/file. - hostname (str): remote hostname or ip address. - username (str): remote host username. - password (str): remote host password. - port (int, optional): remote host connection port. Defaults to 22. - - Returns: - str: '/local/path/to/file' or 'ERROR'. - """ - client = SSHClient() - client.set_missing_host_key_policy(AutoAddPolicy()) - try: - client.connect(hostname=hostname, username=username, password=password, port=port) - with client.open_sftp() as sftp: - sftp.get(remotepath=src_file, localpath=dst_file) - client.close() - except Exception as error: - logging.debug( - msg='' - + '\n' + 'host: ' + hostname + ':' + str(port) - + '\n' + 'user: ' + username - + '\n' + 'pass: ' + password - + '\n' + 'src_file: ' + src_file - + '\n' + 'dst_file: ' + dst_file - + '\n' + 'error: ' + str(error) - ) - return 'ERROR' - ''' @staticmethod # pylint: disable=W0718 @@ -800,7 +795,8 @@ class Connect: ftp: FTP = None, hostname: str = None, username: str = None, - password: str = None + password: str = None, + logger_alias: str = inspect.stack()[0].function ) -> list: """Search files over FTP. @@ -816,14 +812,23 @@ class Connect: Returns: list: list of found files. """ + local_logger = logging.getLogger(logger_alias) + local_logger.debug(msg='' + + '\n' + 'root_path: ' + root_path + + '\n' + 'search_name: ' + str(search_name) + + '\n' + 'ftp: ' + str(ftp) + + '\n' + 'hostname: ' + hostname + + '\n' + 'username: ' + username + + '\n' + 'password: ' + password + ) parent = False if not ftp: try: ftp = FTP(host=hostname) ftp.login(user=username, passwd=password) parent = True - except Exception: - pass + except Exception as error: + local_logger.debug(msg='error: ' + '\n' + str(error)) result = [] ftp.cwd(root_path) @@ -848,16 +853,45 @@ class Connect: @staticmethod # pylint: disable=W0718,C0116 - def ftp_get_file(src_file: str, dst_file: str, hostname: str, username: str, password: str): + def ftp_get_file( + src_file: str, + dst_file: str, + hostname: str, + username: str, + password: str, + logger_alias: str = inspect.stack()[0].function + ) -> bool: + """Download file from FTP. + + Args: + src_file (str): /remote/path/to/file. + dst_file (str): /local/path/to/file. + hostname (str): ftp hostname. + username (str): ftp username. + password (str): ftp password. + logger_alias (str, optional): sublogger name. Defaults to function or method name. + + Returns: + bool: True if successed. + """ + local_logger = logging.getLogger(logger_alias) ftp = FTP(host=hostname) + local_logger.debug(msg='' + + '\n' + 'src_file: ' + src_file + + '\n' + 'dst_file: ' + dst_file + + '\n' + 'hostname: ' + hostname + + '\n' + 'username: ' + username + + '\n' + 'password: ' + password + ) try: ftp.login(user=username, passwd=password) with open(dst_file, "wb+") as file: ftp.retrbinary(f"RETR {src_file}", file.write) ftp.quit() + local_logger.info(msg=dst_file + ' saved') return True except Exception as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) return False @staticmethod @@ -867,10 +901,32 @@ class Connect: dst_file: str, hostname: str, username: str, - password: str + password: str, + logger_alias: str = inspect.stack()[0].function ) -> bool: + """Upload file to FTP. + + Args: + src_file (str): /local/path/to/file. + dst_file (str): /remote/path/to/file. + hostname (str): ftp hostname. + username (str): ftp username. + password (str): ftp password. + logger_alias (str, optional): sublogger name. Defaults to function or method name. + + Returns: + bool: True if successed. + """ + local_logger = logging.getLogger(logger_alias) dst_path = dst_file.split('/')[:-1] ftp = FTP(host=hostname) + local_logger.debug(msg='' + + '\n' + 'src_file: ' + src_file + + '\n' + 'dst_file: ' + dst_file + + '\n' + 'hostname: ' + hostname + + '\n' + 'username: ' + username + + '\n' + 'password: ' + password + ) try: ftp.login(user=username, passwd=password) for path_item in dst_path: @@ -885,9 +941,10 @@ class Connect: with open(src_file, "rb") as file: ftp.storbinary(f"STOR {dst_file}", file) ftp.quit() + local_logger.info(msg=dst_file + ' saved') return True except Exception as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) return False @@ -952,19 +1009,23 @@ class HikISAPI(Connect): else: return 'ERROR' - def capabilities(self) -> bool: + def capabilities(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Get camera capabilities. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. Printing a response with a logger at the INFO level. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._viid) + "/capabilities" ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.info(msg='\n' + response + '\n') + local_logger.info(msg='\n' + response + '\n') return True else: return False @@ -973,7 +1034,8 @@ class HikISAPI(Connect): self, dst_file: str = path.splitext(__file__)[0] + '.jpeg', x: int = 1920, - y: int = 1080 + y: int = 1080, + logger_alias: str = inspect.stack()[0].function ) -> bool: """Get static picture from camera. @@ -981,10 +1043,12 @@ class HikISAPI(Connect): dst_file (str, optional): abs picture's path to save. Defaults to scriptname+'.jpeg'. x (int, optional): picture width. Defaults to 1920. y (int, optional): picture height. Defaults to 1080. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/Streaming/channels/" + str(self._viid) @@ -995,54 +1059,64 @@ class HikISAPI(Connect): response = self.__call(url=url, method='GET') if response != 'ERROR': file.write(response) - logging.debug(msg='\n' + dst_file + '\n') + local_logger.info(msg=dst_file + ' saved') return True else: return False - def getcamerapos(self) -> bool: + def getcamerapos(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Get current camera position. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. Printing a response with a logger at the INFO level. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) + "/status" ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.info(msg='\n' + response + '\n') + local_logger.info(msg='\n' + response + '\n') return True else: return False - def rebootcamera(self) -> bool: + def rebootcamera(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Set camera reboot command. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/System/reboot" ) response = self.__call(url=url, method="PUT") if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovyyu(self, speed: int = 1) -> bool: + def setptzmovyyu(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera moving to up. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1051,20 +1125,22 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovyyd(self, speed: int = 1) -> bool: + def setptzmovyyd(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera moving to down. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1073,20 +1149,22 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovxxl(self, speed: int = 1) -> bool: + def setptzmovxxl(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera moving to left. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1095,20 +1173,22 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovxxr(self, speed: int = 1) -> bool: + def setptzmovxxr(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera moving to right. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1117,20 +1197,22 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovzzi(self, speed: int = 1) -> bool: + def setptzmovzzi(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera zoom in. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1139,20 +1221,22 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzmovzzo(self, speed: int = 1) -> bool: + def setptzmovzzo(self, speed: int = 1, logger_alias: str = inspect.stack()[0].function) -> bool: """Start camera zoom out. Args: speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1161,21 +1245,28 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptzpreset(self, preset: int, speed: int = 1) -> bool: + def setptzpreset( + self, + preset: int, + speed: int = 1, + logger_alias: str = inspect.stack()[0].function + ) -> bool: """Start camera moving to preset. Args: preset (int): saved preset number. speed (int, optional): moving speed from 1 to 7. Defaults to 1. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1185,17 +1276,21 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setptztostop(self) -> bool: + def setptztostop(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Stop any camera moving. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/PTZ/channels/" + str(self._viid) @@ -1203,22 +1298,30 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method='GET') if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setcamerapos(self, x: int = 0, y: int = 0, z: int = 0) -> bool: + def setcamerapos( + self, + x: int = 0, + y: int = 0, + z: int = 0, + logger_alias: str = inspect.stack()[0].function + ) -> bool: """Set camera moving to absolute position. Args: x (int, optional): horisontal camera position from 0 to 3600. Defaults to 0. y (int, optional): vertical camera position from -900 to 2700. Defaults to 0. z (int, optional): zoom camera position from 0 to 1000. Defaults to 0. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) @@ -1234,12 +1337,18 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def __setcameramovcon(self, x: int = 0, y: int = 0, z: int = 0) -> bool: + def __setcameramovcon( + self, + x: int = 0, + y: int = 0, + z: int = 0, + logger_alias: str = inspect.stack()[0].function + ) -> bool: """Set camera moving to direction until other signal or 180 seconds elapse. Args: @@ -1249,10 +1358,13 @@ class HikISAPI(Connect): Defaults to 0. z (int, optional): acceleration of zoom camera movement from -100 to 100. Defaults to 0. + logger_alias (str, optional): sublogger name. + Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) @@ -1268,12 +1380,19 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def __setcameramovmom(self, x: int = 0, y: int = 0, z: int = 0, t: int = 180000) -> bool: + def __setcameramovmom( + self, + x: int = 0, + y: int = 0, + z: int = 0, + t: int = 180000, + logger_alias: str = inspect.stack()[0].function + ) -> bool: """Set camera moving to direction until other signal or duration elapse. Args: @@ -1285,10 +1404,13 @@ class HikISAPI(Connect): Defaults to 0. t (int, optional): duration in ms of acceleration from 0 to 180000. Defaults to 180000. + logger_alias (str, optional): sublogger name. + Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) @@ -1306,7 +1428,7 @@ class HikISAPI(Connect): response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': sleep(t/1000) - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False @@ -1332,12 +1454,16 @@ class HikISAPI(Connect): else: return self.__setcameramovmom(x=int(x), y=int(y), z=int(z), t=int(t)) - def setmovtohome(self) -> bool: + def setmovtohome(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Set camera moving to homeposition. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) @@ -1349,17 +1475,21 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False - def setposashome(self) -> bool: + def setposashome(self, logger_alias: str = inspect.stack()[0].function) -> bool: """Save current camera position as homeposition. + Args: + logger_alias (str, optional): sublogger name. Defaults to function or method name. + Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) url = ( self._prot + '://' + self._host + ':' + str(self._port) + "/ISAPI/PTZCtrl/channels/" + str(self._chan) @@ -1371,7 +1501,7 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False @@ -1381,7 +1511,8 @@ class HikISAPI(Connect): enabled: str = "true", x: int = 0, y: int = 0, - message: str = "" + message: str = "", + logger_alias: str = inspect.stack()[0].function ) -> bool: """Set message as video overlay text. @@ -1390,10 +1521,12 @@ class HikISAPI(Connect): x (int, optional): horizontal text position from 0 to video width. Defaults to 0. y (int, optional): vertical text position from 0 to video heith. Defaults to 0. message (str, optional): overlay text content. Defaults to "". + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: bool: True if successed. """ + local_logger = logging.getLogger(logger_alias) if message == '-': message = "" url = ( @@ -1415,7 +1548,7 @@ class HikISAPI(Connect): ) response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml) if response != 'ERROR': - logging.debug(msg='\n' + response + '\n') + local_logger.debug(msg='\n' + response + '\n') return True else: return False @@ -1461,33 +1594,34 @@ class Sensor(Connect): command=command, hostname=self._host, port=self._port, username=self._user, password=self._pswd - ) + ) # pylint: disable=W0718 - def __temperature(self, nodename: str) -> str: + def __temperature(self, nodename: str, logger_alias: str = inspect.stack()[0].function) -> str: """Preparating request for ds18b20 sensor type. Args: nodename (str): 28-1a2b3c4d5e6f (ds18b20 example). + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: str: formatted string with temperature in Celsius. """ + local_logger = logging.getLogger(logger_alias) command = 'cat /sys/bus/w1/devices/' + nodename + '/temperature' response = self.__call(command=command) + local_logger.debug(msg='' + + '\n' + 'host: ' + self._host + ':' + str(self._port) + + '\n' + 'user: ' + self._user + + '\n' + 'pass: ' + self._pswd + + '\n' + 'command: ' + command + ) if response != 'ERROR': try: temperature = str(int(response)//1000) + "'C" return temperature except Exception as error: - logging.debug( - msg='' - + '\n' + 'host: ' + self._host + ':' + str(self._port) - + '\n' + 'user: ' + self._user - + '\n' + 'pass: ' + self._pswd - + '\n' + 'command: ' + command - + '\n' + 'error: ' + str(error) - ) + local_logger.debug(msg='error: ' + '\n' + str(error)) return 'ERROR' def value(self) -> str: @@ -1537,7 +1671,8 @@ class Wordpress(Connect): date_end: str, date_publish: str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"), all_day: bool = True, - description: str = None + description: str = None, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Create event by 'wp-json' and 'The Events Calendar'. @@ -1549,6 +1684,7 @@ class Wordpress(Connect): date_publish (_type_, optional): '2022-12-31T23:59:59' format. Defaults to now. all_day (bool, optional): all day event duration flag. Defaults to True. description (str, optional): event body. Defaults to None. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Raises: ValueError: date formate is not 2022-12-31T23:59:59. @@ -1557,6 +1693,7 @@ class Wordpress(Connect): Returns: dict: {'success':bool,'result':'http/url/to/event'}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.event_create.__annotations__): pattern = "^([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})+$" if ( @@ -1586,34 +1723,36 @@ class Wordpress(Connect): contenttype='application/json; charset=UTF-8', contentdata=json.dumps(event_json, indent=2) ) - logging.debug( - msg="" + local_logger.debug(msg="" + "\n" + "event API response: " + "\n" + json.dumps(json.loads(response['result']), indent=2) ) if response['success']: for key, val in json.loads(response['result']).items(): if key == "url": - logging.info('event created: %s', val) + local_logger.info('event created: %s', val) return {"success": True, "result": val} else: - logging.warning("event didn't create") + local_logger.warning("event didn't create") return {"success": False, "result": "ERROR"} def media_search( self, media_name: (str, type(None)) = None, - media_type: (str, type(None)) = None + media_type: (str, type(None)) = None, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Search uploaded media by 'wp-json'. Args: media_name (str, type, optional): results matching a string. Defaults to None. media_type (str, type, optional): application,image,video,audio,text. Defaults to None. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'success':bool,'result':['list/of/link/to/media']} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.media_search.__annotations__): url = self.api_media + '?per_page=100' if media_name: @@ -1628,8 +1767,7 @@ class Wordpress(Connect): media_list = [] response = self.http(url=url, method='GET') - logging.debug( - msg="" + local_logger.debug(msg="" + "\n" + "media API response: " + "\n" + json.dumps(json.loads(response['result']), indent=2) ) @@ -1638,14 +1776,15 @@ class Wordpress(Connect): media_list.append(media['guid']['rendered']) return {"success": True, "result": media_list} else: - logging.warning("media didn't list") + local_logger.warning("media didn't list") return {"success": False, "result": "ERROR"} def media_upload( self, mediafile: str, mediatype: str, - aliasfile: str = '' + aliasfile: str = '', + logger_alias: str = inspect.stack()[0].function ) -> dict: """Upload media by 'wp-json'. @@ -1653,6 +1792,7 @@ class Wordpress(Connect): mediafile (str, optional): path to file. mediatype (str, optional): 'image/jpeg', 'video/mp4', etc. aliasfile (str, optional): uploaded media name. Defaults to original file. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Raises: FileExistsError: mediafile is not exist. @@ -1660,6 +1800,7 @@ class Wordpress(Connect): Returns: dict: {'success':bool,'result':'http/url/to/media'}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.media_upload.__annotations__): if not path.exists(mediafile): raise FileExistsError(mediafile + " is not exist") @@ -1683,60 +1824,64 @@ class Wordpress(Connect): 'Cache-Control': 'no-cache' } ) - logging.debug( - msg="" + local_logger.debug(msg="" + "\n" + "media API response: " + "\n" + json.dumps(json.loads(response['result']), indent=2) ) if response['success']: for key, val in json.loads(response['result']).items(): if key == "source_url": - logging.info('media uploaded: %s', val) + local_logger.info('media uploaded: %s', val) return {"success": True, "result": val} else: - logging.warning("media didn't upload") + local_logger.warning("media didn't upload") return {"success": False, "result": "ERROR"} def pages_read( self, - page_id: int + page_id: int, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Read page by 'wp-json'. Args: page_id (int): unique identifier for the page. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'success':bool,'result':'page data'} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.pages_read.__annotations__): page_link = self.api_pages + '/' + str(page_id) response = self.http(url=page_link) if response['success']: - logging.debug( - msg="" + local_logger.debug(msg="" + "\n" + "wp page API response: " + "\n" + json.dumps(json.loads(response['result']), indent=2) ) return {"success": True, "result": response['result']} else: - logging.warning("wp page didn't read") + local_logger.warning("wp page didn't read") return {"success": False, "result": "ERROR"} def pages_update( self, page_id: int, - content: str + content: str, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Update page by 'wp-json'. Args: page_id (int): unique identifier for the page. content (str): the content for the page. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'success':bool,'result':'http/url/to/page'} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.pages_update.__annotations__): page_link = self.api_pages + '/' + str(page_id) page_json = { @@ -1751,18 +1896,17 @@ class Wordpress(Connect): contenttype='application/json; charset=UTF-8', contentdata=json.dumps(page_json) ) - logging.debug( - msg="" + local_logger.debug(msg="" + "\n" + "wp page API response: " + "\n" + json.dumps(json.loads(response['result']), indent=2) ) if response['success']: for key, val in json.loads(response['result']).items(): if key == "link": - logging.info(msg="wp page " + str(page_id) + " updated: " + val) + local_logger.info(msg="wp page " + str(page_id) + " updated: " + val) return {"success": True, "result": val} else: - logging.warning("wp page didn't update") + local_logger.warning("wp page didn't update") return {"success": False, "result": "ERROR"} @@ -1781,17 +1925,25 @@ class Telegram(): self.api_root = 'https://api.telegram.org' self.api_path = self.api_root + '/bot' + self._token - def send_message(self, chat: str, text: str, parse_mode: str = 'HTML') -> dict: + def send_message( + self, + chat: str, + text: str, + parse_mode: str = 'HTML', + logger_alias: str = inspect.stack()[0].function + ) -> dict: """Send text message. Args: chat (str): unique identifier for the target chat or username of the target channel. text (str): text of the message to be sent, 1-4096 characters after entities parsing. parse_mode (str, optional): 'HTML', 'Markdown', 'MarkdownV2'. Defaults to 'HTML'. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {"success":bool,"result":"API response" or "ERROR"} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.send_message.__annotations__): url=self.api_path + '/sendMessage' data = { @@ -1799,11 +1951,11 @@ class Telegram(): "text": text, "parse_mode": parse_mode, "disable_notification": True - } + } response = requests.post(url=url, json=data, timeout=15) if response.status_code == 200: response = response.json() - logging.info(msg="" + local_logger.info(msg="" + "message '" + str(response['result']['message_id']) + "' sent to telegram chat " @@ -1811,32 +1963,39 @@ class Telegram(): ) return {'success': True, 'result': response} else: - logging.warning(msg="message didn't send to telegram chat " + str(chat)) + local_logger.warning(msg="message didn't send to telegram chat " + str(chat)) return {'success': False, 'result': response} - def delete_message(self, chat: str, message_id: int) -> dict: + def delete_message( + self, + chat: str, + message_id: int, + logger_alias: str = inspect.stack()[0].function + ) -> dict: """Delete message. Args: chat (str): unique identifier for the target chat or username of the target channel. message_id (int): identifier of the message to delete. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {"success":bool,"result":"API response" or "ERROR"} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.delete_message.__annotations__): url=self.api_path + '/deleteMessage' data = {"chat_id": chat, "message_id": message_id} response = requests.post(url=url, json=data, timeout=15) if response.status_code == 200: response = response.json() - logging.info(msg="" + local_logger.info(msg="" + "message '" + str(message_id) + "' deleted from telegram chat " + str(chat) ) return {'success': True, 'result': response} else: - logging.warning(msg="" + local_logger.warning(msg="" + "message '" + str(message_id) + "' didn't deleted from telegram chat " + str(chat) ) @@ -1850,7 +2009,8 @@ class Telegram(): caption: (str, type(None)), parse_mode: str, disable_notification: bool, - additional_url_param: (str, type(None)) + additional_url_param: (str, type(None)), + logger_alias: str = inspect.stack()[0].function ) -> dict: """Send media by api.telegram.org. @@ -1862,6 +2022,7 @@ class Telegram(): parse_mode (str): caption 'HTML', 'Markdown', 'MarkdownV2' parse mode. disable_notification (bool): send silently. additional_url_param (str, None): example: '&duration=30&width=960&height=540'. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Raises: ValueError: "'media_type' value is wrong" @@ -1869,6 +2030,7 @@ class Telegram(): Returns: dict: {'success':bool,'result':response}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.__send_media.__annotations__): if ( media_type == 'document' or @@ -1898,7 +2060,7 @@ class Telegram(): file_id = response['result'][media_type][-1]['file_id'] else: file_id = response['result'][media_type]['file_id'] - logging.info(msg="" + local_logger.info(msg="" + media_type + " '" + str(file_id) @@ -1918,7 +2080,7 @@ class Telegram(): file_id = response['result'][media_type][-1]['file_id'] else: file_id = response['result'][media_type]['file_id'] - logging.info(msg="" + local_logger.info(msg="" + media_type + " '" + str(file_id) @@ -1926,7 +2088,8 @@ class Telegram(): + chat ) return {'success': True, 'result': response} - logging.warning( + + local_logger.warning( msg=media_type + " " + media_path + " didn't send to telegram chat " + str(chat) ) return {'success': False, 'result': response} @@ -2036,7 +2199,8 @@ class Telegram(): media: dict, caption: (str, type(None)) = None, parse_mode: str = 'HTML', - disable_notification: bool = True + disable_notification: bool = True, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Send media group of photo, video, audio, documents. @@ -2050,10 +2214,12 @@ class Telegram(): caption (str, type, optional): media caption less 1024 characters. Defaults to None. parse_mode (str): caption 'HTML', 'Markdown', 'MarkdownV2' parse mode. disable_notification (bool, optional): send silently. Defaults to True. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'success':bool,'result':response}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), self.send_mediagroup.__annotations__): url=self.api_path + '/sendMediaGroup' files = {} @@ -2093,15 +2259,16 @@ class Telegram(): response = requests.post(url=url, data=data, files=files, timeout=300) if response.status_code == 200: response = response.json() - logging.info(msg="" + local_logger.info(msg="" + "mediagroup '" + str(response['result'][0]['media_group_id']) + "' sent to telegram chat " + str(chat) ) return {'success': True, 'result': response} - logging.warning(msg="mediagroup didn't send to telegram chat " + str(chat)) - return {'success': False, 'result': response} + else: + local_logger.warning(msg="mediagroup didn't send to telegram chat " + str(chat)) + return {'success': False, 'result': response} class Sequence: @@ -2115,7 +2282,8 @@ class Sequence: temp_path: str, records_root_path: str = None, records_root_user: str = None, - records_root_pass: str = None + records_root_pass: str = None, + logger_alias: str = inspect.stack()[0].function ) -> None: """Sequences executor. @@ -2130,7 +2298,10 @@ class Sequence: Defaults to None. records_root_pass (str, optional): password if path on remote host. Defaults to None. + logger_alias (str, optional): sublogger name. + Defaults to function or method name. """ + local_logger = logging.getLogger(logger_alias) makedirs(temp_path, exist_ok=True) for key, value in sequence.items(): action = value.split(',')[0].strip() @@ -2149,8 +2320,8 @@ class Sequence: m = sensor_value else: m = '' - logging.info(msg='' - + ' action:' + key + ' = ' + action + local_logger.info(msg='' + + 'action:' + key + ' = ' + action + ',' + x + ',' + y + ',' + z + ',' + p + ',' + s + ',' + t + ',' + w + ',' + m @@ -2242,7 +2413,7 @@ class Sequence: try: remove(src_file) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) response = True else: response = False @@ -2261,7 +2432,7 @@ class Sequence: try: remove(src_file) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) response = True else: response = False @@ -2270,7 +2441,12 @@ class Sequence: dst_file = ( hostpath + sep + dy + sep + dm + sep + dv + sep + dd + sep - + records_file_name) + + records_file_name + ) + local_logger.debug(msg='' + + '\n' + 'src_file: ' + src_file + + '\n' + 'dst_file: ' + dst_file + ) try: makedirs( hostpath + sep + dy + sep + dm + sep + dv + sep + dd, @@ -2279,24 +2455,20 @@ class Sequence: replace(src=src_file, dst=dst_file) response = True except OSError as error: - logging.debug(msg='' - + '\n' + 'src_file: ' + src_file - + '\n' + 'dst_file: ' + dst_file - + '\n' + 'error: ' + str(error) - ) + local_logger.debug(msg='error: ' + '\n' + str(error)) response = False else: response = False if w != '-' or float(w) != 0: sleep(float(w)) if response: - logging.info(msg=' result:' + key + ' = OK') + local_logger.info(msg='result:' + key + ' = OK') else: - logging.warning(msg='result:' + key + ' = ERROR') + local_logger.warning(msg='result:' + key + ' = ERROR') try: rmdir(temp_path) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) class Convert: @@ -2317,7 +2489,8 @@ class Convert: image_root_user: (str, type(None)) = None, image_root_pass: (str, type(None)) = None, video_dest_user: (str, type(None)) = None, - video_dest_pass: (str, type(None)) = None + video_dest_pass: (str, type(None)) = None, + logger_alias: str = inspect.stack()[0].function ) -> None: """Converting executor. @@ -2339,7 +2512,10 @@ class Convert: Defaults to None. video_dest_pass (str, type, optional): password to destination video ftp,sftp,smb path. Defaults to None. + logger_alias (str, optional): sublogger name. + Defaults to function or method name. """ + local_logger = logging.getLogger(logger_alias) if isinstance(image_root_path, str): image_root_path = [image_root_path] @@ -2449,11 +2625,11 @@ class Convert: try: remove(temp_file) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) try: rmdir(temp_path) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) class Publish: @@ -2474,7 +2650,8 @@ class Publish: wp_user_pass: (str, type(None)) = None, wp_update_page_id: (int, type(None)) = None, tg_api_key: (str, type(None)) = None, - tg_chat_id: (str, type(None)) = None + tg_chat_id: (str, type(None)) = None, + logger_alias: str = inspect.stack()[0].function ) -> None: """Publishing executor. @@ -2501,7 +2678,10 @@ class Publish: tg_chat_id (str, None, optional): unique identifier for the target chat or username of the target channel. Defaults to None. + logger_alias (str, optional): sublogger name. + Defaults to function or method name. """ + local_logger = logging.getLogger(logger_alias) if isinstance(video_root_path, str): video_root_path = [video_root_path] @@ -2597,11 +2777,11 @@ class Publish: try: remove(temp_file) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) try: rmdir(temp_path) except OSError as error: - logging.debug(msg='\n' + 'error: ' + str(error)) + local_logger.debug(msg='error: ' + '\n' + str(error)) class Do(): @@ -2707,13 +2887,13 @@ class Do(): 'm': target.month, 'w': target.isocalendar()[1], 'd': target.day - } + } date['end'] = { 'y': delta.year, 'm': delta.month, 'w': delta.isocalendar()[1], 'd': delta.day - } + } return date @staticmethod @@ -2759,7 +2939,8 @@ class Do(): targets_media_files: dict, period: str, amount: int, - page_id: int + page_id: int, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Custom Wordpress media routine - upload media, create media events, update media page. @@ -2769,10 +2950,12 @@ class Do(): period (str, optional): 'y','m','w','d'. amount (int, optional): +/- periods. page_id (int): unique identifier for the page. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Returns: dict: {'media upload': bool, 'event create': bool, 'pages update': bool} """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), Do.wp_routine_media.__annotations__): default_media_links = { "day": { @@ -2843,7 +3026,7 @@ class Do(): "https://www.hmp.today/wp-content/uploads/2022/07/point-12_yyyy.mp4" ) } - } + } current_media_links = default_media_links[period] result = {} @@ -2855,7 +3038,7 @@ class Do(): media_type='video' ) if file_found['success'] and len(file_found['result']) > 0: - logging.info( + local_logger.info( msg="" + "upload skipped, " + targets_media_files[period][name] @@ -2960,7 +3143,7 @@ class Do(): if current_media_links[name] != default_media_links[period][name]: pass elif Connect.http(event_api_slug)['success']: - logging.info(msg="event skipped, " + event_api_slug + " found on site") + local_logger.info(msg="event skipped, " + event_api_slug + " found on site") else: event_create = wp.event_create( title=title, @@ -2997,7 +3180,7 @@ class Do(): pattern = wp.url_files + "/[0-9]{4}/[0-9]{2}/" + name + reg_exp for old_str in re.findall(pattern, content): if old_str == new_str: - logging.info( + local_logger.info( msg="" + "page replace skipped, " + new_str @@ -3006,7 +3189,7 @@ class Do(): else: content = content.replace(old_str, new_str) replace += 1 - logging.info(msg="page replace " + old_str + " to " + new_str) + local_logger.info(msg="page replace " + old_str + " to " + new_str) if replace > 0: page_update = wp.pages_update(page_id = page_id, content = content) @@ -3021,7 +3204,8 @@ class Do(): targets_media_files: dict, period: str, amount: int, - chat: str + chat: str, + logger_alias: str = inspect.stack()[0].function ) -> dict: """Custom Telegram media routine - send mediagroup. @@ -3031,6 +3215,7 @@ class Do(): period (str): 'y','m','w','d'. amount (int): +/- periods. chat (str): unique identifier for the target chat or username of the target channel. + logger_alias (str, optional): sublogger name. Defaults to function or method name. Raises: ValueError: filename is not local file. @@ -3038,6 +3223,7 @@ class Do(): Returns: dict: {'success':bool,'result':response}. """ + local_logger = logging.getLogger(logger_alias) if Do.args_valid(locals(), Do.tg_routine_media.__annotations__): default_caption = ("" + "`period:` yyyy.mm.dd\n" @@ -3054,7 +3240,7 @@ class Do(): ), "caption": "source: https://www.hmp.today" } - } + } tmp_files = [] date = Do.date_calc(period=period, amount=amount) @@ -3119,7 +3305,9 @@ class Do(): ] ) if FFmpeg.run(raw=compressing_params) == 0: - logging.info(msg=media_path + " comressed to " + tmp_video_file) + local_logger.info(msg='' + + media_path + " comressed to " + tmp_video_file + ) tmp_files.append(tmp_video_file) cur_video_file = tmp_video_file @@ -3151,7 +3339,7 @@ class Do(): ) for file in tmp_files: if remove(file): - logging.info(msg="deleted " + file) + local_logger.info(msg="deleted " + file) return response_result @@ -3218,7 +3406,7 @@ if __name__ == "__main__": elif conf.data['log_level'] == 'CRITICAL': log_level = logging.CRITICAL logging.basicConfig( - format='%(asctime)s %(levelname)s: %(message)s', + format='%(asctime)s %(levelname)s: %(name)s: %(message)s', datefmt='%Y-%m-%d_%H.%M.%S', handlers=[ logging.FileHandler( @@ -3275,7 +3463,8 @@ if __name__ == "__main__": ffpath=ffpath, watchdog=watchdog, watchsec=watchsec, - onlyonce=onlyonce + onlyonce=onlyonce, + logger_alias='streaming ' + key ) logging.info(msg='' + 'Streaming ' + key + ' finished with exit code: ' @@ -3334,7 +3523,8 @@ if __name__ == "__main__": temp_path=temp_path + sep + Do.random_string(8), records_root_path=records_root_path, records_root_user=records_root_user, - records_root_pass=records_root_pass + records_root_pass=records_root_pass, + logger_alias='sequence ' + key ) logging.info(msg='Sequence ' + key + ' finished') @@ -3465,7 +3655,8 @@ if __name__ == "__main__": video_scale_y=int(convert_config['video_scale_y']), video_framerate=int(convert_config['video_framerate']), video_duration=video_duration, - temp_path=temp_path + sep + Do.random_string(8) + temp_path=temp_path + sep + Do.random_string(8), + logger_alias='converting ' + key ) logging.info(msg='Converting ' + key + ' finished') if args['publisher']: @@ -3528,7 +3719,8 @@ if __name__ == "__main__": wp_user_pass=wp_user_pass, wp_update_page_id=wp_update_page_id, tg_api_key=tg_api_key, - tg_chat_id=tg_chat_id + tg_chat_id=tg_chat_id, + logger_alias='publishing ' + key ) logging.info(msg='Publishing ' + key + ' finished')