CNS-136: expose statement logging sample rate in the operator chart - #38406
Conversation
The operator chart passed `--disable-statement-logging` unconditionally, which made orchestratord set `statement_logging_max_sample_rate=0` and left query history permanently empty in self-managed installs. Replace the boolean orchestratord flag with `--statement-logging-max-sample-rate=<f64>`, surfaced as the `operator.args.statementLoggingMaxSampleRate` chart value. It defaults to 0.1, which keeps the sampling cost that motivated the original opt-out bounded while making query history usable. Setting it to 0 still fully disables statement logging, and leaving it empty falls back to environmentd's own default.
Only a null value omits the flag, an empty string renders an argument orchestratord cannot parse. Name environmentd's own default so the comment stands on its own.
QA LLM Review1. MEDIUM -- Sample rate does not bound statement-logging storage, which is never reclaimed
Turning the default from "off" to DetailsTwo mechanisms make this concrete.
Note also that If the goal is a bounded cost rather than bounded sampling, the lever that actually caps bytes is 2. LOW -- Out-of-range sample rate is rejected two layers away, at environmentd startup
The new value is passed through the chart and orchestratord unvalidated, but environmentd constrains DetailsThe chart has no Blast radius is limited: a rollout only starts when one is requested ( |
environmentd rejects a rate outside [0, 1] by refusing to open its catalog, so a plausible typo such as 10 surfaced as a new generation failing to boot. Reject it at argument-parse time instead. The sample rate bounds the fraction of statements recorded, not the size of the history: sustained write volume is capped by statement_logging_target_data_rate, and the history is never truncated. Say so rather than implying the rate bounds storage.
The sample rate bounds the fraction of statements recorded, not the volume written. On busy environments the target data rate is the binding limit, so it is the lever that actually caps how fast query history grows. Expose it alongside the sample rate, defaulting to unset so environmentd's own default applies.
|
Thanks, both findings verified against the code and both addressed. 1 (storage) — acted on, partly. Confirmed all three mechanics: the five collections are excluded from truncation ( The consequence for this PR is that my values.yaml comment was wrong: it implied the sample rate bounds storage. Corrected to state that it bounds the sampled fraction, that sustained volume is capped separately by Taking your suggestion, On shipping 2 (range validation) — fixed. Added a
On |
QA LLM Review1. MEDIUM --
|
Helm parses values files through YAML to JSON, so numbers arrive as float64 and print in exponential form at or above 1e6. A byte-rate knob invites values that large, and orchestratord's usize parser rejects 1.048576e+06, crashlooping the operator while helm upgrade reports success. Coerce with int64, which handles both the float64 from a values file and the int64 from --set.
|
Confirmed and fixed in a0d9a91. Good catch, this was a real crashloop. Reproduced the whole chain before fixing. Values file at Threshold is exactly where you said, 999999 renders literally and 1000000 becomes Also confirmed your note that Two clarifications on the writeup:
|
check-copyright covers .yaml, so the new fixture failed lint-and-rustfmt.
QA LLM Review1. MEDIUM -- A non-numeric
|
|
Can we use the values we default to in Cloud? Motivation for these numbers: https://app.notion.com/p/materialize/Statement-log-throttling-22913f48d37b803c8074d2be609b4dca (numbers we have in cloud are a bit different, but we had to lower after a few experiments) We recommended this to one of our larger self managed customers: https://materializeinc.slack.com/archives/C085QFLB072/p1768588261168409?thread_ts=1768587781.239839&cid=C085QFLB072 |
| /// volume statement logging writes. Leave unset to keep environmentd's own | ||
| /// default. | ||
| #[clap(long)] | ||
| statement_logging_target_data_rate: Option<usize>, |
There was a problem hiding this comment.
We should do the same input sanitation we do for statement_loggin_max_sample_rate here
Use 0.99, the rate Materialize Cloud runs at, rather than a lower self-managed default. The sample rate does not bound what statement logging writes, the target data rate does, so sampling less only gives up query history completeness. environmentd's defaults for the target data rate and max data credit already match Cloud, so neither needs an override. Reject a target data rate of 0. The token bucket starts empty and refills at that rate, so 0 throttles every statement forever.
|
Both addressed in ccc7e10, thanks — the Cloud numbers settle a question two review rounds had been circling. Cloud defaults. Switched Worth noting the other three are already environmentd's own defaults, so they need no chart override at all:
So a default install now lands on Cloud's exact configuration. Input sanitation. Added a
Also grabbed the throttling doc for context, that's useful background I didn't have. |
SangJunBak
left a comment
There was a problem hiding this comment.
Thanks for making this change! 😀
…ogging sampling is off (#38408) https://linear.app/materializeinc/issue/CNS-138/console-distinct-empty-state-when-the-statement-logging-sample-rate-is ## Problem Query history is backed by statement logging, which an operator can turn off by setting the sample rate to `0`. When that happens the console showed the generic filter-oriented "No results found." state, so the user could not tell sampling was off from their filters being too narrow. ## Solution * New API module `console/src/api/materialize/query-history/statementLoggingMaxSampleRate.ts` reads `SHOW statement_logging_max_sample_rate`, following the existing `maxReplicasPerCluster.ts` pattern. The effective rate is `min(session statement_logging_sample_rate, system statement_logging_max_sample_rate)`, so the cap alone detects a hard opt-out. * `QueryHistoryList` renders a distinct `SamplingDisabledState` when the result set is empty and the cap is `0`, naming both ways to raise it: `ALTER SYSTEM SET statement_logging_max_sample_rate`, and the Materialize operator's Helm chart values for self-managed. The filter-oriented state is unchanged for a non-zero rate. The new query is gated on `enabled: isEmpty`, so it never runs on the path that renders rows. ## Testing Snapshot test for the compiled query, plus two cases in `QueryHistoryList.test.tsx` covering both empty-state branches. While adding them I found `DEFAULT_FETCH_QUERY_LIST_HANDLER` never matched anything: the schema defaults `dateRange` to a window ending at `new Date()`, so its separate `queryHistoryListSchema.parse(...)` produced different filters than the `PARSED_DEFAULT_SCHEMA_VALUES` the component renders with. The handler now reuses the same parsed value. ## Notes for the reviewer * Rebased onto main now that #38407 ([CNS-137](https://linear.app/materializeinc/issue/CNS-137)) has landed. This branch previously carried a cherry-pick of @leedqin's #36533 un-gate; main has that change already, so the duplicate commit was dropped in the rebase. #36533 is now redundant and can be closed. * The Helm chart value the copy alludes to comes from #38406 ([CNS-136](https://linear.app/materializeinc/issue/CNS-136)). The message deliberately names no specific chart key, so it stays accurate regardless of what that PR settles on. * The copy renders in both deployment modes and mentions Helm only in a self-managed-qualified sentence, rather than branching on `AppConfigSwitch`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://linear.app/materializeinc/issue/CNS-136/helm-chart-stop-hard-disabling-statement-logging-expose-sample-rate-as
Problem
The operator chart passed
--disable-statement-loggingunconditionally, so orchestratord always emitted--system-parameter-default=statement_logging_max_sample_rate=0and query history was permanently empty in self-managed installs. There was no way to turn it back on short of forking the chart.Solution
Replace the boolean orchestratord flag with
--statement-logging-max-sample-rate=<f64>(Option<f64>, unset means no override), surfaced as theoperator.args.statementLoggingMaxSampleRatechart value, defaulting to0.99to match Materialize Cloud.0still fully disables statement logging, andnullinherits environmentd's default.The sample rate does not bound what statement logging writes,
statement_logging_target_data_ratedoes. That is exposed asoperator.args.statementLoggingTargetDataRate, defaulting to unset so environmentd's 2071 B/s applies. Since environmentd already defaults to Cloud's values for the target data rate (2071) and max data credit (52428800), a default install lands on Cloud's exact configuration.Both flags validate at parse time: the sample rate to
[0, 1], which environmentd otherwise rejects by refusing to open its catalog, and the data rate to non-zero, since the token bucket refills at that rate and 0 throttles everything forever.Testing
helm unittest misc/helm-charts/operator(43 tests) covers the default, a custom rate,0, and unset for both values, plus a values-file fixture pinning theint64coercion that large byte rates need.cargo clippy/test -p mz-orchestratord,bin/fmt,check-helm-docs.shandcheck-copyright.shpass. Both validators verified against the built binary. No cluster needed.For the reviewer
enableInternalStatementLogging: truedefault was inert while the max rate was pinned at 0, and now becomes live. Internal statements share the singleArc<ThrottlingState>token bucket with user statements, so they do not raise total bytes above the cap, they consume the same budget. Console polling andmz_systemtraffic therefore compete with the user's own queries for the 2071 B/s, and throttled statements are dropped silently. Left as-is to keep this PR to one decision, but worth measuring.UpToDate=False/WaitingForApprovalafter the operator upgrade, and the fix only lands for them once a rollout is requested.--disable-statement-logging. It does break a pinned-old-operator.image.tag+ new-chart combination, as any generation-affecting flag change would.🤖 Generated with Claude Code