Hyperion Core Utilities

Explanation of how to use logging

Short version:

There is a single logging manager that you import in your files. This logging manager can create a logger objects (which you use in your files and classes to do log-prints like logger.info(‘bla’). When creating the logger object, a stream handler (writes to screen) and a file handler are passed with it. These take care of the layout, the level (e.g. whether lower levels like debug or info are printed), and which file to write to. You can choose to disable the stream or file handler, modify their layout and levels individually. The stream handler colors can be turned on or off and the color format can be modified.

Full explanation:

In hyperion.core the class LoggingManager is defined. It is a “Singleton” class meaning that all instantiations of this class are actually one and the same object.|br| In hyperion.core one object is already instantiated by the name of logman.|br| In hyperion __init__.py this is imported under the alias name logging.|br| Because it’s a singleton class the following approaches of importing the logging manager object are all equivalent:

  • from hyperion import logging
  • from hyperion.core import logman as logging
  • from hyperion.core import logman
  • from hyperion.core import LoggingManager import hyperion log = LoggingManager( hyperion.log_path, ‘my_log_name.log’ )
  • import hyperion.core log = hyperion.core.LoggingManager()

In all cases above logging, logman and log refer to the same single object of class LoggingManager. For the rest of the following explanation logman is used, but if you’re modifying an existing file that used logging, you could remove the ‘import logging’ and replace it with ‘from hyperion import logging’. Note, the optional arguments are default_path and default_name for logging file. LoggingManager has two optional arguments default_path and default_name, which are used as default values for creating the log file. By default, the path is hyperion.log_path and the name is ‘hyperion.log’ In your own project you could change those if you like.

Now, to use logging in your module (file) or in your class, you have to create a logger: logger = logman.getLogger(__name__) Note that instead of the usual module name __name__ you could hypothetically put in any string. Note that as a shorthand you can also do directly: logger=logman(__name__) When the logger is created, by default, both the stream handler and the file handler are passed with it. These take care of printing to the screen and to a file. If you don’t want to add both, you could omit adding them by setting the optional keyword arguments add_stream or add_file to False. e.g.; logger = logman.getLogger(__name__, add_file=False)

Before creating a logger object, you can:

  • Change the default path or name of the logfile in the stream_handler: logman.default_path = ‘d:’ logman.default_name = ‘my_project.log’
  • Set the level of the default stream or file handler in the logging manager (defaults are DEBUG) logman.stream_level = logman.WARNING # note: you could also pass in the string ‘WARNING’ logman.file_level = ‘INFO’ # note: you could also pass in logman.INFO (Note that changing the level in the manager after a logger object is created is likely to also affect that logger. This depends if the handler was modified in the meantime. If it wasn’t, then it’s the same object.)
  • Change the default stream or file handler in the logging manager Change layout, file name, colors. See below.
  • Enable/disable whether the stream of the file handler is passed when a logger object is created (default is True). logman.enable_stream = False logman.enable_file = True

After creating a logger object you can still:

  • Add handlers logman.remove_stream_handler(my_handler) logman.remove_file_handler(my_handler)
  • Or remove handlers logman.add_stream_handler(my_handler) logman.add_file_handler(my_handler)
  • And you can modify the logging level of its handers. Just be aware that if the handlers in the manager weren’t modified in the meantime, changing the level of one logger may change the level of others as well. logman.set_logger_stream_level(my_handler, ‘WARNING’) logman.set_logger_file_level(my_handler, logman.INFO)

Finally, explanation of setting up the handlers:

To create (or replace) the handlers use: logman.set_stream( optional arguments ) logman.set_file( optional arguments ) All arguments are optional (they have a default value if omitted) The arguements in both set_stream and set_file are:

  • level If omitted, the default value is used
    (default value can be set by logman.stream_level / logman.file_level)
  • reduce_duplicates Enables a Filer that detect repeated log comments (that were in a loop) and reduces the number
    of lines printed. Defaults to True
  • compact A float between 0 and 1. A measure of how long or compact a line will be. 0 Means full length.
    As the value of compact is increased the lines will become shorter. At 1 the line will be most compact and it will be cut off at length maxwidth. Default value for set_stream is 0.5, default value for set_file is 0
  • maxwidth See description of compact. Default value is 119

Arguments only in set_stream:

  • color A bool that determines whether to use colors when printing levels names. Defaults to True
  • color_scheme A string indicating color_scheme. Possible values are: bright, dim, mixed, bg, universal
    If the logger is used in Spyder it diverts to a modified scheme. To manually select different schemes for both non-Spyder and Spyder do something like color_scheme=(‘mixed’, ‘spy_bright’) Scheme ‘universal’ will be readable and most similar on Spyder, Pycharm, PyCharm-darcula, regular black terminal and blue PowerShell terminal. But it’s not ver esthetically pleasing, so the default is (‘bright’, ‘spy_bright’)
  • All other keyword arguments are passed into logging.StreamHandler().

Arguments only in set_file:

  • pathname The path or only filename or full file-path. If path is not included it will use the default
    path. If name is not included it will use the default name)
  • All other keyword arguments are passed into logging.handlers.RotatingFileHandler(). maxBytes will default to 5MB and backupCount will default to 9

