lager
Advanced tools
+146
| # Byte-compiled / optimized / DLL files | ||
| __pycache__/ | ||
| *.py[cod] | ||
| *$py.class | ||
| *.doctest.txt | ||
| *_tests/ | ||
| *.bak/ | ||
| *.bak | ||
| f.py | ||
| file.py | ||
| # C extensions | ||
| *.so | ||
| # Distribution / packaging | ||
| .Python | ||
| build/ | ||
| develop-eggs/ | ||
| dist/ | ||
| downloads/ | ||
| eggs/ | ||
| .eggs/ | ||
| lib/ | ||
| lib64/ | ||
| parts/ | ||
| sdist/ | ||
| var/ | ||
| wheels/ | ||
| *.egg-info/ | ||
| .installed.cfg | ||
| *.egg | ||
| MANIFEST | ||
| # PyInstaller | ||
| *.manifest | ||
| *.spec | ||
| # Installer logs | ||
| pip-log.txt | ||
| pip-delete-this-directory.txt | ||
| # Unit test / coverage reports | ||
| htmlcov/ | ||
| .tox/ | ||
| .nox/ | ||
| .nox_win/ | ||
| .nox_wsl/ | ||
| .nox_lin/ | ||
| .nox_win.bak/ | ||
| .nox_wsl.bak/ | ||
| .nox_lin.bak/ | ||
| .coverage | ||
| .coverage.* | ||
| .cache | ||
| nosetests.xml | ||
| coverage.xml | ||
| *.cover | ||
| .hypothesis/ | ||
| .pytest_cache/ | ||
| # Translations | ||
| *.mo | ||
| *.pot | ||
| # Django stuff: | ||
| *.log | ||
| local_settings.py | ||
| db.sqlite3 | ||
| # Flask stuff: | ||
| instance/ | ||
| .webassets-cache | ||
| # Scrapy stuff: | ||
| .scrapy | ||
| # Sphinx documentation | ||
| docs/_build/ | ||
| # PyBuilder | ||
| target/ | ||
| # Jupyter Notebook | ||
| .ipynb_checkpoints | ||
| .ipynb_checkpoints/ | ||
| # pyenv | ||
| .python-version | ||
| # Environments | ||
| .env | ||
| .env.json | ||
| .venv | ||
| env/ | ||
| venv/ | ||
| ENV/ | ||
| env.bak/ | ||
| venv.bak/ | ||
| # Spyder project settings | ||
| .spyderproject | ||
| .spyproject | ||
| # Rope project settings | ||
| .ropeproject | ||
| # mkdocs documentation | ||
| /site | ||
| # mypy | ||
| .mypy_cache/ | ||
| # node | ||
| node_modules/ | ||
| ######## | ||
| # MISC # | ||
| ######## | ||
| .DS_Store | ||
| *~ | ||
| .*.sw[po] | ||
| scratch/ | ||
| .pytype/ | ||
| mypy_reports/ | ||
| pythonenv3.8/ | ||
| .idea/ | ||
| monkeytype.sqlite3 | ||
| .parcel-cache/ | ||
| package-lock.json | ||
| .pdm.toml | ||
| __pypackages__ | ||
| pdm.lock | ||
| .vscode/ | ||
| dgpy-packages/ | ||
| temp/ | ||
| thingy.py | ||
| herm.py | ||
| yarn.lock | ||
| .pdm-python | ||
| # used for merging multiple branches at once | ||
| branches.txt |
| # -*- coding: utf-8 -*- | ||
| """Package metadata/info""" | ||
| from __future__ import annotations | ||
| __all__ = ("__description__", "__pkgroot__", "__title__", "__version__") | ||
| __title__ = "lager" | ||
| __description__ = "EZ-PZ logging based on loguru" | ||
| __pkgroot__ = __file__.replace("__about__.py", "").rstrip("/\\") | ||
| __version__ = "0.19.0" |
| # -*- coding: utf-8 -*- | ||
| """Python lager brewed by a loguru""" | ||
| from __future__ import annotations | ||
| from lager import logging | ||
| from lager.__about__ import __version__ | ||
| from lager.const import LAGER_PORT, LOGURU_DEFAULT_FMT, TORNADO_FMT | ||
| from lager.core import ( | ||
| LAGER, | ||
| LN, | ||
| LOG, | ||
| _change_activation, | ||
| _core, | ||
| _find_iter, | ||
| _log, | ||
| _options, | ||
| add, | ||
| bind, | ||
| catch, | ||
| complete, | ||
| configure, | ||
| contextualize, | ||
| critical, | ||
| debug, | ||
| disable, | ||
| enable, | ||
| error, | ||
| exception, | ||
| flog, | ||
| handlers, | ||
| info, | ||
| lager, | ||
| level, | ||
| ln, | ||
| log, | ||
| logger, | ||
| loglevel, | ||
| opt, | ||
| parse, | ||
| patch, | ||
| remove, | ||
| reset, | ||
| start, | ||
| stop, | ||
| success, | ||
| trace, | ||
| warning, | ||
| ) | ||
| __all__ = ( | ||
| "LAGER", | ||
| "LAGER_PORT", | ||
| "LN", | ||
| "LOG", | ||
| "LOGURU_DEFAULT_FMT", | ||
| "TORNADO_FMT", | ||
| "__version__", | ||
| ############# | ||
| ## HOISTED ## | ||
| ############# | ||
| "_change_activation", | ||
| "_core", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "flog", | ||
| "handlers", | ||
| "info", | ||
| "lager", | ||
| "level", | ||
| "ln", | ||
| "log", | ||
| "logger", | ||
| "logging", | ||
| "loglevel", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "reset", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) |
| # -*- coding: utf-8 -*- | ||
| """pkg entry ~ `python -m lager`""" | ||
| from __future__ import annotations | ||
| import sys | ||
| from lager.__about__ import __pkgroot__, __title__, __version__ | ||
| def main() -> None: | ||
| """Print package metadata""" | ||
| import json | ||
| sys.stdout.write( | ||
| json.dumps( | ||
| { | ||
| "package": __title__, | ||
| "version": __version__, | ||
| "pkgroot": __pkgroot__, | ||
| }, | ||
| indent=2, | ||
| ) | ||
| ) | ||
| if __name__ == "__main__": | ||
| main() |
| # -*- coding: utf-8 -*- | ||
| """Package metadata/info""" | ||
| from __future__ import annotations | ||
| import warnings | ||
| from lager.__about__ import __description__, __pkgroot__, __title__, __version__ | ||
| warnings.warn( | ||
| "lager._meta is deprecated, use lager.__about__ instead", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| __all__ = ("__description__", "__pkgroot__", "__title__", "__version__") |
| # -*- coding: utf-8 -*- | ||
| """Constants go here!""" | ||
| from __future__ import annotations | ||
| from typing import Dict | ||
| LAGER_PORT = 52437 | ||
| TORNADO_FMT = "".join( | ||
| [ | ||
| "<level>", | ||
| "[{level.name[0]} ", | ||
| "{time:YYMMDDTHH:mm:ss} ", | ||
| "{name}:{module}:{line}]", | ||
| "</level> ", | ||
| "{message}", | ||
| ] | ||
| ) | ||
| LOGURU_DEFAULT_FMT = "".join( | ||
| [ | ||
| "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green>", | ||
| " | ", | ||
| "<level>{level: <8}</level>", | ||
| " | ", | ||
| "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan>", | ||
| " - ", | ||
| "<level>{message}</level>", | ||
| ] | ||
| ) | ||
| LOG_LEVELS: Dict[str, str] = { | ||
| "notset": "NOTSET", | ||
| "n": "NOTSET", | ||
| "debug": "DEBUG", | ||
| "d": "DEBUG", | ||
| "info": "INFO", | ||
| "i": "INFO", | ||
| "s": "SUCCESS", | ||
| "success": "SUCCESS", | ||
| "warning": "WARNING", | ||
| "warn": "WARNING", | ||
| "w": "WARNING", | ||
| "error": "ERROR", | ||
| "e": "ERROR", | ||
| "critical": "CRITICAL", | ||
| "fatal": "CRITICAL", | ||
| "c": "CRITICAL", | ||
| # enum/enum-strings | ||
| "0": "NOTSET", | ||
| "10": "DEBUG", | ||
| "20": "INFO", | ||
| "25": "SUCCESS", | ||
| "30": "WARNING", | ||
| "40": "ERROR", | ||
| "50": "CRITICAL", | ||
| } |
| # -*- coding: utf-8 -*- | ||
| """Python lager brewed by a loguru""" | ||
| from __future__ import annotations | ||
| import asyncio | ||
| import sys as _sys | ||
| from functools import wraps | ||
| from time import time | ||
| from typing import Any, Callable, Dict, Optional, TypeVar, Union | ||
| from loguru import logger as logger | ||
| from loguru._handler import Handler | ||
| from lager.const import LOG_LEVELS | ||
| T = TypeVar("T") | ||
| try: | ||
| import orjson | ||
| def _stringify_new_line(serializable: Any) -> str: | ||
| return orjson.dumps(serializable, option=orjson.OPT_APPEND_NEWLINE).decode( | ||
| "utf-8" | ||
| ) | ||
| def _stringify_no_new_line(serializable: Any) -> str: | ||
| return f"{orjson.dumps(serializable).decode('utf-8')}\n" | ||
| _stringify = ( | ||
| _stringify_new_line | ||
| if hasattr(orjson, "OPT_APPEND_NEWLINE") | ||
| else _stringify_no_new_line | ||
| ) | ||
| def _serialize_record(text: str, record: Dict[str, Any]) -> str: | ||
| exception = record["exception"] | ||
| if exception is not None: | ||
| exception = { | ||
| "type": None if exception.type is None else exception.type.__name__, | ||
| "value": exception.value, | ||
| "traceback": bool(record["exception"].traceback), | ||
| } | ||
| serializable = { | ||
| "text": text, | ||
| "record": { | ||
| "elapsed": { | ||
| "repr": record["elapsed"], | ||
| "seconds": record["elapsed"].total_seconds(), | ||
| }, | ||
| "exception": exception, | ||
| "extra": record["extra"], | ||
| "file": { | ||
| "name": record["file"].name, | ||
| "path": record["file"].path, | ||
| }, | ||
| "function": record["function"], | ||
| "level": { | ||
| "icon": record["level"].icon, | ||
| "name": record["level"].name, | ||
| "no": record["level"].no, | ||
| }, | ||
| "line": record["line"], | ||
| "message": record["message"], | ||
| "module": record["module"], | ||
| "name": record["name"], | ||
| "process": { | ||
| "id": record["process"].id, | ||
| "name": record["process"].name, | ||
| }, | ||
| "thread": { | ||
| "id": record["thread"].id, | ||
| "name": record["thread"].name, | ||
| }, | ||
| "time": { | ||
| "repr": record["time"], | ||
| "timestamp": record["time"].timestamp(), | ||
| }, | ||
| }, | ||
| } | ||
| return _stringify(serializable) | ||
| Handler._serialize_record = staticmethod(_serialize_record) | ||
| except ModuleNotFoundError: | ||
| pass | ||
| # lager/logger aliases | ||
| log = LOG = logger | ||
| lager = LAGER = logger | ||
| ln = LN = logger # ln => natural log | ||
| def loglevel(level: Union[str, int]) -> str: | ||
| """Convert log-level abrev to a valid loguru log level""" | ||
| return str(LOG_LEVELS[str(level).strip("'").strip('"').lower()]) | ||
| def flog( | ||
| funk: Optional[Callable[..., T]] = None, | ||
| level: Union[str, int] = "debug", | ||
| enter: bool = True, | ||
| exit: bool = True, | ||
| ) -> T: | ||
| """Log function (sync/async) enter and exit using this decorator | ||
| Args: | ||
| funk (Callable): Function to decorate | ||
| level (Union[int, str]): Log level | ||
| enter (bool): Log function entry if True | ||
| exit (bool): Log function exit if False | ||
| Returns: | ||
| A wrapped function that now has logging! | ||
| Usage: | ||
| # SYNC | ||
| @flog | ||
| def add(a, b): | ||
| return a + b | ||
| add(1, 4) | ||
| # ASYNC | ||
| @flog | ||
| async def add_async(a, b): | ||
| return a + b | ||
| import asyncio | ||
| asyncio.run(add_async(1, 4)) | ||
| """ | ||
| def _flog(funk: Callable[..., T]) -> Callable[..., T]: | ||
| name = funk.__name__ | ||
| @wraps(funk) | ||
| def _flog_decorator(*args: Any, **kwargs: Any) -> T: | ||
| logger_ = logger.opt(depth=1) | ||
| if enter: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-ENTER > '{}' (args={}, kwargs={})", | ||
| name, | ||
| args, | ||
| kwargs, | ||
| ) | ||
| ti = time() | ||
| result = funk(*args, **kwargs) | ||
| tf = time() | ||
| if exit: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-EXIT < '{}' (return={}, dt_sec={})", | ||
| name, | ||
| result, | ||
| tf - ti, | ||
| ) | ||
| return result | ||
| @wraps(funk) | ||
| async def _flog_decorator_async(*args: Any, **kwargs: Any) -> T: | ||
| logger_ = logger.opt(depth=7) | ||
| if enter: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-ENTER > '{}' (args={}, kwargs={})", | ||
| name, | ||
| args, | ||
| kwargs, | ||
| ) | ||
| ti = time() | ||
| result: T = await funk(*args, **kwargs) # type: ignore[misc] | ||
| tf = time() | ||
| if exit: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-EXIT < '{}' (return={}, dt_sec={})", | ||
| name, | ||
| result, | ||
| tf - ti, | ||
| ) | ||
| return result | ||
| if asyncio.iscoroutinefunction(funk) or asyncio.iscoroutine(funk): | ||
| return _flog_decorator_async # type: ignore[return-value] | ||
| return _flog_decorator | ||
| return _flog(funk) if funk else _flog # type: ignore[return-value] | ||
| def handlers() -> Dict[int, Handler]: | ||
| """Return all handlers""" | ||
| return logger._core.handlers # type: ignore[no-any-return] | ||
| def reset(level: Optional[Union[str, int]] = None) -> None: | ||
| logger.remove() | ||
| logger.add(_sys.stderr, level=loglevel(level or "debug")) | ||
| __hoisted__ = ( | ||
| "_change_activation", | ||
| "_core", | ||
| "_dynamic_level", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "info", | ||
| "level", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) | ||
| _change_activation = LAGER._change_activation | ||
| _core = LAGER._core | ||
| _find_iter = LAGER._find_iter | ||
| _log = LAGER._log | ||
| _options = LAGER._options | ||
| add = LAGER.add | ||
| bind = LAGER.bind | ||
| catch = LAGER.catch | ||
| complete = LAGER.complete | ||
| configure = LAGER.configure | ||
| contextualize = LAGER.contextualize | ||
| critical = LAGER.critical | ||
| debug = LAGER.debug | ||
| disable = LAGER.disable | ||
| enable = LAGER.enable | ||
| error = LAGER.error | ||
| exception = LAGER.exception | ||
| info = LAGER.info | ||
| level = LAGER.level | ||
| opt = LAGER.opt | ||
| parse = LAGER.parse | ||
| patch = LAGER.patch | ||
| remove = LAGER.remove | ||
| start = LAGER.start | ||
| stop = LAGER.stop | ||
| success = LAGER.success | ||
| trace = LAGER.trace | ||
| warning = LAGER.warning | ||
| __all__ = ( | ||
| "LAGER", | ||
| "LOG", | ||
| "_change_activation", | ||
| "_core", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "flog", | ||
| "handlers", | ||
| "info", | ||
| "lager", | ||
| "level", | ||
| "ln", | ||
| "log", | ||
| "logger", | ||
| "loglevel", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) |
| # -*- coding: utf-8 -*- | ||
| from __future__ import annotations | ||
| from typing import Any | ||
| try: | ||
| import httpx | ||
| _SINKS = [] | ||
| class HttpxSink: | ||
| def __init__(self, url: str, *args: Any, **kwargs: Any) -> None: | ||
| self.url = url | ||
| self.client = httpx.AsyncClient(*args, **kwargs) | ||
| _SINKS.append(self) | ||
| async def __call__(self, msg: Any) -> None: | ||
| httpx.post(self.url, data={"msg": msg}) | ||
| async def handle(self, message: Any) -> None: | ||
| await self.client.post(url=self.url, data={"msg": message}) | ||
| async def await_delete_channels(self) -> None: | ||
| await self.client.aclose() | ||
| except ImportError: | ||
| pass |
| # -*- coding: utf-8 -*- | ||
| """FastAPI logging""" | ||
| from __future__ import annotations | ||
| from typing import List, Optional, Set, Tuple, Union | ||
| from lager.logging import intercept | ||
| __all__ = ("FASTAPI_LOGGERS", "fastapi_intercept") | ||
| FASTAPI_LOGGERS = [ | ||
| "gunicorn", | ||
| "gunicorn.errors", | ||
| "uvicorn", | ||
| "uvicorn.error", | ||
| "fastapi", | ||
| "sqlalchemy", | ||
| ] | ||
| def fastapi_intercept( | ||
| loggers: Optional[Union[List[str], Set[str], Tuple[str, ...]]] = None, | ||
| ) -> None: | ||
| _loggers2intercept = ( | ||
| FASTAPI_LOGGERS if not loggers else sorted(set(*(*FASTAPI_LOGGERS, loggers))) | ||
| ) | ||
| intercept(_loggers2intercept) |
| # -*- coding: utf-8 -*- | ||
| """Lager/Loguru + std logging""" | ||
| from __future__ import annotations | ||
| import logging | ||
| from logging import ( | ||
| BASIC_FORMAT as BASIC_FORMAT, | ||
| CRITICAL as CRITICAL, | ||
| DEBUG as DEBUG, | ||
| ERROR as ERROR, | ||
| FATAL as FATAL, | ||
| INFO as INFO, | ||
| NOTSET as NOTSET, | ||
| WARN as WARN, | ||
| WARNING as WARNING, | ||
| BufferingFormatter as BufferingFormatter, | ||
| FileHandler as FileHandler, | ||
| Filter as Filter, | ||
| Formatter as Formatter, | ||
| Handler as _Handler, | ||
| Logger as _Logger, | ||
| LoggerAdapter as LoggerAdapter, | ||
| LogRecord as LogRecord, | ||
| NullHandler as NullHandler, | ||
| StreamHandler as StreamHandler, | ||
| addLevelName as addLevelName, | ||
| addLevelName as add_level_name, | ||
| basicConfig as basicConfig, | ||
| basicConfig as basic_config, | ||
| captureWarnings as captureWarnings, | ||
| captureWarnings as capture_warnings, | ||
| critical as critical, | ||
| debug as debug, | ||
| disable as disable, | ||
| error as error, | ||
| exception as exception, | ||
| fatal as fatal, | ||
| getLevelName as getLevelName, | ||
| getLevelName as get_level_name, | ||
| getLogger as getLogger, | ||
| getLogger as get_logger, | ||
| getLoggerClass as getLoggerClass, | ||
| getLoggerClass as get_logger_class, | ||
| getLogRecordFactory as getLogRecordFactory, | ||
| getLogRecordFactory as get_log_record_factory, | ||
| info as info, | ||
| lastResort as lastResort, | ||
| lastResort as last_resort, | ||
| log as log, | ||
| makeLogRecord as makeLogRecord, | ||
| makeLogRecord as make_log_record, | ||
| raiseExceptions as raiseExceptions, | ||
| raiseExceptions as raise_exceptions, | ||
| setLoggerClass as setLoggerClass, | ||
| setLoggerClass as set_logger_class, | ||
| setLogRecordFactory as setLogRecordFactory, | ||
| setLogRecordFactory as set_log_record_factory, | ||
| shutdown as shutdown, | ||
| warn as warn, | ||
| warning as warning, | ||
| ) | ||
| from types import TracebackType | ||
| from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, Union | ||
| from typing_extensions import Literal, Self, TypeAlias | ||
| from lager.core import LOG, loglevel | ||
| __all__ = ( | ||
| "BASIC_FORMAT", | ||
| "CRITICAL", | ||
| "DEBUG", | ||
| "ERROR", | ||
| "FATAL", | ||
| "INFO", | ||
| "NOTSET", | ||
| "WARN", | ||
| "WARNING", | ||
| "BufferingFormatter", | ||
| "FileHandler", | ||
| "Filter", | ||
| "Formatter", | ||
| "Handler", | ||
| "LogRecord", | ||
| "Logger", | ||
| "LoggerAdapter", | ||
| "NullHandler", | ||
| "StdLoggingHandler", | ||
| "StreamHandler", | ||
| # lager.logging members | ||
| "__aliases__", | ||
| "addLevelName", | ||
| "add_level_name", | ||
| "basicConfig", | ||
| "basic_config", | ||
| "captureWarnings", | ||
| "capture_warnings", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "error", | ||
| "exception", | ||
| "fatal", | ||
| "getLevelName", | ||
| "getLogRecordFactory", | ||
| "getLogger", | ||
| "getLoggerClass", | ||
| "get_level_name", | ||
| "get_log_record_factory", | ||
| "get_logger", | ||
| "get_logger_class", | ||
| "info", | ||
| "intercept", | ||
| "intercept_all", | ||
| "lastResort", | ||
| "last_resort", | ||
| "log", | ||
| "loggers_dict", | ||
| "makeLogRecord", | ||
| "make_log_record", | ||
| "patch_logging", | ||
| "raiseExceptions", | ||
| "raise_exceptions", | ||
| "setLogRecordFactory", | ||
| "setLoggerClass", | ||
| "set_log_record_factory", | ||
| "set_logger_class", | ||
| "shutdown", | ||
| "warn", | ||
| "warning", | ||
| ) | ||
| # logging snake_case aliases bc I cannot stand camelCase | ||
| __aliases__ = { | ||
| "add_level_name": "addLevelName", | ||
| "basic_config": "basicConfig", | ||
| "capture_warnings": "captureWarnings", | ||
| "get_level_name": "getLevelName", | ||
| "get_log_record_factory": "getLogRecordFactory", | ||
| "get_logger": "getLogger", | ||
| "get_logger_class": "getLoggerClass", | ||
| "last_resort": "lastResort", | ||
| "make_log_record": "makeLogRecord", | ||
| "raise_exceptions": "raiseExceptions", | ||
| "set_log_record_factory": "setLogRecordFactory", | ||
| "set_logger_class": "setLoggerClass", | ||
| } | ||
| _SysExcInfoType: TypeAlias = Union[ | ||
| Tuple[Type[BaseException], BaseException, Union[TracebackType, None]], | ||
| Tuple[None, None, None], | ||
| ] | ||
| _ExcInfoType: TypeAlias = Union[None, bool, _SysExcInfoType, BaseException] | ||
| _ArgsType: TypeAlias = Union[Tuple[object, ...], Mapping[str, object]] | ||
| _FilterType: TypeAlias = Union[Filter, Callable[[LogRecord], bool]] | ||
| _Level: TypeAlias = Union[int, str] | ||
| _FormatStyle: TypeAlias = Literal["%", "{", "$"] | ||
| class Logger(_Logger): | ||
| def __init__(self, name: str, level: _Level = 0) -> None: | ||
| super().__init__(name, level) | ||
| def set_level(self, level: _Level) -> None: | ||
| """snake_case alias for setLevel""" | ||
| self.setLevel(level) | ||
| def is_enabled_for(self, level: int) -> bool: | ||
| """snake_case alias for isEnabledFor""" | ||
| return self.isEnabledFor(level) | ||
| def get_effective_level(self) -> int: | ||
| """snake_case alias for getEffectiveLevel""" | ||
| return self.getEffectiveLevel() | ||
| def get_child(self, suffix: str) -> Self: | ||
| """snake_case alias for getChild""" | ||
| return self.getChild(suffix) | ||
| def find_caller( | ||
| self, stack_info: bool = False, stacklevel: int = 1 | ||
| ) -> Tuple[str, int, str, Union[str, None]]: | ||
| """snake_case alias for findCaller""" | ||
| return self.findCaller(stack_info, stacklevel) | ||
| def add_handler(self, hdlr: Handler) -> None: | ||
| """snake_case alias for addHandler""" | ||
| return self.addHandler(hdlr) | ||
| def remove_handler(self, hdlr: Handler) -> None: | ||
| """snake_case alias for removeHandler""" | ||
| return self.removeHandler(hdlr) | ||
| def make_record( | ||
| self, | ||
| name: str, | ||
| level: int, | ||
| fn: str, | ||
| lno: int, | ||
| msg: object, | ||
| args: _ArgsType, | ||
| exc_info: Union[_SysExcInfoType, None], | ||
| func: Optional[str] = None, | ||
| extra: Union[Mapping[str, object], None] = None, | ||
| sinfo: Optional[str] = None, | ||
| ) -> LogRecord: | ||
| return self.makeRecord( | ||
| name, level, fn, lno, msg, args, exc_info, func, extra, sinfo | ||
| ) | ||
| def has_handlers(self) -> bool: | ||
| """snake_case alias for hasHandlers""" | ||
| return self.hasHandlers() | ||
| def call_handlers(self, record: LogRecord) -> None: | ||
| """snake_case alias for callHandlers""" | ||
| return self.callHandlers(record) | ||
| class Handler(_Handler): | ||
| def __init__(self, level: _Level = 0) -> None: | ||
| super().__init__(level) | ||
| def create_lock(self) -> None: | ||
| """snake_case alias for createLock""" | ||
| return self.createLock() | ||
| def set_level(self, level: _Level) -> None: | ||
| """snake_case alias for setLevel""" | ||
| return self.setLevel(level) | ||
| def set_formatter(self, fmt: Union[Formatter, None]) -> None: | ||
| """snake_case alias for setFormatter""" | ||
| return self.setFormatter(fmt) | ||
| def handle_error(self, record: LogRecord) -> None: | ||
| """snake_case alias for handleError""" | ||
| return self.handleError(record) | ||
| # ===================================================================================== | ||
| def patch_logging() -> None: | ||
| for k, v in __aliases__.items(): | ||
| setattr(logging, k, getattr(logging, v)) | ||
| class StdLoggingHandler(logging.Handler): | ||
| """Logging intercept handler""" | ||
| def emit(self, record: logging.LogRecord) -> None: | ||
| # Get corresponding Loguru level if it exists | ||
| try: | ||
| level = LOG.level(record.levelname).name | ||
| except AttributeError: | ||
| level = loglevel(record.levelno) | ||
| # Find caller from where originated the logging call | ||
| frame = logging.currentframe() | ||
| depth = 2 | ||
| while ( | ||
| frame.f_code.co_filename # pyright: ignore[reportOptionalMemberAccess] | ||
| == logging.__file__ | ||
| ): | ||
| frame = frame.f_back # type: ignore[assignment] | ||
| depth += 1 | ||
| LOG.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage()) | ||
| def _logger_dict() -> Any: | ||
| return logging.root.manager.loggerDict | ||
| def loggers_dict() -> Dict[str, logging.Logger]: | ||
| return {name: logging.getLogger(name) for name in _logger_dict()} | ||
| def intercept(loggers: List[str]) -> None: | ||
| for logger in loggers: | ||
| std_logger = logging.getLogger(logger) | ||
| std_logger.handlers = [StdLoggingHandler()] | ||
| def intercept_all() -> None: | ||
| intercept(list(loggers_dict().keys())) |
| # -*- coding: utf-8 -*- | ||
| """Lager & pydantic""" | ||
| from __future__ import annotations | ||
| from typing import TYPE_CHECKING, Any, Dict, Optional, Type, Union | ||
| from jsonbourne.pydantic import JsonBaseModel | ||
| if TYPE_CHECKING: | ||
| from datetime import datetime, timedelta | ||
| from types import TracebackType | ||
| class RecordFile(JsonBaseModel): | ||
| name: str | ||
| path: str | ||
| class RecordLevel(JsonBaseModel): | ||
| name: str | ||
| no: int | ||
| icon: str | ||
| class RecordThread(JsonBaseModel): | ||
| id: int | ||
| name: str | ||
| class RecordProcess(JsonBaseModel): | ||
| id: int | ||
| name: str | ||
| class RecordException(JsonBaseModel): | ||
| type: Optional[Type[BaseException]] | ||
| value: Optional[BaseException] | ||
| traceback: Optional[TracebackType] | ||
| class Record(JsonBaseModel): | ||
| elapsed: timedelta | ||
| exception: Optional[RecordException] | ||
| extra: Dict[Any, Any] | ||
| file: RecordFile | ||
| function: str | ||
| level: RecordLevel | ||
| line: int | ||
| message: str | ||
| module: str | ||
| name: Union[str, None] | ||
| process: RecordProcess | ||
| thread: RecordThread | ||
| time: datetime | ||
| class Message(JsonBaseModel): | ||
| record: Record |
+8
-6
@@ -1,5 +0,7 @@ | ||
| MIT License | ||
| dgpy-libs | ||
| Copyright (c) 2022 | ||
| The MIT License (MIT) | ||
| Copyright (c) 2019-2025 Dynamic Graphics Inc (dgi) | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
@@ -12,4 +14,4 @@ of this software and associated documentation files (the "Software"), to deal | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| The above copyright notice and this permission notice shall be included in | ||
| all copies or substantial portions of the Software. | ||
@@ -21,3 +23,3 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. |
+11
-16
@@ -1,11 +0,8 @@ | ||
| Metadata-Version: 2.1 | ||
| Metadata-Version: 2.4 | ||
| Name: lager | ||
| Version: 0.18.2 | ||
| Version: 0.19.0 | ||
| Summary: EZ-PZ logging based on loguru | ||
| Home-page: https://github.com/dynamic-graphics-inc/dgpy-libs/tree/main/libs/lager | ||
| License: MIT | ||
| Keywords: logging,dgpy,dgi,loguru,beer | ||
| Author: jesse rubin | ||
| Author-email: jesse@dgi.com | ||
| Requires-Python: >=3.8,<4.0 | ||
| Author-email: jesse rubin <jesse@dgi.com> | ||
| License-File: LICENSE | ||
| Keywords: beer,dgi,dgpy,logging,loguru | ||
| Classifier: Development Status :: 5 - Production/Stable | ||
@@ -15,4 +12,3 @@ Classifier: Intended Audience :: Developers | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3 :: Only | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
@@ -22,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Classifier: Typing :: Typed | ||
| Requires-Dist: loguru (>=0.7.0) | ||
| Requires-Dist: typing-extensions (>=4.5.0,<5.0.0) | ||
| Project-URL: Repository, https://github.com/dynamic-graphics-inc/dgpy-libs | ||
| Requires-Python: <4.0,>=3.9 | ||
| Requires-Dist: loguru>=0.7 | ||
| Requires-Dist: typing-extensions<5,>=4.5 | ||
| Description-Content-Type: text/markdown | ||
@@ -34,3 +30,3 @@ | ||
| # Lager :beer: | ||
| # lager :beer: | ||
@@ -62,2 +58,1 @@ [](https://img.shields.io/pypi/wheel/lager.svg) | ||
| 2022-07-21 08:38:20.263 | INFO | __main__:<cell line: 3>:3 - info | ||
+34
-35
@@ -1,13 +0,15 @@ | ||
| [tool.poetry] | ||
| [build-system] | ||
| build-backend = "hatchling.build" | ||
| requires = [ "hatchling" ] | ||
| [project] | ||
| name = "lager" | ||
| version = "0.18.2" | ||
| version = "0.19.0" | ||
| description = "EZ-PZ logging based on loguru" | ||
| authors = ["jesse rubin <jesse@dgi.com>"] | ||
| license = "MIT" | ||
| repository = "https://github.com/dynamic-graphics-inc/dgpy-libs" | ||
| homepage = "https://github.com/dynamic-graphics-inc/dgpy-libs/tree/main/libs/lager" | ||
| readme = 'README.md' | ||
| packages = [ | ||
| { include = "lager", from = "." }, | ||
| ] | ||
| readme = "README.md" | ||
| keywords = [ "beer", "dgi", "dgpy", "logging", "loguru" ] | ||
| authors = [ { name = "jesse rubin", email = "jesse@dgi.com" } ] | ||
| requires-python = ">=3.9,<4.0" | ||
| classifiers = [ | ||
@@ -18,38 +20,35 @@ "Development Status :: 5 - Production/Stable", | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3.7", | ||
| "Programming Language :: Python :: 3.8", | ||
| "Programming Language :: Python :: 3 :: Only", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Typing :: Typed", | ||
| ] | ||
| keywords = [ | ||
| "logging", | ||
| "dgpy", | ||
| "dgi", | ||
| "loguru", | ||
| "beer", | ||
| ] | ||
| dependencies = [ "loguru>=0.7", "typing-extensions>=4.5,<5" ] | ||
| [tool.poetry.dependencies] | ||
| python = "^3.8" | ||
| loguru = ">=0.7.0" | ||
| typing-extensions = "^4.5.0" | ||
| [tool.hatch] | ||
| [tool.hatch.metadata] | ||
| allow-direct-references = true | ||
| [tool.poetry.dev-dependencies] | ||
| pytest = "^8.0.0" | ||
| pytest-cov = "^4.1.0" | ||
| [tool.hatch.build.targets.wheel] | ||
| packages = [ "src/lager" ] | ||
| [tool.poetry.group.dev.dependencies] | ||
| typing-extensions = "^4.5.0" | ||
| [tool.hatch.build.targets.sdist] | ||
| include = [ | ||
| "src", | ||
| "pyproject.toml", | ||
| "README.md", | ||
| "LICENSE", | ||
| ] | ||
| [build-system] | ||
| requires = ["poetry-core>=1.0.0"] | ||
| build-backend = "poetry.core.masonry.api" | ||
| [tool.ruff] | ||
| extend = "../../pyproject.toml" | ||
| [tool.coverage.run] | ||
| source = ['lager'] | ||
| source = [ 'lager' ] | ||
| branch = true | ||
| context = '${CONTEXT}' | ||
| omit = ["**/__main__.py"] | ||
| omit = [ "**/__main__.py" ] | ||
@@ -70,3 +69,3 @@ [tool.coverage.report] | ||
| [tool.ruff] | ||
| extend = "../../pyproject.toml" | ||
| [tool] | ||
| dev-dependencies = [ "typing-extensions>=4.5.0,<5.0.0" ] |
+1
-1
@@ -5,3 +5,3 @@ <a href="https://github.com/dynamic-graphics-inc/dgpy-libs"> | ||
| # Lager :beer: | ||
| # lager :beer: | ||
@@ -8,0 +8,0 @@ [](https://img.shields.io/pypi/wheel/lager.svg) |
| # -*- coding: utf-8 -*- | ||
| """Package metadata/info""" | ||
| from __future__ import annotations | ||
| __all__ = ("__title__", "__description__", "__pkgroot__", "__version__") | ||
| __title__ = "lager" | ||
| __description__ = "EZ-PZ logging based on loguru" | ||
| __pkgroot__ = __file__.replace("__about__.py", "").rstrip("/\\") | ||
| __version__ = "0.18.2" |
| # -*- coding: utf-8 -*- | ||
| """Python lager brewed by a loguru""" | ||
| from __future__ import annotations | ||
| from lager import logging | ||
| from lager.__about__ import __version__ | ||
| from lager.const import LAGER_PORT, LOGURU_DEFAULT_FMT, TORNADO_FMT | ||
| from lager.core import ( | ||
| LAGER, | ||
| LN, | ||
| LOG, | ||
| _change_activation, | ||
| _core, | ||
| _find_iter, | ||
| _log, | ||
| _options, | ||
| add, | ||
| bind, | ||
| catch, | ||
| complete, | ||
| configure, | ||
| contextualize, | ||
| critical, | ||
| debug, | ||
| disable, | ||
| enable, | ||
| error, | ||
| exception, | ||
| flog, | ||
| handlers, | ||
| info, | ||
| lager, | ||
| level, | ||
| ln, | ||
| log, | ||
| logger, | ||
| loglevel, | ||
| opt, | ||
| parse, | ||
| patch, | ||
| remove, | ||
| reset, | ||
| start, | ||
| stop, | ||
| success, | ||
| trace, | ||
| warning, | ||
| ) | ||
| __all__ = ( | ||
| "__version__", | ||
| "LAGER_PORT", | ||
| "LOGURU_DEFAULT_FMT", | ||
| "TORNADO_FMT", | ||
| "loglevel", | ||
| "handlers", | ||
| "flog", | ||
| "logger", | ||
| "logging", | ||
| "lager", | ||
| "LAGER", | ||
| "LOG", | ||
| "log", | ||
| "ln", | ||
| "LN", | ||
| "reset", | ||
| ############# | ||
| ## HOISTED ## | ||
| ############# | ||
| "_change_activation", | ||
| "_core", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "info", | ||
| "level", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) |
| # -*- coding: utf-8 -*- | ||
| """pkg entry ~ `python -m lager`""" | ||
| from __future__ import annotations | ||
| import sys | ||
| from lager.__about__ import __pkgroot__, __title__, __version__ | ||
| def main() -> None: | ||
| """Print package metadata""" | ||
| import json | ||
| sys.stdout.write( | ||
| json.dumps( | ||
| { | ||
| "package": __title__, | ||
| "version": __version__, | ||
| "pkgroot": __pkgroot__, | ||
| }, | ||
| indent=2, | ||
| ) | ||
| ) | ||
| if __name__ == "__main__": | ||
| main() |
| # -*- coding: utf-8 -*- | ||
| """Package metadata/info""" | ||
| from __future__ import annotations | ||
| import warnings | ||
| from lager.__about__ import __description__, __pkgroot__, __title__, __version__ | ||
| warnings.warn( | ||
| "lager._meta is deprecated, use lager.__about__ instead", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| __all__ = ("__title__", "__description__", "__pkgroot__", "__version__") |
| # -*- coding: utf-8 -*- | ||
| """Constants go here!""" | ||
| from __future__ import annotations | ||
| from typing import Dict | ||
| LAGER_PORT = 52437 | ||
| TORNADO_FMT = "".join( | ||
| [ | ||
| "<level>", | ||
| "[{level.name[0]} ", | ||
| "{time:YYMMDDTHH:mm:ss} ", | ||
| "{name}:{module}:{line}]", | ||
| "</level> ", | ||
| "{message}", | ||
| ] | ||
| ) | ||
| LOGURU_DEFAULT_FMT = "".join( | ||
| [ | ||
| "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green>", | ||
| " | ", | ||
| "<level>{level: <8}</level>", | ||
| " | ", | ||
| "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan>", | ||
| " - ", | ||
| "<level>{message}</level>", | ||
| ] | ||
| ) | ||
| LOG_LEVELS: Dict[str, str] = { | ||
| "notset": "NOTSET", | ||
| "n": "NOTSET", | ||
| "debug": "DEBUG", | ||
| "d": "DEBUG", | ||
| "info": "INFO", | ||
| "i": "INFO", | ||
| "s": "SUCCESS", | ||
| "success": "SUCCESS", | ||
| "warning": "WARNING", | ||
| "warn": "WARNING", | ||
| "w": "WARNING", | ||
| "error": "ERROR", | ||
| "e": "ERROR", | ||
| "critical": "CRITICAL", | ||
| "fatal": "CRITICAL", | ||
| "c": "CRITICAL", | ||
| # enum/enum-strings | ||
| "0": "NOTSET", | ||
| "10": "DEBUG", | ||
| "20": "INFO", | ||
| "25": "SUCCESS", | ||
| "30": "WARNING", | ||
| "40": "ERROR", | ||
| "50": "CRITICAL", | ||
| } |
-299
| # -*- coding: utf-8 -*- | ||
| """Python lager brewed by a loguru""" | ||
| from __future__ import annotations | ||
| import asyncio | ||
| import sys as _sys | ||
| from functools import wraps | ||
| from time import time | ||
| from typing import Any, Callable, Dict, Optional, TypeVar, Union | ||
| from loguru import logger as logger | ||
| from loguru._handler import Handler | ||
| from lager.const import LOG_LEVELS | ||
| T = TypeVar("T") | ||
| try: | ||
| import orjson | ||
| def _stringify_new_line(serializable: Any) -> str: | ||
| return orjson.dumps(serializable, option=orjson.OPT_APPEND_NEWLINE).decode( | ||
| "utf-8" | ||
| ) | ||
| def _stringify_no_new_line(serializable: Any) -> str: | ||
| return f"{orjson.dumps(serializable).decode('utf-8')}\n" | ||
| _stringify = ( | ||
| _stringify_new_line | ||
| if hasattr(orjson, "OPT_APPEND_NEWLINE") | ||
| else _stringify_no_new_line | ||
| ) | ||
| def _serialize_record(text: str, record: Dict[str, Any]) -> str: | ||
| exception = record["exception"] | ||
| if exception is not None: | ||
| exception = { | ||
| "type": None if exception.type is None else exception.type.__name__, | ||
| "value": exception.value, | ||
| "traceback": bool(record["exception"].traceback), | ||
| } | ||
| serializable = { | ||
| "text": text, | ||
| "record": { | ||
| "elapsed": { | ||
| "repr": record["elapsed"], | ||
| "seconds": record["elapsed"].total_seconds(), | ||
| }, | ||
| "exception": exception, | ||
| "extra": record["extra"], | ||
| "file": { | ||
| "name": record["file"].name, | ||
| "path": record["file"].path, | ||
| }, | ||
| "function": record["function"], | ||
| "level": { | ||
| "icon": record["level"].icon, | ||
| "name": record["level"].name, | ||
| "no": record["level"].no, | ||
| }, | ||
| "line": record["line"], | ||
| "message": record["message"], | ||
| "module": record["module"], | ||
| "name": record["name"], | ||
| "process": { | ||
| "id": record["process"].id, | ||
| "name": record["process"].name, | ||
| }, | ||
| "thread": { | ||
| "id": record["thread"].id, | ||
| "name": record["thread"].name, | ||
| }, | ||
| "time": { | ||
| "repr": record["time"], | ||
| "timestamp": record["time"].timestamp(), | ||
| }, | ||
| }, | ||
| } | ||
| return _stringify(serializable) | ||
| Handler._serialize_record = staticmethod(_serialize_record) | ||
| except ModuleNotFoundError: | ||
| pass | ||
| # lager/logger aliases | ||
| log = LOG = logger | ||
| lager = LAGER = logger | ||
| ln = LN = logger # ln => natural log | ||
| def loglevel(level: Union[str, int]) -> str: | ||
| """Convert log-level abrev to a valid loguru log level""" | ||
| return str(LOG_LEVELS[str(level).strip("'").strip('"').lower()]) | ||
| def flog( | ||
| funk: Optional[Callable[..., T]] = None, | ||
| level: Union[str, int] = "debug", | ||
| enter: bool = True, | ||
| exit: bool = True, | ||
| ) -> T: | ||
| """Log function (sync/async) enter and exit using this decorator | ||
| Args: | ||
| funk (Callable): Function to decorate | ||
| level (Union[int, str]): Log level | ||
| enter (bool): Log function entry if True | ||
| exit (bool): Log function exit if False | ||
| Returns: | ||
| A wrapped function that now has logging! | ||
| Usage: | ||
| # SYNC | ||
| @flog | ||
| def add(a, b): | ||
| return a + b | ||
| add(1, 4) | ||
| # ASYNC | ||
| @flog | ||
| async def add_async(a, b): | ||
| return a + b | ||
| import asyncio | ||
| asyncio.run(add_async(1, 4)) | ||
| """ | ||
| def _flog(funk: Callable[..., T]) -> Callable[..., T]: | ||
| name = funk.__name__ | ||
| @wraps(funk) | ||
| def _flog_decorator(*args: Any, **kwargs: Any) -> T: | ||
| logger_ = logger.opt(depth=1) | ||
| if enter: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-ENTER > '{}' (args={}, kwargs={})", | ||
| name, | ||
| args, | ||
| kwargs, | ||
| ) | ||
| ti = time() | ||
| result = funk(*args, **kwargs) | ||
| tf = time() | ||
| if exit: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-EXIT < '{}' (return={}, dt_sec={})", | ||
| name, | ||
| result, | ||
| tf - ti, | ||
| ) | ||
| return result | ||
| @wraps(funk) | ||
| async def _flog_decorator_async(*args: Any, **kwargs: Any) -> T: | ||
| logger_ = logger.opt(depth=7) | ||
| if enter: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-ENTER > '{}' (args={}, kwargs={})", | ||
| name, | ||
| args, | ||
| kwargs, | ||
| ) | ||
| ti = time() | ||
| result: T = await funk(*args, **kwargs) # type: ignore[misc] | ||
| tf = time() | ||
| if exit: | ||
| logger_.log( | ||
| loglevel(level), | ||
| "FLOG-EXIT < '{}' (return={}, dt_sec={})", | ||
| name, | ||
| result, | ||
| tf - ti, | ||
| ) | ||
| return result | ||
| if asyncio.iscoroutinefunction(funk) or asyncio.iscoroutine(funk): | ||
| return _flog_decorator_async # type: ignore[return-value] | ||
| return _flog_decorator | ||
| return _flog(funk) if funk else _flog # type: ignore[return-value] | ||
| def handlers() -> Dict[int, Handler]: | ||
| """Return all handlers""" | ||
| return logger._core.handlers # type: ignore[no-any-return] | ||
| def reset(level: Optional[Union[str, int]] = None) -> None: | ||
| logger.remove() | ||
| logger.add(_sys.stderr, level=loglevel(level or "debug")) | ||
| __hoisted__ = ( | ||
| "_change_activation", | ||
| "_core", | ||
| "_dynamic_level", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "info", | ||
| "level", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) | ||
| _change_activation = LAGER._change_activation | ||
| _core = LAGER._core | ||
| _find_iter = LAGER._find_iter | ||
| _log = LAGER._log | ||
| _options = LAGER._options | ||
| add = LAGER.add | ||
| bind = LAGER.bind | ||
| catch = LAGER.catch | ||
| complete = LAGER.complete | ||
| configure = LAGER.configure | ||
| contextualize = LAGER.contextualize | ||
| critical = LAGER.critical | ||
| debug = LAGER.debug | ||
| disable = LAGER.disable | ||
| enable = LAGER.enable | ||
| error = LAGER.error | ||
| exception = LAGER.exception | ||
| info = LAGER.info | ||
| level = LAGER.level | ||
| opt = LAGER.opt | ||
| parse = LAGER.parse | ||
| patch = LAGER.patch | ||
| remove = LAGER.remove | ||
| start = LAGER.start | ||
| stop = LAGER.stop | ||
| success = LAGER.success | ||
| trace = LAGER.trace | ||
| warning = LAGER.warning | ||
| __all__ = ( | ||
| "LAGER", | ||
| "LOG", | ||
| "_change_activation", | ||
| "_core", | ||
| "_find_iter", | ||
| "_log", | ||
| "_options", | ||
| "add", | ||
| "bind", | ||
| "catch", | ||
| "complete", | ||
| "configure", | ||
| "contextualize", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "enable", | ||
| "error", | ||
| "exception", | ||
| "flog", | ||
| "handlers", | ||
| "info", | ||
| "lager", | ||
| "level", | ||
| "ln", | ||
| "log", | ||
| "logger", | ||
| "loglevel", | ||
| "opt", | ||
| "parse", | ||
| "patch", | ||
| "remove", | ||
| "start", | ||
| "stop", | ||
| "success", | ||
| "trace", | ||
| "warning", | ||
| ) |
-28
| # -*- coding: utf-8 -*- | ||
| from __future__ import annotations | ||
| from typing import Any | ||
| try: | ||
| import httpx | ||
| _SINKS = [] | ||
| class HttpxSink: | ||
| def __init__(self, url: str, *args: Any, **kwargs: Any) -> None: | ||
| self.url = url | ||
| self.client = httpx.AsyncClient(*args, **kwargs) | ||
| _SINKS.append(self) | ||
| async def __call__(self, msg: Any) -> None: | ||
| httpx.post(self.url, data={"msg": msg}) | ||
| async def handle(self, message: Any) -> None: | ||
| await self.client.post(url=self.url, data={"msg": message}) | ||
| async def await_delete_channels(self) -> None: | ||
| await self.client.aclose() | ||
| except ImportError: | ||
| pass |
| # -*- coding: utf-8 -*- | ||
| """FastAPI logging""" | ||
| from __future__ import annotations | ||
| from typing import List, Optional, Set, Tuple, Union | ||
| from lager.logging import intercept | ||
| __all__ = ("FASTAPI_LOGGERS", "fastapi_intercept") | ||
| FASTAPI_LOGGERS = [ | ||
| "gunicorn", | ||
| "gunicorn.errors", | ||
| "uvicorn", | ||
| "uvicorn.error", | ||
| "fastapi", | ||
| "sqlalchemy", | ||
| ] | ||
| def fastapi_intercept( | ||
| loggers: Optional[Union[List[str], Set[str], Tuple[str, ...]]] = None | ||
| ) -> None: | ||
| _loggers2intercept = ( | ||
| FASTAPI_LOGGERS if not loggers else sorted(set(*(*FASTAPI_LOGGERS, loggers))) | ||
| ) | ||
| intercept(_loggers2intercept) |
| # -*- coding: utf-8 -*- | ||
| """Lager/Loguru + std logging""" | ||
| from __future__ import annotations | ||
| import logging | ||
| from logging import ( | ||
| BASIC_FORMAT as BASIC_FORMAT, | ||
| CRITICAL as CRITICAL, | ||
| DEBUG as DEBUG, | ||
| ERROR as ERROR, | ||
| FATAL as FATAL, | ||
| INFO as INFO, | ||
| NOTSET as NOTSET, | ||
| WARN as WARN, | ||
| WARNING as WARNING, | ||
| BufferingFormatter as BufferingFormatter, | ||
| FileHandler as FileHandler, | ||
| Filter as Filter, | ||
| Formatter as Formatter, | ||
| Handler as _Handler, | ||
| Logger as _Logger, | ||
| LoggerAdapter as LoggerAdapter, | ||
| LogRecord as LogRecord, | ||
| NullHandler as NullHandler, | ||
| StreamHandler as StreamHandler, | ||
| addLevelName as addLevelName, | ||
| addLevelName as add_level_name, | ||
| basicConfig as basicConfig, | ||
| basicConfig as basic_config, | ||
| captureWarnings as captureWarnings, | ||
| captureWarnings as capture_warnings, | ||
| critical as critical, | ||
| debug as debug, | ||
| disable as disable, | ||
| error as error, | ||
| exception as exception, | ||
| fatal as fatal, | ||
| getLevelName as getLevelName, | ||
| getLevelName as get_level_name, | ||
| getLogger as getLogger, | ||
| getLogger as get_logger, | ||
| getLoggerClass as getLoggerClass, | ||
| getLoggerClass as get_logger_class, | ||
| getLogRecordFactory as getLogRecordFactory, | ||
| getLogRecordFactory as get_log_record_factory, | ||
| info as info, | ||
| lastResort as lastResort, | ||
| lastResort as last_resort, | ||
| log as log, | ||
| makeLogRecord as makeLogRecord, | ||
| makeLogRecord as make_log_record, | ||
| raiseExceptions as raiseExceptions, | ||
| raiseExceptions as raise_exceptions, | ||
| setLoggerClass as setLoggerClass, | ||
| setLoggerClass as set_logger_class, | ||
| setLogRecordFactory as setLogRecordFactory, | ||
| setLogRecordFactory as set_log_record_factory, | ||
| shutdown as shutdown, | ||
| warn as warn, | ||
| warning as warning, | ||
| ) | ||
| from types import TracebackType | ||
| from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, Union | ||
| from typing_extensions import Literal, Self, TypeAlias | ||
| from lager.core import LOG, loglevel | ||
| __all__ = ( | ||
| "BASIC_FORMAT", | ||
| "BufferingFormatter", | ||
| "CRITICAL", | ||
| "DEBUG", | ||
| "ERROR", | ||
| "FATAL", | ||
| "FileHandler", | ||
| "Filter", | ||
| "Formatter", | ||
| "Handler", | ||
| "INFO", | ||
| "LogRecord", | ||
| "Logger", | ||
| "LoggerAdapter", | ||
| "NOTSET", | ||
| "NullHandler", | ||
| "StreamHandler", | ||
| "WARN", | ||
| "WARNING", | ||
| "addLevelName", | ||
| "add_level_name", | ||
| "basicConfig", | ||
| "basic_config", | ||
| "captureWarnings", | ||
| "capture_warnings", | ||
| "critical", | ||
| "debug", | ||
| "disable", | ||
| "error", | ||
| "exception", | ||
| "fatal", | ||
| "getLevelName", | ||
| "getLogRecordFactory", | ||
| "getLogger", | ||
| "getLoggerClass", | ||
| "get_level_name", | ||
| "get_log_record_factory", | ||
| "get_logger", | ||
| "get_logger_class", | ||
| "info", | ||
| "lastResort", | ||
| "last_resort", | ||
| "log", | ||
| "makeLogRecord", | ||
| "make_log_record", | ||
| "raiseExceptions", | ||
| "raise_exceptions", | ||
| "setLogRecordFactory", | ||
| "setLoggerClass", | ||
| "set_log_record_factory", | ||
| "set_logger_class", | ||
| "shutdown", | ||
| "warn", | ||
| "warning", | ||
| # lager.logging members | ||
| "__aliases__", | ||
| "StdLoggingHandler", | ||
| "loggers_dict", | ||
| "intercept", | ||
| "intercept_all", | ||
| "patch_logging", | ||
| ) | ||
| # logging snake_case aliases bc I cannot stand camelCase | ||
| __aliases__ = { | ||
| "add_level_name": "addLevelName", | ||
| "basic_config": "basicConfig", | ||
| "capture_warnings": "captureWarnings", | ||
| "get_level_name": "getLevelName", | ||
| "get_log_record_factory": "getLogRecordFactory", | ||
| "get_logger": "getLogger", | ||
| "get_logger_class": "getLoggerClass", | ||
| "last_resort": "lastResort", | ||
| "make_log_record": "makeLogRecord", | ||
| "raise_exceptions": "raiseExceptions", | ||
| "set_log_record_factory": "setLogRecordFactory", | ||
| "set_logger_class": "setLoggerClass", | ||
| } | ||
| _SysExcInfoType: TypeAlias = Union[ | ||
| Tuple[Type[BaseException], BaseException, Union[TracebackType, None]], | ||
| Tuple[None, None, None], | ||
| ] | ||
| _ExcInfoType: TypeAlias = Union[None, bool, _SysExcInfoType, BaseException] | ||
| _ArgsType: TypeAlias = Union[Tuple[object, ...], Mapping[str, object]] | ||
| _FilterType: TypeAlias = Union[Filter, Callable[[LogRecord], bool]] | ||
| _Level: TypeAlias = Union[int, str] | ||
| _FormatStyle: TypeAlias = Literal["%", "{", "$"] | ||
| class Logger(_Logger): | ||
| def __init__(self, name: str, level: _Level = 0) -> None: | ||
| super().__init__(name, level) | ||
| def set_level(self, level: _Level) -> None: | ||
| """snake_case alias for setLevel""" | ||
| self.setLevel(level) | ||
| def is_enabled_for(self, level: int) -> bool: | ||
| """snake_case alias for isEnabledFor""" | ||
| return self.isEnabledFor(level) | ||
| def get_effective_level(self) -> int: | ||
| """snake_case alias for getEffectiveLevel""" | ||
| return self.getEffectiveLevel() | ||
| def get_child(self, suffix: str) -> Self: | ||
| """snake_case alias for getChild""" | ||
| return self.getChild(suffix) | ||
| def find_caller( | ||
| self, stack_info: bool = False, stacklevel: int = 1 | ||
| ) -> Tuple[str, int, str, Union[str, None]]: | ||
| """snake_case alias for findCaller""" | ||
| return self.findCaller(stack_info, stacklevel) | ||
| def add_handler(self, hdlr: Handler) -> None: | ||
| """snake_case alias for addHandler""" | ||
| return self.addHandler(hdlr) | ||
| def remove_handler(self, hdlr: Handler) -> None: | ||
| """snake_case alias for removeHandler""" | ||
| return self.removeHandler(hdlr) | ||
| def make_record( | ||
| self, | ||
| name: str, | ||
| level: int, | ||
| fn: str, | ||
| lno: int, | ||
| msg: object, | ||
| args: _ArgsType, | ||
| exc_info: Union[_SysExcInfoType, None], | ||
| func: Optional[str] = None, | ||
| extra: Union[Mapping[str, object], None] = None, | ||
| sinfo: Optional[str] = None, | ||
| ) -> LogRecord: | ||
| return self.makeRecord( | ||
| name, level, fn, lno, msg, args, exc_info, func, extra, sinfo | ||
| ) | ||
| def has_handlers(self) -> bool: | ||
| """snake_case alias for hasHandlers""" | ||
| return self.hasHandlers() | ||
| def call_handlers(self, record: LogRecord) -> None: | ||
| """snake_case alias for callHandlers""" | ||
| return self.callHandlers(record) | ||
| class Handler(_Handler): | ||
| def __init__(self, level: _Level = 0) -> None: | ||
| super().__init__(level) | ||
| def create_lock(self) -> None: | ||
| """snake_case alias for createLock""" | ||
| return self.createLock() | ||
| def set_level(self, level: _Level) -> None: | ||
| """snake_case alias for setLevel""" | ||
| return self.setLevel(level) | ||
| def set_formatter(self, fmt: Union[Formatter, None]) -> None: | ||
| """snake_case alias for setFormatter""" | ||
| return self.setFormatter(fmt) | ||
| def handle_error(self, record: LogRecord) -> None: | ||
| """snake_case alias for handleError""" | ||
| return self.handleError(record) | ||
| # ===================================================================================== | ||
| def patch_logging() -> None: | ||
| for k, v in __aliases__.items(): | ||
| setattr(logging, k, getattr(logging, v)) | ||
| class StdLoggingHandler(logging.Handler): | ||
| """Logging intercept handler""" | ||
| def emit(self, record: logging.LogRecord) -> None: | ||
| # Get corresponding Loguru level if it exists | ||
| try: | ||
| level = LOG.level(record.levelname).name | ||
| except AttributeError: | ||
| level = loglevel(record.levelno) | ||
| # Find caller from where originated the logging call | ||
| frame = logging.currentframe() | ||
| depth = 2 | ||
| while ( | ||
| frame.f_code.co_filename # pyright: ignore[reportOptionalMemberAccess] | ||
| == logging.__file__ | ||
| ): | ||
| frame = frame.f_back # type: ignore[assignment] | ||
| depth += 1 | ||
| LOG.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage()) | ||
| def _logger_dict() -> Any: | ||
| return logging.root.manager.loggerDict | ||
| def loggers_dict() -> Dict[str, logging.Logger]: | ||
| return {name: logging.getLogger(name) for name in _logger_dict()} | ||
| def intercept(loggers: List[str]) -> None: | ||
| for logger in loggers: | ||
| std_logger = logging.getLogger(logger) | ||
| std_logger.handlers = [StdLoggingHandler()] | ||
| def intercept_all() -> None: | ||
| intercept(list(loggers_dict().keys())) |
| # -*- coding: utf-8 -*- | ||
| """Lager & pydantic""" | ||
| from __future__ import annotations | ||
| from datetime import datetime, timedelta | ||
| from types import TracebackType | ||
| from typing import Any, Dict, Optional, Type, Union | ||
| from jsonbourne.pydantic import JsonBaseModel | ||
| class RecordFile(JsonBaseModel): | ||
| name: str | ||
| path: str | ||
| class RecordLevel(JsonBaseModel): | ||
| name: str | ||
| no: int | ||
| icon: str | ||
| class RecordThread(JsonBaseModel): | ||
| id: int | ||
| name: str | ||
| class RecordProcess(JsonBaseModel): | ||
| id: int | ||
| name: str | ||
| class RecordException(JsonBaseModel): | ||
| type: Optional[Type[BaseException]] | ||
| value: Optional[BaseException] | ||
| traceback: Optional[TracebackType] | ||
| class Record(JsonBaseModel): | ||
| elapsed: timedelta | ||
| exception: Optional[RecordException] | ||
| extra: Dict[Any, Any] | ||
| file: RecordFile | ||
| function: str | ||
| level: RecordLevel | ||
| line: int | ||
| message: str | ||
| module: str | ||
| name: Union[str, None] | ||
| process: RecordProcess | ||
| thread: RecordThread | ||
| time: datetime | ||
| class Message(JsonBaseModel): | ||
| record: Record |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
29151
4.88%16
6.67%778
0.13%