mirror of https://github.com/grafana/grafana
Explore metrics: Consolidate filters with the OTel experience (#98371)
* sort otel resources to top of adhoc filters * add bool in datatrail * add function to find non promoted otel resources * add additional super filter variable * hide filters var and keep otel filters var hidden * add nonpromoted resources to state, update otel or var filters when super filter is updated * update comments * update plan * Allow deployment environment values from both metrics and target_info * Remove usage of dep env var in getting resources * update code comments for clarity * Remove dep env variable, autoselect dep env in otelmetricvar and allow updating of vals in otelmetricvar * Fix bug that conflicts with local storage useOtelExperience check * expose metadata to show data source is loaded to prevent otel race conditions * remove filtering check on target_info in the itel join query * update plan with extra issues * refactor update and reset functions for otel experience * use non promoted resources as the standardization check * sort the resources in filters var if using otel experience * add test for sorting resources with otelmetricsvar * update tests for otel experience in datatrail.test * update tests for otel utils * update otel api tests * update trail store tests to remove dep env var * run prettier * remove unused imports * add tests, distinguish on start and when the initial otel check is done, update comments * Fix bug when adding multiple otel resources * fix when adding filter from breakdown * add migration for dep env var * update migration function and write tests * prettier * Update dep env migration to handle bookmarks * fix trailstore tests for reintroducing the dep env var * refactor default env function, we only need the value * remove redundant check * move otel functions to utils and update and add tests * prettier * cleanup * fix migration for fromStart * update tests for migration * use join and use push * fix flow with state * Fix flow in update OTel function * update tests for flow fixes * fix toggle OTel bugs * report when dep env has been migrated and delete dep env filters to not migrate it again * Clear out dep env after migration * run prettier * improve non promoted attribute function * remove unused functions * prettier * default otel experience to off * report when otel experience is used * report when otel is turned on and off * report otel filters changed * prettier * keep default otel off, respect the local storage, but if loading with otel vars from url or bookmark we can turn it on * Add new badge * fix metric scene breakdown add filter bug around non promoted labels on a metric that are different than non promoted labels for all metrics * prettier * make i18n-extract * prettier for translations * change button name to "Filter" * Update public/app/features/trails/Breakdown/AddToFiltersGraphAction.tsx Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/DataTrail.tsx Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/migrations/otelDeploymentEnvironment.ts Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/DataTrail.tsx Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/otel/api.ts Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/otel/util.ts Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Add more padding for pill where capital letter gets to close to the left border and looks off. * clear up comments --------- Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com>pull/98923/head
parent
6883a4b294
commit
fd4718df33
@ -0,0 +1,129 @@ |
|||||||
|
import { AdHocVariableFilter, UrlQueryMap, UrlQueryValue } from '@grafana/data'; |
||||||
|
import { AdHocFiltersVariable, CustomVariable, sceneGraph } from '@grafana/scenes'; |
||||||
|
|
||||||
|
import { DataTrail } from '../DataTrail'; |
||||||
|
import { VAR_OTEL_AND_METRIC_FILTERS, VAR_OTEL_DEPLOYMENT_ENV } from '../shared'; |
||||||
|
|
||||||
|
import { migrateOtelDeploymentEnvironment, migrateAdHocFilters } from './otelDeploymentEnvironment'; |
||||||
|
|
||||||
|
describe('migrate old dep env var to otel and metrics var', () => { |
||||||
|
describe('migrateOtelDeploymentEnvironment', () => { |
||||||
|
let trail = {} as DataTrail; |
||||||
|
beforeEach(() => { |
||||||
|
trail = new DataTrail({ |
||||||
|
useOtelExperience: true, |
||||||
|
}); |
||||||
|
}); |
||||||
|
it('should not be called if var-otel_and_metric_filters is present with label', () => { |
||||||
|
// this variable being present indicates it has already been migrated
|
||||||
|
const urlParams: UrlQueryMap = { |
||||||
|
'var-otel_and_metric_filters': ['key|=|value'], |
||||||
|
}; |
||||||
|
|
||||||
|
migrateOtelDeploymentEnvironment(trail, urlParams); |
||||||
|
|
||||||
|
const otelMetricsVar = getOtelAndMetricsVar(trail); |
||||||
|
|
||||||
|
expect(otelMetricsVar.state.filters).toEqual([]); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should not be called if starting a new trail', () => { |
||||||
|
// new trails do not need to be migrated
|
||||||
|
trail.setState({ startButtonClicked: true }); |
||||||
|
|
||||||
|
const urlParams: UrlQueryMap = { |
||||||
|
'var-otel_and_metric_filters': [''], |
||||||
|
}; |
||||||
|
|
||||||
|
migrateOtelDeploymentEnvironment(trail, urlParams); |
||||||
|
|
||||||
|
const otelMetricsVar = getOtelAndMetricsVar(trail); |
||||||
|
|
||||||
|
expect(otelMetricsVar.state.filters).toEqual([]); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should not migrate if var-deployment_environment is not present', () => { |
||||||
|
const urlParams: UrlQueryMap = {}; |
||||||
|
|
||||||
|
migrateOtelDeploymentEnvironment(trail, urlParams); |
||||||
|
|
||||||
|
const otelMetricsVar = getOtelAndMetricsVar(trail); |
||||||
|
|
||||||
|
expect(otelMetricsVar.state.filters).toEqual([]); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should migrate deployment environment and set filters correctly', () => { |
||||||
|
const urlParams: UrlQueryMap = { |
||||||
|
'var-deployment_environment': ['env1', 'env2'], |
||||||
|
'var-otel_resources': ['otelResource|=|value'], |
||||||
|
'var-filters': ['metricFilter|=|value'], |
||||||
|
}; |
||||||
|
|
||||||
|
migrateOtelDeploymentEnvironment(trail, urlParams); |
||||||
|
|
||||||
|
const expectedFilters = [ |
||||||
|
{ |
||||||
|
key: 'deployment_environment', |
||||||
|
operator: '=~', |
||||||
|
value: 'env1|env2', |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: 'otelResource', |
||||||
|
operator: '=', |
||||||
|
value: 'value', |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: 'metricFilter', |
||||||
|
operator: '=', |
||||||
|
value: 'value', |
||||||
|
}, |
||||||
|
// Add expected otelFilters and metricFilters here
|
||||||
|
]; |
||||||
|
|
||||||
|
const otelMetricsVar = getOtelAndMetricsVar(trail); |
||||||
|
expect(otelMetricsVar.state.filters).toEqual(expectedFilters); |
||||||
|
// should clear out the dep env var
|
||||||
|
const depEnvVar = getDepEnvVar(trail); |
||||||
|
expect(depEnvVar.state.value).toBe(''); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
describe('migrateAdHocFilters', () => { |
||||||
|
it('should return empty array when urlFilter is not present', () => { |
||||||
|
const urlFilter: UrlQueryValue = null; |
||||||
|
const filters: AdHocVariableFilter[] = []; |
||||||
|
migrateAdHocFilters(urlFilter, filters); |
||||||
|
expect(filters).toEqual([]); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should return filters when urlFilter is present', () => { |
||||||
|
const urlFilter: UrlQueryValue = ['someKey|=|someValue']; |
||||||
|
const filters: AdHocVariableFilter[] = []; |
||||||
|
migrateAdHocFilters(urlFilter, filters); |
||||||
|
const expected = [ |
||||||
|
{ |
||||||
|
key: 'someKey', |
||||||
|
operator: '=', |
||||||
|
value: 'someValue', |
||||||
|
}, |
||||||
|
]; |
||||||
|
expect(filters).toEqual(expected); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
function getOtelAndMetricsVar(trail: DataTrail) { |
||||||
|
const variable = sceneGraph.lookupVariable(VAR_OTEL_AND_METRIC_FILTERS, trail); |
||||||
|
if (variable instanceof AdHocFiltersVariable) { |
||||||
|
return variable; |
||||||
|
} |
||||||
|
throw new Error('getOtelAndMetricsVar failed'); |
||||||
|
} |
||||||
|
|
||||||
|
function getDepEnvVar(trail: DataTrail) { |
||||||
|
const variable = sceneGraph.lookupVariable(VAR_OTEL_DEPLOYMENT_ENV, trail); |
||||||
|
if (variable instanceof CustomVariable) { |
||||||
|
return variable; |
||||||
|
} |
||||||
|
throw new Error('getDepVar failed'); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,111 @@ |
|||||||
|
import { AdHocVariableFilter, UrlQueryValue, UrlQueryMap } from '@grafana/data'; |
||||||
|
import { sceneGraph, AdHocFiltersVariable, CustomVariable } from '@grafana/scenes'; |
||||||
|
|
||||||
|
import { DataTrail } from '../DataTrail'; |
||||||
|
import { reportExploreMetrics } from '../interactions'; |
||||||
|
import { VAR_OTEL_AND_METRIC_FILTERS, VAR_OTEL_DEPLOYMENT_ENV } from '../shared'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Migration for the otel deployment environment variable. |
||||||
|
* When the deployment environment is present in the url, "var-deployment_environment", |
||||||
|
* it is migrated to the new variable "var-otel_and_metric_filters." |
||||||
|
* |
||||||
|
* We check if the otel resources vars are also present in the url, "var-otel_resources" |
||||||
|
* and if the metric filters are present in the url, "var-filters". |
||||||
|
* |
||||||
|
* Once all the variables are migrated to "var-otel_and_metric_filters", the rest is handled in trail.updateOtelData. |
||||||
|
* |
||||||
|
* @param trail |
||||||
|
* @returns |
||||||
|
*/ |
||||||
|
export function migrateOtelDeploymentEnvironment(trail: DataTrail, urlParams: UrlQueryMap) { |
||||||
|
const deploymentEnv = urlParams['var-deployment_environment']; |
||||||
|
// does not need to be migrated
|
||||||
|
const otelMetricsVar = urlParams['var-otel_and_metric_filters']; |
||||||
|
|
||||||
|
// this check is if it has already been migrated
|
||||||
|
if ( |
||||||
|
otelMetricsVar && |
||||||
|
Array.isArray(otelMetricsVar) && |
||||||
|
otelMetricsVar.length > 0 && |
||||||
|
(trail.state.startButtonClicked || otelMetricsVar[0] !== '') |
||||||
|
) { |
||||||
|
return; |
||||||
|
} |
||||||
|
// if there is no dep env, does not need to be migrated
|
||||||
|
if (!deploymentEnv) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
let filters: AdHocVariableFilter[] = []; |
||||||
|
// if there is a deployment environment, we must also migrate the otel resources to the new variable
|
||||||
|
const otelResources = urlParams['var-otel_resources']; |
||||||
|
const metricVarfilters = urlParams['var-filters']; |
||||||
|
if ( |
||||||
|
Array.isArray(deploymentEnv) && |
||||||
|
deploymentEnv.length > 0 && |
||||||
|
deploymentEnv[0] !== '' && |
||||||
|
deploymentEnv.every((r) => r && typeof r === 'string') |
||||||
|
) { |
||||||
|
// all the values are strings because they are prometheus labels
|
||||||
|
// so we can safely cast them to strings
|
||||||
|
const stringDepEnv = deploymentEnv.map((r) => r.toString()); |
||||||
|
const value = stringDepEnv.join('|'); |
||||||
|
|
||||||
|
filters.push({ |
||||||
|
key: 'deployment_environment', |
||||||
|
operator: deploymentEnv.length > 1 ? '=~' : '=', |
||||||
|
value, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// mutate the filters and add to them if we need to
|
||||||
|
migrateAdHocFilters(otelResources, filters); |
||||||
|
migrateAdHocFilters(metricVarfilters, filters); |
||||||
|
|
||||||
|
const otelAndMetricsFiltersVariable = sceneGraph.lookupVariable(VAR_OTEL_AND_METRIC_FILTERS, trail); |
||||||
|
const deploymentEnvironmentVariable = sceneGraph.lookupVariable(VAR_OTEL_DEPLOYMENT_ENV, trail); |
||||||
|
|
||||||
|
if ( |
||||||
|
!( |
||||||
|
otelAndMetricsFiltersVariable instanceof AdHocFiltersVariable && |
||||||
|
deploymentEnvironmentVariable instanceof CustomVariable |
||||||
|
) |
||||||
|
) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
otelAndMetricsFiltersVariable.setState({ |
||||||
|
filters, |
||||||
|
}); |
||||||
|
// clear the deployment environment to not migrate it again
|
||||||
|
reportExploreMetrics('deployment_environment_migrated', {}); |
||||||
|
deploymentEnvironmentVariable.setState({ |
||||||
|
value: '', |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function migrateAdHocFilters(urlFilter: UrlQueryValue, filters: AdHocVariableFilter[]) { |
||||||
|
if ( |
||||||
|
!( |
||||||
|
urlFilter && // is present
|
||||||
|
Array.isArray(urlFilter) && // is an array
|
||||||
|
urlFilter.length > 0 && // has values
|
||||||
|
urlFilter[0] !== '' && // empty vars can contain ''
|
||||||
|
urlFilter.every((r) => r && typeof r === 'string') // vars are of any type but ours are all strings
|
||||||
|
) |
||||||
|
) { |
||||||
|
return filters; |
||||||
|
} |
||||||
|
|
||||||
|
urlFilter.forEach((filter) => { |
||||||
|
const parts = filter.toString().split('|'); |
||||||
|
filters.push({ |
||||||
|
key: parts[0].toString(), |
||||||
|
operator: parts[1].toString(), |
||||||
|
value: parts[2].toString(), |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
return filters; |
||||||
|
} |
Loading…
Reference in new issue