diff --git a/lib/esbonio/changes/26.fix.rst b/lib/esbonio/changes/26.fix.rst index ce0227617..3e4b26885 100644 --- a/lib/esbonio/changes/26.fix.rst +++ b/lib/esbonio/changes/26.fix.rst @@ -1,2 +1,2 @@ -Fix discovery of roles so that roles in Sphinx domains are used and that unimplemented -``docutils`` roles are not surfaced. \ No newline at end of file +**Language Server:** Fix discovery of roles so that roles in Sphinx domains are used and +that unimplemented ``docutils`` roles are not surfaced. \ No newline at end of file diff --git a/lib/esbonio/changes/27.feature.rst b/lib/esbonio/changes/27.feature.rst new file mode 100644 index 000000000..395ef222f --- /dev/null +++ b/lib/esbonio/changes/27.feature.rst @@ -0,0 +1 @@ +**Language Server:** Python log events can now published to Language Clients \ No newline at end of file diff --git a/lib/esbonio/esbonio/__main__.py b/lib/esbonio/esbonio/__main__.py index 0dff868d6..372e2ddc6 100644 --- a/lib/esbonio/esbonio/__main__.py +++ b/lib/esbonio/esbonio/__main__.py @@ -1,36 +1,37 @@ import argparse import logging -import pathlib import sys -import appdirs import esbonio.lsp as lsp from esbonio import __version__ +from esbonio.lsp.logger import LspHandler LOG_LEVELS = [logging.ERROR, logging.INFO, logging.DEBUG] -def start_server(verbose): - """Start the language server.""" +def configure_logging(verbose, server): try: - level = LOG_LEVELS[verbose] + level = LOG_LEVELS[-1] except IndexError: level = LOG_LEVELS[-1] - logdir = pathlib.Path(appdirs.user_log_dir("esbonio", "swyddfa")) - if not logdir.exists(): - logdir.mkdir(parents=True) + logger = logging.getLogger("esbonio") + logger.setLevel(level) + + handler = LspHandler(server) + handler.setLevel(level) - logfile = logdir / "language_server.log" - logging.basicConfig( - level=level, - format="[%(levelname)s][%(name)s]: %(message)s", - filemode="w", - filename=str(logfile), - ) + formatter = logging.Formatter("[%(name)s] %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + + +def start_server(verbose): + """Start the language server.""" + configure_logging(verbose, lsp.server) lsp.server.start_io() diff --git a/lib/esbonio/esbonio/lsp/logger.py b/lib/esbonio/esbonio/lsp/logger.py new file mode 100644 index 000000000..b8998c881 --- /dev/null +++ b/lib/esbonio/esbonio/lsp/logger.py @@ -0,0 +1,34 @@ +"""This module defines a custom logging handler that publishes log messages to an LSP +client.""" + +import logging + +from pygls.server import LanguageServer +from pygls.types import MessageType + +_LOG_LEVELS = { + logging.DEBUG: MessageType.Info, + logging.INFO: MessageType.Info, + logging.WARNING: MessageType.Warning, + logging.ERROR: MessageType.Error, + logging.CRITICAL: MessageType.Error, +} + + +class LspHandler(logging.Handler): + """A logging handler that will send log records to an LSP client.""" + + def __init__(self, server: LanguageServer): + super().__init__() + self.server = server + + def emit(self, record: logging.LogRecord) -> None: + """Sends the record to the client.""" + + # To avoid infinite recursions, it's simpler to just ignore all log records + # coming from pygls... + if "pygls" in record.name: + return + + log = self.format(record) + self.server.show_message_log(log, msg_type=_LOG_LEVELS[record.levelno])