# Virus Data Analysis Tool: a data reduction GUI for HETDEX/VIRUS data
# Copyright (C) 2015, 2016 "The HETDEX collaboration"
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Deal with loggers"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import logging
import os
import six
import vdat.config as vdatconfig
[docs]def setup_main_logger(conf, name='logger'):
"""Setup the main vdat logger.
Add to the logger called ``name`` a standard output and a file logger
Parameters
----------
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options,
"""
log = logging.getLogger(name)
# force debug to make handlers decide
log.setLevel(_to_log_level(conf.get('logging',
'logger_level')))
# create and add the handlers
for section in ['logging.main.stdout', 'logging.main.file']:
sconf = add_parent(conf, section) # get the content of the section
h = make_handler(sconf)
log.addHandler(h)
[docs]def make_logger(logger, conf, section=None):
"""Create a handler using the instructions in the configuration ``section``
and add it to the ``logger``.
It looks for the following options:
* ``remove_old``: if True remove all the previous handlers before
adding the new one, default ``False``
* ``remove_std``: if True remove all the previous
:class:`~logging.StreamHandler``, default ``False``
* the ones used by :func:`make_handler`
Parameters
----------
logger : :class:`~logging.Logger` instance
logger
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options
section : string, default
name of the section containing the information to build the logger;
defaults to ``logging.name``, where ``name`` is the logger name
"""
if not section:
section = "logging.{}".format(logger.name)
dconf = add_parent(conf, section)
# get rid of old or std handlers
if dconf.getboolean('remove_old', False):
for h in logger.handlers:
logger.removeHandler(h)
elif dconf.getboolean('remove_std', False):
for h in logger.handlers:
if type(h) == logging.StreamHandler:
logger.removeHandler(h)
else:
pass
# set the logger level
logger.setLevel(_to_log_level(dconf['logger_level']))
handler = make_handler(dconf)
if handler:
logger.addHandler(handler)
[docs]def astropy_handlers(conf):
"""Tweak the astropy logger removing the existing (stream) handlers and
setting a new one if required
Parameters
----------
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options,
"""
from astropy import log as astropy_log
make_logger(astropy_log, conf=conf, section='logging.astropy')
[docs]def ginga_handlers(conf):
"""Create/update the ginga logger removing existing handlers
setting a new one if required
Parameters
----------
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options,
"""
make_logger(logging.getLogger('ginga'), conf=conf)
[docs]def setup_command_loggers(main_config):
"""Set up the loggers for the commands connected or connectible to
buttons
Parameters
----------
main_config : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options,
"""
command_config = vdatconfig.get_config('commands')
section = 'logging.commands'
commands = set()
for k, v in six.iteritems(command_config):
# loop through all the commands and create a logger accordingly
try:
exe_name = v['is_alias_of']
except KeyError:
exe_name = k
commands.add(exe_name)
for c in commands:
file_name = '{}{}'.format(c, main_config[section]['extension'])
main_config[section]['file_name'] = file_name
logger = logging.getLogger(name=c)
make_logger(logger, conf=main_config, section=section)
[docs]def add_parent(conf, section, from_parent=['logdir', 'logger_level']):
"""Extract the ``section`` and, if ``from_parent`` is not an empty list,
extend the section with those entry from the parent, without overwriting
existing entries in ``section``
The parent section of e.g. ``section=logging.main.stdout`` is ``logging``.
Parameters
----------
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` instance
configuration options,
section : string
name of the section in the configuration where to find all the info
Returns
-------
:class:`~pyhetdex.tools.configuration.ConfigParser` section
"""
dconf = conf[section]
if from_parent:
parent_section = section.split('.')[0]
for fp in from_parent:
if fp not in dconf and fp in conf[parent_section]:
dconf[fp] = conf[parent_section][fp]
return dconf
[docs]def make_handler(conf):
"""Create a handler following the instructions contained in ``section``
It looks for the following options:
* enabled: if False, doesn't create a handler and returns None; default
False
* file_name: if not found, a :class:`~logging.StreamHandler` is created, if
exists, a :class:`~logging.FileHandler` is created
* logdir: directory where the log file goes; default '.'
* format: formatting of the message, default %(levelname)s: %(message)s
* level: level of the handler, default INFO
Parameters
----------
conf : :class:`~pyhetdex.tools.configuration.ConfigParser` section
configuration options for the handler; it can be created using
:func:`add_parent`
Returns
-------
None, if enabled is ``False``
:class:`~logging.StreamHandler`: if not file name is given
:class:`~logging.FileHandler`: otherwise
"""
if not conf.getboolean('enabled', False):
return None
file_name = conf.get('file_name', None)
if file_name:
logdir = conf.get('logdir', os.curdir)
if not os.path.exists(logdir):
os.mkdir(logdir)
handler = logging.FileHandler(os.path.join(logdir, file_name))
else:
handler = logging.StreamHandler()
logform = conf.get('format', '%(levelname)s: %(message)s')
handler.setFormatter(logging.Formatter(logform))
handler.setLevel(_to_log_level(conf.get("level", logging.INFO)))
return handler
[docs]def _to_log_level(level, default=logging.INFO):
"""Try to convert ``level`` to int or to extract the level
``level`` from the logging module. If both fail, return the default.
See `here
<https://docs.python.org/3.4/library/logging.html?highlight=logging#logging-levels>`_
for more info about logging levels.
Parameters
----------
level : string
numerical or literal value of the level
Returns
-------
int
handler level
"""
try:
return int(level)
except ValueError: # it's not an integer
pass
return getattr(logging, level, default)