Repository: sphinx-doc/sphinx

Issue:
Show warnings with their "type" and "subtype"?
Similar to #8813, just for warnings instead of exceptions:

Currently, warning messages are shown like this:

```
WARNING: Some warning message
```

If a warning can be disabled, I think it would be helpful to display the warning `type` and `subtype`, maybe like:

```
WARNING (some_type.some_subtype): Some warning message
```

Discussion:
picnixz: I remember there is a related issue or at least a comment about it  Had seen it yesterday so I'll try to find it again.

Patch:
diff --git a/.flake8 b/.flake8
index e01c0e5c8..66f401aee 100644
--- a/.flake8
+++ b/.flake8
@@ -22,6 +22,7 @@ exclude =
     .git,
     .tox,
     .venv,
+    node_modules/*,
     tests/roots/*,
     build/*,
     doc/_build/*,
diff --git a/CHANGES.rst b/CHANGES.rst
index 8ffe9365d..047336578 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -22,6 +22,9 @@ Deprecated
 Features added
 --------------
 
+* #12131: Added :confval:`show_warning_types` configuration option.
+  Patch by Chris Sewell.
+
 * #11701: HTML Search: Adopt the new `<search>`_ element.
   Patch by Bénédikt Tran.
 
diff --git a/Makefile b/Makefile
index 8cfc9fae3..93951925f 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ clean: clean
 
 .PHONY: style-check
 style-check:
+	@flake8 .
 	@ruff check .
 
 .PHONY: type-check
diff --git a/doc/conf.py b/doc/conf.py
index 37f86232d..2816935e6 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -23,6 +23,7 @@
 release = version
 show_authors = True
 nitpicky = True
+show_warning_types = True
 
 html_theme = 'sphinx13'
 html_theme_path = ['_themes']
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index c7b30d054..b5a2b8493 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -326,11 +326,19 @@ General configuration
 
    .. versionadded:: 0.5
 
+.. confval:: show_warning_types
+
+   If ``True``, the type of each warning is added as a suffix to the warning message,
+   e.g., ``WARNING: [...] [index]`` or ``WARNING: [...] [toc.circular]``.
+   The default is ``False``.
+
+   .. versionadded:: 7.3.0
+
 .. confval:: suppress_warnings
 
    A list of warning types to suppress arbitrary warning messages.
 
-   Sphinx supports following warning types:
+   Sphinx core supports following warning types:
 
    * ``app.add_node``
    * ``app.add_directive``
@@ -359,11 +367,11 @@ General configuration
    * ``toc.not_readable``
    * ``toc.secnum``
 
+   Then extensions can also define their own warning types.
+
    You can choose from these types.  You can also give only the first
    component to exclude all warnings attached to it.
 
-   Now, this option should be considered *experimental*.
-
    .. versionadded:: 1.4
 
    .. versionchanged:: 1.5
diff --git a/sphinx/config.py b/sphinx/config.py
index e90c7ebfc..dc8c1c11d 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -227,6 +227,7 @@ class Config:
         'template_bridge': _Opt(None, 'html', frozenset((str,))),
         'keep_warnings': _Opt(False, 'env', ()),
         'suppress_warnings': _Opt([], 'env', ()),
+        'show_warning_types': _Opt(False, 'env', frozenset((bool,))),
         'modindex_common_prefix': _Opt([], 'html', ()),
         'rst_epilog': _Opt(None, 'env', frozenset((str,))),
         'rst_prolog': _Opt(None, 'env', frozenset((str,))),
diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py
index baff07325..a74369862 100644
--- a/sphinx/util/logging.py
+++ b/sphinx/util/logging.py
@@ -480,6 +480,7 @@ class SphinxLogRecordTranslator(logging.Filter):
 
     * Make a instance of SphinxLogRecord
     * docname to path if location given
+    * append warning type/subtype to message if :confval:`show_warning_types` is ``True``
     """
 
     LogRecordClass: type[logging.LogRecord]
@@ -522,6 +523,23 @@ class WarningLogRecordTranslator(SphinxLogRecordTranslator):
 
     LogRecordClass = SphinxWarningLogRecord
 
+    def filter(self, record: SphinxWarningLogRecord) -> bool:  # type: ignore[override]
+        ret = super().filter(record)
+
+        try:
+            show_warning_types = self.app.config.show_warning_types
+        except AttributeError:
+            # config is not initialized yet (ex. in conf.py)
+            show_warning_types = False
+        if show_warning_types:
+            if log_type := getattr(record, 'type', ''):
+                if log_subtype := getattr(record, 'subtype', ''):
+                    record.msg += f' [{log_type}.{log_subtype}]'
+                else:
+                    record.msg += f' [{log_type}]'
+
+        return ret
+
 
 def get_node_location(node: Node) -> str | None:
     source, line = get_source_line(node)


Test patch:
diff --git a/tests/test_util/test_util_logging.py b/tests/test_util/test_util_logging.py
index 4d506a8a8..8c6218803 100644
--- a/tests/test_util/test_util_logging.py
+++ b/tests/test_util/test_util_logging.py
@@ -10,7 +10,7 @@
 from sphinx.errors import SphinxWarning
 from sphinx.testing.util import strip_escseq
 from sphinx.util import logging, osutil
-from sphinx.util.console import colorize
+from sphinx.util.console import colorize, strip_colors
 from sphinx.util.logging import is_suppressed_warning, prefixed_warnings
 from sphinx.util.parallel import ParallelTasks
 
@@ -396,3 +396,20 @@ def test_get_node_location_abspath():
     location = logging.get_node_location(n)
 
     assert location == absolute_filename + ':'
+
+
+@pytest.mark.sphinx(confoverrides={'show_warning_types': True})
+def test_show_warning_types(app, status, warning):
+    logging.setup(app, status, warning)
+    logger = logging.getLogger(__name__)
+    logger.warning('message2')
+    logger.warning('message3', type='test')
+    logger.warning('message4', type='test', subtype='logging')
+
+    warnings = strip_colors(warning.getvalue()).splitlines()
+
+    assert warnings == [
+        'WARNING: message2',
+        'WARNING: message3 [test]',
+        'WARNING: message4 [test.logging]',
+    ]