2018-04-08 17:28:08 +02:00
|
|
|
"""
|
2013-06-29 18:27:40 +02:00
|
|
|
Logging and debuging facility
|
2019-08-06 13:04:33 +02:00
|
|
|
-----------------------------
|
2013-06-29 18:27:40 +02:00
|
|
|
|
|
|
|
Levels:
|
2018-05-26 14:43:21 +02:00
|
|
|
|
2019-08-06 13:04:33 +02:00
|
|
|
DEBUG
|
|
|
|
Detailed information, typically of interest only when diagnosing problems.
|
|
|
|
INFO
|
|
|
|
Confirmation that things are working as expected.
|
|
|
|
WARNING
|
|
|
|
An indication that something unexpected happened, or indicative of
|
|
|
|
some problem in the near future (e.g. 'disk space low'). The software
|
|
|
|
is still working as expected.
|
|
|
|
ERROR
|
|
|
|
Due to a more serious problem, the software has not been able to
|
|
|
|
perform some function.
|
|
|
|
CRITICAL
|
|
|
|
A serious error, indicating that the program itself may be unable to
|
|
|
|
continue running.
|
|
|
|
|
|
|
|
There are three loggers by default: `console_only`, `file_only` and `both`.
|
|
|
|
You can configure logging in the logging.dat in the appdata dir.
|
|
|
|
It's format is described in the :func:`logging.config.fileConfig` doc.
|
|
|
|
|
|
|
|
Use:
|
|
|
|
|
|
|
|
>>> import logging
|
|
|
|
>>> logger = logging.getLogger('default')
|
|
|
|
|
|
|
|
The old form: ``from debug import logger`` is also may be used,
|
|
|
|
but only in the top level modules.
|
|
|
|
|
|
|
|
Logging is thread-safe so you don't have to worry about locks,
|
|
|
|
just import and log.
|
2018-04-08 17:28:08 +02:00
|
|
|
"""
|
2018-05-26 14:43:21 +02:00
|
|
|
|
2013-06-29 18:27:40 +02:00
|
|
|
import logging
|
|
|
|
import logging.config
|
2015-11-18 16:22:17 +01:00
|
|
|
import os
|
2014-04-19 20:45:37 +02:00
|
|
|
import sys
|
2019-08-06 13:04:33 +02:00
|
|
|
|
2021-07-07 20:49:56 +02:00
|
|
|
from six.moves import configparser
|
|
|
|
|
|
|
|
import helper_startup
|
|
|
|
import state
|
2018-04-08 17:28:08 +02:00
|
|
|
|
2014-10-13 07:59:16 +02:00
|
|
|
helper_startup.loadConfig()
|
2013-06-29 18:27:40 +02:00
|
|
|
|
2018-04-08 17:28:08 +02:00
|
|
|
# Now can be overriden from a config file, which uses standard python
|
|
|
|
# logging.config.fileConfig interface
|
|
|
|
# examples are here:
|
2022-08-23 17:02:26 +02:00
|
|
|
# https://web.archive.org/web/20170712122006/https://bitmessage.org/forum/index.php/topic,4820.msg11163.html#msg11163
|
2016-04-30 12:45:01 +02:00
|
|
|
log_level = 'WARNING'
|
2013-06-29 18:27:40 +02:00
|
|
|
|
2018-04-08 17:28:08 +02:00
|
|
|
|
2015-11-18 16:22:17 +01:00
|
|
|
def log_uncaught_exceptions(ex_cls, ex, tb):
|
2019-08-06 13:04:33 +02:00
|
|
|
"""The last resort logging function used for sys.excepthook"""
|
2017-11-30 19:44:03 +01:00
|
|
|
logging.critical('Unhandled exception', exc_info=(ex_cls, ex, tb))
|
2015-11-18 16:22:17 +01:00
|
|
|
|
2018-04-08 17:28:08 +02:00
|
|
|
|
2013-07-15 21:45:03 +02:00
|
|
|
def configureLogging():
|
2019-08-06 13:04:33 +02:00
|
|
|
"""
|
|
|
|
Configure logging,
|
|
|
|
using either logging.dat file in the state.appdata dir
|
|
|
|
or dictionary with hardcoded settings.
|
|
|
|
"""
|
|
|
|
sys.excepthook = log_uncaught_exceptions
|
2018-07-21 11:16:22 +02:00
|
|
|
fail_msg = ''
|
2015-11-18 16:22:17 +01:00
|
|
|
try:
|
2018-07-21 11:16:22 +02:00
|
|
|
logging_config = os.path.join(state.appdata, 'logging.dat')
|
2019-08-30 13:56:46 +02:00
|
|
|
logging.config.fileConfig(
|
|
|
|
logging_config, disable_existing_loggers=False)
|
2018-07-21 11:16:22 +02:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'Loaded logger configuration from %s' % logging_config
|
|
|
|
)
|
2021-07-07 20:49:56 +02:00
|
|
|
except (OSError, configparser.NoSectionError, KeyError):
|
2018-07-21 11:16:22 +02:00
|
|
|
if os.path.isfile(logging_config):
|
|
|
|
fail_msg = \
|
|
|
|
'Failed to load logger configuration from %s, using default' \
|
|
|
|
' logging config\n%s' % \
|
|
|
|
(logging_config, sys.exc_info())
|
2016-08-29 05:56:21 +02:00
|
|
|
else:
|
2019-08-30 13:56:46 +02:00
|
|
|
# no need to confuse the user if the logger config
|
|
|
|
# is missing entirely
|
2018-07-21 11:16:22 +02:00
|
|
|
fail_msg = 'Using default logger configuration'
|
2018-04-08 17:28:08 +02:00
|
|
|
|
2019-08-06 13:04:33 +02:00
|
|
|
logging_config = {
|
2013-07-15 21:45:03 +02:00
|
|
|
'version': 1,
|
|
|
|
'formatters': {
|
|
|
|
'default': {
|
2018-01-25 08:11:42 +01:00
|
|
|
'format': u'%(asctime)s - %(levelname)s - %(message)s',
|
2013-07-15 21:45:03 +02:00
|
|
|
},
|
2013-06-29 18:27:40 +02:00
|
|
|
},
|
2013-07-15 21:45:03 +02:00
|
|
|
'handlers': {
|
|
|
|
'console': {
|
|
|
|
'class': 'logging.StreamHandler',
|
|
|
|
'formatter': 'default',
|
|
|
|
'level': log_level,
|
2017-09-22 23:59:14 +02:00
|
|
|
'stream': 'ext://sys.stderr'
|
2013-07-15 21:45:03 +02:00
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'class': 'logging.handlers.RotatingFileHandler',
|
|
|
|
'formatter': 'default',
|
|
|
|
'level': log_level,
|
2018-07-21 11:16:22 +02:00
|
|
|
'filename': os.path.join(state.appdata, 'debug.log'),
|
2018-04-08 17:28:08 +02:00
|
|
|
'maxBytes': 2097152, # 2 MiB
|
2013-07-15 21:45:03 +02:00
|
|
|
'backupCount': 1,
|
2016-12-06 16:15:37 +01:00
|
|
|
'encoding': 'UTF-8',
|
2013-07-15 21:45:03 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
'loggers': {
|
|
|
|
'console_only': {
|
|
|
|
'handlers': ['console'],
|
2018-04-08 17:28:08 +02:00
|
|
|
'propagate': 0
|
2013-07-15 21:45:03 +02:00
|
|
|
},
|
|
|
|
'file_only': {
|
|
|
|
'handlers': ['file'],
|
2018-04-08 17:28:08 +02:00
|
|
|
'propagate': 0
|
2013-07-15 21:45:03 +02:00
|
|
|
},
|
|
|
|
'both': {
|
|
|
|
'handlers': ['console', 'file'],
|
2018-04-08 17:28:08 +02:00
|
|
|
'propagate': 0
|
2013-07-15 21:45:03 +02:00
|
|
|
},
|
2013-06-29 18:27:40 +02:00
|
|
|
},
|
2013-07-15 21:45:03 +02:00
|
|
|
'root': {
|
2013-06-29 18:27:40 +02:00
|
|
|
'level': log_level,
|
|
|
|
'handlers': ['console'],
|
|
|
|
},
|
2019-08-06 13:04:33 +02:00
|
|
|
}
|
2018-04-08 17:28:08 +02:00
|
|
|
|
2019-08-06 13:04:33 +02:00
|
|
|
logging_config['loggers']['default'] = logging_config['loggers'][
|
|
|
|
'file_only' if '-c' in sys.argv else 'both']
|
|
|
|
logging.config.dictConfig(logging_config)
|
2018-05-26 14:43:21 +02:00
|
|
|
|
2019-08-06 13:04:33 +02:00
|
|
|
return True, fail_msg
|
2018-06-27 10:24:09 +02:00
|
|
|
|
2013-07-15 21:45:03 +02:00
|
|
|
|
2018-07-21 11:16:22 +02:00
|
|
|
def resetLogging():
|
2019-08-06 13:04:33 +02:00
|
|
|
"""Reconfigure logging in runtime when state.appdata dir changed"""
|
2019-10-05 16:43:08 +02:00
|
|
|
# pylint: disable=global-statement, used-before-assignment
|
2013-07-15 21:45:03 +02:00
|
|
|
global logger
|
2019-08-06 13:04:33 +02:00
|
|
|
for i in logger.handlers:
|
2013-07-15 21:45:03 +02:00
|
|
|
logger.removeHandler(i)
|
|
|
|
i.flush()
|
|
|
|
i.close()
|
2019-08-06 13:04:33 +02:00
|
|
|
configureLogging()
|
|
|
|
logger = logging.getLogger('default')
|
2018-06-27 10:24:09 +02:00
|
|
|
|
2018-05-26 14:43:21 +02:00
|
|
|
|
2018-06-27 10:24:09 +02:00
|
|
|
# !
|
2021-03-04 15:15:41 +01:00
|
|
|
|
2019-08-06 13:04:33 +02:00
|
|
|
preconfigured, msg = configureLogging()
|
|
|
|
logger = logging.getLogger('default')
|
|
|
|
if msg:
|
|
|
|
logger.log(logging.WARNING if preconfigured else logging.INFO, msg)
|