Introspection for the ``logging`` logger tree in the Standard Library.
You can install this package with the standard ``pip`` command::
$ pip install logging_tree
The simplest way to use this package is to call ``printout()`` to see
the loggers, filters, and handlers that your application has configured:
>>> import logging
>>> a = logging.getLogger('a')
>>> b = logging.getLogger('a.b').setLevel(logging.DEBUG)
>>> c = logging.getLogger('x.c')
>>> import sys
>>> h = logging.StreamHandler(sys.stdout)
>>> logging.getLogger().addHandler(h)
>>> from logging_tree import printout
>>> printout()
<--""
Level WARNING
Handler Stream <sys.stdout>
|
o<--"a"
| Level NOTSET so inherits level WARNING
| |
| o<--"a.b"
| Level DEBUG
|
o<--[x]
|
o<--"x.c"
Level NOTSET so inherits level WARNING
If you instead want to write the tree diagram to a file, stream, or
other file-like object, use::
file_object.write(logging_tree.format.build_description())
The logging tree should always print successfully, no matter how
complicated. A node whose name is in square brackets, like the ``[x]``
node above, is a "place holder" that has never itself been named in a
``getLogger()`` call, but which was created automatically to serve as
the parent of loggers further down the tree.
Propagation
-----------
A quick reminder about how ``logging`` works: by default, a node will
not only submit a message to its own handlers (if any), but will also
"propagate" each message up to its parent. For example, a ``Stream``
handler attached to the root logger will not only receive messages sent
directly to the root, but also messages that propagate up from a child
like ``a.b``.
>>> logging.getLogger().warning('message sent to the root')
message sent to the root
>>> logging.getLogger('a.b').warning('message sent to a.b')
message sent to a.b
But messages are *not* subjected to filtering as they propagate. So a
debug-level message, which our root node will discard because the root's
level is set to ``WARNING``, will be accepted by the ``a.b`` node and
will be allowed to propagate up to the root handler.
>>> logging.getLogger().debug('this message is ignored')
>>> logging.getLogger('a.b').debug('but this message prints!')
but this message prints!
If both the root node and ``a.b`` have a handler attached, then a
message accepted by ``a.b`` will be printed twice, once by its own node,
and then a second time when the message propagates up to the root.
>>> logging.getLogger('a.b').addHandler(h)
>>> logging.getLogger('a.b').warning('this message prints twice')
this message prints twice
this message prints twice
But you can stop a node from propagating messages to its parent by
setting its ``propagate`` attribute to ``False``.
>>> logging.getLogger('a.b').propagate = False
>>> logging.getLogger('a.b').warning('does not propagate')
does not propagate
The logging tree will indicate that propagate is turned off by no longer
drawing the arrow ``<--`` that points from the node to its parent:
>>> printout()
<--""
Level WARNING
Handler Stream <sys.stdout>
|
o<--"a"
| Level NOTSET so inherits level WARNING
| |
| o "a.b"
| Level DEBUG
| Propagate OFF
| Handler Stream <sys.stdout>
|
o<--[x]
|
o<--"x.c"
Level NOTSET so inherits level WARNING
You can turn propagate back on again by setting the attribute ``True``.
API
---
Even though most users will simply call the top-level ``printout()``
routine, this package also offers a few lower-level calls. Here's the
complete list:
``logging_tree.printout(node=None)``
Prints the current logging tree, or the tree based at the given
`node`, to the standard output.
``logging_tree.format.build_description(node=None)``
Builds and returns the multi-line description of the current logger
tree, or the tree based at the given ``node``, as a single string
with newlines inside and a newline at the end.
``logging_tree.format.describe(node)``
A generator that yields a series of lines that describe the tree
based at the given ``node``. Note that the lines are returned
without newline terminators attached.
``logging_tree.tree()``
Fetch the current tree of loggers from the ``logging`` module.
Returns a node, that is simply a tuple with three fields:
| ``[0]`` the logger name (``""`` for the root logger).
| ``[1]`` the ``logging.Logger`` object itself.
| ``[2]`` a list of zero or more child nodes.
You can find this package's issue tracker `on GitHub
<https://github.com/brandon-rhodes/logging_tree>`_. You can run this
package's test suite with::
$ python -m unittest discover logging_tree
On older versions of Python you will instead have to install
``unittest2`` and use its ``unit2`` command line tool to run the tests.
Changelog
---------
**Version 1.10** - 2024 May 3
Declare compatibility with Python 3.12, and expand the documentation
to describe the basics of log message propagation.
**Version 1.9** - 2021 April 10
Declare compatibility with Python 3.9. Improve how the logging
module's built-in ``Formatter`` class is displayed under old Python
versions where the ``logging`` module uses old-style classes.
**Version 1.8.1** - 2020 January 26
Adjust one test to make it pass under Python 3.8, and update the
distribution classifiers to declare compatibility with Python
versions through 3.8.
**Version 1.8** - 2018 August 5
Improve the output to better explain what happens if a "parent"
attribute has been set to None.
**Version 1.7** - 2016 January 23
Detect whether each logger has the correct "parent" attribute and,
if not, print where its log messages are being sent instead.
**Version 1.6** - 2015 January 8
Fixed a crash that would occur if a custom logging Formatter was
missing its format string attributes.
**Version 1.5** - 2014 December 24
Handlers now display their logging level if one has been set, and
their custom logging formatter if one has been installed.
**Version 1.4** - 2014 January 8
Thanks to a contribution from Dave Brondsema, disabled loggers are
now actually marked as "Disabled" to make it less of a surprise that
they fail to log anything.
**Version 1.3** - 2013 October 29
Be explicit and display the logger level ``NOTSET`` along with the
effective level inherited from the logger's ancestors; and display
the list of ``.filters`` of a custom logging handler even though it
might contain custom code that ignores them.
**Version 1.2** - 2013 January 19
Compatible with Python 3.3 thanks to @ralphbean.
**Version 1.1** - 2012 February 17
Now compatible with 2.3 <= Python <= 3.2.
**Version 1.0** - 2012 February 13
Can display the handler inside a MemoryHandler; entire public
interface documented; 100% test coverage.
**Version 0.6** - 2012 February 10
Added a display format for every ``logging.handlers`` class.
**Version 0.5** - 2012 February 8
Initial release.
Raw data
{
"_id": null,
"home_page": "https://github.com/brandon-rhodes/logging_tree",
"name": "logging-tree",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Brandon Rhodes",
"author_email": "brandon@rhodesmill.org",
"download_url": "https://files.pythonhosted.org/packages/06/8a/4d9bd637ecf05ec6c76179f91824b1a66425a9275abf676e87fe8a9c23a2/logging_tree-1.10.tar.gz",
"platform": null,
"description": "Introspection for the ``logging`` logger tree in the Standard Library.\n\nYou can install this package with the standard ``pip`` command::\n\n $ pip install logging_tree\n\nThe simplest way to use this package is to call ``printout()`` to see\nthe loggers, filters, and handlers that your application has configured:\n\n >>> import logging\n >>> a = logging.getLogger('a')\n >>> b = logging.getLogger('a.b').setLevel(logging.DEBUG)\n >>> c = logging.getLogger('x.c')\n\n >>> import sys\n >>> h = logging.StreamHandler(sys.stdout)\n >>> logging.getLogger().addHandler(h)\n\n >>> from logging_tree import printout\n >>> printout()\n <--\"\"\n Level WARNING\n Handler Stream <sys.stdout>\n |\n o<--\"a\"\n | Level NOTSET so inherits level WARNING\n | |\n | o<--\"a.b\"\n | Level DEBUG\n |\n o<--[x]\n |\n o<--\"x.c\"\n Level NOTSET so inherits level WARNING\n\nIf you instead want to write the tree diagram to a file, stream, or\nother file-like object, use::\n\n file_object.write(logging_tree.format.build_description())\n\nThe logging tree should always print successfully, no matter how\ncomplicated. A node whose name is in square brackets, like the ``[x]``\nnode above, is a \"place holder\" that has never itself been named in a\n``getLogger()`` call, but which was created automatically to serve as\nthe parent of loggers further down the tree.\n\nPropagation\n-----------\n\nA quick reminder about how ``logging`` works: by default, a node will\nnot only submit a message to its own handlers (if any), but will also\n\"propagate\" each message up to its parent. For example, a ``Stream``\nhandler attached to the root logger will not only receive messages sent\ndirectly to the root, but also messages that propagate up from a child\nlike ``a.b``.\n\n >>> logging.getLogger().warning('message sent to the root')\n message sent to the root\n >>> logging.getLogger('a.b').warning('message sent to a.b')\n message sent to a.b\n\nBut messages are *not* subjected to filtering as they propagate. So a\ndebug-level message, which our root node will discard because the root's\nlevel is set to ``WARNING``, will be accepted by the ``a.b`` node and\nwill be allowed to propagate up to the root handler.\n\n >>> logging.getLogger().debug('this message is ignored')\n >>> logging.getLogger('a.b').debug('but this message prints!')\n but this message prints!\n\nIf both the root node and ``a.b`` have a handler attached, then a\nmessage accepted by ``a.b`` will be printed twice, once by its own node,\nand then a second time when the message propagates up to the root.\n\n >>> logging.getLogger('a.b').addHandler(h)\n >>> logging.getLogger('a.b').warning('this message prints twice')\n this message prints twice\n this message prints twice\n\nBut you can stop a node from propagating messages to its parent by\nsetting its ``propagate`` attribute to ``False``.\n\n >>> logging.getLogger('a.b').propagate = False\n >>> logging.getLogger('a.b').warning('does not propagate')\n does not propagate\n\nThe logging tree will indicate that propagate is turned off by no longer\ndrawing the arrow ``<--`` that points from the node to its parent:\n\n >>> printout()\n <--\"\"\n Level WARNING\n Handler Stream <sys.stdout>\n |\n o<--\"a\"\n | Level NOTSET so inherits level WARNING\n | |\n | o \"a.b\"\n | Level DEBUG\n | Propagate OFF\n | Handler Stream <sys.stdout>\n |\n o<--[x]\n |\n o<--\"x.c\"\n Level NOTSET so inherits level WARNING\n\nYou can turn propagate back on again by setting the attribute ``True``.\n\nAPI\n---\n\nEven though most users will simply call the top-level ``printout()``\nroutine, this package also offers a few lower-level calls. Here's the\ncomplete list:\n\n``logging_tree.printout(node=None)``\n\n Prints the current logging tree, or the tree based at the given\n `node`, to the standard output.\n\n``logging_tree.format.build_description(node=None)``\n\n Builds and returns the multi-line description of the current logger\n tree, or the tree based at the given ``node``, as a single string\n with newlines inside and a newline at the end.\n\n``logging_tree.format.describe(node)``\n\n A generator that yields a series of lines that describe the tree\n based at the given ``node``. Note that the lines are returned\n without newline terminators attached.\n\n``logging_tree.tree()``\n\n Fetch the current tree of loggers from the ``logging`` module.\n Returns a node, that is simply a tuple with three fields:\n\n | ``[0]`` the logger name (``\"\"`` for the root logger).\n | ``[1]`` the ``logging.Logger`` object itself.\n | ``[2]`` a list of zero or more child nodes.\n\nYou can find this package's issue tracker `on GitHub\n<https://github.com/brandon-rhodes/logging_tree>`_. You can run this\npackage's test suite with::\n\n $ python -m unittest discover logging_tree\n\nOn older versions of Python you will instead have to install\n``unittest2`` and use its ``unit2`` command line tool to run the tests.\n\nChangelog\n---------\n\n**Version 1.10** - 2024 May 3\n Declare compatibility with Python 3.12, and expand the documentation\n to describe the basics of log message propagation.\n\n**Version 1.9** - 2021 April 10\n Declare compatibility with Python 3.9. Improve how the logging\n module's built-in ``Formatter`` class is displayed under old Python\n versions where the ``logging`` module uses old-style classes.\n\n**Version 1.8.1** - 2020 January 26\n Adjust one test to make it pass under Python 3.8, and update the\n distribution classifiers to declare compatibility with Python\n versions through 3.8.\n\n**Version 1.8** - 2018 August 5\n Improve the output to better explain what happens if a \"parent\"\n attribute has been set to None.\n\n**Version 1.7** - 2016 January 23\n Detect whether each logger has the correct \"parent\" attribute and,\n if not, print where its log messages are being sent instead.\n\n**Version 1.6** - 2015 January 8\n Fixed a crash that would occur if a custom logging Formatter was\n missing its format string attributes.\n\n**Version 1.5** - 2014 December 24\n Handlers now display their logging level if one has been set, and\n their custom logging formatter if one has been installed.\n\n**Version 1.4** - 2014 January 8\n Thanks to a contribution from Dave Brondsema, disabled loggers are\n now actually marked as \"Disabled\" to make it less of a surprise that\n they fail to log anything.\n\n**Version 1.3** - 2013 October 29\n Be explicit and display the logger level ``NOTSET`` along with the\n effective level inherited from the logger's ancestors; and display\n the list of ``.filters`` of a custom logging handler even though it\n might contain custom code that ignores them.\n\n**Version 1.2** - 2013 January 19\n Compatible with Python 3.3 thanks to @ralphbean.\n\n**Version 1.1** - 2012 February 17\n Now compatible with 2.3 <= Python <= 3.2.\n\n**Version 1.0** - 2012 February 13\n Can display the handler inside a MemoryHandler; entire public\n interface documented; 100% test coverage.\n\n**Version 0.6** - 2012 February 10\n Added a display format for every ``logging.handlers`` class.\n\n**Version 0.5** - 2012 February 8\n Initial release.\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Introspect and display the logger tree inside \"logging\"",
"version": "1.10",
"project_urls": {
"Homepage": "https://github.com/brandon-rhodes/logging_tree"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7a1c8e9c092e0faa0eb5ac8f5e859a62bd82239eba0259c05f6fd9bb6ddd6b91",
"md5": "4773ecba7eb459dba46d723a44aaa6bd",
"sha256": "f0e9f4645e6476e48c563ba2b858286079f886b2d5ad8abeaffd38e536a387d8"
},
"downloads": -1,
"filename": "logging_tree-1.10-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "4773ecba7eb459dba46d723a44aaa6bd",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 13280,
"upload_time": "2024-05-03T16:05:10",
"upload_time_iso_8601": "2024-05-03T16:05:10.674685Z",
"url": "https://files.pythonhosted.org/packages/7a/1c/8e9c092e0faa0eb5ac8f5e859a62bd82239eba0259c05f6fd9bb6ddd6b91/logging_tree-1.10-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "068a4d9bd637ecf05ec6c76179f91824b1a66425a9275abf676e87fe8a9c23a2",
"md5": "3c0e960c4d56c5a5acdc084e7b4f3d58",
"sha256": "cd78848fe0ee4aafcc64fa8a66f96f177186ff3d883619b1d7f3628564802095"
},
"downloads": -1,
"filename": "logging_tree-1.10.tar.gz",
"has_sig": false,
"md5_digest": "3c0e960c4d56c5a5acdc084e7b4f3d58",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 12731,
"upload_time": "2024-05-03T16:05:18",
"upload_time_iso_8601": "2024-05-03T16:05:18.892451Z",
"url": "https://files.pythonhosted.org/packages/06/8a/4d9bd637ecf05ec6c76179f91824b1a66425a9275abf676e87fe8a9c23a2/logging_tree-1.10.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-03 16:05:18",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "brandon-rhodes",
"github_project": "logging_tree",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "logging-tree"
}