f-stack/dpdk/dts/framework/logger.py

114 lines
3.2 KiB
Python

# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation
# Copyright(c) 2022 PANTHEON.tech s.r.o.
# Copyright(c) 2022 University of New Hampshire
"""
DTS logger module with several log level. DTS framework and TestSuite logs
are saved in different log files.
"""
import logging
import os.path
from typing import TypedDict
from .settings import SETTINGS
date_fmt = "%Y/%m/%d %H:%M:%S"
stream_fmt = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
class LoggerDictType(TypedDict):
logger: "DTSLOG"
name: str
node: str
# List for saving all using loggers
Loggers: list[LoggerDictType] = []
class DTSLOG(logging.LoggerAdapter):
"""
DTS log class for framework and testsuite.
"""
logger: logging.Logger
node: str
sh: logging.StreamHandler
fh: logging.FileHandler
verbose_fh: logging.FileHandler
def __init__(self, logger: logging.Logger, node: str = "suite"):
self.logger = logger
# 1 means log everything, this will be used by file handlers if their level
# is not set
self.logger.setLevel(1)
self.node = node
# add handler to emit to stdout
sh = logging.StreamHandler()
sh.setFormatter(logging.Formatter(stream_fmt, date_fmt))
sh.setLevel(logging.INFO) # console handler default level
if SETTINGS.verbose is True:
sh.setLevel(logging.DEBUG)
self.logger.addHandler(sh)
self.sh = sh
logging_path_prefix = os.path.join(SETTINGS.output_dir, node)
fh = logging.FileHandler(f"{logging_path_prefix}.log")
fh.setFormatter(
logging.Formatter(
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt=date_fmt,
)
)
self.logger.addHandler(fh)
self.fh = fh
# This outputs EVERYTHING, intended for post-mortem debugging
# Also optimized for processing via AWK (awk -F '|' ...)
verbose_fh = logging.FileHandler(f"{logging_path_prefix}.verbose.log")
verbose_fh.setFormatter(
logging.Formatter(
fmt="%(asctime)s|%(name)s|%(levelname)s|%(pathname)s|%(lineno)d|"
"%(funcName)s|%(process)d|%(thread)d|%(threadName)s|%(message)s",
datefmt=date_fmt,
)
)
self.logger.addHandler(verbose_fh)
self.verbose_fh = verbose_fh
super(DTSLOG, self).__init__(self.logger, dict(node=self.node))
def logger_exit(self) -> None:
"""
Remove stream handler and logfile handler.
"""
for handler in (self.sh, self.fh, self.verbose_fh):
handler.flush()
self.logger.removeHandler(handler)
def getLogger(name: str, node: str = "suite") -> DTSLOG:
"""
Get logger handler and if there's no handler for specified Node will create one.
"""
global Loggers
# return saved logger
logger: LoggerDictType
for logger in Loggers:
if logger["name"] == name and logger["node"] == node:
return logger["logger"]
# return new logger
dts_logger: DTSLOG = DTSLOG(logging.getLogger(name), node)
Loggers.append({"logger": dts_logger, "name": name, "node": node})
return dts_logger