Measured
blocks/loader.ts labels the loader_cache counter with ctx.resolverId:
const loader = ctx.resolverId || "unknown";
resolverId carries the full resolver chain, so label values look like:
Categories@sections.variants.1.value.5.sections.0.section.page
SearchResults Global@sections.0.section.page
Categories@sections.variants.1.value.2.jsonLD
Every section position, in every page variant, on every page becomes a distinct series.
Production ClickHouse, distinct loader values in 3h:
| site |
distinct values |
| fila-store |
3,684 |
| todolivrooficial |
3,478 |
| montecarlo |
2,209 |
| farmrio |
1,469 |
| happybooksoficial |
1,028 |
| fleet total |
21,849 |
Against the budget documented in our own o11y guide — >1,000 per site is forbidden as an alert dimension, >100 across the fleet as a cross-fleet aggregation — five sites are over, and the fleet figure is 218× over.
Cost, same window:
loader_cache = 11,485,954 of 14,998,196 rows in otel_metrics_sum — 76.6% of the whole table
otel_metrics_sum on disk: 48.4 GB
For contrast, cache_hit covers 194 tenants in 9 series, and the @decocms/start runtime does the equivalent job with 37 series and 13 distinct deco.cache.profile values (vtex/productDetailsPage, vtex/relatedProducts, site/categoryTree).
Why this is an issue and not a PR
The obvious fix — label with the resolver name instead of the chain — loses information. The chain tells you which section of which variant of which page a loader instance sits in, and that is genuinely useful when answering "which section is slow". Truncating trades debuggability for cost, and that is a call for whoever owns the metric, not a mechanical patch.
Options worth weighing:
- Label with the resolver name only (
vtex/loaders/legacy/productListingPage.ts), matching the @decocms/start design. Cheapest, loses section attribution.
- Keep the chain but only on a sampled/opt-in basis, with the name as the always-on label.
- Keep the chain as a span attribute (where high cardinality is acceptable for point lookups) and use the name for the metric.
Option 3 preserves both properties and is what the o11y guide's own rule implies — high-cardinality attributes are fine for filtering and point lookups, forbidden as aggregation keys.
Happy to send the PR once there is a direction.
Context
Surfaced while building unsampled loader-cache panels on the general-overview-otel dashboard. Those panels are usable today only with a tenant selected — a fleet-wide GROUP BY on this label is precisely the forbidden case.
🤖 Generated with Claude Code
Measured
blocks/loader.tslabels theloader_cachecounter withctx.resolverId:resolverIdcarries the full resolver chain, so label values look like:Every section position, in every page variant, on every page becomes a distinct series.
Production ClickHouse, distinct
loadervalues in 3h:Against the budget documented in our own o11y guide — >1,000 per site is forbidden as an alert dimension, >100 across the fleet as a cross-fleet aggregation — five sites are over, and the fleet figure is 218× over.
Cost, same window:
loader_cache= 11,485,954 of 14,998,196 rows inotel_metrics_sum— 76.6% of the whole tableotel_metrics_sumon disk: 48.4 GBFor contrast,
cache_hitcovers 194 tenants in 9 series, and the@decocms/startruntime does the equivalent job with 37 series and 13 distinctdeco.cache.profilevalues (vtex/productDetailsPage,vtex/relatedProducts,site/categoryTree).Why this is an issue and not a PR
The obvious fix — label with the resolver name instead of the chain — loses information. The chain tells you which section of which variant of which page a loader instance sits in, and that is genuinely useful when answering "which section is slow". Truncating trades debuggability for cost, and that is a call for whoever owns the metric, not a mechanical patch.
Options worth weighing:
vtex/loaders/legacy/productListingPage.ts), matching the@decocms/startdesign. Cheapest, loses section attribution.Option 3 preserves both properties and is what the o11y guide's own rule implies — high-cardinality attributes are fine for filtering and point lookups, forbidden as aggregation keys.
Happy to send the PR once there is a direction.
Context
Surfaced while building unsampled loader-cache panels on the
general-overview-oteldashboard. Those panels are usable today only with a tenant selected — a fleet-wideGROUP BYon this label is precisely the forbidden case.🤖 Generated with Claude Code