@perses-dev/prometheus-plugin 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +54 -0
- package/dist/cjs/model/api-types.js +14 -0
- package/dist/cjs/model/datasource.js +36 -0
- package/dist/cjs/model/parse-sample-values.js +44 -0
- package/dist/cjs/model/prometheus-client.js +101 -0
- package/dist/cjs/model/templating.js +122 -0
- package/dist/cjs/model/time.js +68 -0
- package/dist/cjs/plugins/graph-query.js +80 -0
- package/dist/cjs/plugins/interval-variable.js +26 -0
- package/dist/cjs/plugins/label-names-variable.js +44 -0
- package/dist/cjs/plugins/label-values-variable.js +45 -0
- package/package.json +9 -10
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.setup = void 0;
|
|
16
|
+
const graph_query_1 = require("./plugins/graph-query");
|
|
17
|
+
const interval_variable_1 = require("./plugins/interval-variable");
|
|
18
|
+
const label_names_variable_1 = require("./plugins/label-names-variable");
|
|
19
|
+
const label_values_variable_1 = require("./plugins/label-values-variable");
|
|
20
|
+
const setup = (registerPlugin) => {
|
|
21
|
+
registerPlugin({
|
|
22
|
+
pluginType: 'Variable',
|
|
23
|
+
kind: label_names_variable_1.PrometheusLabelNamesKind,
|
|
24
|
+
validate: undefined,
|
|
25
|
+
plugin: {
|
|
26
|
+
useVariableOptions: label_names_variable_1.usePrometheusLabelNames,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
registerPlugin({
|
|
30
|
+
pluginType: 'Variable',
|
|
31
|
+
kind: label_values_variable_1.PrometheusLabelValuesKind,
|
|
32
|
+
validate: undefined,
|
|
33
|
+
plugin: {
|
|
34
|
+
useVariableOptions: label_values_variable_1.usePrometheusLabelValues,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
registerPlugin({
|
|
38
|
+
pluginType: 'Variable',
|
|
39
|
+
kind: interval_variable_1.IntervalKind,
|
|
40
|
+
validate: undefined,
|
|
41
|
+
plugin: {
|
|
42
|
+
useVariableOptions: interval_variable_1.useIntervalValues,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
registerPlugin({
|
|
46
|
+
pluginType: 'GraphQuery',
|
|
47
|
+
kind: graph_query_1.PrometheusGraphQueryKind,
|
|
48
|
+
validate: undefined,
|
|
49
|
+
plugin: {
|
|
50
|
+
useGraphQuery: graph_query_1.usePrometheusGraphQuery,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
exports.setup = setup;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.usePrometheusConfig = void 0;
|
|
16
|
+
const plugin_system_1 = require("@perses-dev/plugin-system");
|
|
17
|
+
function isPrometheusDatasource(def) {
|
|
18
|
+
return def.kind === 'Prometheus';
|
|
19
|
+
}
|
|
20
|
+
function usePrometheusConfig(selector) {
|
|
21
|
+
const datasources = (0, plugin_system_1.useDatasources)();
|
|
22
|
+
const models = selector === undefined ? [datasources.defaultDatasource] : datasources.getDatasources(selector);
|
|
23
|
+
if (models.length > 1) {
|
|
24
|
+
throw new Error('More than one Datasource found');
|
|
25
|
+
}
|
|
26
|
+
const model = models[0];
|
|
27
|
+
if (model === undefined) {
|
|
28
|
+
throw new Error('Datasource not found');
|
|
29
|
+
}
|
|
30
|
+
const spec = model.spec;
|
|
31
|
+
if (isPrometheusDatasource(spec)) {
|
|
32
|
+
return { ...model, spec };
|
|
33
|
+
}
|
|
34
|
+
throw new Error('Datasource is not a valid Prometheus Datasource');
|
|
35
|
+
}
|
|
36
|
+
exports.usePrometheusConfig = usePrometheusConfig;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.parseSampleValue = exports.parseValueTuple = void 0;
|
|
16
|
+
/**
|
|
17
|
+
* Parse a ValueTuple from a PromServer response into the a millisecond-based
|
|
18
|
+
* unix time and a numeric sample value.
|
|
19
|
+
*/
|
|
20
|
+
function parseValueTuple(data) {
|
|
21
|
+
const [unixTimeSeconds, sampleValue] = data;
|
|
22
|
+
// Prom returns unix time in seconds, so convert to ms
|
|
23
|
+
return [unixTimeSeconds * 1000, parseSampleValue(sampleValue)];
|
|
24
|
+
}
|
|
25
|
+
exports.parseValueTuple = parseValueTuple;
|
|
26
|
+
/**
|
|
27
|
+
* Parses a string sample value from Prometheus, usually included as the
|
|
28
|
+
* second member of a ValueTuple.
|
|
29
|
+
*/
|
|
30
|
+
function parseSampleValue(sampleValue) {
|
|
31
|
+
// Account for Prometheus' representation of +/- infinity, otherwise just
|
|
32
|
+
// parse the sample value as a float
|
|
33
|
+
let value;
|
|
34
|
+
switch (sampleValue) {
|
|
35
|
+
case '+Inf':
|
|
36
|
+
value = Number.POSITIVE_INFINITY;
|
|
37
|
+
case '-Inf':
|
|
38
|
+
value = Number.NEGATIVE_INFINITY;
|
|
39
|
+
default:
|
|
40
|
+
value = parseFloat(sampleValue);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
exports.parseSampleValue = parseSampleValue;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useLabelValues = exports.useLabelNames = exports.useRangeQuery = exports.useInstantQuery = void 0;
|
|
16
|
+
const react_query_1 = require("react-query");
|
|
17
|
+
const core_1 = require("@perses-dev/core");
|
|
18
|
+
const datasource_1 = require("./datasource");
|
|
19
|
+
/**
|
|
20
|
+
* Calls the `/api/v1/query` endpoint to get metrics data.
|
|
21
|
+
*/
|
|
22
|
+
function useInstantQuery(params, queryOptions) {
|
|
23
|
+
return useQueryWithPost('/api/v1/query', params, queryOptions);
|
|
24
|
+
}
|
|
25
|
+
exports.useInstantQuery = useInstantQuery;
|
|
26
|
+
/**
|
|
27
|
+
* Calls the `/api/v1/query_range` endpoint to get metrics data.
|
|
28
|
+
*/
|
|
29
|
+
function useRangeQuery(params, queryOptions) {
|
|
30
|
+
return useQueryWithPost('/api/v1/query_range', params, queryOptions);
|
|
31
|
+
}
|
|
32
|
+
exports.useRangeQuery = useRangeQuery;
|
|
33
|
+
/**
|
|
34
|
+
* Calls the `/api/v1/labels` endpoint to get a list of label names.
|
|
35
|
+
*/
|
|
36
|
+
function useLabelNames(params, queryOptions) {
|
|
37
|
+
return useQueryWithPost('/api/v1/labels', params, queryOptions);
|
|
38
|
+
}
|
|
39
|
+
exports.useLabelNames = useLabelNames;
|
|
40
|
+
/**
|
|
41
|
+
* Calls the `/api/v1/label/{labelName}/values` endpoint to get a list of
|
|
42
|
+
* values for a label.
|
|
43
|
+
*/
|
|
44
|
+
function useLabelValues(params, queryOptions) {
|
|
45
|
+
const { labelName, ...searchParams } = params;
|
|
46
|
+
const apiURI = `/api/v1/label/${encodeURIComponent(labelName)}/values`;
|
|
47
|
+
return useQueryWithGet(apiURI, searchParams, queryOptions);
|
|
48
|
+
}
|
|
49
|
+
exports.useLabelValues = useLabelValues;
|
|
50
|
+
function useQueryWithGet(apiURI, params, queryOptions) {
|
|
51
|
+
const config = (0, datasource_1.usePrometheusConfig)(queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.datasource);
|
|
52
|
+
const datasourceURL = (0, core_1.buildDatasourceURL)(config.metadata.name, config.spec.http);
|
|
53
|
+
const key = [datasourceURL, apiURI, params];
|
|
54
|
+
return (0, react_query_1.useQuery)(key, () => {
|
|
55
|
+
let url = `${datasourceURL}${apiURI}`;
|
|
56
|
+
const urlParams = createSearchParams(params).toString();
|
|
57
|
+
if (urlParams !== '') {
|
|
58
|
+
url += `?${urlParams}`;
|
|
59
|
+
}
|
|
60
|
+
return (0, core_1.fetchJson)(url, { method: 'GET' });
|
|
61
|
+
}, queryOptions);
|
|
62
|
+
}
|
|
63
|
+
function useQueryWithPost(apiURI, params, queryOptions) {
|
|
64
|
+
const config = (0, datasource_1.usePrometheusConfig)(queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.datasource);
|
|
65
|
+
const datasourceURL = (0, core_1.buildDatasourceURL)(config.metadata.name, config.spec.http);
|
|
66
|
+
const key = [datasourceURL, apiURI, params];
|
|
67
|
+
return (0, react_query_1.useQuery)(key, () => {
|
|
68
|
+
const url = `${datasourceURL}${apiURI}`;
|
|
69
|
+
const init = {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
73
|
+
},
|
|
74
|
+
body: createSearchParams(params),
|
|
75
|
+
};
|
|
76
|
+
return (0, core_1.fetchJson)(url, init);
|
|
77
|
+
}, queryOptions);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates URLSearchParams from a request params object.
|
|
81
|
+
*/
|
|
82
|
+
function createSearchParams(params) {
|
|
83
|
+
const searchParams = new URLSearchParams();
|
|
84
|
+
for (const key in params) {
|
|
85
|
+
const value = params[key];
|
|
86
|
+
if (value === undefined)
|
|
87
|
+
continue;
|
|
88
|
+
if (typeof value === 'string') {
|
|
89
|
+
searchParams.append(key, value);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === 'number') {
|
|
93
|
+
searchParams.append(key, value.toString());
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
for (const val of value) {
|
|
97
|
+
searchParams.append(key, val);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return searchParams;
|
|
101
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useReplaceTemplateString = exports.useReplaceTemplateStrings = void 0;
|
|
16
|
+
const lezer_promql_1 = require("lezer-promql");
|
|
17
|
+
const core_1 = require("@perses-dev/core");
|
|
18
|
+
const plugin_system_1 = require("@perses-dev/plugin-system");
|
|
19
|
+
const REPLACE_IN_NODE_TYPES = new Set([lezer_promql_1.StringLiteral, lezer_promql_1.Duration]);
|
|
20
|
+
/**
|
|
21
|
+
* Replaces template variable placeholders with variable values from the current
|
|
22
|
+
* dashbboard in multiple template strings. Since template strings are often
|
|
23
|
+
* used as request parameters, the results are memoized and only recalculated
|
|
24
|
+
* if the templateStrings or variable values change.
|
|
25
|
+
*/
|
|
26
|
+
function useReplaceTemplateStrings(templateStrings) {
|
|
27
|
+
const { variables } = (0, plugin_system_1.useTemplateVariables)();
|
|
28
|
+
// Replace template string placeholders with variable values
|
|
29
|
+
return (0, core_1.useMemoized)(() => {
|
|
30
|
+
const result = [];
|
|
31
|
+
const needsVariableValuesFor = new Set();
|
|
32
|
+
for (const templateString of templateStrings !== null && templateStrings !== void 0 ? templateStrings : []) {
|
|
33
|
+
const replaced = replaceTemplateVariables(templateString, variables);
|
|
34
|
+
result.push(replaced.result);
|
|
35
|
+
for (const varName of replaced.needsVariableValuesFor) {
|
|
36
|
+
needsVariableValuesFor.add(varName);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { result, needsVariableValuesFor };
|
|
40
|
+
}, [templateStrings, variables]);
|
|
41
|
+
}
|
|
42
|
+
exports.useReplaceTemplateStrings = useReplaceTemplateStrings;
|
|
43
|
+
/**
|
|
44
|
+
* Replaces template variable placeholders with variable values from the current
|
|
45
|
+
* dashboard in a single template string. Since template strings are often
|
|
46
|
+
* used as request parameters, the results are memoized and only recalculated
|
|
47
|
+
* if the templateString or variable values change.
|
|
48
|
+
*/
|
|
49
|
+
function useReplaceTemplateString(templateString) {
|
|
50
|
+
const { variables } = (0, plugin_system_1.useTemplateVariables)();
|
|
51
|
+
// Replace template string placeholders with variable values
|
|
52
|
+
return (0, core_1.useMemoized)(() => {
|
|
53
|
+
if (templateString === undefined) {
|
|
54
|
+
return { result: '', needsVariableValuesFor: new Set() };
|
|
55
|
+
}
|
|
56
|
+
return replaceTemplateVariables(templateString, variables);
|
|
57
|
+
}, [templateString, variables]);
|
|
58
|
+
}
|
|
59
|
+
exports.useReplaceTemplateString = useReplaceTemplateString;
|
|
60
|
+
/**
|
|
61
|
+
* Replace template variable placeholders with variable values.
|
|
62
|
+
*/
|
|
63
|
+
function replaceTemplateVariables(templateString, variablesState) {
|
|
64
|
+
const needsVariableValuesFor = new Set();
|
|
65
|
+
let indexAdjustment = 0;
|
|
66
|
+
const tree = lezer_promql_1.parser.parse(templateString);
|
|
67
|
+
const cursor = tree.cursor();
|
|
68
|
+
do {
|
|
69
|
+
// Only replace variables in string literals for now
|
|
70
|
+
if (REPLACE_IN_NODE_TYPES.has(cursor.node.type.id))
|
|
71
|
+
continue;
|
|
72
|
+
let { from, to } = cursor.node;
|
|
73
|
+
from += indexAdjustment;
|
|
74
|
+
to += indexAdjustment;
|
|
75
|
+
let nodeText = templateString.substring(from, to);
|
|
76
|
+
nodeText = nodeText.replaceAll(/\$([a-zA-Z0-9_-]+)/g, (match, variableName) => {
|
|
77
|
+
const state = variablesState[variableName];
|
|
78
|
+
if (state === undefined) {
|
|
79
|
+
throw new Error(`Unknown variable '${variableName}'`);
|
|
80
|
+
}
|
|
81
|
+
const { value, options } = state;
|
|
82
|
+
let replacement;
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
let selectedValues = value;
|
|
85
|
+
// Is the default ALL value?
|
|
86
|
+
if (value.length === 1 && value[0] === core_1.DEFAULT_ALL_VALUE) {
|
|
87
|
+
// For the default ALL value, we want to use all options as the
|
|
88
|
+
// selected values
|
|
89
|
+
if (options === undefined) {
|
|
90
|
+
// Wait until options are loaded before we do replacement
|
|
91
|
+
needsVariableValuesFor.add(variableName);
|
|
92
|
+
return match;
|
|
93
|
+
}
|
|
94
|
+
selectedValues = options;
|
|
95
|
+
}
|
|
96
|
+
// TODO: Escape v for regex
|
|
97
|
+
replacement = selectedValues.map((v) => v).join('|');
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
replacement = escapeVariableValue(value);
|
|
101
|
+
}
|
|
102
|
+
return replacement;
|
|
103
|
+
});
|
|
104
|
+
// Replace the string literal with the new one and since that may change the
|
|
105
|
+
// overall length of the string, keep track of an "index adjustment" so we
|
|
106
|
+
// can shift positions in the tree accordingly
|
|
107
|
+
const oldLength = to - from;
|
|
108
|
+
indexAdjustment += nodeText.length - oldLength;
|
|
109
|
+
templateString = templateString.substring(0, from) + nodeText + templateString.substring(from + oldLength);
|
|
110
|
+
} while (cursor.next());
|
|
111
|
+
return {
|
|
112
|
+
result: templateString,
|
|
113
|
+
needsVariableValuesFor,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const SINGLE_BACKSLASH = '\\';
|
|
117
|
+
const DOUBLE_BACKSLASH = '\\\\';
|
|
118
|
+
function escapeVariableValue(value) {
|
|
119
|
+
// TODO: What about ["'`]? Do we need to know what kind of quotes the
|
|
120
|
+
// string literal is using?
|
|
121
|
+
return value.replaceAll(SINGLE_BACKSLASH, DOUBLE_BACKSLASH);
|
|
122
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getDurationStringSeconds = exports.usePanelRangeStep = exports.useDashboardPrometheusTimeRange = void 0;
|
|
16
|
+
const core_1 = require("@perses-dev/core");
|
|
17
|
+
const plugin_system_1 = require("@perses-dev/plugin-system");
|
|
18
|
+
const date_fns_1 = require("date-fns");
|
|
19
|
+
const react_1 = require("react");
|
|
20
|
+
/**
|
|
21
|
+
* Get the time range for the current dashboard, converted to Prometheus time.
|
|
22
|
+
*/
|
|
23
|
+
function useDashboardPrometheusTimeRange() {
|
|
24
|
+
const { timeRange: { start, end }, } = (0, plugin_system_1.useTimeRange)();
|
|
25
|
+
// Only recalculate the time range if the value on the dashboard changes
|
|
26
|
+
return (0, core_1.useMemoized)(() => {
|
|
27
|
+
return {
|
|
28
|
+
start: Math.ceil((0, date_fns_1.getUnixTime)(start)),
|
|
29
|
+
end: Math.ceil((0, date_fns_1.getUnixTime)(end)),
|
|
30
|
+
};
|
|
31
|
+
}, [start, end]);
|
|
32
|
+
}
|
|
33
|
+
exports.useDashboardPrometheusTimeRange = useDashboardPrometheusTimeRange;
|
|
34
|
+
// Max data points to allow returning from a Prom Query, used to calculate a
|
|
35
|
+
// "safe" step for a range query
|
|
36
|
+
const MAX_PROM_DATA_POINTS = 10000;
|
|
37
|
+
/**
|
|
38
|
+
* Gets the step to use for a Panel range query. Tries to take into account
|
|
39
|
+
* the width of the panel, any minimum step/resolution set by the user, and
|
|
40
|
+
* a "safe" step based on the max data points we want to allow returning from
|
|
41
|
+
* a Prom query.
|
|
42
|
+
*/
|
|
43
|
+
function usePanelRangeStep(timeRange, minStepSeconds = 15, resolution = 1, suggestedStepMs = 0) {
|
|
44
|
+
// Keep track of the latest suggested step so we don't re-run the query if it changes
|
|
45
|
+
const latestSuggestedStep = (0, react_1.useRef)(suggestedStepMs * 1000);
|
|
46
|
+
latestSuggestedStep.current = suggestedStepMs * 1000;
|
|
47
|
+
// Whenever the time range changes, recalculate the appropriate step
|
|
48
|
+
return (0, core_1.useMemoized)(() => {
|
|
49
|
+
const queryRangeSeconds = timeRange.end - timeRange.start;
|
|
50
|
+
let safeStep = queryRangeSeconds / MAX_PROM_DATA_POINTS;
|
|
51
|
+
if (safeStep > 1) {
|
|
52
|
+
safeStep = Math.ceil(safeStep);
|
|
53
|
+
}
|
|
54
|
+
return Math.max(latestSuggestedStep.current * resolution, minStepSeconds, safeStep);
|
|
55
|
+
}, [timeRange, minStepSeconds, resolution]);
|
|
56
|
+
}
|
|
57
|
+
exports.usePanelRangeStep = usePanelRangeStep;
|
|
58
|
+
/**
|
|
59
|
+
* Converts a DurationString to seconds, rounding down.
|
|
60
|
+
*/
|
|
61
|
+
function getDurationStringSeconds(durationString) {
|
|
62
|
+
if (durationString === undefined)
|
|
63
|
+
return undefined;
|
|
64
|
+
const duration = (0, core_1.parseDurationString)(durationString);
|
|
65
|
+
const ms = (0, date_fns_1.milliseconds)(duration);
|
|
66
|
+
return Math.floor(ms / 1000);
|
|
67
|
+
}
|
|
68
|
+
exports.getDurationStringSeconds = getDurationStringSeconds;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.usePrometheusGraphQuery = exports.PrometheusGraphQueryKind = void 0;
|
|
16
|
+
const core_1 = require("@perses-dev/core");
|
|
17
|
+
const date_fns_1 = require("date-fns");
|
|
18
|
+
const react_1 = require("react");
|
|
19
|
+
const parse_sample_values_1 = require("../model/parse-sample-values");
|
|
20
|
+
const prometheus_client_1 = require("../model/prometheus-client");
|
|
21
|
+
const templating_1 = require("../model/templating");
|
|
22
|
+
const time_1 = require("../model/time");
|
|
23
|
+
exports.PrometheusGraphQueryKind = 'PrometheusGraphQuery';
|
|
24
|
+
function usePrometheusGraphQuery(definition, hookOptions) {
|
|
25
|
+
const minStep = (0, time_1.getDurationStringSeconds)(definition.options.min_step);
|
|
26
|
+
const timeRange = (0, time_1.useDashboardPrometheusTimeRange)();
|
|
27
|
+
const step = (0, time_1.usePanelRangeStep)(timeRange, minStep, undefined, hookOptions === null || hookOptions === void 0 ? void 0 : hookOptions.suggestedStepMs);
|
|
28
|
+
// Align the time range so that it's a multiple of the step (TODO: we may
|
|
29
|
+
// ultimately want to return this from the hook so that charts will know what
|
|
30
|
+
// time range was actually used?)
|
|
31
|
+
const { start, end } = (0, core_1.useMemoized)(() => {
|
|
32
|
+
const { start, end } = timeRange;
|
|
33
|
+
const utcOffsetSec = new Date().getTimezoneOffset() * 60;
|
|
34
|
+
const alignedEnd = Math.floor((end + utcOffsetSec) / step) * step - utcOffsetSec;
|
|
35
|
+
const alignedStart = Math.floor((start + utcOffsetSec) / step) * step - utcOffsetSec;
|
|
36
|
+
return {
|
|
37
|
+
start: alignedStart,
|
|
38
|
+
end: alignedEnd,
|
|
39
|
+
};
|
|
40
|
+
}, [timeRange, step]);
|
|
41
|
+
const { result: query, needsVariableValuesFor } = (0, templating_1.useReplaceTemplateString)(definition.options.query);
|
|
42
|
+
const request = {
|
|
43
|
+
query,
|
|
44
|
+
start,
|
|
45
|
+
end,
|
|
46
|
+
step,
|
|
47
|
+
};
|
|
48
|
+
const { data: response, isLoading: loading, error, } = (0, prometheus_client_1.useRangeQuery)(request, {
|
|
49
|
+
enabled: needsVariableValuesFor.size === 0,
|
|
50
|
+
});
|
|
51
|
+
const data = (0, react_1.useMemo)(() => {
|
|
52
|
+
if (response === undefined)
|
|
53
|
+
return undefined;
|
|
54
|
+
if (response.status === 'error')
|
|
55
|
+
return undefined;
|
|
56
|
+
// TODO: Maybe do a proper Iterable implementation that defers some of this
|
|
57
|
+
// processing until its needed
|
|
58
|
+
const chartData = {
|
|
59
|
+
timeRange: { start: (0, date_fns_1.fromUnixTime)(start), end: (0, date_fns_1.fromUnixTime)(end) },
|
|
60
|
+
stepMs: step * 1000,
|
|
61
|
+
series: response.data.result.map((value) => {
|
|
62
|
+
const { metric, values } = value;
|
|
63
|
+
// Name the series after the metric labels or if no metric, just use the
|
|
64
|
+
// overall query
|
|
65
|
+
let name = Object.entries(metric)
|
|
66
|
+
.map(([labelName, labelValue]) => `${labelName}="${labelValue}"`)
|
|
67
|
+
.join(', ');
|
|
68
|
+
if (name === '')
|
|
69
|
+
name = query;
|
|
70
|
+
return {
|
|
71
|
+
name,
|
|
72
|
+
values: values.map(parse_sample_values_1.parseValueTuple),
|
|
73
|
+
};
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
return chartData;
|
|
77
|
+
}, [response, start, end, step, query]);
|
|
78
|
+
return { data, loading, error: error !== null && error !== void 0 ? error : undefined };
|
|
79
|
+
}
|
|
80
|
+
exports.usePrometheusGraphQuery = usePrometheusGraphQuery;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useIntervalValues = exports.IntervalKind = void 0;
|
|
16
|
+
exports.IntervalKind = 'Inverval';
|
|
17
|
+
/**
|
|
18
|
+
* Variable plugin for getting a list of variable options from a predefined
|
|
19
|
+
* list of duration values.
|
|
20
|
+
*/
|
|
21
|
+
function useIntervalValues(definition) {
|
|
22
|
+
// TODO: What about auto?
|
|
23
|
+
const { options: { values }, } = definition;
|
|
24
|
+
return { loading: false, error: undefined, data: values };
|
|
25
|
+
}
|
|
26
|
+
exports.useIntervalValues = useIntervalValues;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.usePrometheusLabelNames = exports.PrometheusLabelNamesKind = void 0;
|
|
16
|
+
const templating_1 = require("../model/templating");
|
|
17
|
+
const time_1 = require("../model/time");
|
|
18
|
+
const prometheus_client_1 = require("../model/prometheus-client");
|
|
19
|
+
exports.PrometheusLabelNamesKind = 'PrometheusLabelNames';
|
|
20
|
+
/**
|
|
21
|
+
* Get variable option values by running a Prometheus label names query.
|
|
22
|
+
*/
|
|
23
|
+
function usePrometheusLabelNames(definition) {
|
|
24
|
+
var _a;
|
|
25
|
+
const { start, end } = (0, time_1.useDashboardPrometheusTimeRange)();
|
|
26
|
+
const { result: match, needsVariableValuesFor } = (0, templating_1.useReplaceTemplateStrings)(definition.options.match);
|
|
27
|
+
// Make the request, pausing any requests that are still waiting on variable
|
|
28
|
+
// values to be filled in/selected
|
|
29
|
+
const request = {
|
|
30
|
+
'match[]': match,
|
|
31
|
+
start,
|
|
32
|
+
end,
|
|
33
|
+
};
|
|
34
|
+
const { data: response, isLoading: loading, error, } = (0, prometheus_client_1.useLabelNames)(request, {
|
|
35
|
+
enabled: needsVariableValuesFor.size === 0,
|
|
36
|
+
});
|
|
37
|
+
const data = (_a = response === null || response === void 0 ? void 0 : response.data) !== null && _a !== void 0 ? _a : [];
|
|
38
|
+
return {
|
|
39
|
+
data: data,
|
|
40
|
+
loading: loading || needsVariableValuesFor.size > 0,
|
|
41
|
+
error: error !== null && error !== void 0 ? error : undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.usePrometheusLabelNames = usePrometheusLabelNames;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2021 The Perses Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.usePrometheusLabelValues = exports.PrometheusLabelValuesKind = void 0;
|
|
16
|
+
const core_1 = require("@perses-dev/core");
|
|
17
|
+
const time_1 = require("../model/time");
|
|
18
|
+
const templating_1 = require("../model/templating");
|
|
19
|
+
const prometheus_client_1 = require("../model/prometheus-client");
|
|
20
|
+
exports.PrometheusLabelValuesKind = 'PrometheusLabelValues';
|
|
21
|
+
/**
|
|
22
|
+
* Get variable option values by running a Prometheus label values query.
|
|
23
|
+
*/
|
|
24
|
+
function usePrometheusLabelValues(definition) {
|
|
25
|
+
const { start, end } = (0, time_1.useDashboardPrometheusTimeRange)();
|
|
26
|
+
const { result: match, needsVariableValuesFor } = (0, templating_1.useReplaceTemplateStrings)(definition.options.match);
|
|
27
|
+
// Make the request, pausing any requests that are still waiting on variable
|
|
28
|
+
// values to be filled in/selected
|
|
29
|
+
const request = {
|
|
30
|
+
labelName: definition.options.label_name,
|
|
31
|
+
'match[]': match,
|
|
32
|
+
start,
|
|
33
|
+
end,
|
|
34
|
+
};
|
|
35
|
+
const { data: response, isLoading: loading, error, } = (0, prometheus_client_1.useLabelValues)(request, {
|
|
36
|
+
enabled: needsVariableValuesFor.size === 0,
|
|
37
|
+
});
|
|
38
|
+
const data = (0, core_1.useMemoized)(() => { var _a; return (_a = response === null || response === void 0 ? void 0 : response.data) !== null && _a !== void 0 ? _a : []; }, [response]);
|
|
39
|
+
return {
|
|
40
|
+
data: data,
|
|
41
|
+
loading: loading || needsVariableValuesFor.size > 0,
|
|
42
|
+
error: error !== null && error !== void 0 ? error : undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
exports.usePrometheusLabelValues = usePrometheusLabelValues;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perses-dev/prometheus-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Prometheus plugin for Perses",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/perses/perses/blob/main/README.md",
|
|
@@ -12,27 +12,26 @@
|
|
|
12
12
|
"url": "https://github.com/perses/perses/issues"
|
|
13
13
|
},
|
|
14
14
|
"module": "dist/index.js",
|
|
15
|
+
"main": "dist/cjs/index.js",
|
|
15
16
|
"types": "dist/index.d.ts",
|
|
16
17
|
"scripts": {
|
|
17
18
|
"clean": "rimraf dist/",
|
|
18
|
-
"build": "tsc",
|
|
19
|
+
"build": "tsc --build",
|
|
20
|
+
"build:cjs": "tsc --project ./tsconfig.cjs.json",
|
|
19
21
|
"test": "echo 'no test to run' && exit 0",
|
|
20
22
|
"lint": "eslint src --ext .ts,.tsx",
|
|
21
23
|
"lint:fix": "eslint --fix src --ext .ts,.tsx"
|
|
22
24
|
},
|
|
23
25
|
"dependencies": {
|
|
24
26
|
"@lezer/lr": "^0.15.8",
|
|
25
|
-
"@perses-dev/core": "^0.
|
|
26
|
-
"@perses-dev/plugin-system": "^0.
|
|
27
|
+
"@perses-dev/core": "^0.4.0",
|
|
28
|
+
"@perses-dev/plugin-system": "^0.4.0",
|
|
27
29
|
"date-fns": "^2.28.0",
|
|
28
|
-
"lezer-promql": "^0.22.0"
|
|
29
|
-
"react-query": "^3.34.16"
|
|
30
|
-
},
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"react": "^17.0.2"
|
|
30
|
+
"lezer-promql": "^0.22.0"
|
|
33
31
|
},
|
|
34
32
|
"peerDependencies": {
|
|
35
|
-
"react": "^17.0.2"
|
|
33
|
+
"react": "^17.0.2",
|
|
34
|
+
"react-query": "^3.34.16"
|
|
36
35
|
},
|
|
37
36
|
"perses": {
|
|
38
37
|
"kind": "Plugin",
|