Skip to content

Commit 84d3fb3

Browse files
committed
Report plugin name in dedicated loggers
1 parent e9755f6 commit 84d3fb3

File tree

11 files changed

+62
-27
lines changed

11 files changed

+62
-27
lines changed

src/lmstudio/_logging.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,7 @@ def critical(
147147
self._log(logging.CRITICAL, msg, exc_info, stack_info, stacklevel, event_dict)
148148

149149

150-
def get_logger(name: str, /, *args: Any, **kwds: Any) -> StructuredLogger:
150+
def new_logger(name: str, /, *args: Any, **kwds: Any) -> StructuredLogger:
151+
# Loggers contain runtime state, so they are NOT shared based on their names
152+
# Function name reflects this to avoid false expectations from stdlib logging
151153
return StructuredLogger(logging.getLogger(name, *args, **kwds))

src/lmstudio/_ws_impl.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from .schemas import DictObject
3333
from .json_api import LMStudioWebsocket, LMStudioWebsocketError
3434

35-
from ._logging import get_logger, LogEventContext
35+
from ._logging import new_logger, LogEventContext
3636

3737

3838
# 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:
281281
class AsyncWebsocketThread(BackgroundThread):
282282
def __init__(self, log_context: LogEventContext | None = None) -> None:
283283
super().__init__(task_target=self._log_thread_execution)
284-
self._logger = logger = get_logger(type(self).__name__)
284+
self._logger = logger = new_logger(type(self).__name__)
285285
logger.update_context(log_context, thread_id=self.name)
286286

287287
async def _log_thread_execution(self) -> None:
@@ -322,8 +322,8 @@ def __init__(
322322
self._ws_disconnected = asyncio.Event()
323323
self._rx_task: asyncio.Task[None] | None = None
324324
self._enqueue_message = enqueue_message
325-
self._logger = get_logger(type(self).__name__)
326-
self._logger = logger = get_logger(type(self).__name__)
325+
self._logger = new_logger(type(self).__name__)
326+
self._logger = logger = new_logger(type(self).__name__)
327327
logger.update_context(log_context)
328328

329329
async def connect(self) -> bool:

src/lmstudio/async_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
ModelCompatibilityType,
104104
)
105105

106-
from ._logging import get_logger, LogEventContext
106+
from ._logging import new_logger, LogEventContext
107107

108108
# Only the async API itself is published from
109109
# this module. Anything needed for type hints
@@ -197,7 +197,7 @@ def __init__(
197197
"""Initialize asynchronous remote procedure call."""
198198
self._rx_queue = rx_queue
199199
self._rpc = RemoteCallHandler(call_id, log_context, notice_prefix)
200-
self._logger = logger = get_logger(type(self).__name__)
200+
self._logger = logger = new_logger(type(self).__name__)
201201
logger.update_context(log_context, call_id=call_id)
202202

203203
def get_rpc_message(

src/lmstudio/json_api.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
RepositoryRpcSearchModelsParameter,
118118
SerializedLMSExtendedError,
119119
)
120-
from ._logging import get_logger, LogEventContext, StructuredLogger
120+
from ._logging import new_logger, LogEventContext, StructuredLogger
121121

122122
# The sync and async modules publish the main SDK client API.
123123
# From here, we publish everything that might be needed
@@ -661,7 +661,7 @@ def __init__(
661661
# Channel processing state tracking
662662
self._is_finished = False
663663
self._result: T | None = None
664-
self._logger = logger = get_logger(type(self).__name__)
664+
self._logger = logger = new_logger(type(self).__name__)
665665
logger.update_context(endpoint=self._API_ENDPOINT)
666666

667667
@property
@@ -1602,7 +1602,7 @@ def __init__(
16021602
self._is_finished = False
16031603
self._channel_id = channel_id
16041604
self._endpoint = endpoint
1605-
self._logger = logger = get_logger(type(self).__name__)
1605+
self._logger = logger = new_logger(type(self).__name__)
16061606
logger.update_context(log_context, channel_id=channel_id)
16071607

16081608
@property
@@ -1688,7 +1688,7 @@ def __init__(
16881688
) -> None:
16891689
"""Initialize websocket remote procedure call."""
16901690
self._call_id = call_id
1691-
self._logger = logger = get_logger(type(self).__name__)
1691+
self._logger = logger = new_logger(type(self).__name__)
16921692
logger.update_context(log_context, call_id=call_id)
16931693
self._notice_prefix = notice_prefix
16941694

@@ -1783,7 +1783,7 @@ def __init__(
17831783
"""Initialize I/O independent websocket details."""
17841784
self._ws_url = ws_url
17851785
self._auth_details = auth_details
1786-
self._logger = logger = get_logger(type(self).__name__)
1786+
self._logger = logger = new_logger(type(self).__name__)
17871787
logger.update_context(log_context, ws_url=ws_url)
17881788
self._mux = MultiplexingManager(logger)
17891789
# Subclasses handle actually creating a websocket instance
@@ -2055,7 +2055,7 @@ def __init__(self, model_identifier: str, session: TSession) -> None:
20552055
"""Initialize the LM Studio model reference."""
20562056
self.identifier = model_identifier
20572057
self._session = session
2058-
self._logger = logger = get_logger(type(self).__name__)
2058+
self._logger = logger = new_logger(type(self).__name__)
20592059
logger.update_context(model_identifier=model_identifier)
20602060

20612061
def __repr__(self) -> str:

src/lmstudio/plugin/_dev_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def handle_rx_event(self, event: DevPluginRegistrationRxEvent) -> None:
9393

9494
class DevPluginClient(PluginClient):
9595
def _get_registration_endpoint(self) -> DevPluginRegistrationEndpoint:
96-
return DevPluginRegistrationEndpoint(self._owner, self._name)
96+
return DevPluginRegistrationEndpoint(self.owner, self.name)
9797

9898
@asynccontextmanager
9999
async def register_dev_plugin(self) -> AsyncGenerator[tuple[str, str], None]:

src/lmstudio/plugin/hooks/prompt_preprocessor.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from anyio import create_task_group
1717

18-
from ..._logging import get_logger
18+
from ..._logging import new_logger
1919
from ...schemas import DictObject, EmptyDict, ValidationError
2020
from ...history import UserMessage, UserMessageDict
2121
from ...json_api import (
@@ -187,14 +187,16 @@ async def notify_done(self, message: str) -> None:
187187

188188

189189
async def run_prompt_preprocessor(
190+
plugin_name: str,
190191
hook_impl: PromptPreprocessorHook,
191192
plugin_config_schema: type[BaseConfigSchema],
192193
global_config_schema: type[BaseConfigSchema],
193194
session: AsyncSessionPlugins,
194195
notify_ready: Callable[[], Any],
195196
) -> None:
196197
"""Accept prompt preprocessing requests."""
197-
logger = get_logger(__name__)
198+
logger = new_logger(__name__)
199+
logger.update_context(plugin_name=plugin_name)
198200
endpoint = PromptPreprocessingEndpoint()
199201
async with session._create_channel(endpoint) as channel:
200202
notify_ready()

src/lmstudio/plugin/hooks/token_generator.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
PluginsChannelSetGeneratorToClientPacketGenerate as TokenGenerationRequest,
77
)
88

9+
from ..config_schemas import BaseConfigSchema
910
from .common import (
11+
AsyncSessionPlugins,
1012
HookController,
1113
TPluginConfigSchema,
1214
TGlobalConfigSchema,
@@ -16,7 +18,7 @@
1618
__all__ = [
1719
"TokenGeneratorController",
1820
"TokenGeneratorHook",
19-
# "run_token_generator",
21+
"run_token_generator",
2022
]
2123

2224

@@ -27,3 +29,15 @@ class TokenGeneratorController(
2729

2830

2931
TokenGeneratorHook = Callable[[TokenGeneratorController[Any, Any]], Awaitable[None]]
32+
33+
34+
async def run_token_generator(
35+
plugin_name: str,
36+
hook_impl: TokenGeneratorHook,
37+
plugin_config_schema: type[BaseConfigSchema],
38+
global_config_schema: type[BaseConfigSchema],
39+
session: AsyncSessionPlugins,
40+
notify_ready: Callable[[], Any],
41+
) -> None:
42+
"""Accept token generation requests."""
43+
raise NotImplementedError

src/lmstudio/plugin/hooks/tools_provider.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
PluginsChannelSetToolsProviderToClientPacketInitSession as ProvideToolsInitSession,
1212
)
1313

14+
from ..config_schemas import BaseConfigSchema
1415
from .common import (
16+
AsyncSessionPlugins,
1517
HookController,
1618
TPluginConfigSchema,
1719
TGlobalConfigSchema,
@@ -21,7 +23,7 @@
2123
__all__ = [
2224
"ToolsProviderController",
2325
"ToolsProviderHook",
24-
# "run_tools_provider",
26+
"run_tools_provider",
2527
]
2628

2729

@@ -34,3 +36,15 @@ class ToolsProviderController(
3436
ToolsProviderHook = Callable[
3537
[ToolsProviderController[Any, Any]], Awaitable[Iterable[ToolDefinition]]
3638
]
39+
40+
41+
async def run_tools_provider(
42+
plugin_name: str,
43+
hook_impl: ToolsProviderHook,
44+
plugin_config_schema: type[BaseConfigSchema],
45+
global_config_schema: type[BaseConfigSchema],
46+
session: AsyncSessionPlugins,
47+
notify_ready: Callable[[], Any],
48+
) -> None:
49+
"""Accept tools provider session requests."""
50+
raise NotImplementedError

src/lmstudio/plugin/runner.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from anyio import create_task_group
1818

19-
from .._logging import get_logger
19+
from .._logging import new_logger
2020
from ..sdk_api import LMStudioFileNotFoundError, sdk_public_api
2121
from ..schemas import DictObject
2222
from ..async_api import AsyncClient
@@ -51,6 +51,7 @@
5151
ReadyCallback: TypeAlias = Callable[[], Any]
5252
HookRunner: TypeAlias = Callable[
5353
[
54+
str, # Plugin name
5455
THookImpl,
5556
type[TPluginConfigSchema],
5657
type[TGlobalConfigSchema],
@@ -92,9 +93,9 @@ def __init__(
9293
raise LMStudioPluginInitError(
9394
f'Invalid manifest runner: {manifest["runner"]} (expected "python")'
9495
)
95-
self._owner = manifest["owner"]
96-
self._name = name = manifest["name"]
97-
self._logger = logger = get_logger(__name__)
96+
self.owner = manifest["owner"]
97+
self.name = name = manifest["name"]
98+
self._logger = logger = new_logger(__name__)
9899
logger.update_context(plugin=name)
99100

100101
_ALL_SESSIONS = (
@@ -124,6 +125,7 @@ async def _run_hook_impl(
124125
) -> None:
125126
"""Run the given hook implementation."""
126127
await hook_runner(
128+
self.name,
127129
hook_impl,
128130
plugin_config_schema,
129131
global_config_schema,
@@ -179,6 +181,7 @@ async def run_plugin(self, *, allow_local_imports: bool = False) -> int:
179181
raise LMStudioFileNotFoundError(source_path)
180182
# TODO: Consider passing this logger to hook runners (instead of each creating their own)
181183
logger = self._logger
184+
logger.update_context(plugin_name=self.name)
182185
logger.info(f"Running {source_path}")
183186
if allow_local_imports:
184187
# We don't try to revert the path change, as that can have odd side-effects
@@ -208,7 +211,7 @@ async def run_plugin(self, *, allow_local_imports: bool = False) -> int:
208211
hook_ready_event.set,
209212
)
210213
)
211-
plugin = self._name
214+
plugin = self.name
212215
if not implemented_hooks:
213216
print(
214217
f"No plugin hooks defined in {plugin!r}, "

src/lmstudio/sync_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
ModelCompatibilityType,
122122
)
123123

124-
from ._logging import get_logger, LogEventContext
124+
from ._logging import new_logger, LogEventContext
125125

126126
# Only the sync API itself is published from
127127
# this module. Anything needed for type hints
@@ -223,7 +223,7 @@ def __init__(
223223
"""Initialize synchronous remote procedure call."""
224224
self._rx_queue = rx_queue
225225
self._rpc = RemoteCallHandler(call_id, log_context, notice_prefix)
226-
self._logger = logger = get_logger(type(self).__name__)
226+
self._logger = logger = new_logger(type(self).__name__)
227227
logger.update_context(log_context, call_id=call_id)
228228

229229
def get_rpc_message(

0 commit comments

Comments
 (0)