stable/freqtrade/loggers.py

133 lines
5.1 KiB
Python
Raw Normal View History

2019-07-06 22:40:52 +00:00
import logging
import sys
2019-10-25 06:50:37 +00:00
from logging import Formatter
2020-09-28 17:39:41 +00:00
from logging.handlers import BufferingHandler, RotatingFileHandler, SysLogHandler
2019-07-06 22:40:52 +00:00
2022-09-18 11:20:36 +00:00
from freqtrade.constants import Config
from freqtrade.exceptions import OperationalException
2019-10-25 06:50:37 +00:00
2020-09-28 17:39:41 +00:00
class FTBufferingHandler(BufferingHandler):
def flush(self):
"""
Override Flush behaviour - we keep half of the configured capacity
otherwise, we have moments with "empty" logs.
"""
self.acquire()
try:
# Keep half of the records in buffer.
self.buffer = self.buffer[-int(self.capacity / 2):]
finally:
self.release()
2019-07-06 22:40:52 +00:00
logger = logging.getLogger(__name__)
2020-08-14 12:41:46 +00:00
LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
2019-07-06 22:40:52 +00:00
# Initialize bufferhandler - will be used for /log endpoints
bufferHandler = FTBufferingHandler(1000)
bufferHandler.setFormatter(Formatter(LOGFORMAT))
2019-07-06 22:40:52 +00:00
def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None:
2019-07-06 22:40:52 +00:00
"""
2019-07-07 07:17:01 +00:00
Set the logging level for third party libraries
2019-07-06 22:40:52 +00:00
:return: None
"""
logging.getLogger('requests').setLevel(
2020-03-10 19:30:36 +00:00
logging.INFO if verbosity <= 1 else logging.DEBUG
2019-07-06 22:40:52 +00:00
)
logging.getLogger("urllib3").setLevel(
2020-03-10 19:30:36 +00:00
logging.INFO if verbosity <= 1 else logging.DEBUG
2019-07-06 22:40:52 +00:00
)
logging.getLogger('ccxt.base.exchange').setLevel(
2020-03-10 19:30:36 +00:00
logging.INFO if verbosity <= 2 else logging.DEBUG
2019-07-06 22:40:52 +00:00
)
logging.getLogger('telegram').setLevel(logging.INFO)
logging.getLogger('werkzeug').setLevel(
logging.ERROR if api_verbosity == 'error' else logging.INFO
)
2019-07-06 22:40:52 +00:00
2020-11-25 13:31:34 +00:00
def get_existing_handlers(handlertype):
"""
Returns Existing handler or None (if the handler has not yet been added to the root handlers).
"""
return next((h for h in logging.root.handlers if isinstance(h, handlertype)), None)
2020-08-14 12:41:46 +00:00
def setup_logging_pre() -> None:
"""
2020-08-14 18:12:59 +00:00
Early setup for logging.
Uses INFO loglevel and only the Streamhandler.
Early messages (before proper logging setup) will therefore only be sent to additional
logging handlers after the real initialization, because we don't know which
ones the user desires beforehand.
2020-08-14 12:41:46 +00:00
"""
2020-08-14 12:53:21 +00:00
logging.basicConfig(
level=logging.INFO,
format=LOGFORMAT,
handlers=[logging.StreamHandler(sys.stderr), bufferHandler]
2020-08-14 12:53:21 +00:00
)
2020-08-14 12:41:46 +00:00
2022-09-18 11:20:36 +00:00
def setup_logging(config: Config) -> None:
2019-07-06 22:40:52 +00:00
"""
Process -v/--verbose, --logfile options
2019-07-06 22:40:52 +00:00
"""
# Log level
verbosity = config['verbosity']
logging.root.addHandler(bufferHandler)
2019-07-06 22:40:52 +00:00
2019-10-25 06:50:37 +00:00
logfile = config.get('logfile')
2019-10-25 06:50:37 +00:00
if logfile:
s = logfile.split(':')
if s[0] == 'syslog':
# Address can be either a string (socket filename) for Unix domain socket or
# a tuple (hostname, port) for UDP socket.
# Address can be omitted (i.e. simple 'syslog' used as the value of
# config['logfilename']), which defaults to '/dev/log', applicable for most
# of the systems.
address = (s[1], int(s[2])) if len(s) > 2 else s[1] if len(s) > 1 else '/dev/log'
2020-11-25 13:31:34 +00:00
handler_sl = get_existing_handlers(SysLogHandler)
if handler_sl:
logging.root.removeHandler(handler_sl)
handler_sl = SysLogHandler(address=address)
2019-10-25 06:50:37 +00:00
# No datetime field for logging into syslog, to allow syslog
# to perform reduction of repeating messages if this is set in the
# syslog config. The messages should be equal for this.
2020-11-25 13:31:34 +00:00
handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s'))
logging.root.addHandler(handler_sl)
elif s[0] == 'journald': # pragma: no cover
2019-10-25 06:50:37 +00:00
try:
from cysystemd.journal import JournaldLogHandler
2019-10-25 06:50:37 +00:00
except ImportError:
raise OperationalException("You need the systemd python package be installed in "
"order to use logging to journald.")
2020-11-25 13:31:34 +00:00
handler_jd = get_existing_handlers(JournaldLogHandler)
if handler_jd:
logging.root.removeHandler(handler_jd)
2020-08-15 06:15:18 +00:00
handler_jd = JournaldLogHandler()
2019-10-25 06:50:37 +00:00
# No datetime field for logging into journald, to allow syslog
# to perform reduction of repeating messages if this is set in the
# syslog config. The messages should be equal for this.
2020-08-15 06:15:18 +00:00
handler_jd.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s'))
logging.root.addHandler(handler_jd)
2019-10-25 06:50:37 +00:00
else:
2020-11-25 13:31:34 +00:00
handler_rf = get_existing_handlers(RotatingFileHandler)
if handler_rf:
logging.root.removeHandler(handler_rf)
2020-08-15 06:15:18 +00:00
handler_rf = RotatingFileHandler(logfile,
maxBytes=1024 * 1024 * 10, # 10Mb
backupCount=10)
handler_rf.setFormatter(Formatter(LOGFORMAT))
logging.root.addHandler(handler_rf)
2020-08-14 12:41:46 +00:00
logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG)
_set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info'))
2020-08-14 12:53:21 +00:00
2019-07-06 22:40:52 +00:00
logger.info('Verbosity set to %s', verbosity)