using `pynng <https://pypi.org/project/pynng/>`_, which is a Python binding to
`NNG <https://nng.nanomsg.org/>`_, billed as a spiritual successor to ZeroMQ.
The following snippets illustrate -- you can test them in an environment which has
-``pynng`` installed. Juat for variety, we present the listener first.
+``pynng`` installed. Just for variety, we present the listener first.
Subclass ``QueueListener``
.. code-block:: python
+ # listener.py
import json
import logging
import logging.handlers
break
except pynng.Timeout:
pass
- except pynng.Closed: # sometimes hit when you hit Ctrl-C
+ except pynng.Closed: # sometimes happens when you hit Ctrl-C
break
if data is None:
return None
.. code-block:: python
+ # sender.py
import json
import logging
import logging.handlers
logging.getLogger('pynng').propagate = False
handler = NNGSocketHandler(DEFAULT_ADDR)
+ # Make sure the process ID is in the output
logging.basicConfig(level=logging.DEBUG,
handlers=[logging.StreamHandler(), handler],
- format='%(levelname)-8s %(name)10s %(message)s')
+ format='%(levelname)-8s %(name)10s %(process)6s %(message)s')
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,
logging.CRITICAL)
logger_names = ('myapp', 'myapp.lib1', 'myapp.lib2')
delay = random.random() * 2 + 0.5
time.sleep(delay)
-You can run the above two snippets in separate command shells.
+You can run the above two snippets in separate command shells. If we run the
+listener in one shell and run the sender in two separate shells, we should see
+something like the following. In the first sender shell:
+
+.. code-block:: console
+
+ $ python sender.py
+ DEBUG myapp 613 Message no. 1
+ WARNING myapp.lib2 613 Message no. 2
+ CRITICAL myapp.lib2 613 Message no. 3
+ WARNING myapp.lib2 613 Message no. 4
+ CRITICAL myapp.lib1 613 Message no. 5
+ DEBUG myapp 613 Message no. 6
+ CRITICAL myapp.lib1 613 Message no. 7
+ INFO myapp.lib1 613 Message no. 8
+ (and so on)
+
+In the second sender shell:
+
+.. code-block:: console
+
+ $ python sender.py
+ INFO myapp.lib2 657 Message no. 1
+ CRITICAL myapp.lib2 657 Message no. 2
+ CRITICAL myapp 657 Message no. 3
+ CRITICAL myapp.lib1 657 Message no. 4
+ INFO myapp.lib1 657 Message no. 5
+ WARNING myapp.lib2 657 Message no. 6
+ CRITICAL myapp 657 Message no. 7
+ DEBUG myapp.lib1 657 Message no. 8
+ (and so on)
+
+In the listener shell:
+
+.. code-block:: console
+
+ $ python listener.py
+ Press Ctrl-C to stop.
+ DEBUG myapp 613 Message no. 1
+ WARNING myapp.lib2 613 Message no. 2
+ INFO myapp.lib2 657 Message no. 1
+ CRITICAL myapp.lib2 613 Message no. 3
+ CRITICAL myapp.lib2 657 Message no. 2
+ CRITICAL myapp 657 Message no. 3
+ WARNING myapp.lib2 613 Message no. 4
+ CRITICAL myapp.lib1 613 Message no. 5
+ CRITICAL myapp.lib1 657 Message no. 4
+ INFO myapp.lib1 657 Message no. 5
+ DEBUG myapp 613 Message no. 6
+ WARNING myapp.lib2 657 Message no. 6
+ CRITICAL myapp 657 Message no. 7
+ CRITICAL myapp.lib1 613 Message no. 7
+ INFO myapp.lib1 613 Message no. 8
+ DEBUG myapp.lib1 657 Message no. 8
+ (and so on)
+
+As you can see, the logging from the two sender processes is interleaved in the
+listener's output.
An example dictionary-based configuration
INFO:mylib:Doing something
INFO:__main__:Finished
-The key features of this idiomatic usage is that the majority of code is simply
+The key feature of this idiomatic usage is that the majority of code is simply
creating a module level logger with ``getLogger(__name__)``, and using that
-logger to do any needed logging. This is concise while allowing downstream code
-fine grained control if needed. Logged messages to the module-level logger get
-forwarded up to handlers of loggers in higher-level modules, all the way up to
-the root logger; for this reason this approach is known as hierarchical logging.
+logger to do any needed logging. This is concise, while allowing downstream
+code fine-grained control if needed. Logged messages to the module-level logger
+get forwarded to handlers of loggers in higher-level modules, all the way up to
+the highest-level logger known as the root logger; this approach is known as
+hierarchical logging.
For logging to be useful, it needs to be configured: setting the levels and
destinations for each logger, potentially changing how specific modules log,
unfamiliar with logging, the best way to get to grips with it is to view the
tutorials (**see the links above and on the right**).
-The basic classes defined by the module, together with their functions, are
-listed below.
+The basic classes defined by the module, together with their attributes and
+methods, are listed in the sections below.
* Loggers expose the interface that application code directly uses.
* Handlers send the log records (created by loggers) to the appropriate