woocommerce Case study
A2 Perf Logger
You cannot fix a performance problem you can only reproduce in production. Xdebug and Query Monitor are not options on a live store under real traffic, so I wrote a logger that runs there permanently and costs almost nothing on a fast request.
The business problem
Cart, search and add-to-cart requests were intermittently slow, and intermittently is the hard part. Staging could not reproduce it because the trigger was real traffic against a real catalog. Any profiler that captures every request would itself become the performance problem, so the logger had to be cheap on the requests that are fine and detailed only on the ones that are not.
What I delivered
- a2-perf-logger.php, a 458-line MU plugin at version 1.2.0 that writes to a rotating log file with a 5MB rotation limit.
- A tiered capture policy: anything past 800ms is logged, anything past 2.5s triggers deep capture, and everything else is sampled at 5%.
- Slow-query attribution that records queries over 250ms together with the caller stack, so a query is tied to the plugin that issued it rather than reported as a bare SQL string.
- Request classification, so cart, search and add-to-cart requests are always logged regardless of timing while assets and 404s are ignored.
- Bounded output at every level: at most 6 slow queries, 10 query owners, 8 callers, 10 tables, 8 stack frames and 12 errors per entry.
- Cookie, header and bot-hint capture, which is what separates a slow request from a logged-in customer and a slow request from a crawler.
- A PHP error and exception handler that attaches whatever went wrong to the same log entry.
Technical approach
- The decision to log happens at shutdown, once the real duration is known, so a fast request never pays for the capture machinery.
- Query logging is enabled at the earliest hook that fires so that queries from other MU plugins are not missed, and it is re-attempted at several later hooks in case something turned it off.
- The log path resolves to a primary location and falls back to uploads, and the directory is created if missing, because a logger that fails silently on a fresh install is worse than none.
- Every list is capped by an explicit constant rather than being truncated at write time, which keeps a pathological request from producing a megabyte of log.
- Sensitive request classes are always captured even when fast, because knowing what normal looks like on the checkout path is what makes an outlier readable.
Result and evidence
Slow requests became attributable. The logger is what turned intermittent cart and search slowness into named queries with named callers, which is the input every other performance fix on this store started from. It has run in production continuously since, and the tiering is what makes that affordable.
Commercial value
Most WooCommerce performance advice is generic because most people are guessing. Having per-request evidence from the live site is what let the work stay narrow, and narrow fixes are the ones that do not cause incidents.
Readable implementation brief
implementation_brief {
project: "A2 Perf Logger"
file: "mu-plugins/a2-perf-logger.php (458 lines, v1.2.0)"
threshold: "log > 800ms, deep capture > 2500ms"
sampling: "5% of everything else; sensitive classes always"
attribution: "queries > 250ms with caller stack + tables"
caps: "6 queries / 10 owners / 8 callers / 10 tables /
8 frames / 12 errors per entry"
ignores: "static assets and 404s"
output: "rotating file, 5MB, uploads fallback"
decision_point: "shutdown, once real duration is known"
}What this project shows
The constants at the top of this file are the design. The thresholds, the sample rate and every cap were chosen so the logger stays affordable on a store doing real traffic.
I care more about tools that are safe to leave running than tools that capture everything. A profiler you have to turn off is a profiler that is off when you need it.