2020-11-19 11:33:52 +01:00
|
|
|
import {
|
2021-09-30 15:46:11 +02:00
|
|
|
AbsoluteTimeRange,
|
2021-01-07 11:26:56 +01:00
|
|
|
DataSourceApi,
|
2020-11-19 11:33:52 +01:00
|
|
|
EventBusExtended,
|
2021-01-07 11:26:56 +01:00
|
|
|
getDefaultTimeRange,
|
|
|
|
|
HistoryItem,
|
2020-11-19 11:33:52 +01:00
|
|
|
LoadingState,
|
2023-04-20 05:21:28 -03:00
|
|
|
LogRowModel,
|
2020-11-19 11:33:52 +01:00
|
|
|
PanelData,
|
2023-06-06 15:31:39 +01:00
|
|
|
RawTimeRange,
|
|
|
|
|
TimeFragment,
|
|
|
|
|
TimeRange,
|
|
|
|
|
dateMath,
|
|
|
|
|
DateTime,
|
|
|
|
|
isDateTime,
|
|
|
|
|
toUtc,
|
2020-11-19 11:33:52 +01:00
|
|
|
} from '@grafana/data';
|
2023-06-06 15:31:39 +01:00
|
|
|
import { DataSourceRef, TimeZone } from '@grafana/schema';
|
2022-03-03 08:54:06 +00:00
|
|
|
import { ExplorePanelData } from 'app/types';
|
2023-01-20 14:20:49 +01:00
|
|
|
import { ExploreItemState } from 'app/types/explore';
|
2022-04-22 14:33:13 +01:00
|
|
|
|
2020-11-19 11:33:52 +01:00
|
|
|
import store from '../../../core/store';
|
2023-06-06 15:31:39 +01:00
|
|
|
import { setLastUsedDatasourceUID } from '../../../core/utils/explore';
|
2022-04-22 14:33:13 +01:00
|
|
|
import { getDatasourceSrv } from '../../plugins/datasource_srv';
|
2023-01-20 14:20:49 +01:00
|
|
|
import { loadSupplementaryQueries } from '../utils/supplementaryQueries';
|
2020-11-09 14:48:24 +01:00
|
|
|
|
|
|
|
|
export const DEFAULT_RANGE = {
|
|
|
|
|
from: 'now-6h',
|
|
|
|
|
to: 'now',
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-26 15:51:59 +02:00
|
|
|
const GRAPH_STYLE_KEY = 'grafana.explore.style.graph';
|
|
|
|
|
export const storeGraphStyle = (graphStyle: string): void => {
|
|
|
|
|
store.set(GRAPH_STYLE_KEY, graphStyle);
|
|
|
|
|
};
|
|
|
|
|
|
2020-11-09 14:48:24 +01:00
|
|
|
/**
|
|
|
|
|
* Returns a fresh Explore area state
|
|
|
|
|
*/
|
|
|
|
|
export const makeExplorePaneState = (): ExploreItemState => ({
|
|
|
|
|
containerWidth: 0,
|
|
|
|
|
datasourceInstance: null,
|
|
|
|
|
history: [],
|
|
|
|
|
queries: [],
|
|
|
|
|
initialized: false,
|
|
|
|
|
range: {
|
|
|
|
|
from: null,
|
|
|
|
|
to: null,
|
|
|
|
|
raw: DEFAULT_RANGE,
|
|
|
|
|
} as any,
|
|
|
|
|
absoluteRange: {
|
|
|
|
|
from: null,
|
|
|
|
|
to: null,
|
|
|
|
|
} as any,
|
|
|
|
|
scanning: false,
|
|
|
|
|
loading: false,
|
|
|
|
|
queryKeys: [],
|
|
|
|
|
isLive: false,
|
|
|
|
|
isPaused: false,
|
|
|
|
|
queryResponse: createEmptyQueryResponse(),
|
|
|
|
|
tableResult: null,
|
|
|
|
|
graphResult: null,
|
|
|
|
|
logsResult: null,
|
2023-04-20 05:21:28 -03:00
|
|
|
clearedAtIndex: null,
|
2023-01-04 10:46:03 -06:00
|
|
|
rawPrometheusResult: null,
|
2022-02-02 12:02:32 +00:00
|
|
|
eventBridge: null as unknown as EventBusExtended,
|
2021-05-24 13:56:48 +02:00
|
|
|
cache: [],
|
2022-04-06 13:49:25 +02:00
|
|
|
richHistory: [],
|
2023-01-09 18:33:48 +01:00
|
|
|
supplementaryQueries: loadSupplementaryQueries(),
|
2022-01-24 10:49:35 -05:00
|
|
|
panelsState: {},
|
2020-11-09 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
|
2022-03-03 08:54:06 +00:00
|
|
|
export const createEmptyQueryResponse = (): ExplorePanelData => ({
|
2020-11-09 14:48:24 +01:00
|
|
|
state: LoadingState.NotStarted,
|
|
|
|
|
series: [],
|
2021-01-07 11:26:56 +01:00
|
|
|
timeRange: getDefaultTimeRange(),
|
2022-03-03 08:54:06 +00:00
|
|
|
graphFrames: [],
|
|
|
|
|
logsFrames: [],
|
|
|
|
|
traceFrames: [],
|
|
|
|
|
nodeGraphFrames: [],
|
2022-10-07 11:39:14 +01:00
|
|
|
flameGraphFrames: [],
|
2022-03-03 08:54:06 +00:00
|
|
|
tableFrames: [],
|
2023-01-04 10:46:03 -06:00
|
|
|
rawPrometheusFrames: [],
|
|
|
|
|
rawPrometheusResult: null,
|
2022-03-03 08:54:06 +00:00
|
|
|
graphResult: null,
|
|
|
|
|
logsResult: null,
|
|
|
|
|
tableResult: null,
|
2020-11-09 14:48:24 +01:00
|
|
|
});
|
2020-11-19 11:33:52 +01:00
|
|
|
|
|
|
|
|
export async function loadAndInitDatasource(
|
|
|
|
|
orgId: number,
|
2022-07-25 13:05:57 -05:00
|
|
|
datasource: DataSourceRef | string
|
2020-11-19 11:33:52 +01:00
|
|
|
): Promise<{ history: HistoryItem[]; instance: DataSourceApi }> {
|
2021-04-16 08:32:33 +02:00
|
|
|
let instance;
|
|
|
|
|
try {
|
2022-07-25 13:05:57 -05:00
|
|
|
// let datasource be a ref if we have the info, otherwise a name or uid will do for lookup
|
|
|
|
|
instance = await getDatasourceSrv().get(datasource);
|
2021-04-16 08:32:33 +02:00
|
|
|
} catch (error) {
|
|
|
|
|
// Falling back to the default data source in case the provided data source was not found.
|
|
|
|
|
// It may happen if last used data source or the data source provided in the URL has been
|
|
|
|
|
// removed or it is not provisioned anymore.
|
|
|
|
|
instance = await getDatasourceSrv().get();
|
|
|
|
|
}
|
2020-11-19 11:33:52 +01:00
|
|
|
if (instance.init) {
|
|
|
|
|
try {
|
|
|
|
|
instance.init();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// TODO: should probably be handled better
|
|
|
|
|
console.error(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const historyKey = `grafana.explore.history.${instance.meta?.id}`;
|
2022-03-02 14:02:09 +00:00
|
|
|
const history = store.getObject<HistoryItem[]>(historyKey, []);
|
2020-11-19 11:33:52 +01:00
|
|
|
// Save last-used datasource
|
|
|
|
|
|
2023-06-06 15:31:39 +01:00
|
|
|
setLastUsedDatasourceUID(orgId, instance.uid);
|
2020-11-19 11:33:52 +01:00
|
|
|
return { history, instance };
|
|
|
|
|
}
|
2021-02-12 21:33:26 +01:00
|
|
|
|
2021-05-24 13:56:48 +02:00
|
|
|
export function createCacheKey(absRange: AbsoluteTimeRange) {
|
|
|
|
|
const params = {
|
|
|
|
|
from: absRange.from,
|
|
|
|
|
to: absRange.to,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const cacheKey = Object.entries(params)
|
|
|
|
|
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v.toString())}`)
|
|
|
|
|
.join('&');
|
|
|
|
|
return cacheKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getResultsFromCache(
|
|
|
|
|
cache: Array<{ key: string; value: PanelData }>,
|
|
|
|
|
absoluteRange: AbsoluteTimeRange
|
|
|
|
|
): PanelData | undefined {
|
|
|
|
|
const cacheKey = createCacheKey(absoluteRange);
|
|
|
|
|
const cacheIdx = cache.findIndex((c) => c.key === cacheKey);
|
|
|
|
|
const cacheValue = cacheIdx >= 0 ? cache[cacheIdx].value : undefined;
|
|
|
|
|
return cacheValue;
|
|
|
|
|
}
|
2023-04-20 05:21:28 -03:00
|
|
|
|
2023-06-06 15:31:39 +01:00
|
|
|
export function getRange(range: RawTimeRange, timeZone: TimeZone): TimeRange {
|
|
|
|
|
const raw = {
|
|
|
|
|
from: parseRawTime(range.from)!,
|
|
|
|
|
to: parseRawTime(range.to)!,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
from: dateMath.parse(raw.from, false, timeZone)!,
|
|
|
|
|
to: dateMath.parse(raw.to, true, timeZone)!,
|
|
|
|
|
raw,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseRawTime(value: string | DateTime): TimeFragment | null {
|
|
|
|
|
if (value === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isDateTime(value)) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value.indexOf('now') !== -1) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
if (value.length === 8) {
|
|
|
|
|
return toUtc(value, 'YYYYMMDD');
|
|
|
|
|
}
|
|
|
|
|
if (value.length === 15) {
|
|
|
|
|
return toUtc(value, 'YYYYMMDDTHHmmss');
|
|
|
|
|
}
|
|
|
|
|
// Backward compatibility
|
|
|
|
|
if (value.length === 19) {
|
|
|
|
|
return toUtc(value, 'YYYY-MM-DD HH:mm:ss');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This should handle cases where value is an epoch time as string
|
|
|
|
|
if (value.match(/^\d+$/)) {
|
|
|
|
|
const epoch = parseInt(value, 10);
|
|
|
|
|
return toUtc(epoch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This should handle ISO strings
|
|
|
|
|
const time = toUtc(value);
|
|
|
|
|
if (time.isValid()) {
|
|
|
|
|
return time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 05:21:28 -03:00
|
|
|
export const filterLogRowsByIndex = (
|
|
|
|
|
clearedAtIndex: ExploreItemState['clearedAtIndex'],
|
|
|
|
|
logRows?: LogRowModel[]
|
|
|
|
|
): LogRowModel[] => {
|
|
|
|
|
if (!logRows) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clearedAtIndex) {
|
|
|
|
|
const filteredRows = logRows.slice(clearedAtIndex + 1);
|
|
|
|
|
return filteredRows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return logRows;
|
|
|
|
|
};
|