From e6b8b3b6b42370a9336ae4e9b6961d6b8752d7a4 Mon Sep 17 00:00:00 2001
From: Veit Schiele <veit@cusy.io>
Date: Fri, 6 Dec 2024 18:08:52 +0100
Subject: [PATCH] :memo: Move logging to Python basics

---
 CHANGELOG.rst                                 |   1 +
 docs/intro.rst                                |   6 +-
 docs/productive/envs/uv/docker.rst            |   6 +-
 docs/productive/envs/uv/index.rst             |   2 +-
 docs/productive/git/advanced/gitlab/ci-cd.rst |   2 +-
 docs/productive/index.rst                     |   6 +-
 docs/productive/licensing.rst                 |   2 +-
 docs/productive/logging.rst                   |   5 +
 docs/productive/logging/development.ini       |  25 -
 docs/productive/logging/examples.ipynb        | 890 ------------------
 .../productive/logging/examples.ipynb.license |   3 -
 docs/productive/logging/index.rst             |  52 -
 12 files changed, 18 insertions(+), 982 deletions(-)
 create mode 100644 docs/productive/logging.rst
 delete mode 100644 docs/productive/logging/development.ini
 delete mode 100644 docs/productive/logging/examples.ipynb
 delete mode 100644 docs/productive/logging/examples.ipynb.license
 delete mode 100644 docs/productive/logging/index.rst

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 85aa417ba..ab699bfc0 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -44,6 +44,7 @@ Added
 Removed
 ~~~~~~~
 
+* đź“ť Move logging to Python basics
 * ✏️ Remove link to Objectivity/DB
 * đź“ť Move SOLID principles to Python Basics
 
diff --git a/docs/intro.rst b/docs/intro.rst
index 6a7b86932..fc4d11ea6 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -52,9 +52,9 @@ From Chapter 2, the tutorial follows the prototype of a research project:
     code should be :doc:`packed into programme libraries <productive/packaging>`
     with :doc:`documentation <productive/documenting>`, :doc:`licence(s)
     <productive/licensing>`, :doc:`tests <productive/testing>` and
-    :doc:`logging <productive/logging/index>`. Finally, the chapter includes
-    advice on :doc:`improving code quality <productive/qa/index>` and
-    :doc:`secure operation <productive/security>`.
+    :doc:`python-basics:logging/index`. Finally, the chapter includes advice on
+    :doc:`improving code quality <productive/qa/index>` and :doc:`secure
+    operation <productive/security>`.
 #.  :doc:`web/index` can either generate dashboards from Jupyter notebooks or
     require more comprehensive application logic, such as demonstrated in
     :doc:`pyviz:bokeh/embedding-export/flask`, or provide data via a `RESTful
diff --git a/docs/productive/envs/uv/docker.rst b/docs/productive/envs/uv/docker.rst
index 40bfaa263..1f1c38eca 100644
--- a/docs/productive/envs/uv/docker.rst
+++ b/docs/productive/envs/uv/docker.rst
@@ -5,8 +5,8 @@ We divide our Docker workflow into different layers. This allows us to provide
 new builds more quickly. We start with the layers that change the least so that
 we can cache the artefacts for as long as possible. This is also the reason why
 we keep the installations of the dependencies from :file:`uv.lock` and the
-installation of our :doc:`application <python-basics:apps>` strictly separate –
-our code probably changes faster than that of the dependencies.
+installation of our :doc:`application <python-basics:packs/apps>` strictly
+separate – our code probably changes faster than that of the dependencies.
 
 .. seealso::
    * `Order your layers
