Source code for mycroft.util.log

# Copyright 2017 Mycroft AI Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


"""
Mycroft Logging module.

This module provides the LOG pseudo function quickly creating a logger instance
for use.

The default log level of the logger created here can ONLY be set in
/etc/mycroft/mycroft.conf or ~/.config/mycroft/mycroft.conf

The default log level can also be programatically be changed by setting the
LOG.level parameter.
"""

import inspect
import logging
import sys

import mycroft


[docs]def getLogger(name="MYCROFT"): """Depreciated. Use LOG instead""" return logging.getLogger(name)
def _make_log_method(fn): @classmethod def method(cls, *args, **kwargs): cls._log(fn, *args, **kwargs) method.__func__.__doc__ = fn.__doc__ return method
[docs]class LOG: """ Custom logger class that acts like logging.Logger The logger name is automatically generated by the module of the caller Usage: >>> LOG.debug('My message: %s', debug_str) 13:12:43.673 - :<module>:1 - DEBUG - My message: hi >>> LOG('custom_name').debug('Another message') 13:13:10.462 - custom_name - DEBUG - Another message """ _custom_name = None handler = None level = logging.getLevelName('INFO') # Copy actual logging methods from logging.Logger # Usage: LOG.debug(message) debug = _make_log_method(logging.Logger.debug) info = _make_log_method(logging.Logger.info) warning = _make_log_method(logging.Logger.warning) error = _make_log_method(logging.Logger.error) exception = _make_log_method(logging.Logger.exception)
[docs] @classmethod def init(cls): """ Initializes the class, sets the default log level and creates the required handlers. """ log_message_format = ( '{asctime} | {levelname:8} | {process:5} | {name} | {message}' ) formatter = logging.Formatter(log_message_format, style='{') formatter.default_msec_format = '%s.%03d' cls.handler = logging.StreamHandler(sys.stdout) cls.handler.setFormatter(formatter) config = mycroft.configuration.Configuration.get(cache=False, remote=False) if config.get('log_format'): formatter = logging.Formatter(config.get('log_format'), style='{') cls.handler.setFormatter(formatter) cls.level = logging.getLevelName(config.get('log_level', 'INFO')) # Enable logging in external modules cls.create_logger('').setLevel(cls.level)
@classmethod def create_logger(cls, name): logger = logging.getLogger(name) logger.propagate = False logger.addHandler(cls.handler) return logger def __init__(self, name): LOG._custom_name = name @classmethod def _log(cls, func, *args, **kwargs): if cls._custom_name is not None: name = cls._custom_name cls._custom_name = None else: # Stack: # [0] - _log() # [1] - debug(), info(), warning(), or error() # [2] - caller try: stack = inspect.stack() # Record: # [0] - frame object # [1] - filename # [2] - line number # [3] - function # ... record = stack[2] mod = inspect.getmodule(record[0]) module_name = mod.__name__ if mod else '' name = module_name + ':' + record[3] + ':' + str(record[2]) except Exception: # The location couldn't be determined name = 'Mycroft' func(cls.create_logger(name), *args, **kwargs)