diff --git a/README.rst b/README.rst
index 627f4f8..e772c10 100644
--- a/README.rst
+++ b/README.rst
@@ -23,6 +23,23 @@ the file LICENSE.txt in the distribution for the full license text.
 
 Reference documentation is available at https://zconfig.readthedocs.io.
 
+Information on the latest released version of the ZConfig package is
+available at
+
+  https://pypi.python.org/pypi/ZConfig/
+
+You may either create an RPM and install this, or install directly from
+the source distribution.
+
+There is a mailing list for discussions and questions about ZConfig;
+more information on the list is available at
+
+  http://mail.zope.org/mailman/listinfo/zconfig/
+
+
+Configuring Logging
+-------------------
+
 One common use of ZConfig is to configure the Python logging
 framework. This is extremely simple to do as the following example
 demonstrates:
@@ -50,21 +67,7 @@ or above to the console, as we can see in the following example:
 A more common configuration would see STDOUT replaced with a path to
 the file into which log entries would be written.
 
-For more information, see section 5.2 on the ZConfig documentation and
-the examples in ZConfig/components/logger/tests.
-
-Information on the latest released version of the ZConfig package is
-available at
-
-  https://pypi.python.org/pypi/ZConfig/
-
-You may either create an RPM and install this, or install directly from
-the source distribution.
-
-There is a mailing list for discussions and questions about ZConfig;
-more information on the list is available at
-
-  http://mail.zope.org/mailman/listinfo/zconfig/
+For more information, see the `the documentation <https://zconfig.readthedocs.io>`_.
 
 
 Installing from the source distribution
diff --git a/doc/developing-with-zconfig.rst b/doc/developing-with-zconfig.rst
index 20f90ba..4ef663a 100644
--- a/doc/developing-with-zconfig.rst
+++ b/doc/developing-with-zconfig.rst
@@ -9,5 +9,6 @@
    writing-schema
    standard-datatypes
    standard-components
+   logging-components
    writing-components
    documenting-components
diff --git a/doc/index.rst b/doc/index.rst
index 19d2cbb..fa1173b 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -18,7 +18,8 @@ ZODB, and is easily used by other projects. ZConfig only relies on the
 Python standard library.
 
 For information on reading and writing configuration documents, see
-:doc:`using-zconfig`.
+:doc:`using-zconfig`. For the extremely common usage of configuring
+the Python :mod:`logging` framework, see :doc:`using-logging`.
 
 For information on using ZConfig to create custom configurations for
 you projects, see :doc:`developing-with-zconfig`.
