1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-15 16:56:54 +08:00

Fix logging_level: make logging level specified in qlib.init applies to all loggers (#1368)

* fix logging_level: make logging level specified in qlib.init apply to all loggers

* downgrade loglevel in expmanager __init__ to debug (it will be called in each process in multiprocessing operations such as read data)

* correct gramma error

* fix black lint

* use functor to cache loggers and set level

* correct black lint

* correct pylint

* correct pylint
This commit is contained in:
YQ Tsui
2022-11-29 08:09:22 +08:00
committed by GitHub
parent 4f5ae4d224
commit 6a47416a2d
7 changed files with 42 additions and 34 deletions

View File

@@ -16,7 +16,7 @@ When you submit a PR request, you can check whether your code passes the CI test
1. Qlib will check the code format with black. The PR will raise error if your code does not align to the standard of Qlib(e.g. a common error is the mixed use of space and tab). 1. Qlib will check the code format with black. The PR will raise error if your code does not align to the standard of Qlib(e.g. a common error is the mixed use of space and tab).
You can fix the bug by inputing the following code in the command line. You can fix the bug by inputting the following code in the command line.
.. code-block:: bash .. code-block:: bash

View File

@@ -10,7 +10,7 @@ import yaml
import logging import logging
import platform import platform
import subprocess import subprocess
from .log import get_module_logger from .log import get_module_logger, set_global_logger_level
# init qlib # init qlib
@@ -34,8 +34,7 @@ def init(default_conf="client", **kwargs):
from .config import C # pylint: disable=C0415 from .config import C # pylint: disable=C0415
from .data.cache import H # pylint: disable=C0415 from .data.cache import H # pylint: disable=C0415
# FIXME: this logger ignored the level in config logger = get_module_logger("Initialization")
logger = get_module_logger("Initialization", level=logging.INFO)
skip_if_reg = kwargs.pop("skip_if_reg", False) skip_if_reg = kwargs.pop("skip_if_reg", False)
if skip_if_reg and C.registered: if skip_if_reg and C.registered:
@@ -48,6 +47,7 @@ def init(default_conf="client", **kwargs):
if clear_mem_cache: if clear_mem_cache:
H.clear() H.clear()
C.set(default_conf, **kwargs) C.set(default_conf, **kwargs)
get_module_logger.setLevel(C.logging_level)
# mount nfs # mount nfs
for _freq, provider_uri in C.provider_uri.items(): for _freq, provider_uri in C.provider_uri.items():

View File

@@ -411,8 +411,7 @@ class QlibConfig(Config):
if _logging_config: if _logging_config:
set_log_with_config(_logging_config) set_log_with_config(_logging_config)
# FIXME: this logger ignored the level in config logger = get_module_logger("Initialization", kwargs.get("logging_level", self.logging_level))
logger = get_module_logger("Initialization", level=logging.INFO)
logger.info(f"default_conf: {default_conf}.") logger.info(f"default_conf: {default_conf}.")
self.set_mode(default_conf) self.set_mode(default_conf)

View File

@@ -48,33 +48,44 @@ class QlibLogger(metaclass=MetaLogger):
return self.logger.__getattribute__(name) return self.logger.__getattribute__(name)
def get_module_logger(module_name, level: Optional[int] = None) -> QlibLogger: class _QLibLoggerManager:
""" def __init__(self):
Get a logger for a specific module. self._loggers = {}
:param module_name: str def setLevel(self, level):
Logic module name. for logger in self._loggers.values():
:param level: int logger.setLevel(level)
:return: Logger
Logger object.
"""
if level is None:
level = C.logging_level
if not module_name.startswith("qlib."): def __call__(self, module_name, level: Optional[int] = None) -> QlibLogger:
# Add a prefix of qlib. when the requested ``module_name`` doesn't start with ``qlib.``. """
# If the module_name is already qlib.xxx, we do not format here. Otherwise, it will become qlib.qlib.xxx. Get a logger for a specific module.
module_name = "qlib.{}".format(module_name)
# Get logger. :param module_name: str
module_logger = QlibLogger(module_name) Logic module name.
module_logger.setLevel(level) :param level: int
return module_logger :return: Logger
Logger object.
"""
if level is None:
level = C.logging_level
if not module_name.startswith("qlib."):
# Add a prefix of qlib. when the requested ``module_name`` doesn't start with ``qlib.``.
# If the module_name is already qlib.xxx, we do not format here. Otherwise, it will become qlib.qlib.xxx.
module_name = "qlib.{}".format(module_name)
# Get logger.
module_logger = self._loggers.setdefault(module_name, QlibLogger(module_name))
module_logger.setLevel(level)
return module_logger
get_module_logger = _QLibLoggerManager()
class TimeInspector: class TimeInspector:
timer_logger = get_module_logger("timer", level=logging.INFO) timer_logger = get_module_logger("timer")
time_marks = [] time_marks = []

View File

@@ -4,13 +4,12 @@
from typing import Dict, List, Union from typing import Dict, List, Union
from qlib.typehint import Literal from qlib.typehint import Literal
import mlflow import mlflow
import logging
from mlflow.entities import ViewType from mlflow.entities import ViewType
from mlflow.exceptions import MlflowException from mlflow.exceptions import MlflowException
from .recorder import Recorder, MLflowRecorder from .recorder import Recorder, MLflowRecorder
from ..log import get_module_logger from ..log import get_module_logger
logger = get_module_logger("workflow", logging.INFO) logger = get_module_logger("workflow")
class Experiment: class Experiment:
@@ -22,7 +21,7 @@ class Experiment:
def __init__(self, id, name): def __init__(self, id, name):
self.id = id self.id = id
self.name = name self.name = name
self.active_recorder = None # only one recorder can running each time self.active_recorder = None # only one recorder can run each time
self._default_rec_name = "abstract_recorder" self._default_rec_name = "abstract_recorder"
def __repr__(self): def __repr__(self):
@@ -232,7 +231,7 @@ class Experiment:
Returns Returns
------- -------
The return type depent on `rtype` The return type depends on `rtype`
if `rtype` == "dict": if `rtype` == "dict":
A dictionary (id -> recorder) of recorder information that being stored. A dictionary (id -> recorder) of recorder information that being stored.
elif `rtype` == "list": elif `rtype` == "list":
@@ -354,7 +353,7 @@ class MLflowExperiment(Experiment):
Parameters Parameters
---------- ----------
max_results : int max_results : int
the number limitation of the results the number limitation of the results'
status : str status : str
the criteria based on status to filter results. the criteria based on status to filter results.
`None` indicates no filtering. `None` indicates no filtering.

View File

@@ -37,7 +37,7 @@ class ExpManager:
self._active_exp_uri = None # No active experiments. So it is set to None self._active_exp_uri = None # No active experiments. So it is set to None
self._default_exp_name = default_exp_name self._default_exp_name = default_exp_name
self.active_experiment = None # only one experiment can be active each time self.active_experiment = None # only one experiment can be active each time
logger.info(f"experiment manager uri is at {self.uri}") logger.debug(f"experiment manager uri is at {self.uri}")
def __repr__(self): def __repr__(self):
return "{name}(uri={uri})".format(name=self.__class__.__name__, uri=self.uri) return "{name}(uri={uri})".format(name=self.__class__.__name__, uri=self.uri)

View File

@@ -5,7 +5,6 @@ import os
import sys import sys
from typing import Optional from typing import Optional
import mlflow import mlflow
import logging
import shutil import shutil
import pickle import pickle
import tempfile import tempfile
@@ -20,7 +19,7 @@ from qlib.utils.paral import AsyncCaller
from ..log import TimeInspector, get_module_logger from ..log import TimeInspector, get_module_logger
from mlflow.store.artifact.azure_blob_artifact_repo import AzureBlobArtifactRepository from mlflow.store.artifact.azure_blob_artifact_repo import AzureBlobArtifactRepository
logger = get_module_logger("workflow", logging.INFO) logger = get_module_logger("workflow")
# mlflow limits the length of log_param to 500, but this caused errors when using qrun, so we extended the mlflow limit. # mlflow limits the length of log_param to 500, but this caused errors when using qrun, so we extended the mlflow limit.
mlflow.utils.validation.MAX_PARAM_VAL_LENGTH = 1000 mlflow.utils.validation.MAX_PARAM_VAL_LENGTH = 1000