Link to home
Create AccountLog in
Avatar of naseeam
naseeamFlag for United States of America

asked on

What is logging.getLoggerClass() ?

I'm using python version 3.6.8.  

I'm looking at large python project.  In beginning of __init__.py, there is following statement:

Logger = logging.getLoggerClass()

Open in new window

Is getLoggerClass a class?  Is above code instantiating this class?
What is the purpose of above code?
Avatar of naseeam
naseeam
Flag of United States of America image

ASKER

Following is some code from __init__.py

Logger = logging.getLoggerClass()
class BBLogger(Logger):
    def __init__(self, name):
        if name.split(".")[0] == "BitBake":
            self.debug = self.bbdebug
        Logger.__init__(self, name)

    def bbdebug(self, level, msg, *args, **kwargs):
        return self.log(logging.DEBUG - level + 1, msg, *args, **kwargs)

    def plain(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 1, msg, *args, **kwargs)

    def verbose(self, msg, *args, **kwargs):
        return self.log(logging.INFO - 1, msg, *args, **kwargs)

    def verbnote(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 2, msg, *args, **kwargs)


logging.raiseExceptions = False
logging.setLoggerClass(BBLogger)

logger = logging.getLogger("BitBake")
logger.addHandler(NullHandler())
logger.setLevel(logging.DEBUG - 2)

mainlogger = logging.getLogger("BitBake.Main")

# This has to be imported after the setLoggerClass, as the import of bb.msg
# can result in construction of the various loggers.
import bb.msg

from bb import fetch2 as fetch
sys.modules['bb.fetch'] = sys.modules['bb.fetch2']

Open in new window

Avatar of Mark Brady
logging.getLoggerClass() returns an instantiated logger yes. Here is a few examples and explanations on how to use it.

https://www.programcreek.com/python/example/10123/logging.getLoggerClass
Avatar of naseeam

ASKER

>>  https://www.programcreek.com/python/example/10123/logging.getLoggerClass
I went through these explanations previously but couldn't understand.  
Please provide few complete working examples that use getLoggerClass( ), setLoggerClass( ), and class BBLogger(Logger) in __init__.py file.
There seems to be some connections between getLoggerClass( ), setLoggerClass( ), and class BBLogger(Logger) ?
Following is entire __init__.py file.

__init__.py
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Build System Python Library
#
# Copyright (C) 2003  Holger Schurig
# Copyright (C) 2003, 2004  Chris Larson
#
# Based on Gentoo's portage.py.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

__version__ = "1.40.0"

import sys
if sys.version_info < (3, 4, 0):
    raise RuntimeError("Sorry, python 3.4.0 or later is required for this version of bitbake")


class BBHandledException(Exception):
    """
    The big dilemma for generic bitbake code is what information to give the user
    when an exception occurs. Any exception inheriting this base exception class
    has already provided information to the user via some 'fired' message type such as
    an explicitly fired event using bb.fire, or a bb.error message. If bitbake 
    encounters an exception derived from this class, no backtrace or other information 
    will be given to the user, its assumed the earlier event provided the relevant information.
    """
    pass

import os
import logging


class NullHandler(logging.Handler):
    def emit(self, record):
        pass

Logger = logging.getLoggerClass()
class BBLogger(Logger):
    def __init__(self, name):
        if name.split(".")[0] == "BitBake":
            self.debug = self.bbdebug
        Logger.__init__(self, name)

    def bbdebug(self, level, msg, *args, **kwargs):
        return self.log(logging.DEBUG - level + 1, msg, *args, **kwargs)

    def plain(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 1, msg, *args, **kwargs)

    def verbose(self, msg, *args, **kwargs):
        return self.log(logging.INFO - 1, msg, *args, **kwargs)

    def verbnote(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 2, msg, *args, **kwargs)


logging.raiseExceptions = False
logging.setLoggerClass(BBLogger)

logger = logging.getLogger("BitBake")
logger.addHandler(NullHandler())
logger.setLevel(logging.DEBUG - 2)

mainlogger = logging.getLogger("BitBake.Main")

# This has to be imported after the setLoggerClass, as the import of bb.msg
# can result in construction of the various loggers.
import bb.msg

from bb import fetch2 as fetch
sys.modules['bb.fetch'] = sys.modules['bb.fetch2']

# Messaging convenience functions
def plain(*args):
    mainlogger.plain(''.join(args))

def debug(lvl, *args):
    if isinstance(lvl, str):
        mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
        args = (lvl,) + args
        lvl = 1
    mainlogger.debug(lvl, ''.join(args))

def note(*args):
    mainlogger.info(''.join(args))

