mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 17:43:35 -06:00
Loki: Use fixed bucket size for logs volume (#40873)
* Use fixed bucket size for logs volume * Fix unit tests
This commit is contained in:
parent
fbd68c4e96
commit
877c726246
@ -60,7 +60,7 @@ export function LogsVolumePanel(props: Props) {
|
|||||||
if (zoomRatio !== undefined && zoomRatio < 1) {
|
if (zoomRatio !== undefined && zoomRatio < 1) {
|
||||||
zoomLevelInfo = (
|
zoomLevelInfo = (
|
||||||
<>
|
<>
|
||||||
<span className={styles.zoomInfo}>Reload to show higher resolution</span>
|
<span className={styles.zoomInfo}>Reload logs volume</span>
|
||||||
<Button size="xs" icon="sync" variant="secondary" onClick={onLoadLogsVolume} />
|
<Button size="xs" icon="sync" variant="secondary" onClick={onLoadLogsVolume} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -40,6 +40,11 @@ describe('LokiLogsVolumeProvider', () => {
|
|||||||
request = ({
|
request = ({
|
||||||
targets: [{ expr: '{app="app01"}' }, { expr: '{app="app02"}' }],
|
targets: [{ expr: '{app="app01"}' }, { expr: '{app="app02"}' }],
|
||||||
range: { from: 0, to: 1 },
|
range: { from: 0, to: 1 },
|
||||||
|
scopedVars: {
|
||||||
|
__interval_ms: {
|
||||||
|
value: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
} as unknown) as DataQueryRequest<LokiQuery>;
|
} as unknown) as DataQueryRequest<LokiQuery>;
|
||||||
volumeProvider = createLokiLogsVolumeProvider((datasource as unknown) as LokiDatasource, request);
|
volumeProvider = createLokiLogsVolumeProvider((datasource as unknown) as LokiDatasource, request);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
LoadingState,
|
LoadingState,
|
||||||
LogLevel,
|
LogLevel,
|
||||||
MutableDataFrame,
|
MutableDataFrame,
|
||||||
|
ScopedVars,
|
||||||
toDataFrame,
|
toDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { LokiQuery } from '../types';
|
import { LokiQuery } from '../types';
|
||||||
@ -20,26 +21,36 @@ import LokiDatasource, { isMetricsQuery } from '../datasource';
|
|||||||
import { LogLevelColor } from '../../../../core/logs_model';
|
import { LogLevelColor } from '../../../../core/logs_model';
|
||||||
import { BarAlignment, GraphDrawStyle, StackingMode } from '@grafana/schema';
|
import { BarAlignment, GraphDrawStyle, StackingMode } from '@grafana/schema';
|
||||||
|
|
||||||
|
const SECOND = 1000;
|
||||||
|
const MINUTE = 60 * SECOND;
|
||||||
|
const HOUR = 60 * MINUTE;
|
||||||
|
const DAY = 24 * HOUR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs volume query may be expensive as it requires counting all logs in the selected range. If such query
|
* Logs volume query may be expensive as it requires counting all logs in the selected range. If such query
|
||||||
* takes too much time it may need be made more specific to limit number of logs processed under the hood.
|
* takes too much time it may need be made more specific to limit number of logs processed under the hood.
|
||||||
*/
|
*/
|
||||||
const TIMEOUT = 10000;
|
const TIMEOUT = 10 * SECOND;
|
||||||
|
|
||||||
export function createLokiLogsVolumeProvider(
|
export function createLokiLogsVolumeProvider(
|
||||||
datasource: LokiDatasource,
|
datasource: LokiDatasource,
|
||||||
dataQueryRequest: DataQueryRequest<LokiQuery>
|
dataQueryRequest: DataQueryRequest<LokiQuery>
|
||||||
): Observable<DataQueryResponse> {
|
): Observable<DataQueryResponse> {
|
||||||
const logsVolumeRequest = cloneDeep(dataQueryRequest);
|
const logsVolumeRequest = cloneDeep(dataQueryRequest);
|
||||||
|
const intervalInfo = getIntervalInfo(dataQueryRequest.scopedVars);
|
||||||
logsVolumeRequest.targets = logsVolumeRequest.targets
|
logsVolumeRequest.targets = logsVolumeRequest.targets
|
||||||
.filter((target) => target.expr && !isMetricsQuery(target.expr))
|
.filter((target) => target.expr && !isMetricsQuery(target.expr))
|
||||||
.map((target) => {
|
.map((target) => {
|
||||||
return {
|
return {
|
||||||
...target,
|
...target,
|
||||||
instant: false,
|
instant: false,
|
||||||
expr: `sum by (level) (count_over_time(${target.expr}[$__interval]))`,
|
expr: `sum by (level) (count_over_time(${target.expr}[${intervalInfo.interval}]))`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
logsVolumeRequest.interval = intervalInfo.interval;
|
||||||
|
if (intervalInfo.intervalMs !== undefined) {
|
||||||
|
logsVolumeRequest.intervalMs = intervalInfo.intervalMs;
|
||||||
|
}
|
||||||
|
|
||||||
return new Observable((observer) => {
|
return new Observable((observer) => {
|
||||||
let rawLogsVolume: DataFrame[] = [];
|
let rawLogsVolume: DataFrame[] = [];
|
||||||
@ -54,7 +65,12 @@ export function createLokiLogsVolumeProvider(
|
|||||||
.pipe(
|
.pipe(
|
||||||
timeout({
|
timeout({
|
||||||
each: TIMEOUT,
|
each: TIMEOUT,
|
||||||
with: () => throwError(new Error('Request timed-out. Please make your query more specific and try again.')),
|
with: () =>
|
||||||
|
throwError(
|
||||||
|
new Error(
|
||||||
|
'Request timed-out. Please try making your query more specific or narrow selected time range and try again.'
|
||||||
|
)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
@ -133,8 +149,6 @@ function getFieldConfig(level: LogLevel, levels: number) {
|
|||||||
custom: {
|
custom: {
|
||||||
drawStyle: GraphDrawStyle.Bars,
|
drawStyle: GraphDrawStyle.Bars,
|
||||||
barAlignment: BarAlignment.Center,
|
barAlignment: BarAlignment.Center,
|
||||||
barWidthFactor: 0.9,
|
|
||||||
barMaxWidth: 5,
|
|
||||||
lineColor: color,
|
lineColor: color,
|
||||||
pointColor: color,
|
pointColor: color,
|
||||||
fillColor: color,
|
fillColor: color,
|
||||||
@ -196,3 +210,27 @@ function getLogLevelFromLabels(labels: Labels): LogLevel {
|
|||||||
}
|
}
|
||||||
return levelLabel ? getLogLevelFromKey(labels[levelLabel]) : LogLevel.unknown;
|
return levelLabel ? getLogLevelFromKey(labels[levelLabel]) : LogLevel.unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIntervalInfo(scopedVars: ScopedVars): { interval: string; intervalMs?: number } {
|
||||||
|
if (scopedVars.__interval) {
|
||||||
|
let intervalMs: number = scopedVars.__interval_ms.value;
|
||||||
|
let interval = '';
|
||||||
|
if (intervalMs > HOUR) {
|
||||||
|
intervalMs = DAY;
|
||||||
|
interval = '1d';
|
||||||
|
} else if (intervalMs > MINUTE) {
|
||||||
|
intervalMs = HOUR;
|
||||||
|
interval = '1h';
|
||||||
|
} else if (intervalMs > SECOND) {
|
||||||
|
intervalMs = MINUTE;
|
||||||
|
interval = '1m';
|
||||||
|
} else {
|
||||||
|
intervalMs = SECOND;
|
||||||
|
interval = '1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
return { interval, intervalMs };
|
||||||
|
} else {
|
||||||
|
return { interval: '$__interval' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user