PyBitmessage/src/debug.py

141 lines
4.0 KiB
Python
Raw Normal View History

2018-04-08 15:28:08 +00:00
"""
Logging and debuging facility
=============================
Levels:
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: `console_only`, `file_only` and `both`.
Use: `from debug import logger` to import this facility into whatever module you wish to log messages from.
Logging is thread-safe so you don't have to worry about locks, just import and log.
2018-04-08 15:28:08 +00:00
"""
import ConfigParser
import logging
import logging.config
import os
import sys
2014-10-13 05:59:16 +00:00
import helper_startup
import state
2018-04-08 15:28:08 +00:00
2014-10-13 05:59:16 +00:00
helper_startup.loadConfig()
2018-04-08 15:28:08 +00:00
# Now can be overriden from a config file, which uses standard python
# logging.config.fileConfig interface
# examples are here:
# https://bitmessage.org/forum/index.php/topic,4820.msg11163.html#msg11163
log_level = 'WARNING'
2018-04-08 15:28:08 +00:00
def log_uncaught_exceptions(ex_cls, ex, tb):
logging.critical('Unhandled exception', exc_info=(ex_cls, ex, tb))
2018-04-08 15:28:08 +00:00
2013-07-15 19:45:03 +00:00
def configureLogging():
fail_msg = ''
try:
logging_config = os.path.join(state.appdata, 'logging.dat')
logging.config.fileConfig(logging_config)
return (
False,
'Loaded logger configuration from %s' % logging_config
)
except (OSError, ConfigParser.NoSectionError):
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())
else:
# no need to confuse the user if the logger config is missing entirely
fail_msg = 'Using default logger configuration'
2018-04-08 15:28:08 +00:00
sys.excepthook = log_uncaught_exceptions
2013-07-15 19:45:03 +00:00
logging.config.dictConfig({
'version': 1,
'formatters': {
'default': {
'format': u'%(asctime)s - %(levelname)s - %(message)s',
2013-07-15 19:45:03 +00:00
},
},
2013-07-15 19:45:03 +00:00
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'default',
'level': log_level,
'stream': 'ext://sys.stderr'
2013-07-15 19:45:03 +00:00
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'default',
'level': log_level,
'filename': os.path.join(state.appdata, 'debug.log'),
2018-04-08 15:28:08 +00:00
'maxBytes': 2097152, # 2 MiB
2013-07-15 19:45:03 +00:00
'backupCount': 1,
'encoding': 'UTF-8',
2013-07-15 19:45:03 +00:00
}
},
'loggers': {
'console_only': {
'handlers': ['console'],
2018-04-08 15:28:08 +00:00
'propagate': 0
2013-07-15 19:45:03 +00:00
},
'file_only': {
'handlers': ['file'],
2018-04-08 15:28:08 +00:00
'propagate': 0
2013-07-15 19:45:03 +00:00
},
'both': {
'handlers': ['console', 'file'],
2018-04-08 15:28:08 +00:00
'propagate': 0
2013-07-15 19:45:03 +00:00
},
},
2013-07-15 19:45:03 +00:00
'root': {
'level': log_level,
'handlers': ['console'],
},
2013-07-15 19:45:03 +00:00
})
return True, fail_msg
2018-04-08 15:28:08 +00:00
def initLogging():
preconfigured, msg = configureLogging()
if preconfigured:
if '-c' in sys.argv:
logger = logging.getLogger('file_only')
else:
logger = logging.getLogger('both')
else:
logger = logging.getLogger('default')
if msg:
logger.log(logging.WARNING if preconfigured else logging.INFO, msg)
return logger
2013-07-15 19:45:03 +00:00
def resetLogging():
2013-07-15 19:45:03 +00:00
global logger
for i in logger.handlers.iterkeys():
2013-07-15 19:45:03 +00:00
logger.removeHandler(i)
i.flush()
i.close()
logger = initLogging()
# !
logger = initLogging()