Graphite: Expand metric names for variables (#33694)

* Allow expanding metrics names in variable queries

* Simplify docs

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/datasources/graphite.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Clean up docs

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
Piotr Jamróz 2021-05-11 09:39:44 +02:00 committed by GitHub
parent 3e59ae7e56
commit 60cf0c8338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 6 deletions

View File

@ -138,9 +138,34 @@ For more details, see the [Graphite docs on the autocomplete API for tags](http:
### Query variable
The query you specify in the query field should be a metric find type of query. For example, a query like `prod.servers.*` will fill the
The query you specify in the query field should be a metric find type of query. For example, a query like `prod.servers.*` fills the
variable with all possible values that exist in the wildcard position.
The results contain all possible values occurring only at the last level of the query. To get full metric names matching the query
use expand function (`expand(*.servers.*)`).
#### Comparison between expanded and non-expanded metric search results
The expanded query returns the full names of matching metrics. In combination with regex, it can extract any part of the metric name. By contrast, a non-expanded query only returns the last part of the metric name. It does not allow you to extract other parts of metric names.
Here are some example metrics:
- `prod.servers.001.cpu`
- `prod.servers.002.cpu`
- `test.servers.001.cpu`
The following examples show how expanded and non-expanded queries can be used to fetch specific parts of the metrics name.
| non-expanded query | results | expanded query | expanded results |
|--------------|---------|----------------|------------------|
| `*` | prod, test | `expand(*)` | prod, test
| `*.servers` | servers | `expand(*.servers)` | prod.servers, test.servers |
| `test.servers` | servers | `expand(test.servers)` | test.servers |
| `*.servers.*` | 001,002 | `expand(*.servers.*)` | prod.servers.001, prod.servers.002, test.servers.001 |
| `test.servers.*` | 001 | `expand(test.servers.*)` | test.servers.001 |
| `*.servers.*.cpu` | cpu | `expand(*.servers.*.cpu)` | prod.servers.001.cpu, prod.servers.002.cpu, test.servers.001.cpu |
As you can see from the results, the non-expanded query is the same as an expanded query with a regex matching the last part of the name.
You can also create nested variables that use other variables in their definition. For example
`apps.$app.servers.*` uses the variable `$app` in its query definition.

View File

@ -512,6 +512,16 @@ describe('graphiteDatasource', () => {
expect(requestOptions.data).toEqual('query=app.*');
expect(results).not.toBe(null);
});
it('should request expanded metrics', () => {
ctx.ds.metricFindQuery('expand(*.servers.*)').then((data: any) => {
results = data;
});
expect(requestOptions.url).toBe('/api/datasources/proxy/1/metrics/expand');
expect(requestOptions.params.query).toBe('*.servers.*');
expect(results).not.toBe(null);
});
});
});

View File

@ -365,6 +365,8 @@ export class GraphiteDatasource extends DataSourceApi<
metricFindQuery(query: string, optionalOptions?: any): Promise<MetricFindValue[]> {
const options: any = optionalOptions || {};
// First attempt to check for tag-related functions (using empty wildcard for interpolation)
let interpolatedQuery = this.templateSrv.replace(
query,
getSearchFilterScopedVar({ query, wildcardChar: '', options: optionalOptions })
@ -386,26 +388,60 @@ export class GraphiteDatasource extends DataSourceApi<
return this.getTagsAutoComplete(expressions, undefined, options);
}
// If no tag-related query was found, perform metric-based search (using * as the wildcard for interpolation)
let useExpand = query.match(/^expand\((.*)\)$/);
query = useExpand ? useExpand[1] : query;
interpolatedQuery = this.templateSrv.replace(
query,
getSearchFilterScopedVar({ query, wildcardChar: '*', options: optionalOptions })
);
let range;
if (options.range) {
range = {
from: this.translateTime(options.range.from, false, options.timezone),
until: this.translateTime(options.range.to, true, options.timezone),
};
}
if (useExpand) {
return this.requestMetricExpand(interpolatedQuery, options.requestId, range);
} else {
return this.requestMetricFind(interpolatedQuery, options.requestId, range);
}
}
/**
* Search for metrics matching giving pattern using /metrics/find endpoint. It will
* return all possible values at the last level of the query, for example:
*
* metrics: prod.servers.001.cpu, prod.servers.002.cpu
* query: *.servers.*
* result: 001, 002
*
* For more complex searches use requestMetricExpand
*/
private requestMetricFind(
query: string,
requestId: string,
range?: { from: any; until: any }
): Promise<MetricFindValue[]> {
const httpOptions: any = {
method: 'POST',
url: '/metrics/find',
params: {},
data: `query=${interpolatedQuery}`,
data: `query=${query}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
// for cancellations
requestId: options.requestId,
requestId: requestId,
};
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
if (range) {
httpOptions.params.from = range.from;
httpOptions.params.until = range.until;
}
return this.doGraphiteRequest(httpOptions)
@ -422,6 +458,46 @@ export class GraphiteDatasource extends DataSourceApi<
.toPromise();
}
/**
* Search for metrics matching giving pattern using /metrics/expand endpoint.
* The result will contain all metrics (with full name) matching provided query.
* It's a more flexible version of /metrics/find endpoint (@see requestMetricFind)
*/
private requestMetricExpand(
query: string,
requestId: string,
range?: { from: any; until: any }
): Promise<MetricFindValue[]> {
const httpOptions: any = {
method: 'GET',
url: '/metrics/expand',
params: { query },
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
// for cancellations
requestId,
};
if (range) {
httpOptions.params.from = range.from;
httpOptions.params.until = range.until;
}
return this.doGraphiteRequest(httpOptions)
.pipe(
map((results: any) => {
return _map(results.data.results, (metric) => {
return {
text: metric,
expandable: false,
};
});
})
)
.toPromise();
}
getTags(optionalOptions: any) {
const options = optionalOptions || {};