Source code for vdat.libvdat.loggers

# 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)