Merge branch 'develop' into pr/hippocritical/8369
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.10.11-slim-bullseye as base
|
FROM python:3.11.4-slim-bullseye as base
|
||||||
|
|
||||||
# Setup env
|
# Setup env
|
||||||
ENV LANG C.UTF-8
|
ENV LANG C.UTF-8
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from logging.handlers import RotatingFileHandler, SysLogHandler
|
|||||||
from freqtrade.constants import Config
|
from freqtrade.constants import Config
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.loggers.buffering_handler import FTBufferingHandler
|
from freqtrade.loggers.buffering_handler import FTBufferingHandler
|
||||||
|
from freqtrade.loggers.set_log_levels import set_loggers
|
||||||
from freqtrade.loggers.std_err_stream_handler import FTStdErrStreamHandler
|
from freqtrade.loggers.std_err_stream_handler import FTStdErrStreamHandler
|
||||||
|
|
||||||
|
|
||||||
@@ -16,29 +17,6 @@ bufferHandler = FTBufferingHandler(1000)
|
|||||||
bufferHandler.setFormatter(Formatter(LOGFORMAT))
|
bufferHandler.setFormatter(Formatter(LOGFORMAT))
|
||||||
|
|
||||||
|
|
||||||
def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None:
|
|
||||||
"""
|
|
||||||
Set the logging level for third party libraries
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
|
|
||||||
logging.getLogger('requests').setLevel(
|
|
||||||
logging.INFO if verbosity <= 1 else logging.DEBUG
|
|
||||||
)
|
|
||||||
logging.getLogger("urllib3").setLevel(
|
|
||||||
logging.INFO if verbosity <= 1 else logging.DEBUG
|
|
||||||
)
|
|
||||||
logging.getLogger('ccxt.base.exchange').setLevel(
|
|
||||||
logging.INFO if verbosity <= 2 else logging.DEBUG
|
|
||||||
)
|
|
||||||
logging.getLogger('telegram').setLevel(logging.INFO)
|
|
||||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
|
||||||
|
|
||||||
logging.getLogger('werkzeug').setLevel(
|
|
||||||
logging.ERROR if api_verbosity == 'error' else logging.INFO
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_existing_handlers(handlertype):
|
def get_existing_handlers(handlertype):
|
||||||
"""
|
"""
|
||||||
Returns Existing handler or None (if the handler has not yet been added to the root handlers).
|
Returns Existing handler or None (if the handler has not yet been added to the root handlers).
|
||||||
@@ -115,6 +93,6 @@ def setup_logging(config: Config) -> None:
|
|||||||
logging.root.addHandler(handler_rf)
|
logging.root.addHandler(handler_rf)
|
||||||
|
|
||||||
logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG)
|
logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG)
|
||||||
_set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info'))
|
set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info'))
|
||||||
|
|
||||||
logger.info('Verbosity set to %s', verbosity)
|
logger.info('Verbosity set to %s', verbosity)
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
def set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None:
|
||||||
|
"""
|
||||||
|
Set the logging level for third party libraries
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
logging.getLogger('requests').setLevel(
|
||||||
|
logging.INFO if verbosity <= 1 else logging.DEBUG
|
||||||
|
)
|
||||||
|
logging.getLogger("urllib3").setLevel(
|
||||||
|
logging.INFO if verbosity <= 1 else logging.DEBUG
|
||||||
|
)
|
||||||
|
logging.getLogger('ccxt.base.exchange').setLevel(
|
||||||
|
logging.INFO if verbosity <= 2 else logging.DEBUG
|
||||||
|
)
|
||||||
|
logging.getLogger('telegram').setLevel(logging.INFO)
|
||||||
|
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
logging.getLogger('werkzeug').setLevel(
|
||||||
|
logging.ERROR if api_verbosity == 'error' else logging.INFO
|
||||||
|
)
|
||||||
@@ -1114,7 +1114,9 @@ class Telegram(RPCHandler):
|
|||||||
async def _force_exit_action(self, trade_id):
|
async def _force_exit_action(self, trade_id):
|
||||||
if trade_id != 'cancel':
|
if trade_id != 'cancel':
|
||||||
try:
|
try:
|
||||||
self._rpc._rpc_force_exit(trade_id)
|
loop = asyncio.get_running_loop()
|
||||||
|
# Workaround to avoid nested loops
|
||||||
|
await loop.run_in_executor(None, self._rpc._rpc_force_exit, trade_id)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
await self._send_msg(str(e))
|
await self._send_msg(str(e))
|
||||||
|
|
||||||
@@ -1140,7 +1142,11 @@ class Telegram(RPCHandler):
|
|||||||
async def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection):
|
async def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection):
|
||||||
if pair != 'cancel':
|
if pair != 'cancel':
|
||||||
try:
|
try:
|
||||||
|
def _force_enter():
|
||||||
self._rpc._rpc_force_entry(pair, price, order_side=order_side)
|
self._rpc._rpc_force_entry(pair, price, order_side=order_side)
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
# Workaround to avoid nested loops
|
||||||
|
await loop.run_in_executor(None, _force_enter)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
logger.exception("Forcebuy error!")
|
logger.exception("Forcebuy error!")
|
||||||
await self._send_msg(str(e), ParseMode.HTML)
|
await self._send_msg(str(e), ParseMode.HTML)
|
||||||
|
|||||||
+1
-126
@@ -1,7 +1,5 @@
|
|||||||
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
|
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
import warnings
|
import warnings
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -23,8 +21,6 @@ from freqtrade.configuration.load_config import (load_config_file, load_file, lo
|
|||||||
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL, ENV_VAR_PREFIX
|
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL, ENV_VAR_PREFIX
|
||||||
from freqtrade.enums import RunMode
|
from freqtrade.enums import RunMode
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.loggers import (FTBufferingHandler, FTStdErrStreamHandler, _set_loggers,
|
|
||||||
setup_logging, setup_logging_pre)
|
|
||||||
from tests.conftest import (CURRENT_TEST_STRATEGY, log_has, log_has_re,
|
from tests.conftest import (CURRENT_TEST_STRATEGY, log_has, log_has_re,
|
||||||
patched_configuration_load_config_file)
|
patched_configuration_load_config_file)
|
||||||
|
|
||||||
@@ -594,7 +590,7 @@ def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
# Prevent setting loggers
|
# Prevent setting loggers
|
||||||
mocker.patch('freqtrade.loggers._set_loggers', MagicMock)
|
mocker.patch('freqtrade.loggers.set_loggers', MagicMock)
|
||||||
arglist = ['trade', '-vvv']
|
arglist = ['trade', '-vvv']
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
|
|
||||||
@@ -605,127 +601,6 @@ def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
|
|||||||
assert log_has('Verbosity set to 3', caplog)
|
assert log_has('Verbosity set to 3', caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_set_loggers() -> None:
|
|
||||||
# Reset Logging to Debug, otherwise this fails randomly as it's set globally
|
|
||||||
logging.getLogger('requests').setLevel(logging.DEBUG)
|
|
||||||
logging.getLogger("urllib3").setLevel(logging.DEBUG)
|
|
||||||
logging.getLogger('ccxt.base.exchange').setLevel(logging.DEBUG)
|
|
||||||
logging.getLogger('telegram').setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
previous_value1 = logging.getLogger('requests').level
|
|
||||||
previous_value2 = logging.getLogger('ccxt.base.exchange').level
|
|
||||||
previous_value3 = logging.getLogger('telegram').level
|
|
||||||
|
|
||||||
_set_loggers()
|
|
||||||
|
|
||||||
value1 = logging.getLogger('requests').level
|
|
||||||
assert previous_value1 is not value1
|
|
||||||
assert value1 is logging.INFO
|
|
||||||
|
|
||||||
value2 = logging.getLogger('ccxt.base.exchange').level
|
|
||||||
assert previous_value2 is not value2
|
|
||||||
assert value2 is logging.INFO
|
|
||||||
|
|
||||||
value3 = logging.getLogger('telegram').level
|
|
||||||
assert previous_value3 is not value3
|
|
||||||
assert value3 is logging.INFO
|
|
||||||
|
|
||||||
_set_loggers(verbosity=2)
|
|
||||||
|
|
||||||
assert logging.getLogger('requests').level is logging.DEBUG
|
|
||||||
assert logging.getLogger('ccxt.base.exchange').level is logging.INFO
|
|
||||||
assert logging.getLogger('telegram').level is logging.INFO
|
|
||||||
assert logging.getLogger('werkzeug').level is logging.INFO
|
|
||||||
|
|
||||||
_set_loggers(verbosity=3, api_verbosity='error')
|
|
||||||
|
|
||||||
assert logging.getLogger('requests').level is logging.DEBUG
|
|
||||||
assert logging.getLogger('ccxt.base.exchange').level is logging.DEBUG
|
|
||||||
assert logging.getLogger('telegram').level is logging.INFO
|
|
||||||
assert logging.getLogger('werkzeug').level is logging.ERROR
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
|
||||||
def test_set_loggers_syslog():
|
|
||||||
logger = logging.getLogger()
|
|
||||||
orig_handlers = logger.handlers
|
|
||||||
logger.handlers = []
|
|
||||||
|
|
||||||
config = {'verbosity': 2,
|
|
||||||
'logfile': 'syslog:/dev/log',
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_logging_pre()
|
|
||||||
setup_logging(config)
|
|
||||||
assert len(logger.handlers) == 3
|
|
||||||
assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler]
|
|
||||||
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
|
||||||
assert [x for x in logger.handlers if type(x) == FTBufferingHandler]
|
|
||||||
# setting up logging again should NOT cause the loggers to be added a second time.
|
|
||||||
setup_logging(config)
|
|
||||||
assert len(logger.handlers) == 3
|
|
||||||
# reset handlers to not break pytest
|
|
||||||
logger.handlers = orig_handlers
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
|
||||||
def test_set_loggers_Filehandler(tmpdir):
|
|
||||||
logger = logging.getLogger()
|
|
||||||
orig_handlers = logger.handlers
|
|
||||||
logger.handlers = []
|
|
||||||
logfile = Path(tmpdir) / 'ft_logfile.log'
|
|
||||||
config = {'verbosity': 2,
|
|
||||||
'logfile': str(logfile),
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_logging_pre()
|
|
||||||
setup_logging(config)
|
|
||||||
assert len(logger.handlers) == 3
|
|
||||||
assert [x for x in logger.handlers if type(x) == logging.handlers.RotatingFileHandler]
|
|
||||||
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
|
||||||
assert [x for x in logger.handlers if type(x) == FTBufferingHandler]
|
|
||||||
# setting up logging again should NOT cause the loggers to be added a second time.
|
|
||||||
setup_logging(config)
|
|
||||||
assert len(logger.handlers) == 3
|
|
||||||
# reset handlers to not break pytest
|
|
||||||
if logfile.exists:
|
|
||||||
logfile.unlink()
|
|
||||||
logger.handlers = orig_handlers
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip(reason="systemd is not installed on every system, so we're not testing this.")
|
|
||||||
def test_set_loggers_journald(mocker):
|
|
||||||
logger = logging.getLogger()
|
|
||||||
orig_handlers = logger.handlers
|
|
||||||
logger.handlers = []
|
|
||||||
|
|
||||||
config = {'verbosity': 2,
|
|
||||||
'logfile': 'journald',
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_logging_pre()
|
|
||||||
setup_logging(config)
|
|
||||||
assert len(logger.handlers) == 3
|
|
||||||
assert [x for x in logger.handlers if type(x).__name__ == "JournaldLogHandler"]
|
|
||||||
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
|
||||||
# reset handlers to not break pytest
|
|
||||||
logger.handlers = orig_handlers
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_loggers_journald_importerror(import_fails):
|
|
||||||
logger = logging.getLogger()
|
|
||||||
orig_handlers = logger.handlers
|
|
||||||
logger.handlers = []
|
|
||||||
|
|
||||||
config = {'verbosity': 2,
|
|
||||||
'logfile': 'journald',
|
|
||||||
}
|
|
||||||
with pytest.raises(OperationalException,
|
|
||||||
match=r'You need the cysystemd python package.*'):
|
|
||||||
setup_logging(config)
|
|
||||||
logger.handlers = orig_handlers
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_logfile(default_conf, mocker, tmpdir):
|
def test_set_logfile(default_conf, mocker, tmpdir):
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
f = Path(tmpdir / "test_file.log")
|
f = Path(tmpdir / "test_file.log")
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from freqtrade.exceptions import OperationalException
|
||||||
|
from freqtrade.loggers import (FTBufferingHandler, FTStdErrStreamHandler, set_loggers,
|
||||||
|
setup_logging, setup_logging_pre)
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_loggers() -> None:
|
||||||
|
# Reset Logging to Debug, otherwise this fails randomly as it's set globally
|
||||||
|
logging.getLogger('requests').setLevel(logging.DEBUG)
|
||||||
|
logging.getLogger("urllib3").setLevel(logging.DEBUG)
|
||||||
|
logging.getLogger('ccxt.base.exchange').setLevel(logging.DEBUG)
|
||||||
|
logging.getLogger('telegram').setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
previous_value1 = logging.getLogger('requests').level
|
||||||
|
previous_value2 = logging.getLogger('ccxt.base.exchange').level
|
||||||
|
previous_value3 = logging.getLogger('telegram').level
|
||||||
|
|
||||||
|
set_loggers()
|
||||||
|
|
||||||
|
value1 = logging.getLogger('requests').level
|
||||||
|
assert previous_value1 is not value1
|
||||||
|
assert value1 is logging.INFO
|
||||||
|
|
||||||
|
value2 = logging.getLogger('ccxt.base.exchange').level
|
||||||
|
assert previous_value2 is not value2
|
||||||
|
assert value2 is logging.INFO
|
||||||
|
|
||||||
|
value3 = logging.getLogger('telegram').level
|
||||||
|
assert previous_value3 is not value3
|
||||||
|
assert value3 is logging.INFO
|
||||||
|
|
||||||
|
set_loggers(verbosity=2)
|
||||||
|
|
||||||
|
assert logging.getLogger('requests').level is logging.DEBUG
|
||||||
|
assert logging.getLogger('ccxt.base.exchange').level is logging.INFO
|
||||||
|
assert logging.getLogger('telegram').level is logging.INFO
|
||||||
|
assert logging.getLogger('werkzeug').level is logging.INFO
|
||||||
|
|
||||||
|
set_loggers(verbosity=3, api_verbosity='error')
|
||||||
|
|
||||||
|
assert logging.getLogger('requests').level is logging.DEBUG
|
||||||
|
assert logging.getLogger('ccxt.base.exchange').level is logging.DEBUG
|
||||||
|
assert logging.getLogger('telegram').level is logging.INFO
|
||||||
|
assert logging.getLogger('werkzeug').level is logging.ERROR
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||||
|
def test_set_loggers_syslog():
|
||||||
|
logger = logging.getLogger()
|
||||||
|
orig_handlers = logger.handlers
|
||||||
|
logger.handlers = []
|
||||||
|
|
||||||
|
config = {'verbosity': 2,
|
||||||
|
'logfile': 'syslog:/dev/log',
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_logging_pre()
|
||||||
|
setup_logging(config)
|
||||||
|
assert len(logger.handlers) == 3
|
||||||
|
assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler]
|
||||||
|
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
||||||
|
assert [x for x in logger.handlers if type(x) == FTBufferingHandler]
|
||||||
|
# setting up logging again should NOT cause the loggers to be added a second time.
|
||||||
|
setup_logging(config)
|
||||||
|
assert len(logger.handlers) == 3
|
||||||
|
# reset handlers to not break pytest
|
||||||
|
logger.handlers = orig_handlers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||||
|
def test_set_loggers_Filehandler(tmpdir):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
orig_handlers = logger.handlers
|
||||||
|
logger.handlers = []
|
||||||
|
logfile = Path(tmpdir) / 'ft_logfile.log'
|
||||||
|
config = {'verbosity': 2,
|
||||||
|
'logfile': str(logfile),
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_logging_pre()
|
||||||
|
setup_logging(config)
|
||||||
|
assert len(logger.handlers) == 3
|
||||||
|
assert [x for x in logger.handlers if type(x) == logging.handlers.RotatingFileHandler]
|
||||||
|
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
||||||
|
assert [x for x in logger.handlers if type(x) == FTBufferingHandler]
|
||||||
|
# setting up logging again should NOT cause the loggers to be added a second time.
|
||||||
|
setup_logging(config)
|
||||||
|
assert len(logger.handlers) == 3
|
||||||
|
# reset handlers to not break pytest
|
||||||
|
if logfile.exists:
|
||||||
|
logfile.unlink()
|
||||||
|
logger.handlers = orig_handlers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="systemd is not installed on every system, so we're not testing this.")
|
||||||
|
def test_set_loggers_journald(mocker):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
orig_handlers = logger.handlers
|
||||||
|
logger.handlers = []
|
||||||
|
|
||||||
|
config = {'verbosity': 2,
|
||||||
|
'logfile': 'journald',
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_logging_pre()
|
||||||
|
setup_logging(config)
|
||||||
|
assert len(logger.handlers) == 3
|
||||||
|
assert [x for x in logger.handlers if type(x).__name__ == "JournaldLogHandler"]
|
||||||
|
assert [x for x in logger.handlers if type(x) == FTStdErrStreamHandler]
|
||||||
|
# reset handlers to not break pytest
|
||||||
|
logger.handlers = orig_handlers
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_loggers_journald_importerror(import_fails):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
orig_handlers = logger.handlers
|
||||||
|
logger.handlers = []
|
||||||
|
|
||||||
|
config = {'verbosity': 2,
|
||||||
|
'logfile': 'journald',
|
||||||
|
}
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match=r'You need the cysystemd python package.*'):
|
||||||
|
setup_logging(config)
|
||||||
|
logger.handlers = orig_handlers
|
||||||
Reference in New Issue
Block a user