Skip to content

Commit e02c98c

Browse files
committed
/* PR_START p/fix_cli_logging 01 */ Fix logging setup in the CLI
1 parent a430e4c commit e02c98c

File tree

2 files changed

+34
-14
lines changed

2 files changed

+34
-14
lines changed

dbt-metricflow/dbt_metricflow/cli/cli_configuration.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import os
55
import pathlib
6+
from logging import StreamHandler
67
from logging.handlers import TimedRotatingFileHandler
78
from typing import Dict, Optional
89

@@ -23,9 +24,13 @@
2324
class CLIConfiguration:
2425
"""Configuration object used for the MetricFlow CLI."""
2526

27+
LOG_FILE_NAME = "metricflow.log"
2628
DBT_PROFILES_DIR_ENV_VAR_NAME = "DBT_PROFILES_DIR"
2729
DBT_PROJECT_DIR_ENV_VAR_NAME = "DBT_PROJECT_DIR"
2830

31+
# Message to log when logging has been set up. Useful for checking the logging in tests.
32+
LOG_SETUP_MESSAGE = "Set up MF CLI logging"
33+
2934
def __init__(self) -> None: # noqa: D107
3035
self.verbose = False
3136
self._dbt_project_metadata: Optional[dbtProjectMetadata] = None
@@ -121,28 +126,44 @@ def _configure_logging(self, log_file_path: pathlib.Path) -> None:
121126
we can swap this out and return to full lazy loading for any context attributes that are slow
122127
to initialize.
123128
"""
124-
logger.debug(LazyFormat("Setting up logging to rotating file", log_file_path=self.log_file_path))
129+
root_logger = logging.getLogger()
130+
previous_root_logger_level = root_logger.level
131+
previous_root_logger_handlers = tuple(root_logger.handlers)
125132

126-
log_format = "%(asctime)s %(levelname)s %(filename)s:%(lineno)d [%(threadName)s] - %(message)s"
127-
logging.basicConfig(level=logging.INFO, format=log_format)
133+
# Show >= CRITICAL logs in the console
134+
stream_handler = StreamHandler()
135+
stream_handler_log_level = logging.CRITICAL
136+
stream_handler.setLevel(stream_handler_log_level)
128137

138+
# Show >= INFO logs in the log file
139+
log_file_handler_log_level = logging.INFO
129140
log_file_handler = TimedRotatingFileHandler(
130141
filename=log_file_path,
131142
# Rotate every day to a new file, keep 7 days worth.
132143
when="D",
133144
interval=1,
134145
backupCount=7,
135146
)
147+
log_file_handler.setLevel(log_file_handler_log_level)
136148

137-
formatter = logging.Formatter(fmt=log_format)
138-
log_file_handler.setFormatter(formatter)
139-
log_file_handler.setLevel(logging.INFO)
149+
root_logger_level = logging.INFO
150+
log_format = "%(asctime)s %(levelname)s %(filename)s:%(lineno)d [%(threadName)s] - %(message)s"
151+
# `logging.basicConfig` is a no-op without the `force=True` if any handlers have been added to the root logger.
152+
# Imported modules might add handlers, so set the flag to ensure that the above handlers are used.
153+
logging.basicConfig(
154+
level=root_logger_level, format=log_format, handlers=[stream_handler, log_file_handler], force=True
155+
)
140156

141-
root_logger = logging.getLogger()
142-
# StreamHandler to the console would have been setup by logging.basicConfig
143-
for handler in root_logger.handlers:
144-
handler.setLevel(logging.CRITICAL)
145-
root_logger.addHandler(log_file_handler)
157+
logger.info(
158+
LazyFormat(
159+
CLIConfiguration.LOG_SETUP_MESSAGE,
160+
root_logger_level=logging.getLevelName(root_logger_level),
161+
root_logger_handlers=root_logger.handlers,
162+
previous_root_logger_level=logging.getLevelName(previous_root_logger_level),
163+
previous_root_logger_handlers=previous_root_logger_handlers,
164+
log_format=log_format,
165+
)
166+
)
146167

147168
@property
148169
def dbt_project_metadata(self) -> dbtProjectMetadata:
@@ -162,7 +183,7 @@ def log_file_path(self) -> pathlib.Path:
162183
# The dbt Project.log_path attribute is currently sourced from the final runtime config value accessible
163184
# through the CLI state flags. As such, it will deviate from the default based on the DBT_LOG_PATH environment
164185
# variable. Should this behavior change, we will need to update this call.
165-
return pathlib.Path(self.dbt_project_metadata.project.log_path, "metricflow.log")
186+
return pathlib.Path(self.dbt_project_metadata.project.log_path, CLIConfiguration.LOG_FILE_NAME)
166187

167188
@property
168189
def sql_client(self) -> SqlClient:

dbt-metricflow/dbt_metricflow/cli/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from dbt_semantic_interfaces.validations.validator_helpers import SemanticManifestValidationResults
2121
from halo import Halo
2222
from metricflow_semantics.dag.dag_visualization import display_dag_as_svg
23-
from metricflow_semantics.toolkit.mf_logging.lazy_formattable import LazyFormat
2423
from update_checker import UpdateChecker
2524

2625
import dbt_metricflow.cli.custom_click_types as click_custom
@@ -90,7 +89,7 @@ def exit_signal_handler(signal_type: int, frame) -> None: # type: ignore
9089

9190
try:
9291
# Note: we may wish to add support for canceling all queries if zombie queries are a problem
93-
logger.debug(LazyFormat(lambda: "Closing client connections"))
92+
logger.debug("Closing client connections")
9493
cfg.sql_client.close()
9594
finally:
9695
sys.exit(-1)

0 commit comments

Comments
 (0)