Skip to content

Custom formatter fails if message contains JSON string #1323

Open
@malcolmdimeglio

Description

@malcolmdimeglio

JSON string parsing error

Problem

When creating a custom logger and providing the new logger with a custom formatter function, Loguru throws a KeyError if the string it's trying to format contains a JSON formatted string.

Environment

Python 3.13.2
loguru==0.7.3

How to reproduce

#! /usr/bin/env python3

import sys
from loguru import logger


def console_format(record: dict) -> str:
    level = record["level"].name.lower()
    timestamp = record["time"].strftime("%Y-%m-%d %H:%M:%S.%f %:z")

    message = record["message"]

    log_message = f"[{timestamp}] [{level}] {message}\n"

    return log_message


if __name__ == "__main__":
    logger.remove()

    logger.add(sys.stderr,
               format=console_format,
               level="DEBUG",
               colorize=False,
               catch=False)

    logger.info("This is an info message")

    # 1. Try with variable substituations
    name = "Alice"
    age = 30
    logger.info(f"Hello {name}, you are {age} years old")

    # 2. Try with json string as variable
    json_str = '{"name": "Bob", "age": 25}'
    logger.info(f"Hello {json_str} world!")

    # 3. Try with dumped json object
    json_obj = {"name": "Bob", "age": 25}
    logger.info(f"Hello {json.dumps(json_obj)} world!")

Error Trace

[2025-03-17 07:19:46.976159 -07:00] [info] This is an info message
[2025-03-17 07:19:46.976263 -07:00] [info] Hello Alice, you are 30 years old
Traceback (most recent call last):
File "./test.py", line 39, in
logger.info(f"Hello {json_str} world!")
File ".venv/lib/python3.13/site-packages/loguru/_logger.py", line 2078, in info
__self._log("INFO", False, __self._options, __message, args, kwargs)
File ".venv/lib/python3.13/site-packages/loguru/_logger.py", line 2066, in _log
handler.emit(log_record, level_id, from_decorator, raw, colored_message)
File ".venv/lib/python3.13/site-packages/loguru/_handler.py", line 161, in emit
formatted = precomputed_format.format_map(formatter_record)
KeyError: '"name"'

Workaround

The only workaround I found to make this work is by changing the following:

# message = record["message"]
message = record["message"].replace("{", "{{").replace("}", "}}")

Output after the workaround

[2025-03-17 08:10:04.773069 -07:00] [info] This is an info message
[2025-03-17 08:10:04.773193 -07:00] [info] Hello Alice, you are 30 years old
[2025-03-17 08:10:04.773231 -07:00] [info] Hello {"name": "Bob", "age": 25} world!
[2025-03-17 08:10:04.773267 -07:00] [info] Hello {"name": "John", "age": 99} world!

Observation

  • This behaviour/limitation is not documented anywhere (AFAIK).
  • The workaround is messy

Maybe it could be a good idea to:

  1. Document this limitation
  2. Update loguru for a more intuitive use where one can simply log a message with an f-string without worrying of what's happening under the hood of the logger. (ideally keeping message = record["message"] even if there is a json string in there

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions