Merge pull request #143 from tiqi-group/fix/logging

configures pydase's logger only (not root logger anymore)
This commit is contained in:
Mose Müller 2024-07-12 07:46:32 +02:00 committed by GitHub
commit 1789a6ad7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 70 additions and 90 deletions

View File

@ -1,14 +1,45 @@
import asyncio
import logging
import logging.config
import sys
from copy import copy
import socketio # type: ignore[import-untyped]
import uvicorn.config
import uvicorn.logging
from uvicorn.config import LOGGING_CONFIG
import pydase.config
logger = logging.getLogger(__name__)
if pydase.config.OperationMode().environment == "development":
LOG_LEVEL = logging.DEBUG
else:
LOG_LEVEL = logging.INFO
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"()": "pydase.utils.logging.DefaultFormatter",
"fmt": "%(asctime)s.%(msecs)03d | %(levelprefix)s | "
"%(name)s:%(funcName)s:%(lineno)d - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
},
"handlers": {
"default": {
"formatter": "default",
"class": "logging.StreamHandler",
"stream": "ext://sys.stderr",
},
},
"loggers": {
"pydase": {"handlers": ["default"], "level": LOG_LEVEL, "propagate": False},
},
}
class DefaultFormatter(uvicorn.logging.ColourizedFormatter):
"""
@ -64,86 +95,31 @@ class SocketIOHandler(logging.Handler):
)
def setup_logging(level: str | int | None = None) -> None:
def setup_logging() -> None:
"""
Configures the logging settings for the application.
This function sets up logging with specific formatting and colorization of log
messages. The log level is determined based on the application's operation mode,
with an option to override the level. By default, in a development environment, the
log level is set to DEBUG, whereas in other environments, it is set to INFO.
Args:
level (Optional[str | int]):
A specific log level to set for the application. If None, the log level is
determined based on the application's operation mode. Accepts standard log
level names ('DEBUG', 'INFO', etc.) and corresponding numerical values.
Example:
```python
>>> import logging
>>> setup_logging(logging.DEBUG)
>>> setup_logging("INFO")
```
messages. The log level is determined based on the application's operation mode. By
default, in a development environment, the log level is set to DEBUG, whereas in
other environments, it is set to INFO.
"""
logger = logging.getLogger()
logger.debug("Configuring pydase logging.")
if pydase.config.OperationMode().environment == "development":
log_level = logging.DEBUG
else:
log_level = logging.INFO
# If a level is specified, check whether it's a string or an integer.
if level is not None:
if isinstance(level, str):
# Convert known log level strings directly to their corresponding logging
# module constants.
level_name = level.upper() # Ensure level names are uppercase
if hasattr(logging, level_name):
log_level = getattr(logging, level_name)
else:
raise ValueError(
f"Invalid log level: {level}. Must be one of 'DEBUG', 'INFO', "
"'WARNING', 'ERROR', etc."
)
elif isinstance(level, int):
log_level = level # Directly use integer levels
else:
raise ValueError("Log level must be a string or an integer.")
# Set the logger's level.
logger.setLevel(log_level)
# create console handler and set level to debug
ch = logging.StreamHandler()
# add formatter to ch
ch.setFormatter(
DefaultFormatter(
fmt=(
"%(asctime)s.%(msecs)03d | %(levelprefix)s | "
"%(name)s:%(funcName)s:%(lineno)d - %(message)s"
),
datefmt="%Y-%m-%d %H:%M:%S",
)
)
# add ch to logger
logger.addHandler(ch)
logger.debug("Configuring service logging.")
logging.getLogger("asyncio").setLevel(logging.INFO)
logging.getLogger("urllib3").setLevel(logging.INFO)
logging.config.dictConfig(LOGGING_CONFIG)
# configuring uvicorn logger
LOGGING_CONFIG["formatters"]["default"][
"fmt"
] = "%(asctime)s.%(msecs)03d | %(levelprefix)s %(message)s"
LOGGING_CONFIG["formatters"]["default"]["datefmt"] = "%Y-%m-%d %H:%M:%S"
LOGGING_CONFIG["formatters"]["access"]["fmt"] = (
uvicorn.config.LOGGING_CONFIG["formatters"]["default"]["fmt"] = (
"%(asctime)s.%(msecs)03d | %(levelprefix)s %(message)s"
)
uvicorn.config.LOGGING_CONFIG["formatters"]["default"]["datefmt"] = (
"%Y-%m-%d %H:%M:%S"
)
uvicorn.config.LOGGING_CONFIG["formatters"]["access"]["fmt"] = (
"%(asctime)s.%(msecs)03d | %(levelprefix)s %(client_addr)s "
'- "%(request_line)s" %(status_code)s'
)
LOGGING_CONFIG["formatters"]["access"]["datefmt"] = "%Y-%m-%d %H:%M:%S"
uvicorn.config.LOGGING_CONFIG["formatters"]["access"]["datefmt"] = (
"%Y-%m-%d %H:%M:%S"
)

View File

@ -8,7 +8,8 @@ from pydase.data_service.data_service_observer import DataServiceObserver
from pydase.data_service.state_manager import StateManager
from pytest import LogCaptureFixture
logger = logging.getLogger(__name__)
logger = logging.getLogger("pydase")
logger.propagate = True
def test_number_slider(caplog: LogCaptureFixture) -> None:

View File

@ -7,7 +7,8 @@ from pydase.data_service.data_service_observer import DataServiceObserver
from pydase.data_service.state_manager import StateManager
from pytest import LogCaptureFixture
logger = logging.getLogger()
logger = logging.getLogger("pydase")
logger.propagate = True
@pytest.mark.asyncio

View File

@ -5,7 +5,8 @@ import pytest
from pydase.observer_pattern.observable import Observable
from pydase.observer_pattern.observer import Observer
logger = logging.getLogger(__name__)
logger = logging.getLogger("pydase")
logger.propagate = True
class MyObserver(Observer):

View File

@ -5,7 +5,8 @@ import pytest
from pydase.observer_pattern.observable import Observable
from pydase.observer_pattern.observer import Observer
logger = logging.getLogger(__name__)
logger = logging.getLogger("pydase")
logger.propagate = True
class MyObserver(Observer):

View File

@ -5,7 +5,8 @@ import pytest
from pydase.observer_pattern.observable import Observable
from pydase.observer_pattern.observer import Observer
logger = logging.getLogger(__name__)
logger = logging.getLogger("pydase")
logger.propagate = True
class MyObserver(Observer):

View File

@ -1,12 +1,12 @@
import logging
from pydase.utils.logging import setup_logging
from pytest import LogCaptureFixture
def test_log_error(caplog: LogCaptureFixture):
setup_logging("ERROR")
logger = logging.getLogger()
logger = logging.getLogger("pydase")
logger.setLevel(logging.ERROR)
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
@ -21,8 +21,9 @@ def test_log_error(caplog: LogCaptureFixture):
def test_log_warning(caplog: LogCaptureFixture):
setup_logging("WARNING")
logger = logging.getLogger()
logger = logging.getLogger("pydase")
logger.setLevel(logging.WARNING)
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
@ -37,10 +38,9 @@ def test_log_warning(caplog: LogCaptureFixture):
def test_log_debug(caplog: LogCaptureFixture):
setup_logging("DEBUG")
logger = (
logging.getLogger()
) # Get the root logger or replace with the appropriate logger.
logger = logging.getLogger("pydase")
logger.setLevel(logging.DEBUG)
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
@ -54,10 +54,9 @@ def test_log_debug(caplog: LogCaptureFixture):
def test_log_info(caplog: LogCaptureFixture):
setup_logging("INFO")
logger = (
logging.getLogger()
) # Get the root logger or replace with the appropriate logger.
logger = logging.getLogger("pydase")
logger.setLevel(logging.INFO)
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")