From 41fb417952dc366c950c0ab57893d9791cbcd931 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 5 Mar 2026 12:35:56 +0100 Subject: [PATCH] :recycle: :wrench: wip on swich to loguru --- client/ayon_core/cli.py | 12 +++-- client/ayon_core/lib/log.py | 94 ++++++++++++++++++++++++++++++++++++- pyproject.toml | 5 +- 3 files changed, 103 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index 88c54e6059d..784ba74a06c 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -24,6 +24,8 @@ ) +log = Logger.get_logger("CLI") + @click.group(invoke_without_command=True) @click.pass_context @click.option( @@ -332,10 +334,10 @@ def main(*args, **kwargs): sys.path.insert(0, path) os.environ["PYTHONPATH"] = os.pathsep.join(split_paths) - print(">>> loading environments ...") - print(" - global AYON ...") + log.info("loading environments ...") + log.debug("[yellow]- global AYON ...[/yellow]") _set_global_environments() - print(" - for addons ...") + log.debug("[yellow]- for addons ...[/yellow]") addons_manager = AddonsManager() _set_addons_environments(addons_manager) _add_addons(addons_manager) @@ -350,6 +352,6 @@ def main(*args, **kwargs): ) except Exception: # noqa exc_info = sys.exc_info() - print("!!! AYON crashed:") - traceback.print_exception(*exc_info) + log.critical("AYON crashed:", exc_info=exc_info) + # traceback.print_exception(*exc_info) sys.exit(1) diff --git a/client/ayon_core/lib/log.py b/client/ayon_core/lib/log.py index 0c2fe5e2d4d..f810fff3302 100644 --- a/client/ayon_core/lib/log.py +++ b/client/ayon_core/lib/log.py @@ -1,3 +1,4 @@ +import contextlib import os import sys import getpass @@ -7,10 +8,20 @@ import time import threading import copy +from loguru import logger +from dataclasses import dataclass from . import Terminal +@dataclass +class ProcessData: + hostname: str + hostip: str + username: str + system_name: str + process_name: str + class LogStreamHandler(logging.StreamHandler): """StreamHandler class. @@ -91,7 +102,88 @@ def format(self, record): return out -class Logger: +class Logger(): + """Logger class. + + This is a wrapper for loguru logger. It is used to provide a unified + interface for logging in AYON. It also provides a way to disable logging + in some cases, for example when running in a headless environment. + + """ + + # Data same for all record documents + process_data: ProcessData = None + + @classmethod + def get_process_data(cls): + """Data about current process which should be same for all records. + + Process data are used for each record sent to mongo database. + """ + if cls.process_data is not None: + return copy.deepcopy(cls.process_data) + + if not cls.initialized: + cls.initialize() + + host_name = socket.gethostname() + try: + host_ip = socket.gethostbyname(host_name) + except socket.gaierror: + host_ip = "127.0.0.1" + + process_name = cls.get_process_name() + + cls.process_data = ProcessData( + hostname=host_name, + hostip=host_ip, + username=getpass.getuser(), + system_name=platform.system(), + process_name=process_name + ) + + return copy.deepcopy(cls.process_data) + + @classmethod + def get_logger(cls, name=None): + return logger.bind(name=name or "__main__") + + @classmethod + def get_process_name(cls) -> str: + """Process name that is like "label" of a process. + + AYON logging can be used from OpenPyppe itself of from hosts. + Even in AYON process it's good to know if logs are from tray or + from other cli commands. This should help to identify that information. + """ + if cls._process_name is not None: + return cls._process_name + + # Get process name + process_name = os.environ.get("AYON_APP_NAME") + if not process_name: + with contextlib.suppress(ImportError): + import psutil + process = psutil.Process(os.getpid()) + process_name = process.name() + + if not process_name: + process_name = os.path.basename(sys.executable) + + cls._process_name = process_name + return cls._process_name + + @classmethod + def set_process_name(cls, process_name: str) -> None: + """Set process name for mongo logs.""" + # Just change the attribute + cls._process_name = process_name + # Update process data if are already set + if cls.process_data is not None: + cls.process_data.process_name = process_name + + +class Legacy_Logger: DFT = '%(levelname)s >>> { %(name)s }: [ %(message)s ] ' DBG = " - { %(name)s }: [ %(message)s ] " INF = ">>> [ %(message)s ] " diff --git a/pyproject.toml b/pyproject.toml index 5434cbbf667..64f761a6fa1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "pytest-print >=1.0.0", "ayon-python-api >=1.0.0", "arrow ==0.17.0", - "ruff >=0.11.7", + "ruff >=0.15.4", "pre-commit >=4.0.0", "codespell >=2.2.6", "semver >=3.0.2", @@ -34,7 +34,8 @@ dependencies = [ "speedcopy >=2.1.0", "qtpy >=2.4.3", "pyside6 >=6.5.2", - "pytest-ayon @ git+https://github.com/ynput/pytest-ayon.git" + "pytest-ayon @ git+https://github.com/ynput/pytest-ayon.git", + "loguru (>=0.7.3,<0.8.0)" ] [tool.codespell]