mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 19:54:10 -06:00
Chore: Remove prometheusIncrementalQueryInstrumentation feature toggle (#89463)
* remove prometheusIncrementalQueryInstrumentation feature toggle * remove profile method * remove more about profiling
This commit is contained in:
parent
78c8a26906
commit
2a714601a7
@ -138,7 +138,6 @@ Experimental features might be changed or removed without prior notice.
|
||||
| `pluginsFrontendSandbox` | Enables the plugins frontend sandbox |
|
||||
| `frontendSandboxMonitorOnly` | Enables monitor only in the plugin frontend sandbox (if enabled) |
|
||||
| `vizAndWidgetSplit` | Split panels between visualizations and widgets |
|
||||
| `prometheusIncrementalQueryInstrumentation` | Adds RudderStack events to incremental queries |
|
||||
| `awsDatasourcesTempCredentials` | Support temporary security credentials in AWS plugins for Grafana Cloud customers |
|
||||
| `mlExpressions` | Enable support for Machine Learning in server-side expressions |
|
||||
| `metricsSummary` | Enables metrics summary queries in the Tempo data source |
|
||||
|
@ -82,7 +82,6 @@ export interface FeatureToggles {
|
||||
sqlDatasourceDatabaseSelection?: boolean;
|
||||
recordedQueriesMulti?: boolean;
|
||||
vizAndWidgetSplit?: boolean;
|
||||
prometheusIncrementalQueryInstrumentation?: boolean;
|
||||
logsExploreTableVisualisation?: boolean;
|
||||
awsDatasourcesTempCredentials?: boolean;
|
||||
transformationsRedesign?: boolean;
|
||||
|
@ -139,7 +139,6 @@ export class PrometheusDatasource
|
||||
this.cache = new QueryCache({
|
||||
getTargetSignature: this.getPrometheusTargetSignature.bind(this),
|
||||
overlapString: instanceSettings.jsonData.incrementalQueryOverlapWindow ?? defaultPrometheusQueryOverlapWindow,
|
||||
profileFunction: this.getPrometheusProfileData.bind(this),
|
||||
});
|
||||
|
||||
// This needs to be here and cannot be static because of how annotations typing affects casting of data source
|
||||
@ -162,14 +161,6 @@ export class PrometheusDatasource
|
||||
return query.expr;
|
||||
}
|
||||
|
||||
getPrometheusProfileData(request: DataQueryRequest<PromQuery>, targ: PromQuery) {
|
||||
return {
|
||||
interval: targ.interval ?? request.interval,
|
||||
expr: this.interpolateString(targ.expr),
|
||||
datasource: 'Prometheus',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get target signature for query caching
|
||||
* @param request
|
||||
|
@ -6,7 +6,7 @@ import { DataFrame, DataQueryRequest, DateTime, dateTime, TimeRange } from '@gra
|
||||
import { QueryEditorMode } from '../querybuilder/shared/types';
|
||||
import { PromQuery } from '../types';
|
||||
|
||||
import { DatasourceProfileData, QueryCache } from './QueryCache';
|
||||
import { QueryCache } from './QueryCache';
|
||||
import { IncrementalStorageDataFrameScenarios } from './QueryCacheTestData';
|
||||
|
||||
// Will not interpolate vars!
|
||||
@ -60,14 +60,6 @@ const mockPromRequest = (request?: Partial<DataQueryRequest<PromQuery>>): DataQu
|
||||
};
|
||||
};
|
||||
|
||||
const getPromProfileData = (request: DataQueryRequest, targ: PromQuery): DatasourceProfileData => {
|
||||
return {
|
||||
expr: targ.expr,
|
||||
interval: targ.interval ?? request.interval,
|
||||
datasource: 'prom',
|
||||
};
|
||||
};
|
||||
|
||||
describe('QueryCache: Generic', function () {
|
||||
it('instantiates', () => {
|
||||
const storage = new QueryCache({
|
||||
@ -192,7 +184,6 @@ describe('QueryCache: Prometheus', function () {
|
||||
const storage = new QueryCache<PromQuery>({
|
||||
getTargetSignature: getPrometheusTargetSignature,
|
||||
overlapString: '10m',
|
||||
profileFunction: getPromProfileData,
|
||||
});
|
||||
const firstFrames = scenario.first.dataFrames as unknown as DataFrame[];
|
||||
const secondFrames = scenario.second.dataFrames as unknown as DataFrame[];
|
||||
@ -328,7 +319,6 @@ describe('QueryCache: Prometheus', function () {
|
||||
const storage = new QueryCache<PromQuery>({
|
||||
getTargetSignature: getPrometheusTargetSignature,
|
||||
overlapString: '10m',
|
||||
profileFunction: getPromProfileData,
|
||||
});
|
||||
|
||||
// Initial request with all data for time range
|
||||
@ -489,7 +479,6 @@ describe('QueryCache: Prometheus', function () {
|
||||
const storage = new QueryCache<PromQuery>({
|
||||
getTargetSignature: getPrometheusTargetSignature,
|
||||
overlapString: '10m',
|
||||
profileFunction: getPromProfileData,
|
||||
});
|
||||
const cacheRequest = storage.requestInfo(request);
|
||||
expect(cacheRequest.requests[0]).toBe(request);
|
||||
@ -501,7 +490,6 @@ describe('QueryCache: Prometheus', function () {
|
||||
const storage = new QueryCache<PromQuery>({
|
||||
getTargetSignature: getPrometheusTargetSignature,
|
||||
overlapString: '10m',
|
||||
profileFunction: getPromProfileData,
|
||||
});
|
||||
const cacheRequest = storage.requestInfo(request);
|
||||
expect(cacheRequest.requests[0]).toBe(request);
|
||||
@ -513,7 +501,6 @@ describe('QueryCache: Prometheus', function () {
|
||||
const storage = new QueryCache<PromQuery>({
|
||||
getTargetSignature: getPrometheusTargetSignature,
|
||||
overlapString: '10m',
|
||||
profileFunction: getPromProfileData,
|
||||
});
|
||||
const cacheRequest = storage.requestInfo(request);
|
||||
expect(cacheRequest.requests[0]).toBe(request);
|
||||
|
@ -9,8 +9,6 @@ import {
|
||||
isValidDuration,
|
||||
parseDuration,
|
||||
} from '@grafana/data';
|
||||
import { faro } from '@grafana/faro-web-sdk';
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
|
||||
import { amendTable, Table, trimTable } from '../gcopypaste/app/features/live/data/amendTimeSeries';
|
||||
import { PromQuery } from '../types';
|
||||
@ -19,8 +17,6 @@ import { PromQuery } from '../types';
|
||||
// (must be stable across query changes, time range changes / interval changes / panel resizes / template variable changes)
|
||||
type TargetIdent = string;
|
||||
|
||||
type RequestID = string;
|
||||
|
||||
// query + template variables + interval + raw time range
|
||||
// used for full target cache busting -> full range re-query
|
||||
type TargetSig = string;
|
||||
@ -44,22 +40,6 @@ export interface CacheRequestInfo<T extends SupportedQueryTypes> {
|
||||
shouldCache: boolean;
|
||||
}
|
||||
|
||||
export interface DatasourceProfileData {
|
||||
interval?: string;
|
||||
expr: string;
|
||||
datasource: string;
|
||||
}
|
||||
|
||||
interface ProfileData extends DatasourceProfileData {
|
||||
identity: string;
|
||||
bytes: number | null;
|
||||
dashboardUID: string;
|
||||
panelId?: number;
|
||||
from: string;
|
||||
queryRangeSeconds: number;
|
||||
refreshIntervalMs: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field identity
|
||||
* This is the string used to uniquely identify a field within a "target"
|
||||
@ -76,40 +56,12 @@ export const getFieldIdent = (field: Field) => `${field.type}|${field.name}|${JS
|
||||
export class QueryCache<T extends SupportedQueryTypes> {
|
||||
private overlapWindowMs: number;
|
||||
private getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;
|
||||
private getProfileData?: (request: DataQueryRequest<T>, target: T) => DatasourceProfileData;
|
||||
|
||||
private perfObeserver?: PerformanceObserver;
|
||||
private shouldProfile: boolean;
|
||||
|
||||
// send profile events every 10 minutes
|
||||
sendEventsInterval = 60000 * 10;
|
||||
|
||||
pendingRequestIdsToTargSigs = new Map<RequestID, ProfileData>();
|
||||
|
||||
pendingAccumulatedEvents = new Map<
|
||||
string,
|
||||
{
|
||||
requestCount: number;
|
||||
savedBytesTotal: number;
|
||||
initialRequestSize: number;
|
||||
lastRequestSize: number;
|
||||
panelId: string;
|
||||
dashId: string;
|
||||
expr: string;
|
||||
refreshIntervalMs: number;
|
||||
sent: boolean;
|
||||
datasource: string;
|
||||
from: string;
|
||||
queryRangeSeconds: number;
|
||||
}
|
||||
>();
|
||||
|
||||
cache = new Map<TargetIdent, TargetCache>();
|
||||
|
||||
constructor(options: {
|
||||
getTargetSignature: (request: DataQueryRequest<T>, target: T) => string;
|
||||
overlapString: string;
|
||||
profileFunction?: (request: DataQueryRequest<T>, target: T) => DatasourceProfileData;
|
||||
}) {
|
||||
const unverifiedOverlap = options.overlapString;
|
||||
if (isValidDuration(unverifiedOverlap)) {
|
||||
@ -120,132 +72,9 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
||||
this.overlapWindowMs = durationToMilliseconds(duration);
|
||||
}
|
||||
|
||||
if (
|
||||
(config.grafanaJavascriptAgent.enabled || config.featureToggles?.prometheusIncrementalQueryInstrumentation) &&
|
||||
options.profileFunction !== undefined
|
||||
) {
|
||||
this.profile();
|
||||
this.shouldProfile = true;
|
||||
} else {
|
||||
this.shouldProfile = false;
|
||||
}
|
||||
this.getProfileData = options.profileFunction;
|
||||
this.getTargetSignature = options.getTargetSignature;
|
||||
}
|
||||
|
||||
private profile() {
|
||||
// Check if PerformanceObserver is supported, and if we have Faro enabled for internal profiling
|
||||
if (typeof PerformanceObserver === 'function') {
|
||||
this.perfObeserver = new PerformanceObserver((list: PerformanceObserverEntryList) => {
|
||||
list.getEntries().forEach((entry) => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const entryTypeCast: PerformanceResourceTiming = entry as PerformanceResourceTiming;
|
||||
|
||||
// Safari support for this is coming in 16.4:
|
||||
// https://caniuse.com/mdn-api_performanceresourcetiming_transfersize
|
||||
// Gating that this exists to prevent runtime errors
|
||||
const isSupported = typeof entryTypeCast?.transferSize === 'number';
|
||||
|
||||
if (entryTypeCast?.initiatorType === 'fetch' && isSupported) {
|
||||
let fetchUrl = entryTypeCast.name;
|
||||
|
||||
if (fetchUrl.includes('/api/ds/query')) {
|
||||
let match = fetchUrl.match(/requestId=([a-z\d]+)/i);
|
||||
|
||||
if (match) {
|
||||
let requestId = match[1];
|
||||
|
||||
const requestTransferSize = Math.round(entryTypeCast.transferSize);
|
||||
const currentRequest = this.pendingRequestIdsToTargSigs.get(requestId);
|
||||
|
||||
if (currentRequest) {
|
||||
const entries = this.pendingRequestIdsToTargSigs.entries();
|
||||
|
||||
for (let [, value] of entries) {
|
||||
if (value.identity === currentRequest.identity && value.bytes !== null) {
|
||||
const previous = this.pendingAccumulatedEvents.get(value.identity);
|
||||
|
||||
const savedBytes = value.bytes - requestTransferSize;
|
||||
|
||||
this.pendingAccumulatedEvents.set(value.identity, {
|
||||
datasource: value.datasource ?? 'N/A',
|
||||
requestCount: (previous?.requestCount ?? 0) + 1,
|
||||
savedBytesTotal: (previous?.savedBytesTotal ?? 0) + savedBytes,
|
||||
initialRequestSize: value.bytes,
|
||||
lastRequestSize: requestTransferSize,
|
||||
panelId: currentRequest.panelId?.toString() ?? '',
|
||||
dashId: currentRequest.dashboardUID ?? '',
|
||||
expr: currentRequest.expr ?? '',
|
||||
refreshIntervalMs: currentRequest.refreshIntervalMs ?? 0,
|
||||
sent: false,
|
||||
from: currentRequest.from ?? '',
|
||||
queryRangeSeconds: currentRequest.queryRangeSeconds ?? 0,
|
||||
});
|
||||
|
||||
// We don't need to save each subsequent request, only the first one
|
||||
this.pendingRequestIdsToTargSigs.delete(requestId);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't return above, this should be the first request, let's save the observed size
|
||||
this.pendingRequestIdsToTargSigs.set(requestId, { ...currentRequest, bytes: requestTransferSize });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.perfObeserver.observe({ type: 'resource', buffered: false });
|
||||
|
||||
setInterval(this.sendPendingTrackingEvents, this.sendEventsInterval);
|
||||
|
||||
// Send any pending profile information when the user navigates away
|
||||
window.addEventListener('beforeunload', this.sendPendingTrackingEvents);
|
||||
}
|
||||
}
|
||||
|
||||
sendPendingTrackingEvents = () => {
|
||||
const entries = this.pendingAccumulatedEvents.entries();
|
||||
|
||||
for (let [key, value] of entries) {
|
||||
if (!value.sent) {
|
||||
const event = {
|
||||
datasource: value.datasource.toString(),
|
||||
requestCount: value.requestCount.toString(),
|
||||
savedBytesTotal: value.savedBytesTotal.toString(),
|
||||
initialRequestSize: value.initialRequestSize.toString(),
|
||||
lastRequestSize: value.lastRequestSize.toString(),
|
||||
panelId: value.panelId.toString(),
|
||||
dashId: value.dashId.toString(),
|
||||
expr: value.expr.toString(),
|
||||
refreshIntervalMs: value.refreshIntervalMs.toString(),
|
||||
from: value.from.toString(),
|
||||
queryRangeSeconds: value.queryRangeSeconds.toString(),
|
||||
};
|
||||
|
||||
if (config.featureToggles.prometheusIncrementalQueryInstrumentation) {
|
||||
reportInteraction('grafana_incremental_queries_profile', event);
|
||||
} else if (faro.api.pushEvent) {
|
||||
faro.api.pushEvent('incremental query response size', event, 'no-interaction', {
|
||||
skipDedupe: true,
|
||||
});
|
||||
}
|
||||
|
||||
this.pendingAccumulatedEvents.set(key, {
|
||||
...value,
|
||||
sent: true,
|
||||
requestCount: 0,
|
||||
savedBytesTotal: 0,
|
||||
initialRequestSize: 0,
|
||||
lastRequestSize: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// can be used to change full range request to partial, split into multiple requests
|
||||
requestInfo(request: DataQueryRequest<T>): CacheRequestInfo<T> {
|
||||
// TODO: align from/to to interval to increase probability of hitting backend cache
|
||||
@ -260,27 +89,11 @@ export class QueryCache<T extends SupportedQueryTypes> {
|
||||
let doPartialQuery = shouldCache;
|
||||
let prevTo: TimestampMs | undefined = undefined;
|
||||
|
||||
const refreshIntervalMs = request.intervalMs;
|
||||
|
||||
// pre-compute reqTargSigs
|
||||
const reqTargSigs = new Map<TargetIdent, TargetSig>();
|
||||
request.targets.forEach((targ) => {
|
||||
let targIdent = `${request.dashboardUID}|${request.panelId}|${targ.refId}`;
|
||||
let targSig = this.getTargetSignature(request, targ); // ${request.maxDataPoints} ?
|
||||
|
||||
if (this.shouldProfile && this.getProfileData) {
|
||||
this.pendingRequestIdsToTargSigs.set(request.requestId, {
|
||||
...this.getProfileData(request, targ),
|
||||
identity: targIdent + '|' + targSig,
|
||||
bytes: null,
|
||||
panelId: request.panelId,
|
||||
dashboardUID: request.dashboardUID ?? '',
|
||||
from: request.rangeRaw?.from.toString() ?? '',
|
||||
queryRangeSeconds: request.range.to.diff(request.range.from, 'seconds') ?? '',
|
||||
refreshIntervalMs: refreshIntervalMs ?? 0,
|
||||
});
|
||||
}
|
||||
|
||||
reqTargSigs.set(targIdent, targSig);
|
||||
});
|
||||
|
||||
|
@ -480,13 +480,6 @@ var (
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaDashboardsSquad,
|
||||
},
|
||||
{
|
||||
Name: "prometheusIncrementalQueryInstrumentation",
|
||||
Description: "Adds RudderStack events to incremental queries",
|
||||
FrontendOnly: true,
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaObservabilityMetricsSquad,
|
||||
},
|
||||
{
|
||||
Name: "logsExploreTableVisualisation",
|
||||
Description: "A table visualisation for logs in Explore",
|
||||
|
@ -63,7 +63,6 @@ frontendSandboxMonitorOnly,experimental,@grafana/plugins-platform-backend,false,
|
||||
sqlDatasourceDatabaseSelection,preview,@grafana/dataviz-squad,false,false,true
|
||||
recordedQueriesMulti,GA,@grafana/observability-metrics,false,false,false
|
||||
vizAndWidgetSplit,experimental,@grafana/dashboards-squad,false,false,true
|
||||
prometheusIncrementalQueryInstrumentation,experimental,@grafana/observability-metrics,false,false,true
|
||||
logsExploreTableVisualisation,GA,@grafana/observability-logs,false,false,true
|
||||
awsDatasourcesTempCredentials,experimental,@grafana/aws-datasources,false,false,false
|
||||
transformationsRedesign,GA,@grafana/observability-metrics,false,false,true
|
||||
|
|
@ -263,10 +263,6 @@ const (
|
||||
// Split panels between visualizations and widgets
|
||||
FlagVizAndWidgetSplit = "vizAndWidgetSplit"
|
||||
|
||||
// FlagPrometheusIncrementalQueryInstrumentation
|
||||
// Adds RudderStack events to incremental queries
|
||||
FlagPrometheusIncrementalQueryInstrumentation = "prometheusIncrementalQueryInstrumentation"
|
||||
|
||||
// FlagLogsExploreTableVisualisation
|
||||
// A table visualisation for logs in Explore
|
||||
FlagLogsExploreTableVisualisation = "logsExploreTableVisualisation"
|
||||
|
@ -1832,7 +1832,8 @@
|
||||
"metadata": {
|
||||
"name": "prometheusIncrementalQueryInstrumentation",
|
||||
"resourceVersion": "1718727528075",
|
||||
"creationTimestamp": "2023-07-05T19:39:49Z"
|
||||
"creationTimestamp": "2023-07-05T19:39:49Z",
|
||||
"deletionTimestamp": "2024-06-20T11:30:37Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Adds RudderStack events to incremental queries",
|
||||
|
Loading…
Reference in New Issue
Block a user