Plate 47
logging.Formatter vs f-string: Localhost Lab
Aditya Challa4 min read
Intro — what this post promises
Format log lines with logging.Formatter vs f-string / %-format assembly — format-only, no handler I/O. This lab reports msgs/s on Linux localhost.
Related links:
- xml etree vs json localhost lab
- math fsum vs sum localhost lab
- fractions vs float localhost lab
- chainmap vs dict merge localhost lab
- ipaddress vs string prefix localhost lab
- statistics quantiles vs manual localhost lab
- random choices vs sample localhost lab
- itertools batched vs chunk localhost lab
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. Differentiates from logging-vs-print (lab 51) — that post compared I/O; this one isolates Formatter.format vs manual string build on prebuilt LogRecords.
Verdict up front (n=50000): Formatter+asctime ~403971 msgs/s; f-string+strftime ~823931; Formatter plain ~1149467; f-string no asctime ~1599896.
Arms
| Arm | Pattern |
|---|---|
Formatter with asctime | full style line |
Formatter plain | level/name/message |
f-string + strftime | manual peer with clock |
%-format + strftime | classic manual peer |
| f-string no asctime | skip clock |
getMessage() only | baseline message merge |
Seven rounds, p50. Records carry extra host / lat attributes like structured logging extras.
Lab topology
Script: lab-evidence/125-logging-formatter-vs-fstring/results/run_lab.py.
Lead table (p50 msgs/s)
| Arm | msgs/s |
|---|---|
| Formatter + asctime | 403971 |
| Formatter plain | 1149467 |
| f-string + strftime | 823931 |
| %-format + strftime | 814939 |
| f-string no asctime | 1599896 |
| getMessage only | 3529817 |
With a clock in the line, manual f-string (~823931) beat full Formatter (~403971). Drop asctime and f-string climbs further (~1599896).
Sample output
Formatter prefix (truncated): '2026-10-01 01:01:09,073 INFO [svc.api] request done id=0 host=n0 lat=0.000'. Manual peer without clock: 'INFO [svc.api] request done id=0 host=n0 lat=0.000'.
Why keep Formatter anyway
Handlers, filters, LogRecord factories, and library code expect Formatter. Hot paths that already hold fields can assemble an f-string for a metrics side channel — but do not fork two divergent layouts without a fixture. Lab 51 still owns the “print vs logging I/O” question.
Reading it for SRE work
- Standard app logging → Formatter (consistency > peak msgs/s).
- Ultra-hot debug string you control → f-string; measure with your fields.
- asctime dominates cost — omit it or use a cheaper clock policy if volume hurts.
- Never compare Formatter+handler I/O to bare f-string and call it a Formatter tax.
Keep one canonical layout in production so log shippers and alerts stay aligned.
asctime is the silent tax
The plain Formatter (no clock) reached ~1149467 msgs/s, while the asctime variant dropped to ~403971. Manual f-string without a stamp hit ~1599896. If your shipper already stamps at ingest, dropping %(asctime)s from the process Formatter is often the cheapest win — measure before and after on the same box.
This lab intentionally skips handler I/O so the Formatter vs f-string comparison is not drowned by write(2). Pair with lab 51 when you need print-vs-logging throughput under a real StreamHandler.
Pitfalls
- Benchmarking
logger.info(...)(includes level checks + handlers) as if it wereFormatter.format. - Forgetting
getMessage()lazy%args when comparing to f-strings that already interpolated. - Divergent layouts between Formatter and manual strings breaking log parsers.
- Assuming %-format and f-string stay equal after adding timezone-aware stamps.
Reproduce
Evidence: summary.json, summary.txt.
Limits
One Linux box. Format-only; no QueueHandler, no JSON formatter libs.
Takeaway
Format-only at 50000 msgs: full Formatter+asctime ~403971 msgs/s vs f-string+strftime ~823931. Prefer Formatter for real logging pipelines; use f-string when you deliberately own a hot, I/O-free format path.
Lab evidence
What I found running this
Lab 1 Oct 2026 IST. Python 3.13.5. n=50000: Formatter+asctime 403971 msgs/s; fstring+strftime 823931; fstring no asctime 1599896. Format-only (not lab 51 I/O). Affiliates: 0. Evidence: lab-evidence/125-logging-formatter-vs-fstring/.
Related links
Plate 66
logging vs print: Throughput Lab
Hands-on logging vs print throughput lab: real lines/s for StreamHandler, StringIO, and a disabled logger, measured on Linux localhost only (eng lab).
30 Sept 2026
Plate 17
platform vs os.uname Inventory: Localhost Lab
Hands-on platform.platform vs os.uname host inventory lab: real ops/s plus cache notes, measured on Linux localhost today in this hands-on lab for SREs.
1 Oct 2026
Plate 75
uuid.uuid4 vs uuid.uuid1: Localhost Lab
Hands-on uuid.uuid4 vs uuid.uuid1 ID generation lab: real ops/s plus version/node checks, measured on Linux localhost today in this hands-on lab for SREs.
1 Oct 2026