diff --git a/src/lmstudio/_logging.py b/src/lmstudio/_logging.py index 0e5f401..6c14c5e 100644 --- a/src/lmstudio/_logging.py +++ b/src/lmstudio/_logging.py @@ -147,5 +147,7 @@ def critical( self._log(logging.CRITICAL, msg, exc_info, stack_info, stacklevel, event_dict) -def get_logger(name: str, /, *args: Any, **kwds: Any) -> StructuredLogger: +def new_logger(name: str, /, *args: Any, **kwds: Any) -> StructuredLogger: + # Loggers contain runtime state, so they are NOT shared based on their names + # Function name reflects this to avoid false expectations from stdlib logging return StructuredLogger(logging.getLogger(name, *args, **kwds)) diff --git a/src/lmstudio/_ws_impl.py b/src/lmstudio/_ws_impl.py index 3a1450c..9458b0e 100644 --- a/src/lmstudio/_ws_impl.py +++ b/src/lmstudio/_ws_impl.py @@ -32,7 +32,7 @@ from .schemas import DictObject from .json_api import LMStudioWebsocket, LMStudioWebsocketError -from ._logging import get_logger, LogEventContext +from ._logging import new_logger, LogEventContext # Allow the core client websocket management to be shared across all SDK interaction APIs @@ -281,7 +281,7 @@ def call_in_background(self, func: Callable[[], Any]) -> None: class AsyncWebsocketThread(BackgroundThread): def __init__(self, log_context: LogEventContext | None = None) -> None: super().__init__(task_target=self._log_thread_execution) - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, thread_id=self.name) async def _log_thread_execution(self) -> None: @@ -322,8 +322,7 @@ def __init__( self._ws_disconnected = asyncio.Event() self._rx_task: asyncio.Task[None] | None = None self._enqueue_message = enqueue_message - self._logger = get_logger(type(self).__name__) - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context) async def connect(self) -> bool: diff --git a/src/lmstudio/async_api.py b/src/lmstudio/async_api.py index 41fdc70..b04e926 100644 --- a/src/lmstudio/async_api.py +++ b/src/lmstudio/async_api.py @@ -103,7 +103,7 @@ ModelCompatibilityType, ) -from ._logging import get_logger, LogEventContext +from ._logging import new_logger, LogEventContext # Only the async API itself is published from # this module. Anything needed for type hints @@ -192,7 +192,7 @@ def __init__( """Initialize asynchronous remote procedure call.""" self._rx_queue = rx_queue self._rpc = RemoteCallHandler(call_id, log_context, notice_prefix) - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, call_id=call_id) def get_rpc_message( diff --git a/src/lmstudio/json_api.py b/src/lmstudio/json_api.py index 4fb5e78..029d2c2 100644 --- a/src/lmstudio/json_api.py +++ b/src/lmstudio/json_api.py @@ -117,7 +117,7 @@ RepositoryRpcSearchModelsParameter, SerializedLMSExtendedError, ) -from ._logging import get_logger, LogEventContext, StructuredLogger +from ._logging import new_logger, LogEventContext, StructuredLogger # The sync and async modules publish the main SDK client API. # From here, we publish everything that might be needed @@ -661,7 +661,7 @@ def __init__( # Channel processing state tracking self._is_finished = False self._result: T | None = None - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(endpoint=self._API_ENDPOINT) @property @@ -1602,7 +1602,7 @@ def __init__( self._is_finished = False self._channel_id = channel_id self._endpoint = endpoint - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, channel_id=channel_id) @property @@ -1681,7 +1681,7 @@ def __init__( ) -> None: """Initialize websocket remote procedure call.""" self._call_id = call_id - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, call_id=call_id) self._notice_prefix = notice_prefix @@ -1776,7 +1776,7 @@ def __init__( """Initialize I/O independent websocket details.""" self._ws_url = ws_url self._auth_details = auth_details - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, ws_url=ws_url) self._mux = MultiplexingManager(logger) # Subclasses handle actually creating a websocket instance @@ -2042,7 +2042,7 @@ def __init__(self, model_identifier: str, session: TSession) -> None: """Initialize the LM Studio model reference.""" self.identifier = model_identifier self._session = session - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(model_identifier=model_identifier) def __repr__(self) -> str: diff --git a/src/lmstudio/sync_api.py b/src/lmstudio/sync_api.py index 7ef2890..d2623ce 100644 --- a/src/lmstudio/sync_api.py +++ b/src/lmstudio/sync_api.py @@ -121,7 +121,7 @@ ModelCompatibilityType, ) -from ._logging import get_logger, LogEventContext +from ._logging import new_logger, LogEventContext # Only the sync API itself is published from # this module. Anything needed for type hints @@ -218,7 +218,7 @@ def __init__( """Initialize synchronous remote procedure call.""" self._rx_queue = rx_queue self._rpc = RemoteCallHandler(call_id, log_context, notice_prefix) - self._logger = logger = get_logger(type(self).__name__) + self._logger = logger = new_logger(type(self).__name__) logger.update_context(log_context, call_id=call_id) def get_rpc_message( diff --git a/tests/test_traceback_filtering.py b/tests/test_traceback_filtering.py index 65841d3..28df001 100644 --- a/tests/test_traceback_filtering.py +++ b/tests/test_traceback_filtering.py @@ -5,7 +5,7 @@ from lmstudio import LMStudioError from lmstudio.sdk_api import sdk_callback_invocation -from lmstudio._logging import get_logger +from lmstudio._logging import new_logger from .support import check_sdk_error, check_unfiltered_error from .support.lmstudio import ( @@ -65,7 +65,7 @@ async def test_async_api_truncation_internal_error(public_api: TestCoro) -> None def test_callback_invocation(caplog: LogCap) -> None: - logger = get_logger(__name__) + logger = new_logger(__name__) exc_to_raise = Exception("This will be raised") with sdk_callback_invocation("Callback test", logger): raise exc_to_raise