Commit 87745e6e by David Kaltschmidt

Explore: label selector for logging

- query all available label keys for logs
- query all values for each key
- build cascader options with label values by key
- lots of temporarily added conditions to reuse the promquery field
parent 1f88bfd2
......@@ -564,6 +564,7 @@ export class Explore extends React.Component<any, IExploreState> {
onClickHintFix={this.onModifyQueries}
onExecuteQuery={this.onSubmit}
onRemoveQueryRow={this.onRemoveQueryRow}
supportsLogs={supportsLogs}
/>
<div className="result-options">
{supportsGraph ? (
......
......@@ -137,12 +137,14 @@ interface PromQueryFieldProps {
onQueryChange?: (value: string, override?: boolean) => void;
portalPrefix?: string;
request?: (url: string) => any;
supportsLogs?: boolean; // To be removed after Logging gets its own query field
}
interface PromQueryFieldState {
histogramMetrics: string[];
labelKeys: { [index: string]: string[] }; // metric -> [labelKey,...]
labelValues: { [index: string]: { [index: string]: string[] } }; // metric -> labelKey -> [labelValue,...]
logLabelOptions: any[];
metrics: string[];
metricsByPrefix: CascaderOption[];
}
......@@ -171,15 +173,40 @@ class PromQueryField extends React.Component<PromQueryFieldProps, PromQueryField
histogramMetrics: props.histogramMetrics || [],
labelKeys: props.labelKeys || {},
labelValues: props.labelValues || {},
logLabelOptions: [],
metrics: props.metrics || [],
metricsByPrefix: props.metricsByPrefix || [],
};
}
componentDidMount() {
// Temporarily reused by logging
const { supportsLogs } = this.props;
if (supportsLogs) {
this.fetchLogLabels();
} else {
// Usual actions
this.fetchMetricNames();
this.fetchHistogramMetrics();
}
}
onChangeLogLabels = (values: string[], selectedOptions: CascaderOption[]) => {
let query;
if (selectedOptions.length === 1) {
if (selectedOptions[0].children.length === 0) {
query = selectedOptions[0].value;
} else {
// Ignore click on group
return;
}
} else {
const key = selectedOptions[0].value;
const value = selectedOptions[1].value;
query = `{${key}="${value}"}`;
}
this.onChangeQuery(query, true);
};
onChangeMetrics = (values: string[], selectedOptions: CascaderOption[]) => {
let query;
......@@ -380,7 +407,8 @@ class PromQueryField extends React.Component<PromQueryFieldProps, PromQueryField
}
// Query labels for selector
if (selector && !this.state.labelValues[selector]) {
// Temporarily add skip for logging
if (selector && !this.state.labelValues[selector] && !this.props.supportsLogs) {
if (selector === EMPTY_SELECTOR) {
// Query label values for default labels
refresher = Promise.all(DEFAULT_KEYS.map(key => this.fetchLabelValues(key)));
......@@ -409,6 +437,38 @@ class PromQueryField extends React.Component<PromQueryFieldProps, PromQueryField
});
}
// Temporarily here while reusing this field for logging
async fetchLogLabels() {
const url = '/api/prom/label';
try {
const res = await this.request(url);
const body = await (res.data || res.json());
const labelKeys = body.data.slice().sort();
const labelKeysBySelector = {
...this.state.labelKeys,
[EMPTY_SELECTOR]: labelKeys,
};
const labelValuesByKey = {};
const logLabelOptions = [];
for (const key of labelKeys) {
const valuesUrl = `/api/prom/label/${key}/values`;
const res = await this.request(valuesUrl);
const body = await (res.data || res.json());
const values = body.data.slice().sort();
labelValuesByKey[key] = values;
logLabelOptions.push({
label: key,
value: key,
children: values.map(value => ({ label: value, value })),
});
}
const labelValues = { [EMPTY_SELECTOR]: labelValuesByKey };
this.setState({ labelKeys: labelKeysBySelector, labelValues, logLabelOptions });
} catch (e) {
console.error(e);
}
}
async fetchLabelValues(key: string) {
const url = `/api/v1/label/${key}/values`;
try {
......@@ -463,8 +523,8 @@ class PromQueryField extends React.Component<PromQueryFieldProps, PromQueryField
}
render() {
const { error, hint } = this.props;
const { histogramMetrics, metricsByPrefix } = this.state;
const { error, hint, supportsLogs } = this.props;
const { histogramMetrics, logLabelOptions, metricsByPrefix } = this.state;
const histogramOptions = histogramMetrics.map(hm => ({ label: hm, value: hm }));
const metricsOptions = [
{ label: 'Histograms', value: HISTOGRAM_GROUP, children: histogramOptions },
......@@ -474,9 +534,15 @@ class PromQueryField extends React.Component<PromQueryFieldProps, PromQueryField
return (
<div className="prom-query-field">
<div className="prom-query-field-tools">
{supportsLogs ? (
<Cascader options={logLabelOptions} onChange={this.onChangeLogLabels}>
<button className="btn navbar-button navbar-button--tight">Log labels</button>
</Cascader>
) : (
<Cascader options={metricsOptions} onChange={this.onChangeMetrics}>
<button className="btn navbar-button navbar-button--tight">Metrics</button>
</Cascader>
)}
</div>
<div className="prom-query-field-wrapper">
<div className="slate-query-field-wrapper">
......
......@@ -44,7 +44,7 @@ class QueryRow extends PureComponent<any, {}> {
};
render() {
const { edited, history, query, queryError, queryHint, request } = this.props;
const { edited, history, query, queryError, queryHint, request, supportsLogs } = this.props;
return (
<div className="query-row">
<div className="query-row-field">
......@@ -58,6 +58,7 @@ class QueryRow extends PureComponent<any, {}> {
onPressEnter={this.onPressEnter}
onQueryChange={this.onChangeQuery}
request={request}
supportsLogs={supportsLogs}
/>
</div>
<div className="query-row-tools">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment