refactor(logging): use lazy %-style formatting in log calls - #1846
Merged
hassiebp merged 2 commits intoAug 28, 2026
Conversation
11 tasks
DavidTraina
force-pushed
the
refactor/lazy-percent-style-logging
branch
2 times, most recently
from
August 28, 2026 01:18
730f32a to
3787e9e
Compare
DavidTraina
force-pushed
the
refactor/lazy-percent-style-logging
branch
from
August 28, 2026 01:31
3787e9e to
6bc62d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Converts all 124 f-string logging calls in
langfuse/to lazy%-style args, and enables ruffG004so they stay that way.f-strings are built before
logger.debug(...)is called, so the message is assembled whether or not the level is enabled. Thelangfuselogger defaults toWARNING, sodebug/infocalls on tracing hot paths were building strings nobody reads.Measured per call, logger at the default
WARNING:CallbackHandler.on_llm_new_tokenCallbackHandler._log_debug_event(15 call sites)span_processor.on_startpropagated attributespropagate_attributes()resource_manager.add_score_task/add_trace_taskFor
warning/errorcalls the effect depends on the configured level, since laziness only pays off when a call is suppressed: 1.85 us -> 2.07 us when the record is emitted (the default), and 0.088 us -> 0.049 us when the SDK is quieted toERRORor above. They are converted anyway so the codebase has one style andG004can be enabled with no exceptions.Also adds
G004pluslogger-objectstopyproject.toml, and documents the rule inAGENTS.mdandcode_review.mdas the maintenance contract inAGENTS.mdrequires.ruff check .is clean repo-wide;tests/andscripts/had no violations to begin with.Overlap with #1845
Both PRs touch the
span_formatterdebug call inon_end. This PR only makes it lazy, which does not remove the cost, because the argument is still evaluated eagerly. #1845 adds theisEnabledForguard that does remove it. Whichever merges second needs a trivial rebase on that one call.I also swept for other expensive arguments hidden behind a disabled level and found none. After this PR, seven
debug/infocalls inlangfuse/still pass a function call as an argument:span_formatter(the one #1845 guards, 28-167 us),_get_scope_namex3 (two attribute lookups),os.getpid()x2 on the fork path, and onedict.get(). Everything exceptspan_formatteris well under a microsecond, and no value built withjson.dumps/serialize/to_json/model_dumphas a log call as its only consumer, so no furtherisEnabledForguards are warranted.Type of change
Verification
The conversion was generated from the AST rather than by hand, and checked three ways:
(format, args)pair back into canonical f-string form and compared againstmain: 124/124 identical, 0 mismatches.%.langfuselogger atDEBUGand a handler that fails on formatting errors, whichloggingnormally swallows viahandleError: 683 passed, 0 formatting errors.Edge cases covered: literal
%escaped to%%,{v:.1f}/{v:.2f}to%.1f/%.2f,f"{name=}"toname=%r, embedded newlines, mixed quoting, implicit concatenation. Original message line-splitting is preserved. The three# type: ignorecomments inpropagation.pyare kept.ruff format --check .flagstests/unit/test_media.py, but that drift pre-exists onmainand is untouched here. CI's lint job runsruff check ., which passes. e2e / live_provider were not run: no network, serialization, or control-flow behavior changes.Checklist
code_review.md.mainat all 124 sites.env.templateif needed.