From 0c4afa47f8f655aa592663ee1de2695779923016 Mon Sep 17 00:00:00 2001 From: "Marc M." <146180665+grafakus@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:15:34 +0100 Subject: [PATCH] refactor(Tracking): Better error logging for Scenes variables (#290) --- .../GroupByVariable/GroupByVariable.tsx | 3 - .../variables/ProfileMetricVariable.tsx | 3 - .../ServiceNameVariable.tsx | 3 - .../infrastructure/labels/LabelsDataSource.ts | 70 +++++++++++++------ .../infrastructure/series/SeriesDataSource.ts | 20 ++++-- 5 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/pages/ProfilesExplorerView/domain/variables/GroupByVariable/GroupByVariable.tsx b/src/pages/ProfilesExplorerView/domain/variables/GroupByVariable/GroupByVariable.tsx index 7a701ba4..cd92f6f3 100644 --- a/src/pages/ProfilesExplorerView/domain/variables/GroupByVariable/GroupByVariable.tsx +++ b/src/pages/ProfilesExplorerView/domain/variables/GroupByVariable/GroupByVariable.tsx @@ -5,7 +5,6 @@ import { Field, Icon, RefreshPicker, Spinner, Tooltip, useStyles2 } from '@grafa import { noOp } from '@shared/domain/noOp'; import { prepareHistoryEntry } from '@shared/domain/prepareHistoryEntry'; import { reportInteraction } from '@shared/domain/reportInteraction'; -import { logger } from '@shared/infrastructure/tracking/logger'; import React, { useMemo } from 'react'; import { lastValueFrom } from 'rxjs'; @@ -94,8 +93,6 @@ export class GroupByVariable extends QueryVariable { } if (error) { - logger.error(error, { info: 'Error while loading "groupBy" variable values!' }); - return (
diff --git a/src/pages/ProfilesExplorerView/domain/variables/ProfileMetricVariable.tsx b/src/pages/ProfilesExplorerView/domain/variables/ProfileMetricVariable.tsx index d9308cb6..8aaed003 100644 --- a/src/pages/ProfilesExplorerView/domain/variables/ProfileMetricVariable.tsx +++ b/src/pages/ProfilesExplorerView/domain/variables/ProfileMetricVariable.tsx @@ -5,7 +5,6 @@ import { Cascader, CascaderOption, Icon, Tooltip, useStyles2 } from '@grafana/ui import { prepareHistoryEntry } from '@shared/domain/prepareHistoryEntry'; import { reportInteraction } from '@shared/domain/reportInteraction'; import { getProfileMetric, ProfileMetricId } from '@shared/infrastructure/profile-metrics/getProfileMetric'; -import { logger } from '@shared/infrastructure/tracking/logger'; import { nanoid } from 'nanoid'; import React, { useMemo } from 'react'; import { lastValueFrom } from 'rxjs'; @@ -121,8 +120,6 @@ export class ProfileMetricVariable extends QueryVariable { }, [options]); if (error) { - logger.error(error, { info: 'Error while loading "profileMetricId" variable values!' }); - return ( diff --git a/src/pages/ProfilesExplorerView/domain/variables/ServiceNameVariable/ServiceNameVariable.tsx b/src/pages/ProfilesExplorerView/domain/variables/ServiceNameVariable/ServiceNameVariable.tsx index b1893951..bbf3b5f8 100644 --- a/src/pages/ProfilesExplorerView/domain/variables/ServiceNameVariable/ServiceNameVariable.tsx +++ b/src/pages/ProfilesExplorerView/domain/variables/ServiceNameVariable/ServiceNameVariable.tsx @@ -10,7 +10,6 @@ import { import { Cascader, Icon, Tooltip, useStyles2 } from '@grafana/ui'; import { prepareHistoryEntry } from '@shared/domain/prepareHistoryEntry'; import { reportInteraction } from '@shared/domain/reportInteraction'; -import { logger } from '@shared/infrastructure/tracking/logger'; import { userStorage } from '@shared/infrastructure/userStorage'; import React, { useMemo } from 'react'; import { lastValueFrom } from 'rxjs'; @@ -107,8 +106,6 @@ export class ServiceNameVariable extends QueryVariable { ); if (error) { - logger.error(error, { info: 'Error while loading "serviceName" variable values!' }); - return ( diff --git a/src/pages/ProfilesExplorerView/infrastructure/labels/LabelsDataSource.ts b/src/pages/ProfilesExplorerView/infrastructure/labels/LabelsDataSource.ts index d8256a5b..dd372485 100644 --- a/src/pages/ProfilesExplorerView/infrastructure/labels/LabelsDataSource.ts +++ b/src/pages/ProfilesExplorerView/infrastructure/labels/LabelsDataSource.ts @@ -73,6 +73,49 @@ export class LabelsDataSource extends RuntimeDataSource { }; } + async fetchLabels(dataSourceUid: string, query: string, from: number, to: number, variableName?: string) { + labelsRepository.setApiClient(new LabelsApiClient({ dataSourceUid })); + + try { + return await labelsRepository.listLabels({ query, from, to }); + } catch (error) { + logger.error(error as Error, { + info: 'Error while loading Pyroscope label names!', + variableName: variableName || '', + }); + + throw error; + } + } + + async fetchLabelValues(query: string, from: number, to: number, labelName: string, variableName?: string) { + let values; + + try { + values = await labelsRepository.listLabelValues({ query, from, to, label: labelName }); + } catch (error) { + logger.error(error as Error, { + info: 'Error while loading Pyroscope label values!', + variableName: variableName || '', + }); + } + + const count = values ? values.length : -1; + + return { + // TODO: check if there's a better way + value: JSON.stringify({ + value: labelName, + groupBy: { + label: labelName, + values: values || [], + }, + }), + text: `${labelName} (${count > -1 ? count : '?'})`, + count, + }; + } + async metricFindQuery(_: string, options: LegacyMetricFindQueryOptions): Promise { const sceneObject = options.scopedVars?.__sceneObject?.value as GroupByVariable; @@ -94,31 +137,12 @@ export class LabelsDataSource extends RuntimeDataSource { return []; } - labelsRepository.setApiClient(new LabelsApiClient({ dataSourceUid })); - - const labels = (await labelsRepository.listLabels({ query, from, to })).filter( - ({ value }) => !isPrivateLabel(value) - ); + const labels = await this.fetchLabels(dataSourceUid, query, from, to, options.variable?.name); const labelsWithValuesAndCount = await Promise.all( - labels.map(({ value }) => - limit(async () => { - const values = await labelsRepository.listLabelValues({ query, from, to, label: value }); - const count = values.length; - return { - // TODO: check if there's a better way - value: JSON.stringify({ - value, - groupBy: { - label: value, - values, - }, - }), - text: `${value} (${count})`, - count, - }; - }) - ) + labels + .filter(({ value }) => !isPrivateLabel(value)) + .map(({ value }) => limit(() => this.fetchLabelValues(query, from, to, value, options.variable?.name))) ); const sortedLabels = labelsWithValuesAndCount diff --git a/src/pages/ProfilesExplorerView/infrastructure/series/SeriesDataSource.ts b/src/pages/ProfilesExplorerView/infrastructure/series/SeriesDataSource.ts index 4b029f9f..bffd9827 100644 --- a/src/pages/ProfilesExplorerView/infrastructure/series/SeriesDataSource.ts +++ b/src/pages/ProfilesExplorerView/infrastructure/series/SeriesDataSource.ts @@ -8,6 +8,7 @@ import { TimeRange, } from '@grafana/data'; import { RuntimeDataSource, sceneGraph } from '@grafana/scenes'; +import { logger } from '@shared/infrastructure/tracking/logger'; import { PYROSCOPE_SERIES_DATA_SOURCE } from '../pyroscope-data-sources'; import { formatSeriesToProfileMetrics } from './formatSeriesToProfileMetrics'; @@ -21,10 +22,19 @@ export class SeriesDataSource extends RuntimeDataSource { super(PYROSCOPE_SERIES_DATA_SOURCE.type, PYROSCOPE_SERIES_DATA_SOURCE.uid); } - async fetchSeries(dataSourceUid: string, timeRange: TimeRange) { - const seriesApiClient = DataSourceProxyClientBuilder.build(dataSourceUid, SeriesApiClient); - seriesRepository.setApiClient(seriesApiClient); - return seriesRepository.list({ timeRange }); + async fetchSeries(dataSourceUid: string, timeRange: TimeRange, variableName?: string) { + seriesRepository.setApiClient(DataSourceProxyClientBuilder.build(dataSourceUid, SeriesApiClient)); + + try { + return await seriesRepository.list({ timeRange }); + } catch (error) { + logger.error(error as Error, { + info: 'Error while loading Pyroscope series!', + variableName: variableName || '', + }); + + throw error; + } } async query(): Promise { @@ -54,7 +64,7 @@ export class SeriesDataSource extends RuntimeDataSource { const serviceName = sceneGraph.interpolate(sceneObject, '$serviceName'); const profileMetricId = sceneGraph.interpolate(sceneObject, '$profileMetricId'); - const pyroscopeSeries = await this.fetchSeries(dataSourceUid, options.range as TimeRange); + const pyroscopeSeries = await this.fetchSeries(dataSourceUid, options.range as TimeRange, options.variable?.name); switch (query) { // queries that depend only on the selected data source