#
# A higher prioity note which will show on the console but isn't a warning
#
# Something is happening the user should be aware of but they probably did
# something to make it happen
#
def verbnote(*args):
    mainlogger.verbnote(''.join(args))

#
# Warnings - things the user likely needs to pay attention to and fix
#
def warn(*args):
    mainlogger.warning(''.join(args))

def error(*args, **kwargs):
    mainlogger.error(''.join(args), extra=kwargs)

def fatal(*args, **kwargs):
    mainlogger.critical(''.join(args), extra=kwargs)
    raise BBHandledException()

def deprecated(func, name=None, advice=""):
    """This is a decorator which can be used to mark functions
    as deprecated. It will result in a warning being emitted
    when the function is used."""
    import warnings

    if advice:
        advice = ": %s" % advice
    if name is None:
        name = func.__name__

    def newFunc(*args, **kwargs):
        warnings.warn("Call to deprecated function %s%s." % (name,
                                                             advice),
                      category=DeprecationWarning,
                      stacklevel=2)
        return func(*args, **kwargs)
    newFunc.__name__ = func.__name__
    newFunc.__doc__ = func.__doc__
    newFunc.__dict__.update(func.__dict__)
    return newFunc

# For compatibility
def deprecate_import(current, modulename, fromlist, renames = None):
    """Import objects from one module into another, wrapping them with a DeprecationWarning"""
    import sys

    module = __import__(modulename, fromlist = fromlist)
    for position, objname in enumerate(fromlist):
        obj = getattr(module, objname)
        newobj = deprecated(obj, "{0}.{1}".format(current, objname),
                            "Please use {0}.{1} instead".format(modulename, objname))
        if renames:
            newname = renames[position]
        else:
            newname = objname

        setattr(sys.modules[current], newname, newobj)

Open in new window

Avatar of naseeam

ASKER

>> https://www.programcreek.com/python/example/10123/logging.getLoggerClass
Each example is a python function.  Please use an example to code python program that logs some events to console.   And please provide explanation of code.
I'm afraid you will have to research that. I simply don't have time to do it right now. Are you locked into using that logger or could you use the standard python logger?
Avatar of naseeam

ASKER

>> Are you locked into using that logger
I just want to understand that logger
Avatar of naseeam

ASKER

Following is part of /usr/lib/python3.6/logging/__init__.py

When above bitbake code calls def getLoggerClass( ) below, _loggerClass is returned.  _loggerClass = Logger     What is Logger?

In above code, logging.setLoggerClass(BBLogger) is called.  In below code in def setLoggerClass(klass), how is BBLogger subclass of Logger?




#---------------------------------------------------------------------------
#   Level related stuff
#---------------------------------------------------------------------------
#
# Default levels and level names, these can be replaced with any positive set
# of values having corresponding names. There is a pseudo-level, NOTSET, which
# is only really there as a lower limit for user-defined levels. Handlers and
# loggers are initialized with NOTSET so that they will log all messages, even
# at user-defined levels.
#

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0


#
#   Determine which class to use when instantiating loggers.
#

def setLoggerClass(klass):
    """
    Set the class to be used when instantiating a logger. The class should
    define __init__() such that only a name argument is required, and the
    __init__() should call Logger.__init__()
    """
    if klass != Logger:
        if not issubclass(klass, Logger):
            raise TypeError("logger not derived from logging.Logger: "
                            + klass.__name__)
    global _loggerClass
    _loggerClass = klass

def getLoggerClass():
    """
    Return the class to be used when instantiating a logger.
    """
    return _loggerClass



class RootLogger(Logger):
    """
    A root logger is not that different to any other logger, except that
    it must have a logging level and there is only one instance of it in
    the hierarchy.
    """
    def __init__(self, level):
        """
        Initialize the logger with the name "root".
        """
        Logger.__init__(self, "root", level)

_loggerClass = Logger


root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)

Open in new window

Avatar of naseeam

ASKER

Please confirm my understanding:

The purpose of getLoggerClass( ) and setLoggerClass( ) is to use application class for logging.  Besides using Logger class from python standard library, application also uses it's own class for logging.
There are Three ways I know to setup logging system:
  1.  call logging.getLogger( ) to use default logger from python standard library
  2.  call logging.getLogger(<name>) to use custom logger from python standard library
  3.  call logging.getLoggerClass( ) so Logger Class from python standard library is returned to application.  Application will derive from this Logger Class.  Call logging.setLoggerClass(<Application derived class>) to inform python standard library that application wants to use it's own class for logging.   Then, when application calls logging.getLogger(<name>), application derived class is instantiated, which includes all the logging features of python standard library parent class Logger.
ASKER CERTIFIED SOLUTION
Avatar of naseeam
naseeam
Flag of United States of America image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Avatar of naseeam

ASKER

Thank you!