diff --git a/doc/source/guidelines/logging.rst b/doc/source/guidelines/logging.rst index 8154082e3..37e2809f8 100644 --- a/doc/source/guidelines/logging.rst +++ b/doc/source/guidelines/logging.rst @@ -1,43 +1,43 @@ Logging Guidelines ################## -This section describes several guidelines for logging in PyAnsys -libraries. These guidelines are best practices discovered through -implementing logging services and modules within PyAnsys -libraries. Suggestions and improvements are welcome. -External resources also describe `basic `__ -and `advanced `__ technics. +This section describes several guidelines for logging in PyAnsys libraries. +These guidelines are best practices discovered through implementing logging +services and modules within PyAnsys libraries. Suggestions and improvements are +welcome. +External resources also describe `basic +`__ and `advanced +`__ technics. Description and usage ===================== -Logging helps to track events occurring in the application. For each of them a log record -is created. It contains a detailed set of information about the current application operation. -Whenever an information must be exposed, displayed and shared, logging is the -way to do it. -It is destinated to both the users and the application developers. -It can serve several purposes: +Logging helps to track events occurring in the application. For each of them a +log record is created. It contains a detailed set of information about the +current application operation. Whenever an information must be exposed, +displayed and shared, logging is the way to do it. +It is destinated to both the users and the application developers. It can serve +several purposes: - extract some valuable data for the final users to know the status of their work. - track the progress and the course of the application usage. - provide the developer with as much information as possible if an issue happens. -The message logged can contain generic information or embed data specific -to the current session. +The message logged can contain generic information or embed data specific to the +current session. Message content is associated to a level of severity (info, warning, error...). Generally, this degree of significance indicates the recipient of the message. -An info message is directed to the user while a debug message is useful for -the developer itself. +An info message is directed to the user while a debug message is useful for the +developer itself. Logging in PyAnsys Libraries ============================ -The logging capabilities in PyAnsys libraries should be built upon the -`standard logging `__ -library. PyAnsys libries should not to replace this library, rather provide -a standardized way to interact between the built-in :mod:`logging` -library and ``PyAnsys`` libraries. +The logging capabilities in PyAnsys libraries should be built upon the `standard +logging `__ library. PyAnsys +libries should not to replace this library, rather provide a standardized way to +interact between the built-in :mod:`logging` library and ``PyAnsys`` libraries. Logging Best Practices @@ -45,18 +45,19 @@ Logging Best Practices Avoid printing to the console ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A common habit while prototyping a new feature is to print message into the command line executable. -Instead of using the common ``Print()`` method, it is advised to use a ``StreamHandler`` and redirect its content. -Indeed that will allow to filter messages based on their level and apply properly the formatter. -To do so, a boolean argument can be added in the initializer of the ``Logger`` class. -This argument specifies how to handle the stream. +A common habit while prototyping a new feature is to print message into the +command line executable. Instead of using the common ``Print()`` method, it is +advised to use a ``StreamHandler`` and redirect its content. Indeed that will +allow to filter messages based on their level and apply properly the formatter. +To do so, a boolean argument can be added in the initializer of the ``Logger`` +class. This argument specifies how to handle the stream. Enable/Disable handlers ~~~~~~~~~~~~~~~~~~~~~~~ -Sometimes the user might want to disable specific handlers such as a -file handler where log messages are written. If so, the existing -handler must be properly closed and removed. Otherwise the file access -might be denied later when you try to write new log content. +Sometimes the user might want to disable specific handlers such as a file +handler where log messages are written. If so, the existing handler must be +properly closed and removed. Otherwise the file access might be denied later +when you try to write new log content. Here's one approach to closing log handlers. @@ -70,12 +71,13 @@ Here's one approach to closing log handlers. App Filter ~~~~~~~~~~ -A filter shows all its value when the content of a message depends on some conditions. -It injects contextual information in the core of the message. -This can be useful to harmonize the message rendering when the application output is not consistent -and vary upon the data processed. -It requires the creation of class based on the logging.Filter and the implementation of -the ``filter`` method. This method will contain all the modified content send to the stream. +A filter shows all its value when the content of a message depends on some +conditions. It injects contextual information in the core of the message. +This can be useful to harmonize the message rendering when the application +output is not consistent and vary upon the data processed. +It requires the creation of class based on the logging.Filter and the +implementation of the ``filter`` method. This method will contain all the +modified content send to the stream. .. code:: python @@ -113,12 +115,12 @@ the ``filter`` method. This method will contain all the modified content send to String format ~~~~~~~~~~~~~ -Even if the current practice recommends using the f-string to format -most strings, when it comes to logging, the former %-formatting is -preferable. This way the string format is not evaluated at -runtime. It is deferred and evaluated only when the message is -emitted. If there is any formatting or evaluation error, these will be -reported as logging errors and will not halt code execution. +Even if the current practice recommends using the f-string to format most +strings, when it comes to logging, the former %-formatting is preferable. This +way the string format is not evaluated at runtime. It is deferred and evaluated +only when the message is emitted. If there is any formatting or evaluation +error, these will be reported as logging errors and will not halt code +execution. .. code:: python @@ -127,18 +129,16 @@ reported as logging errors and will not halt code execution. Application or Service Logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following guidelines describe "Application" or "Service" logging -module for a PyAnsys library, where a PyAnsys library is used to -extend or expose features from an Ansys application, product, or -service that may be local or remote. - -This section describes two main loggers for a PyAnsys library that -exposes or extends a service based application, the *Global logger* -and the *Instance logger*. These loggers are customized classes that wrap -:class:`logging.Logger` from :mod:`logging` module and add specific -features to it. :ref:`logging_in_pymapdl_figure` outlines the logging -approach used by PyMAPDL and the scopes of the global and local -loggers. +The following guidelines describe "Application" or "Service" logging module for +a PyAnsys library, where a PyAnsys library is used to extend or expose features +from an Ansys application, product, or service that may be local or remote. + +This section describes two main loggers for a PyAnsys library that exposes or +extends a service based application, the *Global logger* and the *Instance +logger*. These loggers are customized classes that wrap :class:`logging.Logger` +from :mod:`logging` module and add specific features to it. +:ref:`logging_in_pymapdl_figure` outlines the logging approach used by PyMAPDL +and the scopes of the global and local loggers. .. _logging_in_pymapdl_figure: @@ -167,14 +167,13 @@ Following are some unit tests demonstatring how to use the code implemented abov Example Global logger ~~~~~~~~~~~~~~~~~~~~~ -There is a global logger named ``py*_global`` which is created when -importing ``ansys.product.service`` -(``ansys.product.service.__init__``). This logger is recommended for -most scenarios, especially when complex modules or classes are not -involved, since it does not track instances, rather can be used -globally. If you intend to log the initialization of a library or -module, you should use this logger. To use this global logger, you -must import it at the top of your script or module: +There is a global logger named ``py*_global`` which is created when importing +``ansys.product.service`` (``ansys.product.service.__init__``). This logger is +recommended for most scenarios, especially when complex modules or classes are +not involved, since it does not track instances, rather can be used globally. +If you intend to log the initialization of a library or module, you should use +this logger. To use this global logger, you must import it at the top of your +script or module: .. code:: python @@ -216,13 +215,12 @@ you can add a file handler using: file_path = os.path.join(os.getcwd(), 'pylibrary.log') LOG.log_to_file(file_path) -This enables logging to that file in addition of the standard output. -If you wish to change the characteristics of this global logger from -the beginning of the execution, you must edit the file ``__init__`` in -the directory of your library. +This enables logging to that file in addition of the standard output. If you +wish to change the characteristics of this global logger from the beginning of +the execution, you must edit the file ``__init__`` in the directory of your +library. -To log using this logger, simply call the desired method as a normal -logger. +To log using this logger, simply call the desired method as a normal logger. .. code:: python @@ -237,13 +235,13 @@ logger. Instance logger ~~~~~~~~~~~~~~~ -Every time that the class ``_MapdlCore`` is instantiated, a logger is -created. This logger is recommended when using the ``pool`` library -or when using multiple instances of ``Mapdl``. The main feature of -this logger is that it tracks each instance and it includes its name -when logging. The name of the instances are unique. For example in -case of using the ``gRPC`` ``Mapdl`` version, its name includes the IP -and port of the correspondent instance, making unique its logger. +Every time that the class ``_MapdlCore`` is instantiated, a logger is created. +This logger is recommended when using the ``pool`` library or when using +multiple instances of ``Mapdl``. The main feature of this logger is that it +tracks each instance and it includes its name when logging. The name of the +instances are unique. For example in case of using the ``gRPC`` ``Mapdl`` +version, its name includes the IP and port of the correspondent instance, making +unique its logger. The instance loggers can be accessed in two places: @@ -252,11 +250,11 @@ The instance loggers can be accessed in two places: * ``LOG._instances``. This field is a ``dict`` where the key is the name of the created logger. -These instance loggers inherit from the ``pymapdl_global`` output -handlers and logging level unless otherwise specified. The way this -logger works is very similar to the global logger. You can add a file -handler if you wish using the method ``log_to_file`` or change the log -level using :meth:`logging.Logger.setLevel`. +These instance loggers inherit from the ``pymapdl_global`` output handlers and +logging level unless otherwise specified. The way this logger works is very +similar to the global logger. You can add a file handler if you wish using the +method ``log_to_file`` or change the log level using +:meth:`logging.Logger.setLevel`. You can use this logger like this: @@ -274,17 +272,22 @@ You can use this logger like this: Wrapping Other Loggers ~~~~~~~~~~~~~~~~~~~~~~ -A product, due to its architecture can be made of several loggers. -The ``logging`` library features allows to work with a finite number of loggers. -The factory function logging.getLogger() helps to access each logger by its name. -In addition of this naming-mappings, a hierachy can be established to structure the loggers -parenting and their connection. - - -For instance, if an ANSYS product is using a pre-exsiting custom logger encapsulated inside the product itself, the will benefit from exposing it through the standard python tools. -It is recommended to use the standard library as much as possible. It will facilitate every contribution -both external and internal- to the by exposing common tools that are widely spread. -Each developer will be able to operate quickly and autonomously. -The project will take advantage of the entire set of features exposed in the standard logger and all the upcoming improvements. +A product, due to its architecture can be made of several loggers. The +``logging`` library features allows to work with a finite number of loggers. The +factory function logging.getLogger() helps to access each logger by its name. In +addition of this naming-mappings, a hierachy can be established to structure the +loggers parenting and their connection. + + +For instance, if an ANSYS product is using a pre-exsiting custom logger +encapsulated inside the product itself, the will benefit from +exposing it through the standard python tools. It is recommended to use the +standard library as much as possible. It will facilitate every contribution +-both external and internal- to the by exposing common tools that +are widely spread. Each developer will be able to operate quickly and +autonomously. +The project will take advantage of the entire set of features exposed in the +standard logger and all the upcoming improvements. Create a custom log handler to catch each product message and redirect them on another logger: ============================================================================================== @@ -298,9 +301,12 @@ AEDT product has its own internal logger called the message manager made of 3 ma * *Project*: related to the project * *Design*: related to the design (most specific destination of each 3 loggers.) -The message manager is not using the standard python logging module and this might be a problem later when exporting messages and data from each ANSYS product to a common tool. -In most of the cases, it is easier to work with the standard python module to extract data. -In order to overcome this limitation, the existing message manager is wrapped into a logger based on the standard python `logging `__ module. +The message manager is not using the standard python logging module and this +might be a problem later when exporting messages and data from each ANSYS +product to a common tool. In most of the cases, it is easier to work with the +standard python module to extract data. +In order to overcome this limitation, the existing message manager is wrapped +into a logger based on the standard python :mod:`logging` module. .. figure:: images/log_flow.png @@ -311,8 +317,10 @@ In order to overcome this limitation, the existing message manager is wrapped in **Figure 1: Loggers message passing flow.** -This wrapper implementation boils down to a custom handler. It is based on a class inherited from logging.Handler. -The initializer of this class will require the message manager to be passed as an argument in order to link the standard logging service with the ANSYS internal message manager. +This wrapper implementation boils down to a custom handler. It is based on a +class inherited from logging.Handler. The initializer of this class will require +the message manager to be passed as an argument in order to link the standard +logging service with the ANSYS internal message manager. .. code:: python @@ -330,9 +338,17 @@ The initializer of this class will require the message manager to be passed as a The purpose of this class is to send log messages in AEDT logging stream. -One of the mandatory actions is to overwrite the ``emit`` function. This method operates as a proxy. It will dispatch all the log message toward the message manager. -Based on the record level, the message is sent to the appropriate log level (debug, info, error...) into the message manager to fit the level provided by the ANSYS product. -As a reminder the record is an object containing all kind of information related to the event logged. - -This custom handler is used into the new logger instance (the one based on the standard library). -A good practice before to add a handler on any logger is to verify if any appropriate handler is already available in order to avoid any conflict, message duplication... +One of the mandatory actions is to overwrite the ``emit`` function. This method +operates as a proxy. It will dispatch all the log message toward the message +manager. +Based on the record level, the message is sent to the appropriate log level +(debug, info, error...) into the message manager to fit the level provided by +the ANSYS product. +As a reminder the record is an object containing all kind of information related +to the event logged. + +This custom handler is used into the new logger instance (the one based on the +standard library). +A good practice before to add a handler on any logger is to verify if any +appropriate handler is already available in order to avoid any conflict, message +duplication...