From 823ecc3f4345aab68329466a7a76a06260116e64 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 12 Jan 2022 08:44:37 -0500 Subject: [PATCH 1/2] Fix broken https link and wrap at 80 columns --- doc/source/guidelines/logging.rst | 220 ++++++++++++++++-------------- 1 file changed, 118 insertions(+), 102 deletions(-) diff --git a/doc/source/guidelines/logging.rst b/doc/source/guidelines/logging.rst index 8154082e3..3edb14203 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... From 3fe475ed8228432b2e59c3db2b6ba89b6016fef8 Mon Sep 17 00:00:00 2001 From: Alex Kaszynski Date: Wed, 12 Jan 2022 13:02:45 -0700 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com> --- doc/source/guidelines/logging.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/source/guidelines/logging.rst b/doc/source/guidelines/logging.rst index 3edb14203..37e2809f8 100644 --- a/doc/source/guidelines/logging.rst +++ b/doc/source/guidelines/logging.rst @@ -116,7 +116,7 @@ modified content send to the stream. 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 +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 @@ -237,9 +237,9 @@ 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`` +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. @@ -251,8 +251,8 @@ The instance loggers can be accessed in two places: 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 +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`.