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:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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():
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
51
qlib/log.py
51
qlib/log.py
@@ -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 = []
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user