example code 1:

from hyperion import logging

class A:
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.logger.info('object of class A created')

if __name__=='__main__':
    logging.enable_file = False
    logging.stream_level = 'INFO'
    logging.set_stream(compact=0.4, color=False)
    a = A()

example code 2:

from hyperion.core import logman

class A:
    def __init__(self):
        logger = logman(__name__, add_stream=False)     # no stream logging at all for this class
        logger.info('object of class A created')

class B:
    def __init__(self):
        self.logger = logman(__name__)
        self.logger.info('object B: 1 - info')

        # Temporarily change logging level (note that this may affect other loggers as well)
        lvl = logman.get_logger_stream_level(self.logger)
        logman.set_logger_stream_level(self.logger, 'WARNING')
        self.logger.info('object B: 2 - info')
        self.logger.warning('object B: 2 - warning')
        logman.set_logger_stream_level(self.logger, lvl)

        self.logger.info('object B: 3 - info')

class C:
    def __init__(self):
        self.logger = logman(__name__)
        self.logger.info('object C: 1 - info')

        # Temporarily remove handler from logger
        h = logman.remove_stream_handler(self.logger)       # storing it in h is optional
        self.logger.info('object C: 2 - info')
        self.logger.warning('object C: 2 - warning')
        # To restore the exact handler:
        self.logger.addHandler(h)
        # It's also possible to add the handler from the manager:
        # logman.add_file_handler(self.logger)

        self.logger.info('object C: 3 - info')


if __name__=='__main__':
    logging.default_name = 'my_project.log'
    logging.set_stream(compact=0.4, color=False)
    a = A()
    b = B()
    c = C()
class hyperion.core.ANSIcolorFormat(enable=True)

Class used as a wrapper function to apply colors to console prints. Arguments are the string followed by one or more color ‘decorators’: First letter of basic colors: r, g, y, b, m, c, w for white, k for black. Letter Preceded by an l means a lighter/brighter color (if supported). Letter(s) preceded by an underscore ‘_’ means background color. Notes on PyCharm: ‘emph’ creates bold text. Darcula mode changes colors into bland “pastel-like” colors and inverts pure white and black. Notes on general command/prompt window: ‘emph’ turns dark text to bright. Notes on Spyder: Does not support “light” colors with an “l”, ‘emph’/’norm’ turns both text and background simultaneously to bright/dim.

The ‘decorators’ can be passed as multiple arguments or a tuple or a list. A single string of ansi color code is also accepted (e.g. ‘1;46;31’) If no additional arguments or the argument None is passed it returns the message without adding ansi color codes. The enabled property allows for toggling all color action of this object at once. The class method disable_all() allows to disable all color printing of all objects.

Note: It’s also possible to do from hyperion.core import ansicol
Then you’re using the same object (i.e. toggling that object will influence all)
Example usage:
from hyperion.core import ANSIcolorFormat ansicol = ANSIcolorFormat() print(ansicol(‘Hello World’,’emph’,’r’,’_y’)) print(ansicol(‘Hello World’)) ansicol.enabled = False print(ansicol(‘Hello World’,’emph’,’r’,’_y’))
static disable_all(boolean)

Class Method (with boolean input) to disable all color printing of all ANSIcolorFormat objects at once. Useful if your system can’t deal with ANSI color codes. Note that this will overrule the enabled state of individual objects. Being a class method this can be run both on an object and directly on the class, like ANSIcolorFormat.disable_all(False)

enabled

Boolean property to get or set whether this ANSIcolorFormat object is enabled. If enabled is false it will not print colors. Note that the class disabled_all state overrules this object state. To enable you may also have to do .disable_all(False) on the object or on the class.

class hyperion.core.CustomFormatter(compact=0.0, maxwidth=None, color=False, color_scheme=None)

Custom format for log-prints. Adds a lot of information (time, module, line number, method, LEVEL, message) Setting the compact parameter to a value larger than 0 shrinks the date, module and method. Setting it to 1 (maximum) assures the length is maxwidth characters or less. The possible regular color schemes are: bright, dim, mixed, bg, universal. The optional additional secondary color schemes for Spyder are: spy_bright, spy_dim, spy_mixed, spy_bg, spy_universal. Specifying no color_scheme defaults to bright (and spy_bright if Spyder is detected).