@@ -30,6 +31,7 @@ Development of ZConfig is hosted on `GitHub <https://github.com/zopefoundation/Z
    :caption: Contents:
 
    using-zconfig
+   using-logging
    developing-with-zconfig
    zconfig
    tools
diff --git a/doc/logging-components.rst b/doc/logging-components.rst
new file mode 100644
index 0000000..c0560f4
--- /dev/null
+++ b/doc/logging-components.rst
@@ -0,0 +1,164 @@
+====================
+ Logging Components
+====================
+
+.. highlight:: xml
+
+
+The :mod:`ZConfig.components.logger` package provides configuration
+support for the :mod:`logging` package in Python's standard library.
+This component can be imported using::
+
+
+  <import package="ZConfig.components.logger"/>
+
+
+This component defines two abstract types and several concrete section
+types.  These can be imported as a unit, as above, or as four smaller
+components usable in creating alternate logging packages.
+
+The first of the four smaller components contains the abstract types,
+and can be imported using::
+
+
+  <import package="ZConfig.components.logger" file="abstract.xml"/>
+
+
+The two abstract types imported by this are:
+
+
+**ZConfig.logger.log**
+  Logger objects are represented by this abstract type.
+
+**ZConfig.logger.handler**
+  Each logger object can have one or more "handlers" associated with
+  them.  These handlers are responsible for writing logging events to
+  some form of output stream using appropriate formatting.  The output
+  stream may be a file on a disk, a socket communicating with a server
+  on another system, or a series of ``syslog`` messages.  Section
+  types which implement this type represent these handlers.
+
+
+The second and third of the smaller components provides section types
+that act as factories for :class:`logging.Logger` objects.  These can be
+imported using::
+
+
+  <import package="ZConfig.components.logger" file="eventlog.xml"/>
+  <import package="ZConfig.components.logger" file="logger.xml"/>
+
+The types defined in these components implement the
+**ZConfig.logger.log** abstract type.  The 'eventlog.xml'
+component defines an **eventlog** type which represents the
+root logger from the the :mod:`logging` package (the return value of
+:func:`logging.getLogger`), while the 'logger.xml' component
+defines a **logger** section type which represents a named
+logger.
+
+
+The third of the smaller components provides section types that are
+factories for :class:`logging.Handler` objects.  This can be imported
+using::
+
+
+  <import package="ZConfig.components.logger" file="handlers.xml"/>
+
+
+The types defined in this component implement the
+**ZConfig.logger.handler** abstract type.
+
+
+The configuration objects provided by both the logger and handler
+types are factories for the finished loggers and handlers.  These
+factories should be called with no arguments to retrieve the logger or
+log handler objects.  Calling the factories repeatedly will cause the
+same objects to be returned each time, so it's safe to simply call
+them to retrieve the objects.
+
+The factories for the logger objects, whether the **eventlog**
+or **logger** section type is used, provide a :meth:`~.reopen`
+method which may be called to close any log files and re-open them.
+This is useful when using a UNIX signal to effect log file
+rotation: the signal handler can call this method, and not have to
+worry about what handlers have been registered for the logger.  There
+is also a function in the
+:mod:`ZConfig.components.logger.loghandler` module that re-opens all
+open log files created using ZConfig configuration:
+
+.. py:function:: ZConfig.components.logger.loghandler.reopenFiles()
+
+  Closes and re-opens all the log files held open by handlers created
+  by the factories for ``logfile`` sections.  This is intended to
+  help support log rotation for applications.
+
+.. _using-logging:
+
+Using The Logging Components
+============================
+
+Building an application that uses the logging components is fairly
+straightforward.  The schema needs to import the relevant components
+and declare their use::
+
+
+  <schema>
+    <import package="ZConfig.components.logger" file="eventlog.xml"/>
+    <import package="ZConfig.components.logger" file="handlers.xml"/>
+
+    <section type="eventlog" name="*" attribute="eventlog"
+             required="yes"/>
+  </schema>
+
+
+In the application, the schema and configuration file should be loaded
+normally.  Once the configuration object is available, the logger
+factory should be called to configure Python's :mod:`logging` package:
+
+.. code-block:: python
+
+
+  import os
+  import ZConfig
+
+  def run(configfile):
+    schemafile = os.path.join(os.path.dirname(__file__), "schema.xml")
+    schema = ZConfig.loadSchema(schemafile)
+    config, handlers = ZConfig.loadConfig(schema, configfile)
+
+    # configure the logging package:
+    config.eventlog()
+
+    # now do interesting things
+
+
+An example configuration file for this application may look like this::
+
+
+  <eventlog>
+    level  info
+
+    <logfile>
+      path        /var/log/myapp
+      format      %(asctime)s %(levelname)s %(name)s %(message)s
+      # locale-specific date/time representation
+      dateformat  %c
+    </logfile>
+
+    <syslog>
+      level    error
+      address  syslog.example.net:514
+      format   %(levelname)s %(name)s %(message)s
+    </syslog>
+  </eventlog>
+
+
+Refer to the :class:`logging.LogRecord` documentation for the names
+available in the message format strings (the ``format`` key in the
+log handlers).  The date format strings (the ``dateformat`` key in
+the log handlers) are the same as those accepted by the
+:func:`time.strftime` function.
+
+Configuring The Logging Components
+==================================
+
+For reference documentation on the available handlers, see :ref:`logging-handlers`.
diff --git a/doc/root-and-child-config.conf b/doc/root-and-child-config.conf
new file mode 100644
index 0000000..531b755
--- /dev/null
+++ b/doc/root-and-child-config.conf
@@ -0,0 +1,11 @@
+<logger>
+    level INFO
+    <logfile>
+       path STDOUT
+       format %(levelname)s %(name)s %(message)s
+    </logfile>
+</logger>
+<logger>
+    name my.package
+    level DEBUG
+</logger>
diff --git a/doc/simple-root-config.conf b/doc/simple-root-config.conf
new file mode 100644
index 0000000..02a5461
--- /dev/null
+++ b/doc/simple-root-config.conf
@@ -0,0 +1,7 @@
+<logger>
+    level INFO
+    <logfile>
+       path STDOUT
+       format %(levelname)s %(name)s %(message)s
+    </logfile>
+</logger>
diff --git a/doc/standard-components.rst b/doc/standard-components.rst
index ae36847..2eb1240 100644
--- a/doc/standard-components.rst
+++ b/doc/standard-components.rst
@@ -5,7 +5,7 @@
 ===========================================
 
 :mod:`ZConfig` provides a few convenient schema components as part
-of the package.  These may be used directly or can server as examples
+of the package.  These may be used directly or can serve as examples
 for creating new components.
 
 .. highlight:: xml
@@ -108,174 +108,3 @@ then we can use this as the key type for a derived mapping type::
            type="email-users"
            attribute="email_users"
            />
-
-
-ZConfig.components.logger
-=========================
-
-The :mod:`ZConfig.components.logger` package provides configuration
-support for the :mod:`logging` package in Python's standard library.
-This component can be imported using::
-
-
-  <import package="ZConfig.components.logger"/>
-
-
-This component defines two abstract types and several concrete section
-types.  These can be imported as a unit, as above, or as four smaller
-components usable in creating alternate logging packages.
-
-The first of the four smaller components contains the abstract types,
-and can be imported using::
-
-
-  <import package="ZConfig.components.logger" file="abstract.xml"/>
-
-
-The two abstract types imported by this are:
-
-
-**ZConfig.logger.log**
-  Logger objects are represented by this abstract type.
-
-**ZConfig.logger.handler**
-  Each logger object can have one or more "handlers" associated with
-  them.  These handlers are responsible for writing logging events to
-  some form of output stream using appropriate formatting.  The output
-  stream may be a file on a disk, a socket communicating with a server
-  on another system, or a series of ``syslog`` messages.  Section
-  types which implement this type represent these handlers.
-
-
-The second and third of the smaller components provides section types
-that act as factories for :class:`logging.Logger` objects.  These can be
-imported using::
-
-
-  <import package="ZConfig.components.logger" file="eventlog.xml"/>
-  <import package="ZConfig.components.logger" file="logger.xml"/>
-
-The types defined in these components implement the
-**ZConfig.logger.log** abstract type.  The 'eventlog.xml'
-component defines an **eventlog** type which represents the
-root logger from the the :mod:`logging` package (the return value of
-:func:`logging.getLogger`), while the 'logger.xml' component
-defines a **logger** section type which represents a named
-logger.
-
-
-The third of the smaller components provides section types that are
-factories for :class:`logging.Handler` objects.  This can be imported
-using::
-
-
-  <import package="ZConfig.components.logger" file="handlers.xml"/>
-
-
-The types defined in this component implement the
-**ZConfig.logger.handler** abstract type.
-
-
-The configuration objects provided by both the logger and handler
-types are factories for the finished loggers and handlers.  These
-factories should be called with no arguments to retrieve the logger or
-log handler objects.  Calling the factories repeatedly will cause the
-same objects to be returned each time, so it's safe to simply call
-them to retrieve the objects.
-
-The factories for the logger objects, whether the **eventlog**
-or **logger** section type is used, provide a :meth:`~.reopen`
-method which may be called to close any log files and re-open them.
-This is useful when using a UNIX signal to effect log file
-rotation: the signal handler can call this method, and not have to
-worry about what handlers have been registered for the logger.  There
-is also a function in the
-:mod:`ZConfig.components.logger.loghandler` module that re-opens all
-open log files created using ZConfig configuration:
-
-.. py:function:: ZConfig.components.logger.loghandler.reopenFiles()
-
-  Closes and re-opens all the log files held open by handlers created
-  by the factories for ``logfile`` sections.  This is intended to
-  help support log rotation for applications.
-
-.. _using-logging:
-
-Using The Logging Components
-----------------------------
-
-Building an application that uses the logging components is fairly
-straightforward.  The schema needs to import the relevant components
-and declare their use::
-
-
-  <schema>
-    <import package="ZConfig.components.logger" file="eventlog.xml"/>
-    <import package="ZConfig.components.logger" file="handlers.xml"/>
-
-    <section type="eventlog" name="*" attribute="eventlog"
-             required="yes"/>
-  </schema>
-
-
-In the application, the schema and configuration file should be loaded
-normally.  Once the configuration object is available, the logger
-factory should be called to configure Python's :mod:`logging` package:
-
-.. code-block:: python
-
-
-  import os
-  import ZConfig
-
-  def run(configfile):
-    schemafile = os.path.join(os.path.dirname(__file__), "schema.xml")
-    schema = ZConfig.loadSchema(schemafile)
-    config, handlers = ZConfig.loadConfig(schema, configfile)
-
-    # configure the logging package:
-    config.eventlog()
-
-    # now do interesting things
-
-
-An example configuration file for this application may look like this::
-
-
-  <eventlog>
-    level  info
-
-    <logfile>
-      path        /var/log/myapp
-      format      %(asctime)s %(levelname)s %(name)s %(message)s
-      # locale-specific date/time representation
-      dateformat  %c
-    </logfile>
-
-    <syslog>
-      level    error
-      address  syslog.example.net:514
-      format   %(levelname)s %(name)s %(message)s
-    </syslog>
-  </eventlog>
-
-
-Refer to the :class:`logging.LogRecord` documentation for the names
-available in the message format strings (the ``format`` key in the
-log handlers).  The date format strings (the ``dateformat`` key in
-the log handlers) are the same as those accepted by the
-:func:`time.strftime` function.
-
-Configuring the email logger
-----------------------------
-
-ZConfig has support for Python's :class:`logging.handlers.SMTPHandler`
-via the ``<email-notifier>`` handler.
-
-.. zconfig:: ZConfig.components.logger
-     :file: handlers.xml
-     :members: email-notifier
-
-
-For details about the :class:`~logging.handlers.SMTPHandler` see the
-Python :mod:`logging` module.
diff --git a/doc/using-logging.rst b/doc/using-logging.rst
new file mode 100644
index 0000000..c24a2c1
--- /dev/null
+++ b/doc/using-logging.rst
@@ -0,0 +1,147 @@
+=====================
+ Configuring Logging
+=====================
+
+One common use of ZConfig is to configure the Python :mod:`logging`
+framework. ZConfig provides one simple convenience function to do this:
+
+.. autofunction:: ZConfig.configureLoggers
+
+
+Suppose we have the following logging configuration in a file called ``simple-root-config.conf``:
+
+.. literalinclude:: simple-root-config.conf
+   :language: xml
+
+We can load this file and pass its contents to ``configureLoggers``::
+
+    >>> from ZConfig import configureLoggers
+    >>> with open('simple-root-config.conf') as f:
+    ...   configureLoggers(f.read())
+
+When this returns, the root logger is configured to output messages
+logged at INFO or above to the console, as we can see in the following
+example::
+
+    >>> from logging import getLogger
+    >>> getLogger().info('An info message')
+    INFO root An info message
+    >>> getLogger().debug('A debug message')
+
+A more common configuration would see STDOUT replaced with a path to
+the file into which log entries would be written.
+
+Although loading configuration from a file is common, we could of
+course also pass a string literal to :func:`~.configureLoggers`. Any
+type of Python string (bytes or unicode) is acceptable.
+
+
+Configuration Format
+====================
+
+The configuration text is in the :ref:`ZConfig format <syntax>` and
+supports comments and substitutions.
+
+It can contain multiple ``<logger>`` elements,
+each of which can have any number of :ref:`handler elements <logging-handlers>`.
+
+.. zconfig:: ZConfig.components.logger
+    :file: logger.xml
+    :members: logger
+
+.. highlight:: xml
+
+Examples
+--------
+
+Here's the configuration we looked at above. It configures the root
+(unnamed) logger with one handler (``<logfile>``), operating at the INFO level:
+
+.. literalinclude:: simple-root-config.conf
+   :language: xml
+
+We can configure a different logger in the hierarchy to use the DEBUG
+level at the same time as we configure the root logger. We're not
+specifying a handler for it, but the default ``propagate`` value will
+let the lower level logger use the root logger's handler:
+
+.. literalinclude:: root-and-child-config.conf
+   :language: xml
+
+
+If we load that configuration from ``root-and-child-config.conf``, we
+can expect this behaviour:
+
+..
+  >>> tearDown(None)
+
+.. code-block:: pycon
+
+    >>> with open('root-and-child-config.conf') as f:
+    ...     configureLoggers(f.read())
+    >>> getLogger().info('An info message')
+    INFO root An info message
+    >>> getLogger().debug('A debug message')
+    >>> getLogger('my.package').debug('A debug message')
+    DEBUG my.package A debug message
+
+.. _logging-handlers:
+
+Log Handlers
+============
+
+Many of Python's built-in log handlers can be configured with ZConfig.
+
+
+Files
+-----
+
+The ``<logfile>`` handler writes to files or standard output or standard error
+(when the ``path`` is ``STDOUT`` or ``STDERR`` respectively). It
+configures a :class:`logging.StreamHandler`. When the
+``interval`` or ``max-size`` attributes are set, the files on disk
+will be rotated either at :class:`set intervals
+<logging.handlers.TimedRotatingFileHandler>` or when files
+:class:`reach the set size <logging.handlers.RotatingFileHandler>`, respectively.
+
+.. zconfig:: ZConfig.components.logger
+     :file: handlers.xml
+     :members: logfile
+
+The System Log
+--------------
+
+The ``<syslog>`` handler configures the :class:`logging.handlers.SysLogHandler`.
+
+.. zconfig:: ZConfig.components.logger
+     :file: handlers.xml
+     :members: syslog
+
+Windows Event Log
+-----------------
+
+On Windows, the ``<win32-eventlog>`` configures the :class:`logging.handlers.NTEventLogHandler`.
+
+.. zconfig:: ZConfig.components.logger
+     :file: handlers.xml
+     :members: win32-eventlog
+
+HTTP
+----
+
+The ``<<http-logger>`` element configures :class:`logging.handlers.HTTPHandler`.
+
+.. zconfig:: ZConfig.components.logger
+     :file: handlers.xml
+     :members: http-logger
+
+
+Email
+-----
+
+ZConfig has support for Python's :class:`logging.handlers.SMTPHandler`
+via the ``<email-notifier>`` handler.
+
+.. zconfig:: ZConfig.components.logger
+     :file: handlers.xml
+     :members: email-notifier
diff --git a/doc/using-zconfig.rst b/doc/using-zconfig.rst
index 8e68d12..ed04ef6 100644
--- a/doc/using-zconfig.rst
+++ b/doc/using-zconfig.rst
@@ -11,6 +11,9 @@ Reading Configurations
 For information on using ZConfig configuration documents in Python,
 see :mod:`ZConfig` and especially the example at :ref:`basic-usage`.
 
+For information about configuring the :mod:`logging` framework, see
+:doc:`using-logging`.
+
 .. _syntax:
 
 Writing Configurations
@@ -95,8 +98,9 @@ The terminator looks like this:
 
 
 The configuration data in a non-empty section consists of a sequence
-of one or more key-value pairs and sections.  For example::
+of one or more key-value pairs and sections.  For example:
 
+.. code-block:: xml
 
   <my-section>
     key-1 value-1
@@ -164,7 +168,9 @@ the same way Zope 2 does.  There are some parameters which configure
 the general behavior of the logging mechanism, and an arbitrary number
 of **log handlers** may be specified to control how the log
 messages are handled.  Several log handlers are provided by the
-application.  Here is an example logging configuration::
+application.  Here is an example logging configuration:
+
+.. code-block:: xml
 
 
   <eventlog>

Document logging syntax
IMO, the best way to configure Python logging is with ZConfig, but it's not documented and thus a best-kept secret.

It would be great if this got documented.
diff --git a/ZConfig/tests/test_readme.py b/ZConfig/tests/test_readme.py
index a4ed92b..2a95b6a 100644
--- a/ZConfig/tests/test_readme.py
+++ b/ZConfig/tests/test_readme.py
@@ -12,6 +12,9 @@
 #
 ##############################################################################
 import doctest
+import os
+import os.path
+import unittest
 import logging
 
 
@@ -19,7 +22,6 @@ options = doctest.REPORT_NDIFF | doctest.ELLIPSIS
 
 old = {}
 def setUp(test):
-    global old
     logger = logging.getLogger()
     old['level'] = logger.level
     old['handlers'] = logger.handlers[:]
@@ -29,9 +31,33 @@ def tearDown(test):
     logger.level = old['level']
     logger.handlers = old['handlers']
 
+def docSetUp(test):
+    old['pwd'] = os.getcwd()
+    doc_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        '..',
+        '..',
+        'doc')
+    os.chdir(doc_path)
+    setUp(test)
+
+def docTearDown(test):
+    os.chdir(old['pwd'])
+    tearDown(test)
+
 def test_suite():
-    return doctest.DocFileSuite(
-        '../../README.rst',
-        optionflags=options,
-        setUp=setUp, tearDown=tearDown,
-        )
+    return unittest.TestSuite([
+        doctest.DocFileSuite(
+            '../../README.rst',
+            optionflags=options,
+            setUp=setUp, tearDown=tearDown,
+        ),
+        doctest.DocFileSuite(
+            '../../doc/using-logging.rst',
+            optionflags=options, globs=globals(),
+            setUp=docSetUp, tearDown=docTearDown,
+        ),
+    ])
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

pip install -e .[test]
parse_log_pytest
requirements.txt
zope.testrunner pytest
3.6
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
docutils==0.18.1
importlib-metadata==4.8.3
iniconfig==1.1.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
six==1.17.0
tomli==1.2.3
typing_extensions==4.1.1
-e git+https://github.com/zopefoundation/ZConfig.git@227f96029db86137ddb02f18eedce5b4fcd6d8ba#egg=ZConfig
zipp==3.6.0
zope.exceptions==4.6
zope.interface==5.5.2
zope.testrunner==5.6

name: ZConfig
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - docutils==0.18.1
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - six==1.17.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
      - zope-exceptions==4.6
      - zope-interface==5.5.2
      - zope-testrunner==5.6
prefix: /opt/conda/envs/ZConfig

ZConfig/tests/test_readme.py::test_suite
README.rst doc/root-and-child-config.conf doc/simple-root-config.conf doc/using-logging.rst doc/standard-components.rst doc/developing-with-zconfig.rst doc/index.rst doc/logging-components.rst doc/using-zconfig.rst
README.rst doc/root-and-child-config.conf doc/simple-root-config.conf doc/using-logging.rst doc/standard-components.rst doc/developing-with-zconfig.rst doc/index.rst doc/logging-components.rst doc/using-zconfig.rst