morningman opened a new pull request, #69837:
URL: https://github.com/apache/doris/pull/69837
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary:
**In short:** the FE writes metric label values into its Prometheus output
without escaping them. A table name may contain a backslash, a double quote or
a line feed, and in cloud mode the Master FE labels four per-table series with
the table name, so a single such table leaves the Master's whole `/metrics`
response outside the text format, and Prometheus keeps no sample of a scrape it
cannot parse. This PR escapes every label value that is not a literal through
one function, as the format requires. Ordinary names are written exactly as
before.
#### Background
In the Prometheus text format a label value is written between double
quotes, and a backslash, a double quote or a line feed inside it must be
written as `\\`, `\"` and `\n`; no other character is escaped. A scrape whose
response does not parse fails as a whole.
With `enable_unicode_name_support`, which is on by default, a table name may
contain all three characters: `FeNameFormat.UNICODE_TABLE_NAME_REGEX` only
requires the last character not to be white space. A local cluster with default
settings accepts tables named ``` `a"b` ```, `` `a\b` `` and one with a line
feed in the middle. The names of databases, users, workload groups, jobs and
catalogs keep their restricted patterns.
#### The problem, and what it cost
- `PrometheusMetricVisitor` concatenates label values as they are, in every
place that writes one: the labels of registered metrics (`visit`), both kinds
of histograms, the cloud per-table series (`visitCloudTableStats`), the
workload group series and the JVM GC series.
- In cloud mode the Master FE exports `doris_fe_table_data_size`,
`doris_fe_table_rowset_count`, `doris_fe_table_segment_count` and
`doris_fe_table_row_count` for up to `prom_output_table_metrics_limit` (10000)
tables, labeled with `db_name` and `table_name`. One table whose name holds one
of the three characters makes the response invalid, and every metric of the
Master FE is lost while that table is exported.
- The coming monitoring of table streams and IVM materialized views labels
series with the names of materialized views and streams, which would run into
the same problem in both modes.
#### How this PR fixes it
- `escapeLabelValue` writes a backslash, a double quote and a line feed as
`\\`, `\"` and `\n` and leaves every other character alone, which is the full
set the format requires.
- Every label value that is not a literal goes through it: the two histogram
paths and `visit`, the database and table names of the per-table series
(escaped once per table, not once per series), the workload group name and the
GC name. The JVM GC and workload group names cannot hold these characters
today; they go through the same function so that no label value in the class is
written raw.
- A name without these characters comes back as the same string, so the
output of ordinary names does not change, byte for byte, and costs no extra
allocation (`String.replace` returns the string itself when nothing matches).
#### Results
What the cloud per-table series is written as for each table name, and what
`promtool check metrics` (Prometheus v3.2.0) says about it:
| Table name | Before this PR | promtool | After this PR | promtool |
| --- | --- | --- | --- | --- |
| `t1` | `table_name="t1"` | OK | `table_name="t1"` | OK |
| `a"b` | `table_name="a"b"` | `unexpected end of label value "a"` |
`table_name="a\"b"` | OK |
| `a\b` | `table_name="a\b"` | `invalid escape sequence '\b'` |
`table_name="a\\b"` | OK |
| `a\` | `table_name="a\"` | `label value "a\"} 100" contains unescaped
new-line` | `table_name="a\\"` | OK |
| `a`, line feed, `b` | the sample split over two lines | `label value "a"
contains unescaped new-line` | `table_name="a\nb"` | OK |
A parser that follows the format turns each escaped value back into the
table name itself.
#### Classes, and how they call each other
- `PrometheusMetricVisitor`: the new private `escapeLabelValue`, called
wherever a label value is written.
- `MetricsTest`: `testPrometheusVisitorEscapesLabelValues` (a gauge with an
escaped and a plain label, and both kinds of histograms) and
`testCloudTableStatsEscapeTableName` (the four per-table series, with a mocked
`CloudTabletStatMgr`).
```
MetricsAction (/metrics) -> MetricRepo.getMetric(PrometheusMetricVisitor)
|-- visitJvm GC name -> escapeLabelValue
|-- DORIS_METRIC_REGISTER.accept -> visit labels ->
escapeLabelValue
|-- visitHistograms -> visitHistogram (both) labels ->
escapeLabelValue
|-- visitCloudTableStats db / table name -> escapeLabelValue
`-- visitWorkloadGroup group name -> escapeLabelValue
```
Not changed: the JSON output (`type=json`), which builds its own strings and
would need JSON escaping instead; the core output (`type=core`), which writes
no labels; the metric names and the `# HELP` texts, which are literals.
### Release note
In cloud mode, a table whose name contains a backslash, a double quote or a
line feed no longer makes the FE `/metrics` output unparsable for Prometheus.
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [x] Unit Test
- [x] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
Unit test: `MetricsTest`, 20 cases including the two new ones; both new
cases fail on the code before this PR. Manual: the three table names above
created on a local shared-nothing cluster with default settings, and the
samples in the table checked with `promtool check metrics`.
- Behavior changed:
- [ ] No.
- [x] Yes. <!-- Explain the behavior change -->
A label value that contains a backslash, a double quote or a line feed
is escaped in the Prometheus output; every other output is unchanged.
- Does this need documentation?
- [x] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR should
merge into -->
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]