diff --git a/logbook/compat.py b/logbook/compat.py
index c3896db..b65ac00 100644
--- a/logbook/compat.py
+++ b/logbook/compat.py
@@ -9,12 +9,13 @@
     :copyright: (c) 2010 by Armin Ronacher, Georg Brandl.
     :license: BSD, see LICENSE for more details.
 """
-import sys
+import collections
 import logging
+import sys
 import warnings
-import logbook
 from datetime import date, datetime
 
+import logbook
 from logbook.helpers import u, string_types, iteritems
 
 _epoch_ord = date(1970, 1, 1).toordinal()
@@ -63,8 +64,12 @@ class redirected_logging(object):
 class LoggingCompatRecord(logbook.LogRecord):
 
     def _format_message(self, msg, *args, **kwargs):
-        assert not kwargs
-        return msg % tuple(args)
+        if kwargs:
+            assert not args
+            return msg % kwargs
+        else:
+            assert not kwargs
+            return msg % tuple(args)
 
 
 class RedirectLoggingHandler(logging.Handler):
@@ -124,10 +129,17 @@ class RedirectLoggingHandler(logging.Handler):
 
     def convert_record(self, old_record):
         """Converts an old logging record into a logbook log record."""
+        args = old_record.args
+        kwargs = None
+
+        # Logging allows passing a mapping object, in which case args will be a mapping.
+        if isinstance(args, collections.Mapping):
+            kwargs = args
+            args = None
         record = LoggingCompatRecord(old_record.name,
                                      self.convert_level(old_record.levelno),
-                                     old_record.msg, old_record.args,
-                                     None, old_record.exc_info,
+                                     old_record.msg, args,
+                                     kwargs, old_record.exc_info,
                                      self.find_extra(old_record),
                                      self.find_caller(old_record))
         record.time = self.convert_time(old_record.created)

Exception in LoggingCompatRecord for mapping keys
Example:
```
logger = logging.getLogger("test")
logger.setLevel("DEBUG")
logger.addHandler(RedirectLoggingHandler())

with logbook.StderrHandler():
    logger.debug("test map %(name)s", {"name": "mapname"})     
    # raise exception in LoggingCompatRecord:
   #Traceback (most recent call last):
    #   File "D:\bin\Python34\lib\site-packages\logbook\base.py", line 515, in message
    #    return self._format_message(self.msg, *self.args, **self.kwargs)
    #  File "D:\bin\Python34\lib\site-packages\logbook\compat.py", line 66, in _format_message
    #    return msg % tuple(args)
    # TypeError: format requires a mapping
```

The quote from "logging/\_\_init\_\_.py"
>
        #
        # The following statement allows passing of a dictionary as a sole
        # argument, so that you can do something like
        #  logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2})
        # Suggested by Stefan Behnel.
        # Note that without the test for args[0], we get a problem because
        # during formatting, we test to see if the arg is present using
        # 'if self.args:'. If the event being logged is e.g. 'Value is %d'
        # and if the passed arg fails 'if self.args:' then no formatting
        # is done. For example, logger.warning('Value is %d', 0) would log
        # 'Value is %d' instead of 'Value is 0'.
        # For the use case of passing a dictionary, this should not be a
        # problem.
        # Issue #21172: a request was made to relax the isinstance check
        # to hasattr(args[0], '__getitem__'). However, the docs on string
        # formatting still seem to suggest a mapping object is required.
        # Thus, while not removing the isinstance check, it does now look
        # for collections.Mapping rather than, as before, dict.
        if (args and len(args) == 1 and isinstance(args[0], collections.Mapping)
            and args[0]):
            args = args[0]

diff --git a/tests/test_logging_compat.py b/tests/test_logging_compat.py
index 48dfebe..31fdd40 100644
--- a/tests/test_logging_compat.py
+++ b/tests/test_logging_compat.py
@@ -36,8 +36,11 @@ def test_basic_compat(request, set_root_logger_level):
                 logger.warn('This is from the old %s', 'system')
                 logger.error('This is from the old system')
                 logger.critical('This is from the old system')
+                logger.error('This is a %(what)s %(where)s', {'what': 'mapping', 'where': 'test'})
         assert ('WARNING: %s: This is from the old system' %
                 name) in captured.getvalue()
+        assert ('ERROR: %s: This is a mapping test' %
+                name) in captured.getvalue()
     if set_root_logger_level:
         assert handler.records[0].level == logbook.DEBUG
     else:

pip install -e .[all]
parse_log_pytest
pytest
pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
async-timeout==5.0.1
Cython==3.0.12
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
execnet==2.1.1
greenlet==3.1.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Jinja2==3.1.6
-e git+https://github.com/getlogbook/logbook.git@f4d4d9309d0a0ce097cfa52f0f3dad6280d7f2e3#egg=Logbook
MarkupSafe==3.0.2
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
pytest @ file:///croot/pytest_1738938843180/work
pyzmq==26.3.0
redis==5.2.1
SQLAlchemy==2.0.40
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions==4.13.0

name: logbook
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
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - 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=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - async-timeout==5.0.1
      - cython==3.0.12
      - execnet==2.1.1
      - greenlet==3.1.1
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - pyzmq==26.3.0
      - redis==5.2.1
      - sqlalchemy==2.0.40
      - typing-extensions==4.13.0
prefix: /opt/conda/envs/logbook

tests/test_logging_compat.py::test_basic_compat[True] tests/test_logging_compat.py::test_basic_compat[False]
tests/test_logging_compat.py::test_redirect_logbook tests/test_logging_compat.py::test_warning_redirections
logbook/compat.py
logbook/compat.py