Skip to content

Commit 51306b5

Browse files
dnwillia-workakaszynskiMaxJPRey
authored
Fix broken https link and wrap at 80 columns (#28)
* Fix broken https link and wrap at 80 columns * Apply suggestions from code review Co-authored-by: Maxime Rey <[email protected]> Co-authored-by: Alex Kaszynski <[email protected]> Co-authored-by: Maxime Rey <[email protected]>
1 parent 58dabee commit 51306b5

File tree

1 file changed

+118
-102
lines changed

1 file changed

+118
-102
lines changed

doc/source/guidelines/logging.rst

Lines changed: 118 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,63 @@
11
Logging Guidelines
22
##################
33

4-
This section describes several guidelines for logging in PyAnsys
5-
libraries. These guidelines are best practices discovered through
6-
implementing logging services and modules within PyAnsys
7-
libraries. Suggestions and improvements are welcome.
8-
External resources also describe `basic <https://docs.python-guide.org/writing/logging/>`__
9-
and `advanced <https://coralogix.com/blog/python-logging-best-practices-tips/>`__ technics.
4+
This section describes several guidelines for logging in PyAnsys libraries.
5+
These guidelines are best practices discovered through implementing logging
6+
services and modules within PyAnsys libraries. Suggestions and improvements are
7+
welcome.
8+
External resources also describe `basic
9+
<https://docs.python-guide.org/writing/logging/>`__ and `advanced
10+
<https://coralogix.com/blog/python-logging-best-practices-tips/>`__ technics.
1011

1112

1213
Description and usage
1314
=====================
14-
Logging helps to track events occurring in the application. For each of them a log record
15-
is created. It contains a detailed set of information about the current application operation.
16-
Whenever an information must be exposed, displayed and shared, logging is the
17-
way to do it.
18-
It is destinated to both the users and the application developers.
19-
It can serve several purposes:
15+
Logging helps to track events occurring in the application. For each of them a
16+
log record is created. It contains a detailed set of information about the
17+
current application operation. Whenever an information must be exposed,
18+
displayed and shared, logging is the way to do it.
19+
It is destinated to both the users and the application developers. It can serve
20+
several purposes:
2021

2122
- extract some valuable data for the final users to know the status of their work.
2223
- track the progress and the course of the application usage.
2324
- provide the developer with as much information as possible if an issue happens.
2425

25-
The message logged can contain generic information or embed data specific
26-
to the current session.
26+
The message logged can contain generic information or embed data specific to the
27+
current session.
2728
Message content is associated to a level of severity (info, warning, error...).
2829
Generally, this degree of significance indicates the recipient of the message.
29-
An info message is directed to the user while a debug message is useful for
30-
the developer itself.
30+
An info message is directed to the user while a debug message is useful for the
31+
developer itself.
3132

3233

3334
Logging in PyAnsys Libraries
3435
============================
3536

36-
The logging capabilities in PyAnsys libraries should be built upon the
37-
`standard logging <https://docs.python.org/3/library/logging.html/>`__
38-
library. PyAnsys libries should not to replace this library, rather provide
39-
a standardized way to interact between the built-in :mod:`logging`
40-
library and ``PyAnsys`` libraries.
37+
The logging capabilities in PyAnsys libraries should be built upon the `standard
38+
logging <https://docs.python.org/3/library/logging.html>`__ library. PyAnsys
39+
libries should not to replace this library, rather provide a standardized way to
40+
interact between the built-in :mod:`logging` library and ``PyAnsys`` libraries.
4141

4242

4343
Logging Best Practices
4444
----------------------
4545

4646
Avoid printing to the console
4747
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48-
A common habit while prototyping a new feature is to print message into the command line executable.
49-
Instead of using the common ``Print()`` method, it is advised to use a ``StreamHandler`` and redirect its content.
50-
Indeed that will allow to filter messages based on their level and apply properly the formatter.
51-
To do so, a boolean argument can be added in the initializer of the ``Logger`` class.
52-
This argument specifies how to handle the stream.
48+
A common habit while prototyping a new feature is to print message into the
49+
command line executable. Instead of using the common ``Print()`` method, it is
50+
advised to use a ``StreamHandler`` and redirect its content. Indeed that will
51+
allow to filter messages based on their level and apply properly the formatter.
52+
To do so, a boolean argument can be added in the initializer of the ``Logger``
53+
class. This argument specifies how to handle the stream.
5354

5455
Enable/Disable handlers
5556
~~~~~~~~~~~~~~~~~~~~~~~
56-
Sometimes the user might want to disable specific handlers such as a
57-
file handler where log messages are written. If so, the existing
58-
handler must be properly closed and removed. Otherwise the file access
59-
might be denied later when you try to write new log content.
57+
Sometimes the user might want to disable specific handlers such as a file
58+
handler where log messages are written. If so, the existing handler must be
59+
properly closed and removed. Otherwise the file access might be denied later
60+
when you try to write new log content.
6061

6162
Here's one approach to closing log handlers.
6263

@@ -70,12 +71,13 @@ Here's one approach to closing log handlers.
7071
7172
App Filter
7273
~~~~~~~~~~
73-
A filter shows all its value when the content of a message depends on some conditions.
74-
It injects contextual information in the core of the message.
75-
This can be useful to harmonize the message rendering when the application output is not consistent
76-
and vary upon the data processed.
77-
It requires the creation of class based on the logging.Filter and the implementation of
78-
the ``filter`` method. This method will contain all the modified content send to the stream.
74+
A filter shows all its value when the content of a message depends on some
75+
conditions. It injects contextual information in the core of the message.
76+
This can be useful to harmonize the message rendering when the application
77+
output is not consistent and vary upon the data processed.
78+
It requires the creation of class based on the logging.Filter and the
79+
implementation of the ``filter`` method. This method will contain all the
80+
modified content send to the stream.
7981

8082
.. code:: python
8183
@@ -113,12 +115,12 @@ the ``filter`` method. This method will contain all the modified content send to
113115
114116
String format
115117
~~~~~~~~~~~~~
116-
Even if the current practice recommends using the f-string to format
117-
most strings, when it comes to logging, the former %-formatting is
118-
preferable. This way the string format is not evaluated at
119-
runtime. It is deferred and evaluated only when the message is
120-
emitted. If there is any formatting or evaluation error, these will be
121-
reported as logging errors and will not halt code execution.
118+
Even if the current practice recommends using the f-string to format most
119+
strings, when it comes to logging, the former %-formatting is preferable. This
120+
way the string format is not evaluated at runtime. It is deferred and evaluated
121+
only when the message is emitted. If there is any formatting or evaluation
122+
error, these will be reported as logging errors and will not halt code
123+
execution.
122124

123125
.. code:: python
124126
@@ -127,18 +129,16 @@ reported as logging errors and will not halt code execution.
127129
128130
Application or Service Logging
129131
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
130-
The following guidelines describe "Application" or "Service" logging
131-
module for a PyAnsys library, where a PyAnsys library is used to
132-
extend or expose features from an Ansys application, product, or
133-
service that may be local or remote.
134-
135-
This section describes two main loggers for a PyAnsys library that
136-
exposes or extends a service based application, the *Global logger*
137-
and the *Instance logger*. These loggers are customized classes that wrap
138-
:class:`logging.Logger` from :mod:`logging` module and add specific
139-
features to it. :ref:`logging_in_pymapdl_figure` outlines the logging
140-
approach used by PyMAPDL and the scopes of the global and local
141-
loggers.
132+
The following guidelines describe "Application" or "Service" logging module for
133+
a PyAnsys library, where a PyAnsys library is used to extend or expose features
134+
from an Ansys application, product, or service that may be local or remote.
135+
136+
This section describes two main loggers for a PyAnsys library that exposes or
137+
extends a service based application, the *Global logger* and the *Instance
138+
logger*. These loggers are customized classes that wrap :class:`logging.Logger`
139+
from :mod:`logging` module and add specific features to it.
140+
:ref:`logging_in_pymapdl_figure` outlines the logging approach used by PyMAPDL
141+
and the scopes of the global and local loggers.
142142

143143
.. _logging_in_pymapdl_figure:
144144

@@ -167,14 +167,13 @@ Following are some unit tests demonstatring how to use the code implemented abov
167167
Example Global logger
168168
~~~~~~~~~~~~~~~~~~~~~
169169

170-
There is a global logger named ``py*_global`` which is created when
171-
importing ``ansys.product.service``
172-
(``ansys.product.service.__init__``). This logger is recommended for
173-
most scenarios, especially when complex modules or classes are not
174-
involved, since it does not track instances, rather can be used
175-
globally. If you intend to log the initialization of a library or
176-
module, you should use this logger. To use this global logger, you
177-
must import it at the top of your script or module:
170+
There is a global logger named ``py*_global`` which is created when importing
171+
``ansys.product.service`` (``ansys.product.service.__init__``). This logger is
172+
recommended for most scenarios, especially when complex modules or classes are
173+
not involved, since it does not track instances, rather can be used globally.
174+
If you intend to log the initialization of a library or module, you should use
175+
this logger. To use this global logger, you must import it at the top of your
176+
script or module:
178177

179178
.. code:: python
180179
@@ -216,13 +215,12 @@ you can add a file handler using:
216215
file_path = os.path.join(os.getcwd(), 'pylibrary.log')
217216
LOG.log_to_file(file_path)
218217
219-
This enables logging to that file in addition of the standard output.
220-
If you wish to change the characteristics of this global logger from
221-
the beginning of the execution, you must edit the file ``__init__`` in
222-
the directory of your library.
218+
This enables logging to that file in addition of the standard output. If you
219+
wish to change the characteristics of this global logger from the beginning of
220+
the execution, you must edit the file ``__init__`` in the directory of your
221+
library.
223222

224-
To log using this logger, simply call the desired method as a normal
225-
logger.
223+
To log using this logger, simply call the desired method as a normal logger.
226224

227225
.. code:: python
228226
@@ -237,13 +235,13 @@ logger.
237235
238236
Instance logger
239237
~~~~~~~~~~~~~~~
240-
Every time that the class ``_MapdlCore`` is instantiated, a logger is
241-
created. This logger is recommended when using the ``pool`` library
242-
or when using multiple instances of ``Mapdl``. The main feature of
243-
this logger is that it tracks each instance and it includes its name
244-
when logging. The name of the instances are unique. For example in
245-
case of using the ``gRPC`` ``Mapdl`` version, its name includes the IP
246-
and port of the correspondent instance, making unique its logger.
238+
Every time that the class ``_MapdlCore`` is instantiated, a logger is created.
239+
This logger is recommended when using the ``pool`` library or when using
240+
multiple instances of ``Mapdl``. The main feature of this logger is that it
241+
tracks each instance and it includes its name when logging. The name of the
242+
instances are unique. For example in case of using the ``gRPC`` ``Mapdl``
243+
version, its name includes the IP and port of the correspondent instance, making
244+
unique its logger.
247245

248246

249247
The instance loggers can be accessed in two places:
@@ -252,11 +250,11 @@ The instance loggers can be accessed in two places:
252250
* ``LOG._instances``. This field is a ``dict`` where the key is the
253251
name of the created logger.
254252

255-
These instance loggers inherit from the ``pymapdl_global`` output
256-
handlers and logging level unless otherwise specified. The way this
257-
logger works is very similar to the global logger. You can add a file
258-
handler if you wish using the method ``log_to_file`` or change the log
259-
level using :meth:`logging.Logger.setLevel`.
253+
These instance loggers inherit from the ``pymapdl_global`` output handlers and
254+
logging level unless otherwise specified. The way this logger works is very
255+
similar to the global logger. You can add a file handler if you wish using the
256+
method ``log_to_file`` or change the log level using
257+
:meth:`logging.Logger.setLevel`.
260258

261259
You can use this logger like this:
262260

@@ -274,17 +272,22 @@ You can use this logger like this:
274272
275273
Wrapping Other Loggers
276274
~~~~~~~~~~~~~~~~~~~~~~
277-
A product, due to its architecture can be made of several loggers.
278-
The ``logging`` library features allows to work with a finite number of loggers.
279-
The factory function logging.getLogger() helps to access each logger by its name.
280-
In addition of this naming-mappings, a hierachy can be established to structure the loggers
281-
parenting and their connection.
282-
283-
284-
For instance, if an ANSYS product is using a pre-exsiting custom logger encapsulated inside the product itself, the <PyProject> will benefit from exposing it through the standard python tools.
285-
It is recommended to use the standard library as much as possible. It will facilitate every contribution -both external and internal- to the <PyProject> by exposing common tools that are widely spread.
286-
Each developer will be able to operate quickly and autonomously.
287-
The project will take advantage of the entire set of features exposed in the standard logger and all the upcoming improvements.
275+
A product, due to its architecture can be made of several loggers. The
276+
``logging`` library features allows to work with a finite number of loggers. The
277+
factory function logging.getLogger() helps to access each logger by its name. In
278+
addition of this naming-mappings, a hierachy can be established to structure the
279+
loggers parenting and their connection.
280+
281+
282+
For instance, if an ANSYS product is using a pre-exsiting custom logger
283+
encapsulated inside the product itself, the <PyProject> will benefit from
284+
exposing it through the standard python tools. It is recommended to use the
285+
standard library as much as possible. It will facilitate every contribution
286+
-both external and internal- to the <PyProject> by exposing common tools that
287+
are widely spread. Each developer will be able to operate quickly and
288+
autonomously.
289+
The project will take advantage of the entire set of features exposed in the
290+
standard logger and all the upcoming improvements.
288291

289292
Create a custom log handler to catch each product message and redirect them on another logger:
290293
==============================================================================================
@@ -298,9 +301,12 @@ AEDT product has its own internal logger called the message manager made of 3 ma
298301
* *Project*: related to the project
299302
* *Design*: related to the design (most specific destination of each 3 loggers.)
300303

301-
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.
302-
In most of the cases, it is easier to work with the standard python module to extract data.
303-
In order to overcome this limitation, the existing message manager is wrapped into a logger based on the standard python `logging <https://docs.python.org/3/library/logging.html>`__ module.
304+
The message manager is not using the standard python logging module and this
305+
might be a problem later when exporting messages and data from each ANSYS
306+
product to a common tool. In most of the cases, it is easier to work with the
307+
standard python module to extract data.
308+
In order to overcome this limitation, the existing message manager is wrapped
309+
into a logger based on the standard python :mod:`logging` module.
304310

305311

306312
.. figure:: images/log_flow.png
@@ -311,8 +317,10 @@ In order to overcome this limitation, the existing message manager is wrapped in
311317
**Figure 1: Loggers message passing flow.**
312318

313319

314-
This wrapper implementation boils down to a custom handler. It is based on a class inherited from logging.Handler.
315-
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.
320+
This wrapper implementation boils down to a custom handler. It is based on a
321+
class inherited from logging.Handler. The initializer of this class will require
322+
the message manager to be passed as an argument in order to link the standard
323+
logging service with the ANSYS internal message manager.
316324

317325
.. code:: python
318326
@@ -330,9 +338,17 @@ The initializer of this class will require the message manager to be passed as a
330338
331339
332340
The purpose of this class is to send log messages in AEDT logging stream.
333-
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.
334-
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.
335-
As a reminder the record is an object containing all kind of information related to the event logged.
336-
337-
This custom handler is used into the new logger instance (the one based on the standard library).
338-
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...
341+
One of the mandatory actions is to overwrite the ``emit`` function. This method
342+
operates as a proxy. It will dispatch all the log message toward the message
343+
manager.
344+
Based on the record level, the message is sent to the appropriate log level
345+
(debug, info, error...) into the message manager to fit the level provided by
346+
the ANSYS product.
347+
As a reminder the record is an object containing all kind of information related
348+
to the event logged.
349+
350+
This custom handler is used into the new logger instance (the one based on the
351+
standard library).
352+
A good practice before to add a handler on any logger is to verify if any
353+
appropriate handler is already available in order to avoid any conflict, message
354+
duplication...

0 commit comments

Comments
 (0)