Skip to content

Conversation

@germa89
Copy link
Collaborator

@germa89 germa89 commented Oct 5, 2021

log module

Objective

This module intends to create a general framework for logging in Pyansys.
This module is built upon logging library and it does NOT intend to replace it rather provide a way to interact between logging and Pyansys.

The loggers used in the module include the name of the instance which is intended to be unique.
This name is printed in all the active outputs and it is used to track the different MAPDL instances.

Usage

Global logger

There is a global logger named _Global_ which is created at ansys.mapdl.core.__init__.
If you want to use this global logger, you must call at the top of your module:

    from ansys.mapdl.core import LOG

You could also rename it to avoid conflicts with other loggers (if any):

    from ansys.mapdl.core import LOG as logger

To log using this logger, just call the desired method as a normal logger.

    >>> import logging
    >>> from ansys.mapdl.core.logging import PyansysLogger
    >>> LOG = PyansysLogger(level=logging.DEBUG, to_file=False, to_stdout=True)
    >>> LOG.debug('This is LOG debug message.')
    
    | Level    | Instance        | Module           | Function             | Message
    |----------|-----------------|------------------|----------------------|--------------------------------------------------------
    | DEBUG    |                 |  __init__        | <module>             | This is LOG debug message.

By default, _Global_ does not output to file or stdout. You should activate it from __init__.

Instance logger

Every time that the class _MapdlCore is instantiated, a logger is created and stored in two places:

  • _MapdlCore._log. For backward compatibility.
  • LOG._instances. This field is a dict where the key is the name of the created logger.

These instance loggers inheritate the _Global_ output handlers and logging level unless otherwise specified.

You can use this logger like this:

    >>> from ansys.mapdl.core import launch_mapdl
    >>> mapdl = launch_mapdl()
    >>> mapdl._log.info('This is an useful message')

    | Level    | Instance        | Module           | Function             | Message
    |----------|-----------------|------------------|----------------------|--------------------------------------------------------
    | INFO     | 127.0.0.1:50052 |  test            | <module>             | This is an useful message

Other loggers

You can create your own loggers using python logging library as you would do in any other script.
There shall no be conflicts between these loggers.

Notes

To-Do's

  • Make sure the logging level is changed when instance is created.

EDITED

@germa89 germa89 self-assigned this Oct 5, 2021


def setup_logger(loglevel='INFO', log_file=True):
def setup_logger(loglevel='INFO', log_file=True, mapdl_instance=None):
Copy link
Collaborator

@akaszynski akaszynski Oct 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this at all?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might not need this function, we can probably setup the logger elsewhere. I just wanted to keep backward compatibility in the code by adapting, more than changing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping this in, but we can eventually remove this once this API change has settled.

Copy link
Collaborator

@akaszynski akaszynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall you're on the right track and I think we're close.

A few notes:

  • Great documentation in logging.py. Clean it up to use rst formatting. Right now it's a mix of markdown and rst. If we can get that cleaned up we can just add it directly to our docs.
  • Rename global logger to pymapdl_global. If for whatever reason someone else wanted to use a global logger with the same name we'd conflict. It's a rare but non-zero possibility.
  • Rename PyansysLogger to Logger. I think we're safe to simply call it that, and it's a bit easier to type.
  • There must be a way to get the instance name outside of a getter. I feel like it's something that confuses the API a bit, and it would be better to have it as an attribute or a property (private if needed).

Copy link
Collaborator Author

@germa89 germa89 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review comments.



def setup_logger(loglevel='INFO', log_file=True):
def setup_logger(loglevel='INFO', log_file=True, mapdl_instance=None):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might not need this function, we can probably setup the logger elsewhere. I just wanted to keep backward compatibility in the code by adapting, more than changing.

@germa89
Copy link
Collaborator Author

germa89 commented Oct 13, 2021

Regarding the __getitem__ issue.

I have tried to replace the call to the key name by a call directly to the method:

class PymapdlCustomAdapter(logging.LoggerAdapter):
    def process(self, msg, kwargs):
        kwargs['extra'] = {}
        # This are the extra parameters sent to log
        kwargs['extra']['instance_name'] = self.name #instead of self.extra['name'] 
        return msg, kwargs

And the name of the instance does not get updated:
image

This is why I'm using get item.

@germa89
Copy link
Collaborator Author

germa89 commented Oct 13, 2021

Ok solved.

I'm going to point the Adapter to a new function "get_name", hence it will be force to be updated everytime the adapter is called.

class PymapdlCustomAdapter(logging.LoggerAdapter):
    def process(self, msg, kwargs):
        kwargs['extra'] = {}
        # This are the extra parameters sent to log
        kwargs['extra']['instance_name'] = self.get_name() #instead of self.extra['name'] 
        return msg, kwargs

Hence we do not need to use __getitem__.

@akaszynski akaszynski marked this pull request as ready for review October 15, 2021 05:57
@akaszynski
Copy link
Collaborator

One error lead to another and I had to make a few changes to get this green.

First, Python 3.7 vs. Python 3.8. Apparently there are different parameters in the logger:
https://docs.python.org/3.7/library/logging.html#logging.Formatter

Changed in version 3.8: The validate parameter was added. Incorrect or mismatched style and fmt will raise a ValueError. For example: logging.Formatter('%(asctime)s - %(message)s', style='{').

Additionally, I ended up having to add in InstanceFilter as Python3.7 kept failing as it was unable to find the instance_name key within the formatter string. Nothing, not adding defaults in the formatter (which should have worked), not adding instance_name all over the place, nothing worked. I think InstanceFilter is the way to go regardless.

Copy link
Collaborator

@akaszynski akaszynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. That was another long one. We're ready for release.

Feel free to merge, and I'll release Friday.

@germa89
Copy link
Collaborator Author

germa89 commented Oct 15, 2021

Double checked on Windows, everything seems fine. Let's merge!

@germa89 germa89 merged commit e5cc214 into main Oct 15, 2021
@germa89 germa89 deleted the WPS-Feat/-Main-logger branch October 15, 2021 11:07
@germa89 germa89 linked an issue Oct 26, 2021 that may be closed by this pull request
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A logger at the main level

3 participants