@@ -44,12 +44,13 @@ var (
4444
4545// HandlerConfig Config for a Handler.
4646type HandlerConfig struct {
47- LogQueriesLongerThan time.Duration `yaml:"log_queries_longer_than"`
48- MaxBodySize int64 `yaml:"max_body_size"`
49- QueryStatsEnabled bool `yaml:"query_stats_enabled"`
50- LogFailedQueries bool `yaml:"log_failed_queries"`
51- FailedQueryCacheCapacity int `yaml:"failed_query_cache_capacity"`
52- SlowQueryLogsUserHeader string `yaml:"slow_query_logs_user_header"`
47+ LogQueriesLongerThan time.Duration `yaml:"log_queries_longer_than"`
48+ MaxBodySize int64 `yaml:"max_body_size"`
49+ QueryStatsEnabled bool `yaml:"query_stats_enabled"`
50+ LogFailedQueries bool `yaml:"log_failed_queries"`
51+ FailedQueryCacheCapacity int `yaml:"failed_query_cache_capacity"`
52+ SlowQueryLogsUserHeader string `yaml:"slow_query_logs_user_header"`
53+ LogQueriesMoreExpensiveThan uint64 `yaml:"log_queries_more_expensive_than"`
5354}
5455
5556// Handler accepts queries and forwards them to RoundTripper. It can log slow queries,
@@ -61,12 +62,13 @@ type Handler struct {
6162 failedQueryCache * utils.FailedQueryCache
6263
6364 // Metrics.
64- querySeconds * prometheus.CounterVec
65- querySeries * prometheus.CounterVec
66- queryBytes * prometheus.CounterVec
67- activeUsers * util.ActiveUsersCleanupService
68- slowQueryCount prometheus.Counter
69- failedQueryCount prometheus.Counter
65+ querySeconds * prometheus.CounterVec
66+ querySeries * prometheus.CounterVec
67+ queryBytes * prometheus.CounterVec
68+ activeUsers * util.ActiveUsersCleanupService
69+ slowQueryCount prometheus.Counter
70+ failedQueryCount prometheus.Counter
71+ expensiveQueryCount prometheus.Counter
7072}
7173
7274// NewHandler creates a new frontend handler.
@@ -120,6 +122,10 @@ func NewHandler(cfg HandlerConfig, roundTripper http.RoundTripper, log log.Logge
120122 Name : "cortex_failed_query_total" ,
121123 Help : "Total number of failed queries detected." ,
122124 })
125+ h .expensiveQueryCount = promauto .With (reg ).NewCounter (prometheus.CounterOpts {
126+ Name : "cortex_expensive_query_total" ,
127+ Help : "Total number of expensive queries detected." ,
128+ })
123129 return h
124130}
125131
@@ -205,16 +211,19 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
205211
206212 // Check whether we should parse the query string.
207213 shouldReportSlowQuery := f .cfg .LogQueriesLongerThan != 0 && queryResponseTime > f .cfg .LogQueriesLongerThan
208- if shouldReportSlowQuery || f .cfg .QueryStatsEnabled {
214+ queryBytesFetched := queryrange .GetQueryBytesFetchedFromHeader (resp .Header )
215+ shouldReportExpensiveQuery := f .cfg .LogQueriesMoreExpensiveThan != 0 && queryBytesFetched > f .cfg .LogQueriesMoreExpensiveThan
216+ if shouldReportSlowQuery || shouldReportExpensiveQuery || f .cfg .QueryStatsEnabled {
209217 queryString = f .parseRequestQueryString (r , buf )
210218 }
211219
212220 if shouldReportSlowQuery {
213221 f .reportSlowQuery (r , hs , queryString , queryResponseTime )
214222 }
223+ if shouldReportExpensiveQuery {
224+ f .reportExpensiveQuery (r , queryString , queryBytesFetched , queryResponseTime )
225+ }
215226 if f .cfg .QueryStatsEnabled {
216- stats .FetchedChunkBytes = queryrange .GetQueryBytesFetchedFromHeader (resp .Header )
217- stats .FetchedSeriesCount = queryrange .GetQuerySeriesFetchedFromHeader (resp .Header )
218227 f .reportQueryStats (r , queryString , queryResponseTime , stats )
219228 }
220229}
@@ -248,6 +257,35 @@ func (f *Handler) reportFailedQuery(r *http.Request, queryString url.Values, err
248257 level .Error (util_log .WithContext (r .Context (), f .log )).Log (logMessage ... )
249258}
250259
260+ func (f * Handler ) reportExpensiveQuery (r * http.Request , queryString url.Values , queryBytesFetched uint64 , queryResponseTime time.Duration ) {
261+ f .expensiveQueryCount .Inc ()
262+ // NOTE(GiedriusS): see https://github.com/grafana/grafana/pull/60301 for more info.
263+ grafanaDashboardUID := "-"
264+ if dashboardUID := r .Header .Get ("X-Dashboard-Uid" ); dashboardUID != "" {
265+ grafanaDashboardUID = dashboardUID
266+ }
267+ grafanaPanelID := "-"
268+ if panelID := r .Header .Get ("X-Panel-Id" ); panelID != "" {
269+ grafanaPanelID = panelID
270+ }
271+ remoteUser , _ , _ := r .BasicAuth ()
272+
273+ logMessage := append ([]interface {}{
274+ "msg" , "expensive query" ,
275+ "method" , r .Method ,
276+ "host" , r .Host ,
277+ "path" , r .URL .Path ,
278+ "remote_user" , remoteUser ,
279+ "remote_addr" , r .RemoteAddr ,
280+ "query_megabytes_fetched" , queryBytesFetched / (1024 * 1024 ),
281+ "grafana_dashboard_uid" , grafanaDashboardUID ,
282+ "grafana_panel_id" , grafanaPanelID ,
283+ "query_response_time" , queryResponseTime .String (),
284+ }, formatQueryString (queryString )... )
285+
286+ level .Error (util_log .WithContext (r .Context (), f .log )).Log (logMessage ... )
287+ }
288+
251289// reportSlowQuery reports slow queries.
252290func (f * Handler ) reportSlowQuery (r * http.Request , responseHeaders http.Header , queryString url.Values , queryResponseTime time.Duration ) {
253291 f .slowQueryCount .Inc ()
0 commit comments