@@ -195,7 +195,7 @@ our code probably changes faster than that of the dependencies.
 
    Lines 29–30:
        If your application is not a :doc:`Python package
-       <python-basics:libs/distribution>` installed with ``uv sync``, you must
+       <python-basics:packs/distribution>` installed with ``uv sync``, you must
        copy your application into the container here.
 
    Line 32:
diff --git a/docs/productive/envs/uv/index.rst b/docs/productive/envs/uv/index.rst
index 9a79704c9..523c615fa 100644
--- a/docs/productive/envs/uv/index.rst
+++ b/docs/productive/envs/uv/index.rst
@@ -5,7 +5,7 @@
 
 Both the :ref:`installation of uv  <python-basics:uv>` and the creation of file
 structures for :ref:`libraries <python-basics:uv-package-structure>` or
-:doc:`python-basics:apps` are already described in our
+:doc:`python-basics:packs/apps` are already described in our
 :doc:`python-basics:index` tutorial.
 
 .. _inline-script-metadata:
diff --git a/docs/productive/git/advanced/gitlab/ci-cd.rst b/docs/productive/git/advanced/gitlab/ci-cd.rst
index 3f049baeb..94797b3b8 100644
--- a/docs/productive/git/advanced/gitlab/ci-cd.rst
+++ b/docs/productive/git/advanced/gitlab/ci-cd.rst
@@ -67,7 +67,7 @@ Jobs
     .. seealso::
        * `GitLab Docs: Jobs
          <https://docs.gitlab.com/ee/ci/jobs/index.html>`_
-       * :doc:`python-basics:libs/cibuildwheel`
+       * :doc:`python-basics:packs/cibuildwheel`
        * :ref:`pre-commit Hooks <pre-commit-in-gitlab-ci>`
        * :ref:`Licensing <reuse-in-gitlab-ci>`
 
diff --git a/docs/productive/index.rst b/docs/productive/index.rst
index d46cacb46..29ded9b31 100644
--- a/docs/productive/index.rst
+++ b/docs/productive/index.rst
@@ -33,8 +33,8 @@ There are various tools that support you in creating shareable products. These
 can be tools on the one hand for the :doc:`versioning of the source code
 <git/index>` and the :doc:`training data <dvc/index>` as well as for the
 reproducibility of the :doc:`execution environments <envs/index>`, on the other
-hand for :doc:`testing`, :doc:`logging/index`, :doc:`documenting <documenting>`
-and :doc:`creating packages <python-basics:libs/index>`.
+hand for :doc:`testing`, :doc:`python-basics:logging/index`, :doc:`documenting
+<documenting>` and :doc:`creating packages <python-basics:libs/index>`.
 
 .. seealso::
 
@@ -63,6 +63,6 @@ and :doc:`creating packages <python-basics:libs/index>`.
     licensing
     cite/index
     testing
-    logging/index
+    logging
     qa/index
     security
diff --git a/docs/productive/licensing.rst b/docs/productive/licensing.rst
index 459102cae..f48cb7fbf 100644
--- a/docs/productive/licensing.rst
+++ b/docs/productive/licensing.rst
@@ -487,7 +487,7 @@ Python package metadata
 
 With :pep:`658` the :file:`METADATA` file from distributions becomes available
 in the :pep:`503` repository API on :term:`PyPI`. This allows the metadata of
-:doc:`distribution packages <python-basics:libs/distribution>` to be analysed
+:doc:`distribution packages <python-basics:packs/distribution>` to be analysed
 without having to download the whole package.
 
 In Python packages there are other fields where licence information is stored,
