diff --git a/CHANGELOG.md b/CHANGELOG.md index 95555ce86..025a36c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * Added the `-p`/`--include-path` CLI command to prepend entries to the `sys.path` as an alternative to `PYTHONPATH` (#1027) * Added an empty entry to `sys.path` for all CLI entrypoints (`basilisp run`, `basilisp repl`, etc.) (#1027) + * Added command line arguments for enabling the development logger and configuring the logging level (#1047) ### Changed * The compiler will no longer require `Var` indirection for top-level `do` forms unless those forms specify `^:use-var-indirection` metadata (which currently is only used in the `ns` macro) (#1034) diff --git a/src/basilisp/cli.py b/src/basilisp/cli.py index 48bfb8583..b2ee352de 100644 --- a/src/basilisp/cli.py +++ b/src/basilisp/cli.py @@ -281,6 +281,32 @@ def _add_debug_arg_group(parser: argparse.ArgumentParser) -> None: "(env: BASILISP_DO_NOT_CACHE_NAMESPACES; default: false)" ), ) + group.add_argument( + "--enable-logger", + action=_set_envvar_action( + "BASILISP_USE_DEV_LOGGER", parent=argparse._StoreAction + ), + nargs="?", + const=True, + type=_to_bool, + help=( + "if true, enable the Basilisp root logger " + "(env: BASILISP_USE_DEV_LOGGER; default: false)" + ), + ) + group.add_argument( + "-l", + "--log-level", + action=_set_envvar_action( + "BASILISP_LOGGING_LEVEL", parent=argparse._StoreAction + ), + type=lambda s: s.upper(), + default="WARNING", + help=( + "the logging level for logs emitted by the Basilisp compiler and runtime " + "(env: BASILISP_LOGGING_LEVEL; default: WARNING)" + ), + ) def _add_import_arg_group(parser: argparse.ArgumentParser) -> None: diff --git a/src/basilisp/logconfig.py b/src/basilisp/logconfig.py index bc5104daf..8b6350dd9 100644 --- a/src/basilisp/logconfig.py +++ b/src/basilisp/logconfig.py @@ -1,5 +1,15 @@ import logging import os +from typing import Optional + +TRACE = 5 + +logging.addLevelName(TRACE, "TRACE") + + +DEFAULT_FORMAT = ( + "%(asctime)s %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] - %(message)s" +) def get_level() -> str: @@ -7,7 +17,9 @@ def get_level() -> str: return os.getenv("BASILISP_LOGGING_LEVEL", "WARNING") -def get_handler(level: str, fmt: str) -> logging.Handler: +def get_handler( + level: Optional[str] = None, fmt: str = DEFAULT_FORMAT +) -> logging.Handler: """Get the default logging handler for Basilisp.""" handler = ( logging.StreamHandler() @@ -15,16 +27,15 @@ def get_handler(level: str, fmt: str) -> logging.Handler: else logging.NullHandler() ) handler.setFormatter(logging.Formatter(fmt)) - handler.setLevel(level) + handler.setLevel(level or get_level()) return handler -TRACE = 5 - -logging.addLevelName(TRACE, "TRACE") - -DEFAULT_FORMAT = ( - "%(asctime)s %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] - %(message)s" -) -DEFAULT_LEVEL = get_level() -DEFAULT_HANDLER = get_handler(DEFAULT_LEVEL, DEFAULT_FORMAT) +def configure_root_logger( + level: Optional[str] = None, fmt: str = DEFAULT_FORMAT +) -> None: + """Configure the Basilisp root logger.""" + level = level or get_level() + logger = logging.getLogger("basilisp") + logger.setLevel(level) + logger.addHandler(get_handler(level=level, fmt=fmt)) diff --git a/src/basilisp/main.py b/src/basilisp/main.py index 7cfce8d4c..442942ad9 100644 --- a/src/basilisp/main.py +++ b/src/basilisp/main.py @@ -1,19 +1,14 @@ import importlib -import logging import site from pathlib import Path from typing import List, Optional from basilisp import importer as importer +from basilisp import logconfig from basilisp.lang import runtime as runtime from basilisp.lang.compiler import compiler_opts from basilisp.lang.typing import CompilerOpts from basilisp.lang.util import munge -from basilisp.logconfig import DEFAULT_HANDLER, DEFAULT_LEVEL - -logger = logging.getLogger("basilisp") -logger.setLevel(DEFAULT_LEVEL) -logger.addHandler(DEFAULT_HANDLER) def init(opts: Optional[CompilerOpts] = None) -> None: @@ -27,6 +22,7 @@ def init(opts: Optional[CompilerOpts] = None) -> None: If you want to execute a Basilisp file which is stored in a well-formed package or module structure, you probably want to use :py:func:`bootstrap`. """ + logconfig.configure_root_logger() runtime.init_ns_var() runtime.bootstrap_core(opts if opts is not None else compiler_opts()) importer.hook_imports()