Skip to content

fix(logging): preserve log messages with the literal string "None"#17340

Open
o6ivp wants to merge 1 commit into
googleapis:mainfrom
o6ivp:fix-logging-literal-none-dropped
Open

fix(logging): preserve log messages with the literal string "None"#17340
o6ivp wants to merge 1 commit into
googleapis:mainfrom
o6ivp:fix-logging-literal-none-dropped

Conversation

@o6ivp
Copy link
Copy Markdown

@o6ivp o6ivp commented Jun 2, 2026

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)

Fixes #17339 🦕

What

_format_and_parse_message (in handlers/handlers.py) treated any record whose formatted output equaled the string "None" as empty content, returning None (or omitting the message field when json_fields were present).

This also dropped a legitimate user message consisting of the literal string "None":

logging.getLogger().info("None")   # payload silently became empty / None

Why

The empty-content branch is intended to cover a record whose msg is the Python object None, which logging.Formatter renders as the string "None". Comparing the formatted string against "None" cannot distinguish that case from a user who logged the literal text "None", so real content was lost.

How

Detect the empty case from record.msg is None (before formatting) and the formatted output being "None", instead of from the formatted output alone. This preserves the existing behavior for msg=None (with and without a custom formatter) while keeping a genuine "None" string.

Behavior matrix:

record.msg formatter before after
None none None None (unchanged)
None custom ("name: %(name)s") "name: logname" "name: logname" (unchanged)
"None" (str) none None ❌ dropped "None" ✅ preserved

Tests

Added two unit tests (test_literal_none_string_preserved, test_literal_none_string_preserved_with_json_fields). All tests/unit/handlers/ tests pass (177 passed) and ruff format --check is clean.

`_format_and_parse_message` treated any record whose formatted output
equaled the string "None" as empty, returning `None` (or omitting the
`message` field when `json_fields` were present). This also dropped a
legitimate user message of the literal string "None"
(e.g. `logging.getLogger().info("None")`).

The empty-content case is meant to cover a record whose `msg` is the
Python object `None`, which `logging.Formatter` renders as "None".
Detect that from `record.msg is None` directly so the literal string
"None" is preserved.

Fixes googleapis#17339

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@o6ivp o6ivp requested a review from a team as a code owner June 2, 2026 11:18
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jun 2, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request fixes an issue where a literal string message of "None" was incorrectly treated as an empty message and dropped. It introduces a check to ensure that only records where the original message (record.msg) is actually the Python None object are treated as empty, while preserving the literal string "None". Unit tests have been added to verify this behavior. There are no review comments to address, and the changes look solid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logging the literal string "None" is silently dropped (payload becomes empty)

1 participant