Prometheus: Create feature flag to disable exemplar sampling (#60105)

:Fix rebase
This commit is contained in:
Ludovic Viaud
2022-12-19 16:00:15 +01:00
committed by GitHub
parent bce33eeb85
commit f67b8fe0dc
7 changed files with 64 additions and 38 deletions
@@ -19,16 +19,17 @@ This page contains a list of available feature toggles. To learn how to turn on
Some stable features are enabled by default. You can disable a stable feature by setting the feature flag to "false" in the configuration. Some stable features are enabled by default. You can disable a stable feature by setting the feature flag to "false" in the configuration.
| Feature toggle name | Description | Enabled by default | | Feature toggle name | Description | Enabled by default |
| ---------------------------- | ------------------------------------------------------------------------------------ | ------------------ | | ----------------------------------- | ------------------------------------------------------------------------------------ | ------------------ |
| `disableEnvelopeEncryption` | Disable envelope encryption (emergency only) | | | `disableEnvelopeEncryption` | Disable envelope encryption (emergency only) | |
| `database_metrics` | Add Prometheus metrics for database tables | | | `database_metrics` | Add Prometheus metrics for database tables | |
| `lokiMonacoEditor` | Access to Monaco query editor for Loki | Yes | | `lokiMonacoEditor` | Access to Monaco query editor for Loki | Yes |
| `featureHighlights` | Highlight Grafana Enterprise features | | | `featureHighlights` | Highlight Grafana Enterprise features | |
| `commandPalette` | Enable command palette | Yes | | `commandPalette` | Enable command palette | Yes |
| `cloudWatchDynamicLabels` | Use dynamic labels instead of alias patterns in CloudWatch datasource | Yes | | `cloudWatchDynamicLabels` | Use dynamic labels instead of alias patterns in CloudWatch datasource | Yes |
| `internationalization` | Enables internationalization | Yes | | `internationalization` | Enables internationalization | Yes |
| `accessTokenExpirationCheck` | Enable OAuth access_token expiration check and token refresh using the refresh_token | | | `accessTokenExpirationCheck` | Enable OAuth access_token expiration check and token refresh using the refresh_token | |
| `disablePrometheusExemplarSampling` | Disable Prometheus examplar sampling | |
## Beta feature toggles ## Beta feature toggles
@@ -84,5 +84,6 @@ export interface FeatureToggles {
secureSocksDatasourceProxy?: boolean; secureSocksDatasourceProxy?: boolean;
authnService?: boolean; authnService?: boolean;
sessionRemoteCache?: boolean; sessionRemoteCache?: boolean;
disablePrometheusExemplarSampling?: boolean;
alertingBacktesting?: boolean; alertingBacktesting?: boolean;
} }
+5
View File
@@ -382,6 +382,11 @@ var (
Description: "Enable using remote cache for user sessions", Description: "Enable using remote cache for user sessions",
State: FeatureStateAlpha, State: FeatureStateAlpha,
}, },
{
Name: "disablePrometheusExemplarSampling",
Description: "Disable Prometheus examplar sampling",
State: FeatureStateStable,
},
{ {
Name: "alertingBacktesting", Name: "alertingBacktesting",
Description: "Rule backtesting API for alerting", Description: "Rule backtesting API for alerting",
+4
View File
@@ -279,6 +279,10 @@ const (
// Enable using remote cache for user sessions // Enable using remote cache for user sessions
FlagSessionRemoteCache = "sessionRemoteCache" FlagSessionRemoteCache = "sessionRemoteCache"
// FlagDisablePrometheusExemplarSampling
// Disable Prometheus examplar sampling
FlagDisablePrometheusExemplarSampling = "disablePrometheusExemplarSampling"
// FlagAlertingBacktesting // FlagAlertingBacktesting
// Rule backtesting API for alerting // Rule backtesting API for alerting
FlagAlertingBacktesting = "alertingBacktesting" FlagAlertingBacktesting = "alertingBacktesting"
@@ -16,17 +16,19 @@ type exemplar struct {
} }
type exemplarSampler struct { type exemplarSampler struct {
buckets map[time.Time][]exemplar buckets map[time.Time][]exemplar
labelSet map[string]struct{} labelSet map[string]struct{}
count int disableSampling bool
mean float64 count int
m2 float64 mean float64
m2 float64
} }
func newExemplarSampler() *exemplarSampler { func newExemplarSampler(disableSampling bool) *exemplarSampler {
return &exemplarSampler{ return &exemplarSampler{
buckets: map[time.Time][]exemplar{}, buckets: map[time.Time][]exemplar{},
labelSet: map[string]struct{}{}, labelSet: map[string]struct{}{},
disableSampling: disableSampling,
} }
} }
@@ -98,7 +100,18 @@ func (e *exemplarSampler) getLabelNames() []string {
// getSampledExemplars returns the exemplars sorted by timestamp // getSampledExemplars returns the exemplars sorted by timestamp
func (e *exemplarSampler) getSampledExemplars() []exemplar { func (e *exemplarSampler) getSampledExemplars() []exemplar {
exemplars := make([]exemplar, 0, len(e.buckets)) var exemplars []exemplar
if e.disableSampling {
for _, bucket := range e.buckets {
exemplars = append(exemplars, bucket...)
}
return exemplars
}
exemplars = make([]exemplar, 0, len(e.buckets))
for _, b := range e.buckets { for _, b := range e.buckets {
// sort by value in descending order // sort by value in descending order
sort.SliceStable(b, func(i, j int) bool { sort.SliceStable(b, func(i, j int) bool {
+18 -16
View File
@@ -34,14 +34,15 @@ type ExemplarEvent struct {
// QueryData handles querying but different from buffered package uses a custom client instead of default Go Prom // QueryData handles querying but different from buffered package uses a custom client instead of default Go Prom
// client. // client.
type QueryData struct { type QueryData struct {
intervalCalculator intervalv2.Calculator intervalCalculator intervalv2.Calculator
tracer tracing.Tracer tracer tracing.Tracer
client *client.Client client *client.Client
log log.Logger log log.Logger
ID int64 ID int64
URL string URL string
TimeInterval string TimeInterval string
enableWideSeries bool enableWideSeries bool
disablePrometheusExemplarSampling bool
} }
func New( func New(
@@ -65,14 +66,15 @@ func New(
promClient := client.NewClient(httpClient, httpMethod, settings.URL) promClient := client.NewClient(httpClient, httpMethod, settings.URL)
return &QueryData{ return &QueryData{
intervalCalculator: intervalv2.NewCalculator(), intervalCalculator: intervalv2.NewCalculator(),
tracer: tracer, tracer: tracer,
log: plog, log: plog,
client: promClient, client: promClient,
TimeInterval: timeInterval, TimeInterval: timeInterval,
ID: settings.ID, ID: settings.ID,
URL: settings.URL, URL: settings.URL,
enableWideSeries: features.IsEnabled(featuremgmt.FlagPrometheusWideSeries), enableWideSeries: features.IsEnabled(featuremgmt.FlagPrometheusWideSeries),
disablePrometheusExemplarSampling: features.IsEnabled(featuremgmt.FlagDisablePrometheusExemplarSampling),
}, nil }, nil
} }
+3 -3
View File
@@ -41,7 +41,7 @@ func (s *QueryData) parseResponse(ctx context.Context, q *models.Query, res *htt
} }
} }
r = processExemplars(q, r) r = processExemplars(q, r, s.disablePrometheusExemplarSampling)
return r, nil return r, nil
} }
@@ -136,8 +136,8 @@ func getName(q *models.Query, field *data.Field) string {
return legend return legend
} }
func processExemplars(q *models.Query, dr *backend.DataResponse) *backend.DataResponse { func processExemplars(q *models.Query, dr *backend.DataResponse, disableSampling bool) *backend.DataResponse {
sampler := newExemplarSampler() sampler := newExemplarSampler(disableSampling)
// we are moving from a multi-frame response returned // we are moving from a multi-frame response returned
// by the converter to a single exemplar frame, // by the converter to a single exemplar frame,