first commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,148 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import aiologger
|
||||
import aiologger.handlers.streams
|
||||
import aiologger.handlers.files
|
||||
import aiologger.handlers.base
|
||||
import aiologger.levels
|
||||
import aiologger.formatters.base
|
||||
import aiologger.records
|
||||
import logging
|
||||
import pop.contract
|
||||
import sys
|
||||
|
||||
|
||||
def __init__(hub):
|
||||
hub.log.LOGGER = {}
|
||||
hub.log.FILE_HANDLER = None
|
||||
hub.log.STREAM_HANDLER = None
|
||||
|
||||
|
||||
def _stack_frames(relative_start: int) -> inspect.FrameInfo:
|
||||
"""
|
||||
Efficiently access stack frames.
|
||||
:param relative_start: Starting stack depth; The default, 2 is the parent of the
|
||||
caller of stack_frames - the first function that may be unknown.
|
||||
:return: a stack frame
|
||||
"""
|
||||
if hasattr(sys, "_getframe"):
|
||||
# implementation detail of CPython, speeds things up by 100x.
|
||||
frame = sys._getframe(relative_start)
|
||||
while frame:
|
||||
yield frame
|
||||
frame = frame.f_back
|
||||
else:
|
||||
for frame_info in inspect.stack(context=0)[relative_start:]:
|
||||
yield frame_info.frame
|
||||
|
||||
|
||||
def _get_hub_ref() -> str:
|
||||
# Minimize lookup time by starting at frame 5, it will be at least that far back
|
||||
for frame in _stack_frames(5):
|
||||
if isinstance(frame.f_locals.get("self"), pop.contract.Contracted):
|
||||
contracted = frame.f_locals["self"]
|
||||
break
|
||||
else:
|
||||
# Default to the root reference
|
||||
return "hub"
|
||||
|
||||
return contracted, frame.f_lineno
|
||||
|
||||
|
||||
def _get_logger(hub, name: str = "") -> aiologger.Logger:
|
||||
if name not in hub.log.LOGGER:
|
||||
hub.log.LOGGER[name]: aiologger.Logger = aiologger.Logger(
|
||||
name=name, loop=hub.pop.Loop
|
||||
)
|
||||
hub.log.LOGGER[name].level = hub.log.INT_LEVEL
|
||||
if hub.log.FILE_HANDLER:
|
||||
hub.log.LOGGER[name].handlers.append(hub.log.FILE_HANDLER)
|
||||
if hub.log.STREAM_HANDLER:
|
||||
hub.log.LOGGER[name].handlers.append(hub.log.STREAM_HANDLER)
|
||||
return hub.log.LOGGER[name]
|
||||
|
||||
|
||||
def log(hub, level: int, msg: str, *args, **kwargs):
|
||||
if hub.log.INT_LEVEL <= level:
|
||||
contract, lineno = _get_hub_ref()
|
||||
caller = f"{contract.ref}.{contract.func.__name__}"
|
||||
logger: aiologger.Logger = _get_logger(hub, caller)
|
||||
record = aiologger.records.LogRecord(
|
||||
name=caller,
|
||||
pathname=contract.func.__module__,
|
||||
lineno=lineno,
|
||||
level=0, # We have to overwrite this in a secure way
|
||||
msg=msg,
|
||||
args=args,
|
||||
func=contract.func.__name__,
|
||||
**kwargs,
|
||||
)
|
||||
record.levelno = level
|
||||
if level == 5:
|
||||
record.levelname = "TRACE"
|
||||
else:
|
||||
try:
|
||||
record.levelname = aiologger.records.get_level_name(level)
|
||||
except ValueError:
|
||||
record.levelname = f"LEVEL {level}"
|
||||
|
||||
ret = logger.handle(record)
|
||||
if asyncio.iscoroutine(ret):
|
||||
hub.pop.Loop.create_task(ret)
|
||||
|
||||
|
||||
def setup(hub, conf):
|
||||
"""
|
||||
Given the configuration data set up the logger
|
||||
"""
|
||||
# Make sure the loop exists
|
||||
hub.pop.loop.create()
|
||||
# Use the saved root logger
|
||||
root = _get_logger(hub, name="")
|
||||
|
||||
raw_level = conf["log_level"].strip().lower()
|
||||
if raw_level.isdigit():
|
||||
hub.log.INT_LEVEL = int(raw_level)
|
||||
else:
|
||||
hub.log.INT_LEVEL = hub.log.LEVEL.get(raw_level, root.level)
|
||||
|
||||
root.level = hub.log.INT_LEVEL
|
||||
cf = aiologger.formatters.base.Formatter(
|
||||
fmt=conf["log_fmt_console"], datefmt=conf["log_datefmt"]
|
||||
)
|
||||
ch = aiologger.handlers.streams.AsyncStreamHandler(
|
||||
formatter=cf, loop=hub.pop.Loop, stream=sys.stderr
|
||||
)
|
||||
ch._level = hub.log.INT_LEVEL
|
||||
root.add_handler(ch)
|
||||
hub.log.STREAM_HANDLER = ch
|
||||
|
||||
ff = aiologger.formatters.base.Formatter(
|
||||
fmt=conf["log_fmt_console"], datefmt=conf["log_datefmt"]
|
||||
)
|
||||
fh = aiologger.handlers.files.AsyncFileHandler(conf["log_file"], loop=hub.pop.Loop)
|
||||
fh._level = hub.log.INT_LEVEL
|
||||
fh.formatter = ff
|
||||
root.add_handler(fh)
|
||||
hub.log.FILE_HANDLER = fh
|
||||
|
||||
# Put all these functions higher up on the hub
|
||||
hub.log.log = getattr(hub.log, "async").log
|
||||
hub.log.trace = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=5, msg=msg, *args, **kwargs
|
||||
)
|
||||
hub.log.debug = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=aiologger.levels.LogLevel.DEBUG, msg=msg, *args, **kwargs
|
||||
)
|
||||
hub.log.info = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=aiologger.levels.LogLevel.INFO, msg=msg, *args, **kwargs
|
||||
)
|
||||
hub.log.warning = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=aiologger.levels.LogLevel.WARNING, msg=msg, *args, **kwargs
|
||||
)
|
||||
hub.log.error = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=aiologger.levels.LogLevel.ERROR, msg=msg, *args, **kwargs
|
||||
)
|
||||
hub.log.critical = lambda msg, *args, **kwargs: hub.log.log(
|
||||
level=aiologger.levels.LogLevel.CRITICAL, msg=msg, *args, **kwargs
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
import logging
|
||||
|
||||
|
||||
def setup(hub, conf):
|
||||
"""
|
||||
Given the configuration data set up the logger
|
||||
"""
|
||||
# Use the saved root logger
|
||||
root = logging.getLogger()
|
||||
|
||||
raw_level = conf["log_level"].strip().lower()
|
||||
if raw_level.isdigit():
|
||||
hub.log.INT_LEVEL = int(raw_level)
|
||||
else:
|
||||
hub.log.INT_LEVEL = hub.log.LEVEL.get(raw_level, root.level)
|
||||
|
||||
root.setLevel(hub.log.INT_LEVEL)
|
||||
cf = logging.Formatter(fmt=conf["log_fmt_console"], datefmt=conf["log_datefmt"])
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(hub.log.INT_LEVEL)
|
||||
ch.setFormatter(cf)
|
||||
root.addHandler(ch)
|
||||
|
||||
ff = logging.Formatter(fmt=conf["log_fmt_console"], datefmt=conf["log_datefmt"])
|
||||
fh = logging.FileHandler(conf["log_file"])
|
||||
fh.setFormatter(ff)
|
||||
root.addHandler(fh)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
This sub is used to set up logging for pop projects and injects logging
|
||||
options into conf making it easy to add robust logging
|
||||
"""
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
|
||||
def __init__(hub):
|
||||
"""
|
||||
Set up variables used by the log subsystem
|
||||
"""
|
||||
logging.addLevelName(5, "TRACE")
|
||||
hub.log.LEVEL = {
|
||||
"notset": logging.NOTSET,
|
||||
"trace": 5,
|
||||
"debug": logging.DEBUG,
|
||||
"info": logging.INFO,
|
||||
"warn": logging.WARN,
|
||||
"warning": logging.WARNING,
|
||||
"error": logging.ERROR,
|
||||
"fatal": logging.FATAL,
|
||||
"critical": logging.CRITICAL,
|
||||
}
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# These should be overwritten by the integrated logger, but here's a contingency
|
||||
hub.log.INT_LEVEL = log.getEffectiveLevel()
|
||||
hub.log.log = log.log
|
||||
hub.log.trace = lambda msg, *args, **kwargs: log.log(5, msg, *args, **kwargs)
|
||||
hub.log.debug = log.debug
|
||||
hub.log.info = log.info
|
||||
hub.log.critical = log.critical
|
||||
hub.log.warning = log.warning
|
||||
hub.log.error = log.error
|
||||
Reference in New Issue
Block a user