mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Calculate period based on time range (#21471)
* Calculate min period based on time range and no of queries * Use hardcoded array of periods if period is not defined actively by the user * Fix broken tests * Use a smaller max period for auto interval * Fix broken tests * Test period calculation * Test min retention period * Fix broken test
This commit is contained in:
@@ -165,14 +165,16 @@ export class QueryEditor extends PureComponent<Props, State> {
|
||||
<tr>
|
||||
<th>Metric Data Query ID</th>
|
||||
<th>Metric Data Query Expression</th>
|
||||
<th>Period</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.series[0].meta.gmdMeta.map(({ ID, Expression }: any) => (
|
||||
{data.series[0].meta.gmdMeta.map(({ ID, Expression, Period }: any) => (
|
||||
<tr key={ID}>
|
||||
<td>{ID}</td>
|
||||
<td>{Expression}</td>
|
||||
<td>{Period}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@@ -31,17 +31,15 @@ export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, varia
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{values.length !== stats.length && (
|
||||
<Segment
|
||||
Component={
|
||||
<a className="gf-form-label query-part">
|
||||
<i className="fa fa-plus" />
|
||||
</a>
|
||||
}
|
||||
allowCustomValue
|
||||
onChange={({ value }) => onChange([...values, value])}
|
||||
options={[...stats.filter(({ value }) => !values.includes(value)), variableOptionGroup]}
|
||||
/>
|
||||
)}
|
||||
<Segment
|
||||
Component={
|
||||
<a className="gf-form-label query-part">
|
||||
<i className="fa fa-plus" />
|
||||
</a>
|
||||
}
|
||||
allowCustomValue
|
||||
onChange={({ value }) => onChange([...values, value])}
|
||||
options={[...stats.filter(({ value }) => !values.includes(value)), variableOptionGroup]}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -125,52 +125,29 @@ export default class CloudWatchDatasource extends DataSourceApi<CloudWatchQuery,
|
||||
return this.templateSrv.variables.map(v => `$${v.name}`);
|
||||
}
|
||||
|
||||
getPeriod(target: any, options: any, now?: number) {
|
||||
const start = this.convertToCloudWatchTime(options.range.from, false);
|
||||
now = Math.round((now || Date.now()) / 1000);
|
||||
|
||||
let period;
|
||||
const hourSec = 60 * 60;
|
||||
const daySec = hourSec * 24;
|
||||
if (!target.period) {
|
||||
if (now - start <= daySec * 15) {
|
||||
// until 15 days ago
|
||||
if (target.namespace === 'AWS/EC2') {
|
||||
period = 300;
|
||||
} else {
|
||||
period = 60;
|
||||
}
|
||||
} else if (now - start <= daySec * 63) {
|
||||
// until 63 days ago
|
||||
period = 60 * 5;
|
||||
} else if (now - start <= daySec * 455) {
|
||||
// until 455 days ago
|
||||
period = 60 * 60;
|
||||
} else {
|
||||
// over 455 days, should return error, but try to long period
|
||||
period = 60 * 60;
|
||||
}
|
||||
} else {
|
||||
period = this.templateSrv.replace(target.period, options.scopedVars);
|
||||
getPeriod(target: any, options: any) {
|
||||
let period = this.templateSrv.replace(target.period, options.scopedVars);
|
||||
if (period && period.toLowerCase() !== 'auto') {
|
||||
if (/^\d+$/.test(period)) {
|
||||
period = parseInt(period, 10);
|
||||
} else {
|
||||
period = kbn.interval_to_seconds(period);
|
||||
}
|
||||
}
|
||||
if (period < 1) {
|
||||
period = 1;
|
||||
|
||||
if (period < 1) {
|
||||
period = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return period;
|
||||
}
|
||||
|
||||
buildCloudwatchConsoleUrl(
|
||||
{ region, namespace, metricName, dimensions, statistics, period, expression }: CloudWatchQuery,
|
||||
{ region, namespace, metricName, dimensions, statistics, expression }: CloudWatchQuery,
|
||||
start: string,
|
||||
end: string,
|
||||
title: string,
|
||||
gmdMeta: Array<{ Expression: string }>
|
||||
gmdMeta: Array<{ Expression: string; Period: string }>
|
||||
) {
|
||||
region = this.getActualRegion(region);
|
||||
let conf = {
|
||||
@@ -204,7 +181,7 @@ export default class CloudWatchDatasource extends DataSourceApi<CloudWatchQuery,
|
||||
...Object.entries(dimensions).reduce((acc, [key, value]) => [...acc, key, value[0]], []),
|
||||
{
|
||||
stat,
|
||||
period,
|
||||
period: gmdMeta.length ? gmdMeta[0].Period : 60,
|
||||
},
|
||||
]),
|
||||
],
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('CloudWatchDatasource', () => {
|
||||
A: {
|
||||
error: '',
|
||||
refId: 'A',
|
||||
meta: {},
|
||||
meta: { gmdMeta: [] },
|
||||
series: [
|
||||
{
|
||||
name: 'CPUUtilization_Average',
|
||||
@@ -181,7 +181,7 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
|
||||
it('should be built correctly if theres one search expressions returned in meta for a given query row', done => {
|
||||
response.results['A'].meta.gmdMeta = [{ Expression: `REMOVE_EMPTY(SEARCH('some expression'))` }];
|
||||
response.results['A'].meta.gmdMeta = [{ Expression: `REMOVE_EMPTY(SEARCH('some expression'))`, Period: '300' }];
|
||||
ctx.ds.query(query).then((result: any) => {
|
||||
expect(result.data[0].name).toBe(response.results.A.series[0].name);
|
||||
expect(result.data[0].fields[0].config.links[0].title).toBe('View in CloudWatch console');
|
||||
@@ -208,7 +208,7 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
|
||||
it('should be built correctly if the query is a metric stat query', done => {
|
||||
response.results['A'].meta.gmdMeta = [];
|
||||
response.results['A'].meta.gmdMeta = [{ Period: '300' }];
|
||||
ctx.ds.query(query).then((result: any) => {
|
||||
expect(result.data[0].name).toBe(response.results.A.series[0].name);
|
||||
expect(result.data[0].fields[0].config.links[0].title).toBe('View in CloudWatch console');
|
||||
@@ -415,7 +415,13 @@ describe('CloudWatchDatasource', () => {
|
||||
A: {
|
||||
error: '',
|
||||
refId: 'A',
|
||||
meta: {},
|
||||
meta: {
|
||||
gmdMeta: [
|
||||
{
|
||||
Period: 300,
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'TargetResponseTime_p90.00',
|
||||
@@ -789,97 +795,4 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('should caclculate the correct period', () => {
|
||||
const hourSec = 60 * 60;
|
||||
const daySec = hourSec * 24;
|
||||
const start = 1483196400 * 1000;
|
||||
const testData: any[] = [
|
||||
[
|
||||
{ period: '60s', namespace: 'AWS/EC2' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'AWS/EC2' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
300,
|
||||
],
|
||||
[
|
||||
{ period: '60s', namespace: 'AWS/ELB' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'AWS/ELB' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: '1', namespace: 'CustomMetricsNamespace' },
|
||||
{
|
||||
range: {
|
||||
from: new Date(start),
|
||||
to: new Date(start + (1440 - 1) * 1000),
|
||||
},
|
||||
},
|
||||
hourSec * 3 - 1,
|
||||
1,
|
||||
],
|
||||
[
|
||||
{ period: '1', namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3 - 1,
|
||||
1,
|
||||
],
|
||||
[
|
||||
{ period: '60s', namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3 - 1,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
hourSec * 3,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
daySec * 15,
|
||||
60,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
daySec * 63,
|
||||
300,
|
||||
],
|
||||
[
|
||||
{ period: null, namespace: 'CustomMetricsNamespace' },
|
||||
{ range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
|
||||
daySec * 455,
|
||||
3600,
|
||||
],
|
||||
];
|
||||
for (const t of testData) {
|
||||
const target = t[0];
|
||||
const options = t[1];
|
||||
const now = new Date(options.range.from.valueOf() + t[2] * 1000);
|
||||
const expected = t[3];
|
||||
const actual = ctx.ds.getPeriod(target, options, now);
|
||||
expect(actual).toBe(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user