fix: startup-time numbers printed as literal SLF4J specifiers (1.1.1) - #44
Merged
Conversation
Three log templates used {:+d} / {:.1f}. SLF4J only interpolates {}, so the
specifier was printed literally and every following argument shifted by one:
⏱ Startup Time: 6687ms -> ms ({:+d}ms, {:.1f}% 7178)
The worst one was the startup-time gate's log.error, which is exactly the line
a CI reader lands on. Numbers are now pre-formatted through signed()/oneDecimal()
and passed as plain {} arguments:
⏱ Startup Time: 6687ms -> 7418ms (+731ms, 10.9% slower)
Also routes the percent change written into wiredoctor-gate.status through
oneDecimal(), which pins Locale.ROOT — that file is machine-read, so the
decimal separator must not follow the build machine's default locale.
Docs, found while reproducing on spring-petclinic:
- ci-gating.md prescribed recording the baseline with `spring-boot:run` while
gating on `java -jar`. devtools is on the classpath for one and excluded from
the repackaged jar for the other, which on petclinic is 12 removed beans and a
31% startup delta — a startup-time failure on a build where nobody changed a
line. Step 1 now records from the jar, with a callout on keeping profiles and
web-application-type identical across both runs.
- ci-gating.md now warns that gating through `spring-boot:run` cannot fail a
build: devtools runs main on its own restart thread, so the gate trips,
BUILD SUCCESS prints, and the job exits 0. Falls back to grepping
wiredoctor-gate.status for anyone stuck on a Maven goal.
- configuration.md documents output-path for projects whose build lints the
source tree (nohttp rejects the vendored http:// license headers in the
report), and that scan-packages also keeps WireDoctor's own beans out of the
smell rankings.
- _config.yml declares the warning callout the docs reference; Just the Docs
renders it unstyled otherwise.
Adds WireDoctorLogFormattingTest, including a guard that greps every log
template in the module for a non-{} specifier so the whole defect class stays
fixed.
Filed under [Unreleased] — the fix sits on main and the docs corrections go live via Pages, but there is no reason to cut a patch release to Central for console formatting alone. It rides along in the next release that has its own reason to exist.
Parent version bumped in all three child poms, not just the root — a partial bump is what broke CI on the v0.7.0 release. Install snippets in README.md, docs/index.md and docs/why-wiredoctor.md stay on 1.1.0 deliberately: 1.1.1 is a source tag, and the docs must only ever point at a coordinate that actually resolves from Maven Central.
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.
Correctness pass found by running the published
1.1.0artifact unmodifiedagainst spring-petclinic (Spring Boot 4.1.0, Framework 7.0.8, Java 25.0.2,
470 beans). No API, schema, or configuration changes.
The bug
Three log templates used
{:+d}/{:.1f}. SLF4J interpolates only{}, sothe specifier was printed verbatim and every following argument shifted by one
slot:
It hit the diff summary, its no-regression variant, and the
startup-timegate's
log.error— the last being the line a CI reader lands on first. Numbersare now pre-formatted through
signed(long)/oneDecimal(double)and passed asplain
{}arguments. TheWireDoctorRegressionExceptionmessage was alreadycorrect and is unchanged.
Also:
startupTimePercentChangeinwiredoctor-gate.statuswas written with adefault-locale
String.format("%.1f", …), so a comma-decimal build machineemitted
4,3into a file that is meant to be machine-read. It now goes throughoneDecimal(…), which pinsLocale.ROOT.The docs bug, which is the more damaging one
ci-gating.mdtold you to record the baseline with./mvnw spring-boot:runwhile Step 3 gates on
java -jar. devtools is on the classpath for the formerand excluded from the repackaged jar for the latter — on spring-petclinic that
single difference is 12 removed beans and a 31% startup-time delta, enough to
trip the
startup-timegate on a build where nobody changed a line of code. Thequickstart prescribed the exact mismatch that produces a false failure.
Step 1 now records from the jar, with a callout on keeping profiles and
spring.main.web-application-typeidentical across both runs. Step 3 gains awarning that a Maven-goal gate cannot fail a build at all: with devtools
present,
spring-boot:runrunsmainon its own restart thread, so the gatetrips,
BUILD SUCCESSprints, and the job exits0.configuration.mddocumentsoutput-pathfor projects whose build lints thesource tree (
nohttprejects thehttp://license headers vendored in theself-contained report, failing the next build), and that
scan-packagesalsokeeps WireDoctor's own beans out of the smell rankings.
_config.ymldeclaresthe
warningcallout the docs reference.Verification
End-to-end against the petclinic jar with a locally built WireDoctor — both the
summary line and the armed gate:
Gate run exits
1;wiredoctor-gate.statuscarriesstartupTimePercentChange=4.3.257 tests green — 246 autoconfigure + 11 actuator, +4 new. Among them a guard
that scans every
log.*template in the module for a non-{}specifier, so thewhole defect class stays closed. Verified it actually fails by re-injecting
{:+d}before restoring.Note on publishing
1.1.1is a source tag only — nothing is published to Maven Central by thisPR, so install snippets in
README.md,docs/index.mdanddocs/why-wiredoctor.mddeliberately stay on1.1.0. The valuable half of thischange is the docs, and that ships via GitHub Pages the moment this merges.