Add multiple verbosity levels

This commit is contained in:
Matthias 2018-07-19 21:12:27 +02:00
parent 62701888c9
commit dd1290e38e
6 changed files with 96 additions and 52 deletions

View File

@ -3,7 +3,6 @@ This module contains the argument manager class
""" """
import argparse import argparse
import logging
import os import os
import re import re
from typing import List, NamedTuple, Optional from typing import List, NamedTuple, Optional
@ -64,11 +63,10 @@ class Arguments(object):
""" """
self.parser.add_argument( self.parser.add_argument(
'-v', '--verbose', '-v', '--verbose',
help='be verbose', help='verbose mode (-vv for more, -vvv to get all messages)',
action='store_const', action='count',
dest='loglevel', dest='loglevel',
const=logging.DEBUG, default=0,
default=logging.INFO,
) )
self.parser.add_argument( self.parser.add_argument(
'--version', '--version',

View File

@ -12,10 +12,22 @@ from jsonschema import Draft4Validator, validate
from jsonschema.exceptions import ValidationError, best_match from jsonschema.exceptions import ValidationError, best_match
from freqtrade import OperationalException, constants from freqtrade import OperationalException, constants
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def set_loggers(log_level: int = 0) -> None:
"""
Set the logger level for Third party libs
:return: None
"""
logging.getLogger('requests').setLevel(logging.INFO if log_level <= 1 else logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.INFO if log_level <= 1 else logging.DEBUG)
logging.getLogger('ccxt.base.exchange').setLevel(
logging.INFO if log_level <= 2 else logging.DEBUG)
logging.getLogger('telegram').setLevel(logging.INFO)
class Configuration(object): class Configuration(object):
""" """
Class to read and init the bot configuration Class to read and init the bot configuration
@ -79,12 +91,15 @@ class Configuration(object):
# Log level # Log level
if 'loglevel' in self.args and self.args.loglevel: if 'loglevel' in self.args and self.args.loglevel:
config.update({'loglevel': self.args.loglevel}) config.update({'verbosity': self.args.loglevel})
else:
config.update({'verbosity': 0})
logging.basicConfig( logging.basicConfig(
level=config['loglevel'], level=logging.INFO if config['verbosity'] < 1 else logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
) )
logger.info('Log level set to %s', logging.getLevelName(config['loglevel'])) set_loggers(config['verbosity'])
logger.info('Verbosity set to %s', config['verbosity'])
# Add dynamic_whitelist if found # Add dynamic_whitelist if found
if 'dynamic_whitelist' in self.args and self.args.dynamic_whitelist: if 'dynamic_whitelist' in self.args and self.args.dynamic_whitelist:

View File

@ -10,7 +10,7 @@ from typing import List
from freqtrade import OperationalException from freqtrade import OperationalException
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration, set_loggers
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.state import State from freqtrade.state import State
from freqtrade.rpc import RPCMessageType from freqtrade.rpc import RPCMessageType
@ -84,16 +84,6 @@ def reconfigure(freqtrade: FreqtradeBot, args: Namespace) -> FreqtradeBot:
return freqtrade return freqtrade
def set_loggers() -> None:
"""
Set the logger level for Third party libs
:return: None
"""
logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO)
logging.getLogger('ccxt.base.exchange').setLevel(logging.INFO)
logging.getLogger('telegram').setLevel(logging.INFO)
if __name__ == '__main__': if __name__ == '__main__':
set_loggers() set_loggers()
main(sys.argv[1:]) main(sys.argv[1:])

View File

@ -5,7 +5,6 @@ Unit test file for arguments.py
""" """
import argparse import argparse
import logging
import pytest import pytest
@ -35,7 +34,7 @@ def test_parse_args_defaults() -> None:
args = Arguments([], '').get_parsed_arg() args = Arguments([], '').get_parsed_arg()
assert args.config == 'config.json' assert args.config == 'config.json'
assert args.dynamic_whitelist is None assert args.dynamic_whitelist is None
assert args.loglevel == logging.INFO assert args.loglevel == 0
def test_parse_args_config() -> None: def test_parse_args_config() -> None:
@ -53,10 +52,10 @@ def test_parse_args_db_url() -> None:
def test_parse_args_verbose() -> None: def test_parse_args_verbose() -> None:
args = Arguments(['-v'], '').get_parsed_arg() args = Arguments(['-v'], '').get_parsed_arg()
assert args.loglevel == logging.DEBUG assert args.loglevel == 1
args = Arguments(['--verbose'], '').get_parsed_arg() args = Arguments(['--verbose'], '').get_parsed_arg()
assert args.loglevel == logging.DEBUG assert args.loglevel == 1
def test_scripts_options() -> None: def test_scripts_options() -> None:
@ -153,7 +152,7 @@ def test_parse_args_backtesting_custom() -> None:
call_args = Arguments(args, '').get_parsed_arg() call_args = Arguments(args, '').get_parsed_arg()
assert call_args.config == 'test_conf.json' assert call_args.config == 'test_conf.json'
assert call_args.live is True assert call_args.live is True
assert call_args.loglevel == logging.INFO assert call_args.loglevel == 0
assert call_args.subparser == 'backtesting' assert call_args.subparser == 'backtesting'
assert call_args.func is not None assert call_args.func is not None
assert call_args.ticker_interval == '1m' assert call_args.ticker_interval == '1m'
@ -170,7 +169,7 @@ def test_parse_args_hyperopt_custom() -> None:
call_args = Arguments(args, '').get_parsed_arg() call_args = Arguments(args, '').get_parsed_arg()
assert call_args.config == 'test_conf.json' assert call_args.config == 'test_conf.json'
assert call_args.epochs == 20 assert call_args.epochs == 20
assert call_args.loglevel == logging.INFO assert call_args.loglevel == 0
assert call_args.subparser == 'hyperopt' assert call_args.subparser == 'hyperopt'
assert call_args.spaces == ['buy'] assert call_args.spaces == ['buy']
assert call_args.func is not None assert call_args.func is not None

View File

@ -6,6 +6,7 @@ Unit test file for configuration.py
import json import json
from argparse import Namespace from argparse import Namespace
from copy import deepcopy from copy import deepcopy
import logging
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
@ -13,7 +14,7 @@ from jsonschema import ValidationError
from freqtrade import OperationalException from freqtrade import OperationalException
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration, set_loggers
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
from freqtrade.tests.conftest import log_has from freqtrade.tests.conftest import log_has
@ -406,3 +407,63 @@ def test_check_exchange(default_conf) -> None:
match=r'.*Exchange "unknown_exchange" not supported.*' match=r'.*Exchange "unknown_exchange" not supported.*'
): ):
configuration.check_exchange(conf) configuration.check_exchange(conf)
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
"""
Test Configuration.load_config() with cli params used
"""
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(default_conf)))
# Prevent setting loggers
mocker.patch('freqtrade.configuration.set_loggers', MagicMock)
arglist = ['-vvv']
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('verbosity') == 3
assert log_has('Verbosity set to 3', caplog.record_tuples)
def test_set_loggers() -> None:
"""
Test set_loggers() update the logger level for third-party libraries
"""
# 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(log_level=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
set_loggers(log_level=3)
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

