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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 64 additions and 38 deletions

View File

@ -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.
| Feature toggle name | Description | Enabled by default |
| ---------------------------- | ------------------------------------------------------------------------------------ | ------------------ |
| `disableEnvelopeEncryption` | Disable envelope encryption (emergency only) | |
| `database_metrics` | Add Prometheus metrics for database tables | |
| `lokiMonacoEditor` | Access to Monaco query editor for Loki | Yes |
| `featureHighlights` | Highlight Grafana Enterprise features | |
| `commandPalette` | Enable command palette | Yes |
| `cloudWatchDynamicLabels` | Use dynamic labels instead of alias patterns in CloudWatch datasource | Yes |
| `internationalization` | Enables internationalization | Yes |
| `accessTokenExpirationCheck` | Enable OAuth access_token expiration check and token refresh using the refresh_token | |
| Feature toggle name | Description | Enabled by default |
| ----------------------------------- | ------------------------------------------------------------------------------------ | ------------------ |
| `disableEnvelopeEncryption` | Disable envelope encryption (emergency only) | |
| `database_metrics` | Add Prometheus metrics for database tables | |
| `lokiMonacoEditor` | Access to Monaco query editor for Loki | Yes |
| `featureHighlights` | Highlight Grafana Enterprise features | |
| `commandPalette` | Enable command palette | Yes |
| `cloudWatchDynamicLabels` | Use dynamic labels instead of alias patterns in CloudWatch datasource | Yes |
| `internationalization` | Enables internationalization | Yes |
| `accessTokenExpirationCheck` | Enable OAuth access_token expiration check and token refresh using the refresh_token | |
| `disablePrometheusExemplarSampling` | Disable Prometheus examplar sampling | |
## Beta feature toggles

View File

@ -84,5 +84,6 @@ export interface FeatureToggles {
secureSocksDatasourceProxy?: boolean;
authnService?: boolean;
sessionRemoteCache?: boolean;
disablePrometheusExemplarSampling?: boolean;
alertingBacktesting?: boolean;
}

View File

@ -382,6 +382,11 @@ var (
Description: "Enable using remote cache for user sessions",
State: FeatureStateAlpha,
},
{
Name: "disablePrometheusExemplarSampling",
Description: "Disable Prometheus examplar sampling",
State: FeatureStateStable,
},
{
Name: "alertingBacktesting",
Description: "Rule backtesting API for alerting",

View File

@ -279,6 +279,10 @@ const (
// Enable using remote cache for user sessions
FlagSessionRemoteCache = "sessionRemoteCache"
// FlagDisablePrometheusExemplarSampling
// Disable Prometheus examplar sampling
FlagDisablePrometheusExemplarSampling = "disablePrometheusExemplarSampling"
// FlagAlertingBacktesting
// Rule backtesting API for alerting
FlagAlertingBacktesting = "alertingBacktesting"

View File

@ -16,17 +16,19 @@ type exemplar struct {
}
type exemplarSampler struct {
buckets map[time.Time][]exemplar
labelSet map[string]struct{}
count int
mean float64
m2 float64
buckets map[time.Time][]exemplar
labelSet map[string]struct{}
disableSampling bool
count int
mean float64
m2 float64
}
func newExemplarSampler() *exemplarSampler {
func newExemplarSampler(disableSampling bool) *exemplarSampler {
return &exemplarSampler{
buckets: map[time.Time][]exemplar{},
labelSet: map[string]struct{}{},
buckets: map[time.Time][]exemplar{},
labelSet: map[string]struct{}{},
disableSampling: disableSampling,
}
}
@ -98,7 +100,18 @@ func (e *exemplarSampler) getLabelNames() []string {
// getSampledExemplars returns the exemplars sorted by timestamp
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 {
// sort by value in descending order
sort.SliceStable(b, func(i, j int) bool {

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
// client.
type QueryData struct {
intervalCalculator intervalv2.Calculator
tracer tracing.Tracer
client *client.Client
log log.Logger
ID int64
URL string
TimeInterval string
enableWideSeries bool
intervalCalculator intervalv2.Calculator
tracer tracing.Tracer
client *client.Client
log log.Logger
ID int64
URL string
TimeInterval string
enableWideSeries bool
disablePrometheusExemplarSampling bool
}
func New(
@ -65,14 +66,15 @@ func New(
promClient := client.NewClient(httpClient, httpMethod, settings.URL)
return &QueryData{
intervalCalculator: intervalv2.NewCalculator(),
tracer: tracer,
log: plog,
client: promClient,
TimeInterval: timeInterval,
ID: settings.ID,
URL: settings.URL,
enableWideSeries: features.IsEnabled(featuremgmt.FlagPrometheusWideSeries),
intervalCalculator: intervalv2.NewCalculator(),
tracer: tracer,
log: plog,
client: promClient,
TimeInterval: timeInterval,
ID: settings.ID,
URL: settings.URL,
enableWideSeries: features.IsEnabled(featuremgmt.FlagPrometheusWideSeries),
disablePrometheusExemplarSampling: features.IsEnabled(featuremgmt.FlagDisablePrometheusExemplarSampling),
}, nil
}

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
}
@ -136,8 +136,8 @@ func getName(q *models.Query, field *data.Field) string {
return legend
}
func processExemplars(q *models.Query, dr *backend.DataResponse) *backend.DataResponse {
sampler := newExemplarSampler()
func processExemplars(q *models.Query, dr *backend.DataResponse, disableSampling bool) *backend.DataResponse {
sampler := newExemplarSampler(disableSampling)
// we are moving from a multi-frame response returned
// by the converter to a single exemplar frame,