diff --git a/docs/productive/logging.rst b/docs/productive/logging.rst
new file mode 100644
index 000000000..36ea2613e
--- /dev/null
+++ b/docs/productive/logging.rst
@@ -0,0 +1,5 @@
+Logging
+=======
+
+You can find an introduction to logging in our
+:doc:`python-basics:logging/index`.
diff --git a/docs/productive/logging/development.ini b/docs/productive/logging/development.ini
deleted file mode 100644
index 0941d3771..000000000
--- a/docs/productive/logging/development.ini
+++ /dev/null
@@ -1,25 +0,0 @@
-; SPDX-FileCopyrightText: 2021 Veit Schiele
-;
-; SPDX-License-Identifier: BSD-3-Clause
-
-[loggers]
-keys=root
-
-[handlers]
-keys=stream_handler
-
-[formatters]
-keys=formatter
-
-[logger_root]
-level=DEBUG
-handlers=stream_handler
-
-[handler_stream_handler]
-class=StreamHandler
-level=DEBUG
-formatter=formatter
-args=(sys.stderr,)
-
-[formatter_formatter]
-format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
diff --git a/docs/productive/logging/examples.ipynb b/docs/productive/logging/examples.ipynb
deleted file mode 100644
index 33648148c..000000000
--- a/docs/productive/logging/examples.ipynb
+++ /dev/null
@@ -1,890 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Logging examples"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Creating a log file"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "WARNING:root:This is a warning message\n",
-      "CRITICAL:root:This is a critical message\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "logging.warning(\"This is a warning message\")\n",
-    "logging.critical(\"This is a critical message\")\n",
-    "logging.debug(\"debug\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Logging levels\n",
-    "\n",
-    "Level | Description\n",
-    ":-- | :--\n",
-    "``CRITICAL`` | The programme was stopped\n",
-    "``ERROR`` | A serious error has occurred\n",
-    "``WARNING`` | An indication that something unexpected has happened (default level)\n",
-    "``INFO`` | Confirmation that things are working as expected\n",
-    "``DEBUG`` | Detailed information that is usually only of interest when diagnosing problems"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Setting the logging level"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "ERROR:root:An error has happened!\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "logging.basicConfig(filename=\"example.log\", filemode=\"w\", level=logging.INFO)\n",
-    "\n",
-    "logging.info(\"Informational message\")\n",
-    "logging.error(\"An error has happened!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Creating a Logger Object"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "ERROR:example:Error!\n",
-      "Traceback (most recent call last):\n",
-      "  File \"/var/folders/hk/s8m0bblj0g10hw885gld52mc0000gn/T/ipykernel_14074/2646645271.py\", line 9, in <module>\n",
-      "    raise RuntimeError\n",
-      "RuntimeError\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "logging.basicConfig(filename=\"example.log\")\n",
-    "logger = logging.getLogger(\"example\")\n",
-    "logger.setLevel(logging.INFO)\n",
-    "\n",
-    "try:\n",
-    "    raise RuntimeError\n",
-    "except Exception:\n",
-    "    logger.exception(\"Error!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Logging exceptions"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "ERROR:example:You can’t do that!\n",
-      "Traceback (most recent call last):\n",
-      "  File \"/var/folders/hk/s8m0bblj0g10hw885gld52mc0000gn/T/ipykernel_14074/760044062.py\", line 2, in <module>\n",
-      "    1 / 0\n",
-      "    ~~^~~\n",
-      "ZeroDivisionError: division by zero\n"
-     ]
-    }
-   ],
-   "source": [
-    "try:\n",
-    "    1 / 0\n",
-    "except ZeroDivisionError:\n",
-    "    logger.exception(\"You can’t do that!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Logging handler\n",
-    "\n",
-    "### Handler types\n",
-    "\n",
-    "Handler | Description\n",
-    ":--- | :---\n",
-    "``StreamHandler`` | ``stdout``, ``stderr`` or file-like objects\n",
-    "``FileHandler`` | for writing to disk\n",
-    "``RotatingFileHandler`` | supports log rotation\n",
-    "``TimedRotatingFileHandler`` | supports the rotation of log files on the hard disk at specific time intervals\n",
-    "``SocketHandler`` | sends logging output to a network socket\n",
-    "``SMTPHandler`` | supports sending logging messages to an e-mail address via SMTP\n",
-    "\n",
-    "<div class=\"alert alert-block alert-info\">\n",
-    "\n",
-    "**See also:**\n",
-    "\n",
-    "Further handlers can be found at [Logging handlers](https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers)\n",
-    "</div>"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### StreamHandler"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "This is an informational message\n",
-      "INFO:stream_logger:This is an informational message\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "logger = logging.getLogger(\"stream_logger\")\n",
-    "logger.setLevel(logging.INFO)\n",
-    "\n",
-    "console = logging.StreamHandler()\n",
-    "\n",
-    "logger.addHandler(console)\n",
-    "logger.info(\"This is an informational message\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### SMTPHandler"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "--- Logging error ---\n",
-      "Traceback (most recent call last):\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/logging/handlers.py\", line 1087, in emit\n",
-      "    smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout)\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/smtplib.py\", line 255, in __init__\n",
-      "    (code, msg) = self.connect(host, port)\n",
-      "                  ~~~~~~~~~~~~^^^^^^^^^^^^\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/smtplib.py\", line 341, in connect\n",
-      "    self.sock = self._get_socket(host, port, self.timeout)\n",
-      "                ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/smtplib.py\", line 312, in _get_socket\n",
-      "    return socket.create_connection((host, port), timeout,\n",
-      "           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^\n",
-      "                                    self.source_address)\n",
-      "                                    ^^^^^^^^^^^^^^^^^^^^\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/socket.py\", line 864, in create_connection\n",
-      "    raise exceptions[0]\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/socket.py\", line 849, in create_connection\n",
-      "    sock.connect(sa)\n",
-      "    ~~~~~~~~~~~~^^^^\n",
-      "ConnectionRefusedError: [Errno 61] Connection refused\n",
-      "Call stack:\n",
-      "  File \"<frozen runpy>\", line 198, in _run_module_as_main\n",
-      "  File \"<frozen runpy>\", line 88, in _run_code\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel_launcher.py\", line 18, in <module>\n",
-      "    app.launch_new_instance()\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/traitlets/config/application.py\", line 1075, in launch_instance\n",
-      "    app.start()\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/kernelapp.py\", line 739, in start\n",
-      "    self.io_loop.start()\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/tornado/platform/asyncio.py\", line 205, in start\n",
-      "    self.asyncio_loop.run_forever()\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/asyncio/base_events.py\", line 679, in run_forever\n",
-      "    self._run_once()\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/asyncio/base_events.py\", line 2027, in _run_once\n",
-      "    handle._run()\n",
-      "  File \"/Users/veit/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/asyncio/events.py\", line 89, in _run\n",
-      "    self._context.run(self._callback, *self._args)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/kernelbase.py\", line 545, in dispatch_queue\n",
-      "    await self.process_one()\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/kernelbase.py\", line 534, in process_one\n",
-      "    await dispatch(*args)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/kernelbase.py\", line 437, in dispatch_shell\n",
-      "    await result\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/ipkernel.py\", line 362, in execute_request\n",
-      "    await super().execute_request(stream, ident, parent)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/kernelbase.py\", line 778, in execute_request\n",
-      "    reply_content = await reply_content\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/ipkernel.py\", line 449, in do_execute\n",
-      "    res = shell.run_cell(\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/ipykernel/zmqshell.py\", line 549, in run_cell\n",
-      "    return super().run_cell(*args, **kwargs)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py\", line 3075, in run_cell\n",
-      "    result = self._run_cell(\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py\", line 3130, in _run_cell\n",
-      "    result = runner(coro)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/async_helpers.py\", line 128, in _pseudo_sync_runner\n",
-      "    coro.send(None)\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py\", line 3334, in run_cell_async\n",
-      "    has_raised = await self.run_ast_nodes(code_ast.body, cell_name,\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py\", line 3517, in run_ast_nodes\n",
-      "    if await self.run_code(code, result, async_=asy):\n",
-      "  File \"/Users/veit/cusy/trn/jupyter-tutorial/uvenvs/py313/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py\", line 3577, in run_code\n",
-      "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
-      "  File \"/var/folders/hk/s8m0bblj0g10hw885gld52mc0000gn/T/ipykernel_14074/3660210047.py\", line 14, in <module>\n",
-      "    logger.info(\"This is an informational message\")\n",
-      "Message: 'This is an informational message'\n",
-      "Arguments: ()\n",
-      "INFO:email_logger:This is an informational message\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "import logging.handlers\n",
-    "\n",
-    "\n",
-    "logger = logging.getLogger(\"email_logger\")\n",
-    "logger.setLevel(logging.INFO)\n",
-    "fh = logging.handlers.SMTPHandler(\n",
-    "    \"localhost\",\n",
-    "    fromaddr=\"python-log@localhost\",\n",
-    "    toaddrs=[\"logs@cusy.io\"],\n",
-    "    subject=\"Python log\",\n",
-    ")\n",
-    "logger.addHandler(fh)\n",
-    "logger.info(\"This is an informational message\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Log formatting\n",
-    "\n",
-    "You can use formatters to format log messages."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "formatter = logging.Formatter(\"%(asctime)s - %(name)s - %(message)s\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Besides ``%(asctime)s``, ``%(name)s`` and ``%(message)s`` you will find other attributes in [LogRecord attributes](https://docs.python.org/3/library/logging.html#logrecord-attributes)."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "This is an informational message\n",
-      "2024-11-03 16:40:42,349 - stream_logger - This is an informational message\n",
-      "INFO:stream_logger:This is an informational message\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "logger = logging.getLogger(\"stream_logger\")\n",
-    "logger.setLevel(logging.INFO)\n",
-    "\n",
-    "console = logging.StreamHandler()\n",
-    "formatter = logging.Formatter(\"%(asctime)s - %(name)s - %(message)s\")\n",
-    "console.setFormatter(formatter)\n",
-    "\n",
-    "logger.addHandler(console)\n",
-    "logger.info(\"This is an informational message\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "<div class=\"alert alert-block alert-info\">\n",
-    "\n",
-    "**Note:**\n",
-    "\n",
-    "The logging module is thread-safe. However, logging may not work in asynchronous contexts. In such cases, however, you can use the [QueueHandler](https://docs.python.org/3/library/logging.handlers.html#queuehandler).\n",
-    "</div>\n",
-    "<div class=\"alert alert-block alert-info\">\n",
-    "\n",
-    "**See also:**\n",
-    "\n",
-    "[Logging to a single file from multiple processes](https://docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes)\n",
-    "</div>"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Logging to multiple handlers"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import logging\n",
-    "\n",
-    "\n",
-    "def log(path, multipleLocs=False):\n",
-    "    logger = logging.getLogger(\"Example_logger_%s\" % fname)\n",
-    "    logger.setLevel(logging.INFO)\n",
-    "    fh = logging.FileHandler(path)\n",
-    "    formatter = logging.Formatter(\"%(asctime)s - %(name)s - %(message)s\")\n",
-    "    fh.setFormatter(formatter)\n",
-    "    logger.addHandler(fh)\n",
-    "\n",
-    "    if multipleLocs:\n",
-    "        console = logging.StreamHandler()\n",
-    "        console.setLevel(logging.INFO)\n",
-    "        console.setFormatter(formatter)\n",
-    "        logger.addHandler(console)\n",
-    "\n",
-    "    logger.info(\"This is an informational message\")\n",
-    "    try:\n",
-    "        1 / 0\n",
-    "    except ZeroDivisionError:\n",
-    "        logger.exception(\"You can’t do that!\")\n",
-    "\n",
-    "    logger.critical(\"This is a no-brainer!\")                                                                                                                     "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Configure logging\n",
-    "\n",
-    "<div class=\"alert alert-block alert-info\">\n",
-    "\n",
-    "**See also:**\n",
-    "\n",
-    "* [logging configuration](https://docs.python.org/3/howto/logging.html#configuring-logging)\n",
-    "</div>"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### … in an INI file\n",
-    "\n",
-    "In the following example, the file `development.ini` is loaded in this directory:\n",
-    "\n",
-    "``` ini\n",
-    "[loggers]\n",
-    "keys=root\n",
-    "\n",
-    "[handlers]\n",
-    "keys=stream_handler\n",
-    "\n",
-    "[formatters]\n",
-    "keys=formatter\n",
-    "\n",
-    "[logger_root]\n",
-    "level=DEBUG\n",
-    "handlers=stream_handler\n",
-    "\n",
-    "[handler_stream_handler]\n",
-    "class=StreamHandler\n",
-    "level=DEBUG\n",
-    "formatter=formatter\n",
-    "args=(sys.stderr,)\n",
-    "\n",
-    "[formatter_formatter]\n",
-    "format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s\n",
-    "```"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import logging\n",
-    "import logging.config\n",
-    "\n",
-    "from logging.config import fileConfig\n",
-    "\n",
-    "\n",
-    "logging.config.fileConfig(\"development.ini\")\n",
-    "logger = logging.getLogger(\"example\")\n",
-    "\n",
-    "logger.info(\"Program started\")\n",
-    "logger.info(\"Done!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "**Pro:**\n",
-    "\n",
-    "* Ability to update the configuration on the fly by using the `logging.config.listen()` function to listen on a socket.\n",
-    "* Different configurations can be used in different environments, so for example, `DEBUG` can be specified as the log level in `development.ini`, while `WARN` is used in `production.ini`.\n",
-    "\n",
-    "**Con:**\n",
-    "\n",
-    "* Less control for example over custom filters or loggers configured in code."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### … in a `dict` config"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 11,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import logging\n",
-    "import logging.config\n",
-    "\n",
-    "\n",
-    "dictLogConfig = {\n",
-    "    \"version\": 1,\n",
-    "    \"handlers\": {\n",
-    "        \"fileHandler\": {\n",
-    "            \"class\": \"logging.FileHandler\",\n",
-    "            \"formatter\": \"exampleFormatter\",\n",
-    "            \"filename\": \"dict_config.log\",\n",
-    "        }\n",
-    "    },\n",
-    "    \"loggers\": {\n",
-    "        \"exampleApp\": {\n",
-    "            \"handlers\": [\"fileHandler\"],\n",
-    "            \"level\": \"INFO\",\n",
-    "        }\n",
-    "    },\n",
-    "    \"formatters\": {\n",
-    "        \"exampleFormatter\": {\n",
-    "            \"format\": \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n",
-    "        }\n",
-    "    },\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "2024-11-03 16:40:42,364 exampleApp   INFO     Program started\n",
-      "2024-11-03 16:40:42,365 exampleApp   INFO     Done!\n"
-     ]
-    }
-   ],
-   "source": [
-    "logging.config.dictConfig(dictLogConfig)\n",
-    "\n",
-    "logger = logging.getLogger(\"exampleApp\")\n",
-    "\n",
-    "logger.info(\"Program started\")\n",
-    "logger.info(\"Done!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "**Pro:**\n",
-    "\n",
-    "* Update on the fly\n",
-    "\n",
-    "**Con:**\n",
-    "\n",
-    "* Less control than configuring a logger in code"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### … directly in the code"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "logger = logging.getLogger()\n",
-    "handler = logging.StreamHandler()\n",
-    "formatter = logging.Formatter(\n",
-    "    \"%(asctime)s %(name)-12s %(levelname)-8s %(message)s\"\n",
-    ")\n",
-    "handler.setFormatter(formatter)\n",
-    "logger.addHandler(handler)\n",
-    "logger.setLevel(logging.DEBUG)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## *Magic Commands*\n",
-    "\n",
-    "| Befehl         | Beschreibung                                                                              |\n",
-    "| -------------- | ----------------------------------------------------------------------------------------- |\n",
-    "| `%logstart`    | Starts logging anywhere in a session                                                      |\n",
-    "|                | `%logstart [-o\\|-r\\|-t\\|-q] [log_name [log_mode]]`                                        |\n",
-    "|                | If no name is given, `ipython_log.py` is used in the current directory.                   |\n",
-    "|                | `log_mode` is an optional parameter. The following modes can be specified:                |\n",
-    "|                | * `append` appends the logging information to the end of an existing file                 |\n",
-    "|                | * `backup` renames the existing file to `name~` and writes to `name`                      |\n",
-    "|                | * `global` appends the logging information at the end of an existing file                 |\n",
-    "|                | * `over` overwrites an existing log file                                                  |\n",
-    "|                | * `rotate` creates rotating log files: `name.1~`, `name.2~`, etc.                         |\n",
-    "|                | Options:                                                                                  |\n",
-    "|                | * `-o` also logs the output of IPython                                                    |\n",
-    "|                | * `-r` logs raw output                                                                    |\n",
-    "|                | * `-t` writes a time stamp in front of each log entry                                     |\n",
-    "|                | * `-q` suppresses the logging output                                                      |\n",
-    "| `%logon`       | Restart the logging                                                                       |\n",
-    "| `%logoff`      | Temporary termination of logging                                                          |\n",
-    "\n",
-    "**Pro:**\n",
-    "\n",
-    "* Complete control over the configuration\n",
-    "\n",
-    "**Con:**\n",
-    "\n",
-    "* Changes in the configuration require a change in the source code"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Logs rotate"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "2024-11-03 16:40:42,370 Rotating Log INFO     This is an example log line 0\n",
-      "2024-11-03 16:40:42,370 Rotating Log INFO     This is an example log line 0\n",
-      "2024-11-03 16:40:43,876 Rotating Log INFO     This is an example log line 1\n",
-      "2024-11-03 16:40:43,876 Rotating Log INFO     This is an example log line 1\n",
-      "2024-11-03 16:40:45,384 Rotating Log INFO     This is an example log line 2\n",
-      "2024-11-03 16:40:45,384 Rotating Log INFO     This is an example log line 2\n",
-      "2024-11-03 16:40:46,893 Rotating Log INFO     This is an example log line 3\n",
-      "2024-11-03 16:40:46,893 Rotating Log INFO     This is an example log line 3\n",
-      "2024-11-03 16:40:48,399 Rotating Log INFO     This is an example log line 4\n",
-      "2024-11-03 16:40:48,399 Rotating Log INFO     This is an example log line 4\n",
-      "2024-11-03 16:40:49,908 Rotating Log INFO     This is an example log line 5\n",
-      "2024-11-03 16:40:49,908 Rotating Log INFO     This is an example log line 5\n",
-      "2024-11-03 16:40:51,414 Rotating Log INFO     This is an example log line 6\n",
-      "2024-11-03 16:40:51,414 Rotating Log INFO     This is an example log line 6\n",
-      "2024-11-03 16:40:52,922 Rotating Log INFO     This is an example log line 7\n",
-      "2024-11-03 16:40:52,922 Rotating Log INFO     This is an example log line 7\n",
-      "2024-11-03 16:40:54,428 Rotating Log INFO     This is an example log line 8\n",
-      "2024-11-03 16:40:54,428 Rotating Log INFO     This is an example log line 8\n",
-      "2024-11-03 16:40:55,938 Rotating Log INFO     This is an example log line 9\n",
-      "2024-11-03 16:40:55,938 Rotating Log INFO     This is an example log line 9\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "import time\n",
-    "\n",
-    "from logging.handlers import RotatingFileHandler\n",
-    "\n",
-    "\n",
-    "def create_rotating_log(path):\n",
-    "    logger = logging.getLogger(\"Rotating Log\")\n",
-    "    logger.setLevel(logging.INFO)\n",
-    "\n",
-    "    handler = RotatingFileHandler(path, maxBytes=20, backupCount=5)\n",
-    "    logger.addHandler(handler)\n",
-    "\n",
-    "    for i in range(10):\n",
-    "        logger.info(f\"This is an example log line {i}\")\n",
-    "        time.sleep(1.5)\n",
-    "\n",
-    "\n",
-    "if __name__ == \"__main__\":\n",
-    "    log_file = \"rotated.log\"\n",
-    "    create_rotating_log(log_file)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Rotate logs time-controlled"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "2024-11-03 16:40:57,454 Rotating Log INFO     This is an example!\n",
-      "2024-11-03 16:40:57,454 Rotating Log INFO     This is an example!\n"
-     ]
-    }
-   ],
-   "source": [
-    "import logging\n",
-    "import time\n",
-    "\n",
-    "from logging.handlers import TimedRotatingFileHandler\n",
-    "\n",
-    "\n",
-    "def create_timed_rotating_log(path):\n",
-    "    \"\"\"\"\"\"\n",
-    "    logger = logging.getLogger(\"Rotating Log\")\n",
-    "    logger.setLevel(logging.INFO)\n",
-    "\n",
-    "    handler = TimedRotatingFileHandler(\n",
-    "        path, when=\"s\", interval=5, backupCount=5\n",
-    "    )\n",
-    "    logger.addHandler(handler)\n",
-    "\n",
-    "    for i in range(6):\n",
-    "        logger.info(\"This is an example!\")\n",
-    "        time.sleep(75)\n",
-    "\n",
-    "\n",
-    "if __name__ == \"__main__\":\n",
-    "    log_file = \"timed_rotation.log\"\n",
-    "    create_timed_rotating_log(log_file)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Create a logging decorator\n",
-    "\n",
-    "<div class=\"alert alert-block alert-info\">\n",
-    "\n",
-    "**See also:**\n",
-    "\n",
-    "* [How to Create an Exception Logging Decorator](https://www.blog.pythonlibrary.org/2016/06/09/python-how-to-create-an-exception-logging-decorator/)\n",
-    "</div>"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Create a logging filter"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import logging\n",
-    "import sys\n",
-    "\n",
-    "\n",
-    "class ExampleFilter(logging.Filter):\n",
-    "    def filter(self, record):\n",
-    "        if record.funcName == \"foo\":\n",
-    "            return False\n",
-    "        return True\n",
-    "\n",
-    "\n",
-    "logger = logging.getLogger(\"filter_example\")\n",
-    "logger.addFilter(ExampleFilter())\n",
-    "\n",
-    "\n",
-    "def foo():\n",
-    "    \"\"\"\n",
-    "    Ignore this function’s log messages\n",
-    "    \"\"\"\n",
-    "    logger.debug(\"Message from function foo\")\n",
-    "\n",
-    "\n",
-    "def bar():\n",
-    "    logger.debug(\"Message from bar\")\n",
-    "\n",
-    "\n",
-    "if __name__ == \"__main__\":\n",
-    "    logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)\n",
-    "    foo()\n",
-    "    bar()"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3.13 Kernel",
-   "language": "python",
-   "name": "python313"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.13.0"
-  },
-  "latex_envs": {
-   "LaTeX_envs_menu_present": true,
-   "autoclose": false,
-   "autocomplete": true,
-   "bibliofile": "biblio.bib",
-   "cite_by": "apalike",
-   "current_citInitial": 1,
-   "eqLabelWithNumbers": true,
-   "eqNumInitial": 1,
-   "hotkeys": {
-    "equation": "Ctrl-E",
-    "itemize": "Ctrl-I"
-   },
-   "labels_anchors": false,
-   "latex_user_defs": false,
-   "report_style_numbering": false,
-   "user_envs_cfg": false
-  },
-  "varInspector": {
-   "cols": {
-    "lenName": 16,
-    "lenType": 16,
-    "lenVar": 40
-   },
-   "kernels_config": {
-    "python": {
-     "delete_cmd_postfix": "",
-     "delete_cmd_prefix": "del ",
-     "library": "var_list.py",
-     "varRefreshCmd": "print(var_dic_list())"
-    },
-    "r": {
-     "delete_cmd_postfix": ") ",
-     "delete_cmd_prefix": "rm(",
-     "library": "var_list.r",
-     "varRefreshCmd": "cat(var_dic_list()) "
-    }
-   },
-   "types_to_exclude": [
-    "module",
-    "function",
-    "builtin_function_or_method",
-    "instance",
-    "_Feature"
-   ],
-   "window_display": false
-  },
-  "widgets": {
-   "application/vnd.jupyter.widget-state+json": {
-    "state": {},
-    "version_major": 2,
-    "version_minor": 0
-   }
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/docs/productive/logging/examples.ipynb.license b/docs/productive/logging/examples.ipynb.license
deleted file mode 100644
index cc22f3a34..000000000
--- a/docs/productive/logging/examples.ipynb.license
+++ /dev/null
@@ -1,3 +0,0 @@
-SPDX-FileCopyrightText: 2021 Veit Schiele
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/productive/logging/index.rst b/docs/productive/logging/index.rst
deleted file mode 100644
index 2bfe5bbbd..000000000
--- a/docs/productive/logging/index.rst
+++ /dev/null
@@ -1,52 +0,0 @@
-.. SPDX-FileCopyrightText: 2021 Veit Schiele
-..
-.. SPDX-License-Identifier: BSD-3-Clause
-
-Logging
-=======
-
-The `logging <https://docs.python.org/3/library/logging.html#module-logging>`_
-module is part of the Python standard library. It is described in :pep:`0282`.r
-You can get a first introduction to the module in the `Basic Logging Tutorial
-<https://docs.python.org/3/howto/logging.html#logging-basic-tutorial>`_.
-
-Logging usually serves two different purposes:
-
-* Diagnosis:
-
-  * You can display the context of certain events.
-  * Tools like `Sentry <https://sentry.io/welcome/>`_ group related events and
-    facilitate user identification, etc., so that developers can find the cause
-    of the error more quickly.
-
-* Monitoring:
-
-  * The logging records events for user-defined heuristics, for example for
-    business analyses. These records can be used for reports or optimisation of
-    the business goals and, if necessary, visualised.
-
-What are the advantages of  ``logging`` over  ``print``?
-
-* The log file contains all available diagnostic information such as file name,
-  path, function and line number.
-* All events are automatically available via the root logger unless they are
-  explicitly filtered out.
-* Logging can be muted using either of the following two methods:
-  `logging.Logger.setLevel()
-  <https://docs.python.org/3/library/logging.html#logging.Logger.setLevel>`_ or
-  `logging.disabled
-  <https://docs.python.org/3/library/logging.html#logging.disable>`_.
-
-.. seealso::
-
-   * `loguru <https://github.com/Delgan/loguru>`_, which makes logging almost as
-     easy as using print instructions.
-   * `structlog <https://www.structlog.org/en/stable/>`_ adds structure to your
-     log entries.
-
-.. toctree::
-    :hidden:
-    :titlesonly:
-    :maxdepth: 0
-
-    examples.ipynb