ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 47

  1. Blog

logging.Formatter vs f-string: Localhost Lab

Aditya Challa·1 October 2026·4 min read

Summary
On this page
  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 msgs/s)
  5. Sample output
  6. Why keep Formatter anyway
  7. Reading it for SRE work
  8. asctime is the silent tax
  9. Pitfalls
  10. Reproduce
  11. Limits
  12. Takeaway

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

ArmPattern
Formatter with asctimefull style line
Formatter plainlevel/name/message
f-string + strftimemanual peer with clock
%-format + strftimeclassic manual peer
f-string no asctimeskip clock
getMessage() onlybaseline message merge

Seven rounds, p50. Records carry extra host / lat attributes like structured logging extras.


Lab topology

n=50000 LogRecords · 7 rounds · p50
metric: msgs/s = n / p50_s
no StreamHandler / no disk write

Script: lab-evidence/125-logging-formatter-vs-fstring/results/run_lab.py.


Lead table (p50 msgs/s)

Armmsgs/s
Formatter + asctime403971
Formatter plain1149467
f-string + strftime823931
%-format + strftime814939
f-string no asctime1599896
getMessage only3529817

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 were Formatter.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

python3 lab-evidence/125-logging-formatter-vs-fstring/results/run_lab.py

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.

logging.formatterf-stringlogrecordpython logginglocalhost labsremsgs/s

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/.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

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

On this page

  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 msgs/s)
  5. Sample output
  6. Why keep Formatter anyway
  7. Reading it for SRE work
  8. asctime is the silent tax
  9. Pitfalls
  10. Reproduce
  11. Limits
  12. Takeaway
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove