From 3dd8bdc669f5a918b770e2a459e0c56c4520156b Mon Sep 17 00:00:00 2001 From: Chaeeon Lim Date: Tue, 30 Aug 2022 13:06:23 +0900 Subject: [PATCH] update --- .gitignore | 4 ++ lib/__init__.py | 0 lib/config.py | 24 ++++++++ lib/logger.py | 79 ++++++++++++++++++++++++++ log-config.yml | 10 ++++ pyLogger.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++ pyLogger.service | 10 ++++ requirements.txt | 2 + runLogger | 44 +++++++++++++++ 9 files changed, 313 insertions(+) create mode 100644 .gitignore create mode 100644 lib/__init__.py create mode 100644 lib/config.py create mode 100644 lib/logger.py create mode 100644 log-config.yml create mode 100644 pyLogger.py create mode 100644 pyLogger.service create mode 100644 requirements.txt create mode 100644 runLogger diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d8682c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*venv*/ +__pycache__/ +*.pyc +logs/ diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/config.py b/lib/config.py new file mode 100644 index 0000000..0c4beae --- /dev/null +++ b/lib/config.py @@ -0,0 +1,24 @@ +import yaml +import json +import logging + +logger = logging.getLogger("fds") + +class Config(): + def __init__(self, config_file: str): + with open(config_file, "r") as cfile: + self.__dict__ = yaml.safe_load(cfile) + self.set_params(self.__dict__) + + def set_params(self, config: dict): + for k, v in config.items(): + # if type(v) is dict: + # set_params(v) + setattr(self, k, v) + + def __repr__(self): + return json.dumps(self.__dict__, indent=4) + +class LogConfig(Config): + ... + \ No newline at end of file diff --git a/lib/logger.py b/lib/logger.py new file mode 100644 index 0000000..7fe4b66 --- /dev/null +++ b/lib/logger.py @@ -0,0 +1,79 @@ +import os +import logging +from logging.handlers import RotatingFileHandler + +# COLORED_FORMAT = '%(asctime)-15s [%(levelname)s] %(threadName)-12s ' +# NORMAL_FORMAT = '%(filename)s %(funcName)s, line %(lineno)s: %(message)s' +COLORED_FORMAT = '[%(levelname)s] %(threadName)-12s ' +NORMAL_FORMAT = '%(message)s' # '%(filename)s %(funcName)s, line %(lineno)s: %(message)s' +FORMAT = COLORED_FORMAT + NORMAL_FORMAT + +class ColoredFormatter(logging.Formatter): + + grey = "\x1b[38;20m" + yellow = "\x1b[33;20m" + red = "\x1b[31;20m" + bold_red = "\x1b[31;1m" + white = "\x1b[33;97m" + green = "\x1b[33;92m" + reset = "\x1b[0m" + + FORMATS = { + logging.DEBUG: white + COLORED_FORMAT + reset + NORMAL_FORMAT, + logging.INFO: green + COLORED_FORMAT + reset + NORMAL_FORMAT, + logging.WARNING: yellow + COLORED_FORMAT + reset + NORMAL_FORMAT, + logging.ERROR: red + COLORED_FORMAT + reset + NORMAL_FORMAT, + logging.CRITICAL: bold_red + COLORED_FORMAT + reset + NORMAL_FORMAT + } + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt, datefmt='%Y-%m-%d %I:%M:%S%p') + return formatter.format(record) + +def set_log_folder(path: str): + dir = os.path.dirname(path) + if len(dir) == 0: + dir = "./" + + os.makedirs(dir, exist_ok=True) + +def set_logger(name: str = "fds", filename: str = "main.log", level: str = "info", logtest=False): + set_log_folder(filename) + logging_levels = ( + logging.CRITICAL, + logging.ERROR, + logging.WARNING, + logging.INFO, + logging.DEBUG, + ) + log_level = getattr(logging, level.upper()) + + assert log_level in logging_levels + + + log = logging.getLogger(name) + log.setLevel(log_level) + + file_handler = RotatingFileHandler(filename, maxBytes=100000000, backupCount=10) + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(logging.Formatter(FORMAT)) + log.addHandler(file_handler) + + stream_handler = logging.StreamHandler() + # stream_handler.setLevel(log_level) + stream_handler.setLevel(logging.DEBUG) + stream_handler.setFormatter(ColoredFormatter()) + log.addHandler(stream_handler) + + if logtest: + t_log = getattr(log, level) + t_log(f"Logging level: {level.upper()}") + log.info("You can see below log labels") + log.debug("DEBUG level") + log.info("INFO level") + log.warning("WARNING level") + log.error("ERROR level") + log.critical("CRITICAL level") + + return log diff --git a/log-config.yml b/log-config.yml new file mode 100644 index 0000000..5ae4d65 --- /dev/null +++ b/log-config.yml @@ -0,0 +1,10 @@ +Config: + - name: ttyUSB2 + device: /dev/ttyUSB2 + baudrate: 115200 + - name: ttyUSB1 + device: /dev/ttyUSB1 + baudrate: 115200 + - name: ttyUSB3 + device: /dev/ttyUSB3 + baudrate: 115200 diff --git a/pyLogger.py b/pyLogger.py new file mode 100644 index 0000000..8c53df3 --- /dev/null +++ b/pyLogger.py @@ -0,0 +1,140 @@ +import os +import sys +import json +import serial +import signal +import logging +import argparse +from threading import Thread +from contextlib import contextmanager, ExitStack +from signal import SIGINT, SIGTERM +from serial.tools import list_ports +from datetime import datetime as dt + +from lib.logger import set_logger +from lib.config import LogConfig + + +def parsing_argument(): + parser = argparse.ArgumentParser(description="USB-UART Serial logging.") + # parser.add_argument('-p', '--serial-path', type=str, default="/dev/ttyUSB2", help="Path to device file") + # parser.add_argument('-b', '--baudrate', type=int, default=115200, help="Baudrate") + parser.add_argument('-f', '--log-file', type=str, default="logs/main.log", help="Name of log file") + parser.add_argument('-d', '--log-level', type=str, default="info", choices=['notset', 'info', 'debug', 'warning', 'error', 'critical'], help="Set log level") + parser.add_argument('-c', '--log-config', type=str, default="log-config.yml", help="Config for logging") + args = parser.parse_args() + # device = os.path.basename(args.serial_path) + # if len(args.log_file) == 0: + # args.log_file = f"{device}.log" + return args + +class SerialLogger(): + def __init__(self, config): + self.set_params(config) + # self.name = + if not hasattr(self, 'log_file') or len(self.log_file) == 0: + self.log_file = f"logs/{self.name}.log" + if not hasattr(self, 'log_level'): + self.log_level='info' + + self.logger = set_logger(name=self.name, filename=self.log_file, level=self.log_level) + + self.stop=False + + print("") + self.logger.info("-----------------------------------------------") + self.logger.info(f"Logger launched {dt.now().strftime('%Y/%m/%d %a %H:%M:%S')}") + self.logger.info(f"Target device: {self.device}, Baudrate: {self.baudrate}") + self.logger.info(f"Log level: {self.log_level.upper()}, saved in \'{self.log_file}\'") + self.logger.info("-----------------------------------------------\n") + + def set_params(self, config: dict): + for k, v in config.items(): + # if type(v) is dict: + # set_params(v) + setattr(self, k, v) + + @contextmanager + def run(self): + thread = Thread(target=self.listen, name=f"{self.name}") + thread.start() + try: + yield + finally: + self.stop = True + thread.join() + + def listen(self): + tmp="" + with serial.Serial(self.device, self.baudrate) as dev: + while not self.stop: + data = dev.readline(dev.inWaiting()).decode("latin1") + if data: + if "Ramdisk addr" in data: + self.logger.info("") + self.logger.info("-----------------------------------------") + self.logger.info(f"FPGA Initialized. {dt.now().strftime('%Y/%m/%d %a %H:%M:%S')}") + self.logger.info("-----------------------------------------") + if data[-1] == '\n': + tmp += data.strip() + self.logger.info(tmp) + tmp = "" + else: + tmp+= data.strip() + + #self.logger.info(data.strip()) + + +def main(args=None): + LOG = set_logger(filename=args.log_file, level=args.log_level) + LOG.info("-----------------------------------------------") + LOG.info(f"Logger launched {dt.now().strftime('%Y/%m/%d %a %H:%M:%S')}") + LOG.info(f"Logging configs: {args.log_config}") + LOG.info(f"Log level: {args.log_level.upper()}, saved in \'{args.log_file}\'") + LOG.info("-----------------------------------------------\n") + + LOG.info("Available ports") + for i, p in enumerate(list_ports.comports()): + LOG.info(f"{i+1}) Deivce: {p.device}") + LOG.info(f"\tDescription : {p.description}") + LOG.info(f"\tHWID : {p.hwid}") + LOG.info(f"\tSerial # : {p.serial_number}") + LOG.info(f"\tLocation : {p.location}") + LOG.info(f"\tManufacturer : {p.manufacturer}") + LOG.info(f"\tProduct : {p.product}") + LOG.info(f"\tInterface : {p.interface}\n") + + + def signal_handler(sig, frame): + sign = signal.Signals(sig) + print("") + LOG.info(f"Stop program by {signal.strsignal(sign)} ({sign.name})\n") + + configs = LogConfig(args.log_config).Config + with ExitStack() as stack: + for cfg in configs: + LOG.info(f"Logging config:\n{json.dumps(cfg, indent=4)}") + sl = SerialLogger(cfg) + stack.enter_context(sl.run()) + signal.signal(SIGINT, signal_handler) + signal.signal(SIGTERM, signal_handler) + print('\t To terminate the program, press Ctrl-c\n') + signal.pause() + + + + + + return 0 + + +def test(): + config = LogConfig("log-config.yml") + print(type(config.Config[0])) + pass + +if __name__ == "__main__": + # test() + sys.exit( + main(parsing_argument()) + ) diff --git a/pyLogger.service b/pyLogger.service new file mode 100644 index 0000000..6e4fa89 --- /dev/null +++ b/pyLogger.service @@ -0,0 +1,10 @@ +[Unit] +Description=Python Serial Logger + +[Service] +Type=simple +WorkingDirectory=/home/fds-l1/Work/NVMe_Test/chaeeon.dev/sw +ExecStart=/home/fds-l1/Work/NVMe_Test/chaeeon.dev/sw/python/peta-venv/bin/python /home/fds-l1/Work/NVMe_Test/chaeeon.dev/sw/python/pyLogger.py --log-config /home/fds-l1/Work/NVMe_Test/chaeeon.dev/sw/python/log-config.yml + +[Install] +WantedBy=multi-user.target diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c43cbbf --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pyyaml +pyserial \ No newline at end of file diff --git a/runLogger b/runLogger new file mode 100644 index 0000000..e1ce49d --- /dev/null +++ b/runLogger @@ -0,0 +1,44 @@ +#!/bin/bash + + + +DEVICE_NUM=${1:-"2"} +DEVICE=ttyUSB${DEVICE_NUM} +DEVICE_FILE=/dev/${DEVICE} +BAUDRATE=115200 +LOGDIR=logs +LOGFILE=${LOGDIR}/${DEVICE}.log + +TAG=${2:-"None"} + +log_message() { + msg=${1:-""} + echo ${msg} >> ${LOGFILE} +} + +launch_message() { + log_message + log_message "-----------------------------" + log_message " Logging launched: $(date)" + log_message " Get logs from \'${DEVICE_FILE}\'" + log_message " Logfile saved at \'${LOGFILE}\'" + log_message " TAG: ${TAG}" + log_message "-----------------------------" +} + +old_main() { + launch_message + + sudo screen -L -Logfile ${LOGFILE} ${DEVICE_FILE} ${BAUDRATE} + sudo chown $USER:$USER ${LOGFILE} + + log_message + log_message +} + + +main() { + sudo python3 python/pyLogger.py --log-config python/log-config.yml +} + +main