Parameters:
  • compact – float from 0 for full length, to 1 for very compact (defaults to 0)
  • maxwidth – integer indicating max line width when compact is 1. None (default) uses 119.
  • color – boolean indicating if ANSI colors should be used (defaults to False)
  • color_scheme – string or tuple/list of two strings (defaults to bright / spy_bri)
format(record)

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class hyperion.core.DuplicateFilter(name='')

Adding this filter to a logging handler will reduce repeated log-prints

filter(record)

Determine if the specified record is to be logged.

Is the specified record to be logged? Returns 0 for no, nonzero for yes. If deemed appropriate, the record may be modified in-place.

class hyperion.core.LoggingManager(default_path='/home/docs/checkouts/readthedocs.org/user_builds/nanooptics-hyperion/envs/latest/lib/python3.7/site-packages/logs', default_name='hyperion.log')

LogginManager class. This is a “Singleton” class which means that all of its instantiatons refer to one and the same object. If one tries to create a second object, the original object is returned. For a more elaborate explanation on how to use, see beginning of page.

Variables:
  • enable_stream – (bool) If true, the stream handler is passed to newly created logger objects (default is True)
  • enable_file – (bool) If true, the file handler is passed to newly created logger objects (default is True)
  • default_path – (str) Default path for logfile when file handler is created without specifying path (default hyperion.log_path)
  • default_name – (str) Default filename for logfile when file handler is created without specifying filename (default ‘hyperion.log;)
add_file_handler(logger)

Add file_handler to an existing logger object.

Parameters:logger – a logger object
add_stream_handler(logger)

Add stream_handler to an existing logger object.

Parameters:logger – a logger object
file_level

Property to read and set the level of the current file handler. When setting it also updates the default level.

getLogger(name, add_stream=None, add_file=None)

Returns logger object.

Parameters:
  • name – (str) Name, usually the module name. i.e. __name__
  • add_stream – (bool or None) add the streamhandler. None (default) uses object.enalbe_stream
  • add_file – (bool or None) add the streamhandler. None (default) uses object.enalbe_stream
Returns:

logger object

get_logger_file_level(logger)

Get the level of the (first) file handler of an existing logger object.

Parameters:logger – existing logger object
get_logger_stream_level(logger)

Get the level of the (first) stream handler of an existing logger object.

Parameters:logger – existing logger object
remove_file_handlers(logger)

Remove stream_handlers from an existing logger object.

Parameters:logger – a logger object
Returns:the removed file handler object (or None)
remove_stream_handler(logger)

Remove stream_handlers from an existing logger object.

Parameters:logger – a logger object
Returns:the removed stream handler object (or None)
set_file(pathname=None, level=None, compact=0, reduce_duplicates=True, maxwidth=None, maxBytes=5242880, backupCount=9, **kwargs)

Sets (replaces) the file handler in the logging manager object.

Parameters:
  • pathname – path or filename or full file-path (if only name or path is given, the other will use the default value)
  • level – logging level. If omitted, default is used. To change default see file_level
  • compact – see CustomFormatter (defaults to 0)
  • maxwidth – see CustomFormatter
  • reduce_duplicates – (bool) (defaults to True)
  • maxBytes – see logging.handlers.RotatingFileHandler() (defaults to 5 * 1024 * 1024)
  • backupCount – see logging.handlers.RotatingFileHandler() (defaults to 9)
  • **kwargs

    additional keyword arguments are passed into logging.handlers.RotatingFileHandler()

set_logger_file_level(logger, level)

Change level of the file handler of an existing logger object. Note that this may affect other logger object, because they may share the same file handler object.

Parameters:
  • logger – existing logger object
  • level – string like ‘WARNING’ or level like logman.WARNING
set_logger_stream_level(logger, level)

Change level of the stream handler of an existing logger object. Note that this may affect other logger object, because they may share the same stream handler object.

Parameters:
  • logger – existing logger object
  • level – string like ‘WARNING’ or level like logman.WARNING
set_stream(color=True, level=None, compact=0.5, reduce_duplicates=True, maxwidth=None, color_scheme=None, **kwargs)

Sets (replaces) the stream handler in the logging manager object.

Parameters:
  • color – (bool) whether to print levelnames with color
  • level – logging level. If omitted, default is used. To change default see file_level
  • compact – see CustomFormatter (defaults to 0)
  • maxwidth – see CustomFormatter
  • reduce_duplicates – (bool) (defaults to True)
  • color_scheme – (str or (str,str) ) color scheme to use, see above for possible values
  • **kwargs

    additional keyword arguments are passed into logging.StreamHandler()

Returns:

stream_level

Property to read and set the level of the current stream handler. When setting it also updates the default level.

class hyperion.core.Singleton

Metaclass to use for classes of which you only want one instance to exist. use like: class MyClass(ParentClass, metaclass=Singleton): If one tries to create a second object, the original object is returned.