mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Correlations: Expose correlations logic through correlations service (#98124)
* Correlations: Expose correlations logic through correlations service * Resolve remaining todos * Marked new items as @alpha
This commit is contained in:
parent
33a91f22c0
commit
e45eb95812
@ -57,3 +57,12 @@ export { hasPermission, hasPermissionInMetadata, hasAllPermissions, hasAnyPermis
|
||||
export { QueryEditorWithMigration } from './components/QueryEditorWithMigration';
|
||||
export { type MigrationHandler, isMigrationHandler, migrateQuery, migrateRequest } from './utils/migrationHandler';
|
||||
export { usePluginUserStorage } from './utils/userStorage';
|
||||
export {
|
||||
type CorrelationsService,
|
||||
type CorrelationData,
|
||||
type CorrelationsData,
|
||||
type CorrelationExternal,
|
||||
type CorrelationQuery,
|
||||
getCorrelationsService,
|
||||
setCorrelationsService,
|
||||
} from './services/CorrelationsService';
|
||||
|
126
packages/grafana-runtime/src/services/CorrelationsService.ts
Normal file
126
packages/grafana-runtime/src/services/CorrelationsService.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import {
|
||||
DataFrame,
|
||||
DataLinkPostProcessor,
|
||||
DataLinkTransformationConfig,
|
||||
DataSourceInstanceSettings,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
|
||||
export type CorrelationConfigQuery = {
|
||||
field: string;
|
||||
target: object; // for queries, this contains anything that would go in the query editor, so any extension off DataQuery a datasource would have, and needs to be generic.
|
||||
transformations?: DataLinkTransformationConfig[];
|
||||
};
|
||||
|
||||
export type CorrelationConfigExternal = {
|
||||
field: string;
|
||||
target: {
|
||||
url: string; // For external, this simply contains a URL
|
||||
};
|
||||
transformations?: DataLinkTransformationConfig[];
|
||||
};
|
||||
|
||||
type CorrelationBase = {
|
||||
uid: string;
|
||||
sourceUID: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
provisioned: boolean;
|
||||
orgId?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type CorrelationExternal = CorrelationBase & {
|
||||
type: 'external';
|
||||
config: CorrelationConfigExternal;
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type CorrelationQuery = CorrelationBase & {
|
||||
type: 'query';
|
||||
config: CorrelationConfigQuery;
|
||||
targetUID: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type CorrelationData =
|
||||
| (Omit<CorrelationExternal, 'sourceUID'> & {
|
||||
source: DataSourceInstanceSettings;
|
||||
})
|
||||
| (Omit<CorrelationQuery, 'sourceUID' | 'targetUID'> & {
|
||||
source: DataSourceInstanceSettings;
|
||||
target: DataSourceInstanceSettings;
|
||||
});
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface CorrelationsData {
|
||||
correlations: CorrelationData[];
|
||||
page: number;
|
||||
limit: number;
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to work with user defined correlations.
|
||||
* Should be accessed via {@link getCorrelationsService} function.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export interface CorrelationsService {
|
||||
/**
|
||||
* Creates data links in data frames from provided correlations
|
||||
*
|
||||
* @param dataFrames list of data frames to be processed
|
||||
* @param correlations list of of possible correlations that can be applied
|
||||
* @param dataFrameRefIdToDataSourceUid a map that for provided refId references corresponding data source ui
|
||||
*/
|
||||
attachCorrelationsToDataFrames: (
|
||||
dataFrames: DataFrame[],
|
||||
correlations: CorrelationData[],
|
||||
dataFrameRefIdToDataSourceUid: Record<string, string>
|
||||
) => DataFrame[];
|
||||
|
||||
/**
|
||||
* Creates a link post processor function that handles correlation transformations
|
||||
*
|
||||
* @param timeRange The current time range
|
||||
*/
|
||||
correlationsDataLinkPostProcessorFactory: (timeRange: TimeRange) => DataLinkPostProcessor;
|
||||
|
||||
/**
|
||||
* Loads all the correlations defined for the given data sources.
|
||||
*
|
||||
* @param sourceUIDs Data source UIDs
|
||||
*/
|
||||
getCorrelationsBySourceUIDs: (sourceUIDs: string[]) => Promise<CorrelationsData>;
|
||||
}
|
||||
|
||||
let singletonInstance: CorrelationsService;
|
||||
|
||||
/**
|
||||
* Used during startup by Grafana to set the CorrelationsService so it is available
|
||||
* via {@link getCorrelationsService} to the rest of the application.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function setCorrelationsService(instance: CorrelationsService) {
|
||||
console.log('setCorrelationsService', instance);
|
||||
singletonInstance = instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to retrieve the {@link CorrelationsService}.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export function getCorrelationsService(): CorrelationsService {
|
||||
return singletonInstance;
|
||||
}
|
@ -40,6 +40,7 @@ import {
|
||||
setCurrentUser,
|
||||
setChromeHeaderHeightHook,
|
||||
setPluginLinksHook,
|
||||
setCorrelationsService,
|
||||
} from '@grafana/runtime';
|
||||
import { setPanelDataErrorView } from '@grafana/runtime/src/components/PanelDataErrorView';
|
||||
import { setPanelRenderer } from '@grafana/runtime/src/components/PanelRenderer';
|
||||
@ -60,6 +61,7 @@ import { initializeCrashDetection } from './core/crash';
|
||||
import { initializeI18n } from './core/internationalization';
|
||||
import { setMonacoEnv } from './core/monacoEnv';
|
||||
import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
|
||||
import { CorrelationsService } from './core/services/CorrelationsService';
|
||||
import { NewFrontendAssetsChecker } from './core/services/NewFrontendAssetsChecker';
|
||||
import { backendSrv } from './core/services/backend_srv';
|
||||
import { contextSrv, RedirectToUrlKey } from './core/services/context_srv';
|
||||
@ -146,6 +148,7 @@ export class GrafanaApp {
|
||||
setPluginPage(PluginPage);
|
||||
setPanelDataErrorView(PanelDataErrorView);
|
||||
setLocationSrv(locationService);
|
||||
setCorrelationsService(new CorrelationsService());
|
||||
setEmbeddedDashboard(EmbeddedDashboardLazy);
|
||||
setTimeZoneResolver(() => config.bootData.user.timezone);
|
||||
initGrafanaLive();
|
||||
|
22
public/app/core/services/CorrelationsService.ts
Normal file
22
public/app/core/services/CorrelationsService.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { DataFrame, TimeRange } from '@grafana/data';
|
||||
import type { CorrelationData, CorrelationsService as CorrelationsServiceInterface } from '@grafana/runtime';
|
||||
import { attachCorrelationsToDataFrames, getCorrelationsBySourceUIDs } from 'app/features/correlations/utils';
|
||||
import { exploreDataLinkPostProcessorFactory } from 'app/features/explore/utils/links';
|
||||
|
||||
export class CorrelationsService implements CorrelationsServiceInterface {
|
||||
attachCorrelationsToDataFrames(
|
||||
dataFrames: DataFrame[],
|
||||
correlations: CorrelationData[],
|
||||
dataFrameRefIdToDataSourceUid: Record<string, string>
|
||||
) {
|
||||
return attachCorrelationsToDataFrames(dataFrames, correlations, dataFrameRefIdToDataSourceUid);
|
||||
}
|
||||
|
||||
correlationsDataLinkPostProcessorFactory(timeRange: TimeRange) {
|
||||
return exploreDataLinkPostProcessorFactory(undefined, timeRange);
|
||||
}
|
||||
|
||||
getCorrelationsBySourceUIDs(sourceUIDs: string[]) {
|
||||
return getCorrelationsBySourceUIDs(sourceUIDs);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import { negate } from 'lodash';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
|
||||
import { isFetchError, reportInteraction } from '@grafana/runtime';
|
||||
import { CorrelationData, isFetchError, reportInteraction } from '@grafana/runtime';
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@ -28,7 +28,7 @@ import { AddCorrelationForm } from './Forms/AddCorrelationForm';
|
||||
import { EditCorrelationForm } from './Forms/EditCorrelationForm';
|
||||
import { EmptyCorrelationsCTA } from './components/EmptyCorrelationsCTA';
|
||||
import type { Correlation, RemoveCorrelationParams } from './types';
|
||||
import { CorrelationData, useCorrelations } from './useCorrelations';
|
||||
import { useCorrelations } from './useCorrelations';
|
||||
|
||||
const sortDatasource: SortByFn<CorrelationData> = (a, b, column) =>
|
||||
a.values[column].name.localeCompare(b.values[column].name);
|
||||
|
@ -2,11 +2,12 @@ import { css } from '@emotion/css';
|
||||
import { Controller, FieldError, useFormContext, useWatch } from 'react-hook-form';
|
||||
|
||||
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
|
||||
import { CorrelationExternal } from '@grafana/runtime';
|
||||
import { Field, FieldSet, Input, Select, useStyles2 } from '@grafana/ui';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
|
||||
|
||||
import { CorrelationType, ExternalTypeTarget } from '../types';
|
||||
import { CorrelationType } from '../types';
|
||||
|
||||
import { QueryEditorField } from './QueryEditorField';
|
||||
import { useCorrelationsFormContext } from './correlationsFormContext';
|
||||
@ -146,7 +147,7 @@ export const ConfigureCorrelationTargetForm = () => {
|
||||
},
|
||||
}}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
const castVal = value as ExternalTypeTarget; // the target under "query" type can contain anything a datasource query contains
|
||||
const castVal = value as CorrelationExternal['config']['target']; // the target under "query" type can contain anything a datasource query contains
|
||||
return (
|
||||
<Field
|
||||
label={t('correlations.target-form.target-label', 'Target')}
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { DeepMap, FieldError, FieldErrors } from 'react-hook-form';
|
||||
|
||||
import { SupportedTransformationType } from '@grafana/data';
|
||||
import { CorrelationExternal, CorrelationQuery } from '@grafana/runtime';
|
||||
import { t } from 'app/core/internationalization';
|
||||
|
||||
import { CorrelationConfigExternal, CorrelationConfigQuery, OmitUnion } from '../types';
|
||||
import { OmitUnion } from '../types';
|
||||
|
||||
export interface FormExternalDTO {
|
||||
sourceUID: string;
|
||||
label: string;
|
||||
description: string;
|
||||
type: 'external';
|
||||
config: CorrelationConfigExternal;
|
||||
config: CorrelationExternal['config'];
|
||||
}
|
||||
|
||||
export interface FormQueryDTO {
|
||||
@ -19,7 +20,7 @@ export interface FormQueryDTO {
|
||||
label: string;
|
||||
description: string;
|
||||
type: 'query';
|
||||
config: CorrelationConfigQuery;
|
||||
config: CorrelationQuery['config'];
|
||||
}
|
||||
|
||||
export type FormDTO = FormExternalDTO | FormQueryDTO;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataLinkTransformationConfig } from '@grafana/data';
|
||||
import { CorrelationExternal, CorrelationQuery } from '@grafana/runtime';
|
||||
|
||||
export interface AddCorrelationResponse {
|
||||
correlation: Correlation;
|
||||
@ -28,40 +28,6 @@ export interface RemoveCorrelationResponse {
|
||||
|
||||
export type CorrelationType = 'query' | 'external';
|
||||
|
||||
export type ExternalTypeTarget = { url: string };
|
||||
|
||||
export type CorrelationConfigQuery = {
|
||||
field: string;
|
||||
target: object; // for queries, this contains anything that would go in the query editor, so any extension off DataQuery a datasource would have, and needs to be generic.
|
||||
transformations?: DataLinkTransformationConfig[];
|
||||
};
|
||||
|
||||
export type CorrelationConfigExternal = {
|
||||
field: string;
|
||||
target: ExternalTypeTarget; // For external, this simply contains a URL
|
||||
transformations?: DataLinkTransformationConfig[];
|
||||
};
|
||||
|
||||
type CorrelationBase = {
|
||||
uid: string;
|
||||
sourceUID: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
provisioned: boolean;
|
||||
orgId?: number;
|
||||
};
|
||||
|
||||
export type CorrelationExternal = CorrelationBase & {
|
||||
type: 'external';
|
||||
config: CorrelationConfigExternal;
|
||||
};
|
||||
|
||||
export type CorrelationQuery = CorrelationBase & {
|
||||
type: 'query';
|
||||
config: CorrelationConfigQuery;
|
||||
targetUID: string;
|
||||
};
|
||||
|
||||
export type Correlation = CorrelationExternal | CorrelationQuery;
|
||||
|
||||
export type GetCorrelationsParams = {
|
||||
|
@ -1,14 +1,11 @@
|
||||
import { useAsyncFn } from 'react-use';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { getDataSourceSrv, FetchResponse } from '@grafana/runtime';
|
||||
import { getDataSourceSrv, FetchResponse, CorrelationData, CorrelationsData } from '@grafana/runtime';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
|
||||
import {
|
||||
Correlation,
|
||||
CorrelationExternal,
|
||||
CorrelationQuery,
|
||||
CreateCorrelationParams,
|
||||
CreateCorrelationResponse,
|
||||
GetCorrelationsParams,
|
||||
@ -26,22 +23,6 @@ export interface CorrelationsResponse {
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
export type CorrelationData =
|
||||
| (Omit<CorrelationExternal, 'sourceUID'> & {
|
||||
source: DataSourceInstanceSettings;
|
||||
})
|
||||
| (Omit<CorrelationQuery, 'sourceUID' | 'targetUID'> & {
|
||||
source: DataSourceInstanceSettings;
|
||||
target: DataSourceInstanceSettings;
|
||||
});
|
||||
|
||||
export interface CorrelationsData {
|
||||
correlations: CorrelationData[];
|
||||
page: number;
|
||||
limit: number;
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
const toEnrichedCorrelationData = ({ sourceUID, ...correlation }: Correlation): CorrelationData | undefined => {
|
||||
const sourceDatasource = getDataSourceSrv().getInstanceSettings(sourceUID);
|
||||
const targetDatasource =
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { DataFrame, DataFrameType, DataSourceInstanceSettings, FieldType, toDataFrame } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { config, CorrelationData } from '@grafana/runtime';
|
||||
|
||||
import { CorrelationData } from './useCorrelations';
|
||||
import { attachCorrelationsToDataFrames } from './utils';
|
||||
|
||||
describe('correlations utils', () => {
|
||||
|
@ -1,20 +1,21 @@
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { DataFrame, DataLinkConfigOrigin } from '@grafana/data';
|
||||
import { config, createMonitoringLogger, getBackendSrv, getDataSourceSrv } from '@grafana/runtime';
|
||||
import {
|
||||
config,
|
||||
CorrelationData,
|
||||
CorrelationsData,
|
||||
createMonitoringLogger,
|
||||
getBackendSrv,
|
||||
getDataSourceSrv,
|
||||
} from '@grafana/runtime';
|
||||
import { ExploreItemState } from 'app/types';
|
||||
|
||||
import { formatValueName } from '../explore/PrometheusListView/ItemLabels';
|
||||
import { parseLogsFrame } from '../logs/logsFrame';
|
||||
|
||||
import { CreateCorrelationParams, CreateCorrelationResponse } from './types';
|
||||
import {
|
||||
CorrelationData,
|
||||
CorrelationsData,
|
||||
CorrelationsResponse,
|
||||
getData,
|
||||
toEnrichedCorrelationsData,
|
||||
} from './useCorrelations';
|
||||
import { CorrelationsResponse, getData, toEnrichedCorrelationsData } from './useCorrelations';
|
||||
|
||||
type DataFrameRefIdToDataSourceUid = Record<string, string>;
|
||||
|
||||
@ -85,7 +86,7 @@ const decorateDataFrameWithInternalDataLinks = (dataFrame: DataFrame, correlatio
|
||||
};
|
||||
|
||||
/*
|
||||
If a correlation was made based on the log line field prior to the loki data plane, they would use the field "Line"
|
||||
If a correlation was made based on the log line field prior to the loki data plane, they would use the field "Line"
|
||||
|
||||
Change it to use whatever the body field name is post-loki data plane
|
||||
*/
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { DataLinkTransformationConfig } from '@grafana/data';
|
||||
import { getDataSourceSrv, reportInteraction } from '@grafana/runtime';
|
||||
import { CorrelationData, getDataSourceSrv, reportInteraction } from '@grafana/runtime';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createErrorNotification } from 'app/core/copy/appNotification';
|
||||
import { CreateCorrelationParams } from 'app/features/correlations/types';
|
||||
import { CorrelationData } from 'app/features/correlations/useCorrelations';
|
||||
import { getCorrelationsBySourceUIDs, createCorrelation, generateDefaultLabel } from 'app/features/correlations/utils';
|
||||
import { store } from 'app/store/store';
|
||||
import { ThunkResult } from 'app/types';
|
||||
|
@ -11,9 +11,9 @@ import {
|
||||
ExploreCorrelationHelperData,
|
||||
EventBusExtended,
|
||||
} from '@grafana/data';
|
||||
import { CorrelationData } from '@grafana/runtime';
|
||||
import { DataQuery, DataSourceRef } from '@grafana/schema';
|
||||
import { getQueryKeys } from 'app/core/utils/explore';
|
||||
import { CorrelationData } from 'app/features/correlations/useCorrelations';
|
||||
import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { createAsyncThunk, ThunkResult } from 'app/types';
|
||||
|
@ -10,9 +10,9 @@ import {
|
||||
DataSourceApi,
|
||||
DataSourceInstanceSettings,
|
||||
} from '@grafana/data';
|
||||
import { CorrelationData } from '@grafana/runtime';
|
||||
import { DataSourceJsonData, DataQuery } from '@grafana/schema';
|
||||
import TableModel from 'app/core/TableModel';
|
||||
import { CorrelationData } from 'app/features/correlations/useCorrelations';
|
||||
import { ExplorePanelData } from 'app/types';
|
||||
|
||||
import {
|
||||
|
@ -14,12 +14,11 @@ import {
|
||||
getRawDisplayProcessor,
|
||||
DataSourceApi,
|
||||
} from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { config, CorrelationData } from '@grafana/runtime';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
|
||||
import { refreshIntervalToSortOrder } from '../../../core/utils/explore';
|
||||
import { ExplorePanelData } from '../../../types';
|
||||
import { CorrelationData } from '../../correlations/useCorrelations';
|
||||
import { attachCorrelationsToDataFrames } from '../../correlations/utils';
|
||||
import { dataFrameToLogsModel } from '../../logs/logsModel';
|
||||
import { sortLogsResult } from '../../logs/utils';
|
||||
|
@ -19,10 +19,9 @@ import {
|
||||
ExploreCorrelationHelperData,
|
||||
DataLinkTransformationConfig,
|
||||
} from '@grafana/data';
|
||||
import { CorrelationData } from '@grafana/runtime';
|
||||
import { RichHistorySearchFilters, RichHistorySettings } from 'app/core/utils/richHistoryTypes';
|
||||
|
||||
import { CorrelationData } from '../features/correlations/useCorrelations';
|
||||
|
||||
export type ExploreQueryParams = UrlQueryMap;
|
||||
|
||||
export enum CORRELATION_EDITOR_POST_CONFIRM_ACTION {
|
||||
|
Loading…
Reference in New Issue
Block a user