View File

@ -2,7 +2,6 @@
Unit test file for main.py Unit test file for main.py
""" """
import logging
from copy import deepcopy from copy import deepcopy
from unittest.mock import MagicMock from unittest.mock import MagicMock
@ -11,7 +10,7 @@ import pytest
from freqtrade import OperationalException from freqtrade import OperationalException
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.main import main, reconfigure, set_loggers from freqtrade.main import main, reconfigure
from freqtrade.state import State from freqtrade.state import State
from freqtrade.tests.conftest import log_has, patch_exchange from freqtrade.tests.conftest import log_has, patch_exchange
@ -27,7 +26,7 @@ def test_parse_args_backtesting(mocker) -> None:
call_args = backtesting_mock.call_args[0][0] call_args = backtesting_mock.call_args[0][0]
assert call_args.config == 'config.json' assert call_args.config == 'config.json'
assert call_args.live is False assert call_args.live is False
assert call_args.loglevel == 20 assert call_args.loglevel == 0
assert call_args.subparser == 'backtesting' assert call_args.subparser == 'backtesting'
assert call_args.func is not None assert call_args.func is not None
assert call_args.ticker_interval is None assert call_args.ticker_interval is None
@ -42,29 +41,11 @@ def test_main_start_hyperopt(mocker) -> None:
assert hyperopt_mock.call_count == 1 assert hyperopt_mock.call_count == 1
call_args = hyperopt_mock.call_args[0][0] call_args = hyperopt_mock.call_args[0][0]
assert call_args.config == 'config.json' assert call_args.config == 'config.json'
assert call_args.loglevel == 20 assert call_args.loglevel == 0
assert call_args.subparser == 'hyperopt' assert call_args.subparser == 'hyperopt'
assert call_args.func is not None assert call_args.func is not None
def test_set_loggers() -> None:
"""
Test set_loggers() update the logger level for third-party libraries
"""
previous_value1 = logging.getLogger('requests.packages.urllib3').level
previous_value2 = logging.getLogger('telegram').level
set_loggers()
value1 = logging.getLogger('requests.packages.urllib3').level
assert previous_value1 is not value1
assert value1 is logging.INFO
value2 = logging.getLogger('telegram').level
assert previous_value2 is not value2
assert value2 is logging.INFO
def test_main_fatal_exception(mocker, default_conf, caplog) -> None: def test_main_fatal_exception(mocker, default_conf, caplog) -> None:
""" """
Test main() function Test main() function