# -*- coding: utf-8 -*-
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved. #
# This file is part of the AiiDA code. #
# #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida_core #
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
import logging
from copy import deepcopy
from logging import config
from aiida.common import setup
from aiida.backends.utils import is_dbenv_loaded
# Custom logging level, intended specifically for informative log messages
# reported during WorkChains and Workflows. We want the level between INFO(20)
# and WARNING(30) such that it will be logged for the default loglevel, however
# the value 25 is already reserved for SUBWARNING by the multiprocessing module.
LOG_LEVEL_REPORT = 23
logging.addLevelName(LOG_LEVEL_REPORT, 'REPORT')
# Convenience dictionary of available log level names and their log level integer
LOG_LEVELS = {
logging.getLevelName(logging.DEBUG): logging.DEBUG,
logging.getLevelName(logging.INFO): logging.INFO,
logging.getLevelName(LOG_LEVEL_REPORT): LOG_LEVEL_REPORT,
logging.getLevelName(logging.WARNING): logging.WARNING,
logging.getLevelName(logging.ERROR): logging.ERROR,
logging.getLevelName(logging.CRITICAL): logging.CRITICAL,
}
# The AiiDA logger
aiidalogger = logging.getLogger('aiida')
# A logging filter that can be used to disable logging
[docs]class NotInTestingFilter(logging.Filter):
[docs] def filter(self, record):
from aiida import settings
return not settings.TESTING_MODE
# A logging handler that will store the log record in the database DbLog table
[docs]class DBLogHandler(logging.Handler):
[docs] def emit(self, record):
# If this is reached before a backend is defined, simply pass
if not is_dbenv_loaded():
return
from aiida.orm.backend import construct
from django.core.exceptions import ImproperlyConfigured
try:
backend = construct()
backend.log.create_entry_from_record(record)
except ImproperlyConfigured:
# Probably, the logger was called without the
# Django settings module loaded. Then,
# This ignore should be a no-op.
pass
except Exception:
# To avoid loops with the error handler, I just print.
# Hopefully, though, this should not happen!
import traceback
traceback.print_exc()
# The default logging dictionary for AiiDA that can be used in conjunction
# with the config.dictConfig method of python's logging module
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d '
'%(thread)d %(message)s',
},
'halfverbose': {
'format': '%(asctime)s, %(name)s: [%(levelname)s] %(message)s',
'datefmt': '%m/%d/%Y %I:%M:%S %p',
},
},
'filters': {
'testing': {
'()': NotInTestingFilter
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'halfverbose',
'filters': ['testing']
},
'dblogger': {
# setup.get_property takes the property from the config json file
# The key used in the json, and the default value, are
# specified in the _property_table inside aiida.common.setup
# NOTE: To modify properties, use the 'verdi devel setproperty'
# command and similar ones (getproperty, describeproperties, ...)
'level': setup.get_property('logging.db_loglevel'),
'class': 'aiida.common.log.DBLogHandler',
},
},
'loggers': {
'aiida': {
'handlers': ['console', 'dblogger'],
'level': setup.get_property('logging.aiida_loglevel'),
'propagate': False,
},
'paramiko': {
'handlers': ['console'],
'level': setup.get_property('logging.paramiko_loglevel'),
'propagate': False,
},
'alembic': {
'handlers': ['console'],
'level': setup.get_property('logging.alembic_loglevel'),
'propagate': False,
},
'sqlalchemy': {
'handlers': ['console'],
'level': setup.get_property('logging.sqlalchemy_loglevel'),
'propagate': False,
'qualname': 'sqlalchemy.engine',
},
},
}