@@ -58,29 +58,18 @@ type Handler struct {
5858 cfg HandlerConfig
5959 log log.Logger
6060 roundTripper http.RoundTripper
61- lru * lru.Cache
61+ lruCache * lru.Cache
6262 regex * regexp.Regexp
6363 errorExtract * regexp.Regexp
6464
6565 // Metrics.
6666 querySeconds * prometheus.CounterVec
6767 querySeries * prometheus.CounterVec
6868 queryBytes * prometheus.CounterVec
69- totalQueries prometheus.Counter
7069 cachedHits prometheus.Counter
7170 activeUsers * util.ActiveUsersCleanupService
7271}
7372
74- // isCacheableError Returns true if response code is in pre-defined cacheable errors list, else returns false
75- func isCacheableError (statusCode int ) bool {
76- for _ , errStatusCode := range cacheableResponseCodes {
77- if errStatusCode == statusCode {
78- return true
79- }
80- }
81- return false
82- }
83-
8473// NewHandler creates a new frontend handler.
8574func NewHandler (cfg HandlerConfig , roundTripper http.RoundTripper , log log.Logger , reg prometheus.Registerer ) http.Handler {
8675 var (
@@ -100,7 +89,7 @@ func NewHandler(cfg HandlerConfig, roundTripper http.RoundTripper, log log.Logge
10089 cfg : cfg ,
10190 log : log ,
10291 roundTripper : roundTripper ,
103- lru : LruCache ,
92+ lruCache : LruCache ,
10493 regex : regexp .MustCompile (`[\s\n\t]+` ),
10594 errorExtract : regexp .MustCompile (`Code\((\d+)\)` ),
10695 }
@@ -133,7 +122,7 @@ func NewHandler(cfg HandlerConfig, roundTripper http.RoundTripper, log log.Logge
133122
134123 h .cachedHits = promauto .With (reg ).NewCounter (prometheus.CounterOpts {
135124 Name : "cached_failed_queries_count" ,
136- Help : "Total number of queries that hit the cache." ,
125+ Help : "Total number of queries that hit the failed query cache." ,
137126 })
138127
139128 return h
@@ -165,31 +154,18 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
165154 r .Body = http .MaxBytesReader (w , r .Body , f .cfg .MaxBodySize )
166155 r .Body = io .NopCloser (io .TeeReader (r .Body , & buf ))
167156
168- // Check if caching is enabled
169- if f .lru != nil {
170- // Store query expression
157+ // Check if caching is enabled.
158+ if f .lruCache != nil {
159+ // Store query expression.
171160 queryExpressionNormalized = f .regex .ReplaceAllString (r .URL .Query ().Get ("query" ), " " )
172161
173- // Time range length for queries, if either of "start" or "end" are not present, return 0
174- getQueryRangeSeconds := func () int {
175- start , err := strconv .Atoi (r .URL .Query ().Get ("start" ))
176- if err != nil {
177- return 0
178- }
179- end , err := strconv .Atoi (r .URL .Query ().Get ("end" ))
180- if err != nil {
181- return 0
182- }
183- return end - start
184- }
185-
186- // Store query time range length
187- queryExpressionRangeLength = getQueryRangeSeconds ()
162+ // Store query time range length.
163+ queryExpressionRangeLength = getQueryRangeSeconds (r )
188164
189- // Check if query in cache and whether value exceeds time range length
190- if value , ok := f .lru .Get (queryExpressionNormalized ); ok && value .(int ) >= queryExpressionRangeLength {
165+ // Check if query in cache and whether value exceeds time range length.
166+ if value , ok := f .lruCache .Get (queryExpressionNormalized ); ok && value .(int ) >= queryExpressionRangeLength {
191167 w .WriteHeader (http .StatusForbidden )
192- level .Warn (util_log .WithContext (r .Context (), f .log )).Log ("msg" , "FOUND QUERY IN CACHE: CAUSED ERROR: " , "query expression" , queryExpressionNormalized )
168+ level .Warn (util_log .WithContext (r .Context (), f .log )).Log ("msg" , "Retrieved query from cache " , "Query expression" , queryExpressionNormalized )
193169 f .cachedHits .Inc ()
194170 return
195171 }
@@ -203,47 +179,9 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
203179 writeError (w , err )
204180 queryString = f .parseRequestQueryString (r , buf )
205181
206- // Check if caching is enabled
207- if f .lru != nil {
208- // Extracting error code
209- codeExtract := f .errorExtract .FindStringSubmatch (err .Error ())
210-
211- // Checking if error code extracted successfully
212- if codeExtract != nil && len (codeExtract ) >= 2 {
213-
214- // Converting error code to int
215- errCode , strConvError := strconv .Atoi (codeExtract [1 ])
216-
217- // Checking if error code extracted properly
218- if strConvError != nil {
219- level .Error (util_log .WithContext (r .Context (), f .log )).Log (
220- "msg" , "String to int conversion error" , "response " , resp ,
221- )
222- }
223-
224- // If error should be cached, store it in cache
225- if isCacheableError (errCode ) {
226- //checks if queryExpression is already in cache, and updates time range length value if it is shorter
227- if contains , _ := f .lru .ContainsOrAdd (queryExpressionNormalized , queryExpressionRangeLength ); contains {
228- if oldValue , ok := f .lru .Get (queryExpressionNormalized ); ok {
229- queryExpressionRangeLength = min (queryExpressionRangeLength , oldValue .(int ))
230- }
231- f .lru .Add (queryExpressionNormalized , queryExpressionRangeLength )
232- }
233-
234- level .Info (util_log .WithContext (r .Context (), f .log )).Log (
235- "msg" , "Cached query due to cacheable error code" , "response " , resp ,
236- )
237- } else {
238- level .Info (util_log .WithContext (r .Context (), f .log )).Log (
239- "msg" , "Did not cache query due to non-cacheable error code" , "response " , resp ,
240- )
241- }
242- } else {
243- level .Error (util_log .WithContext (r .Context (), f .log )).Log (
244- "msg" , "Error string regex conversion error" , "response " , resp ,
245- )
246- }
182+ // Check if caching is enabled.
183+ if f .lruCache != nil {
184+ f .updateFailedQueryCache (err , queryExpressionNormalized , queryExpressionRangeLength , r )
247185 }
248186
249187 if f .cfg .LogFailedQueries {
@@ -282,6 +220,69 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
282220 }
283221}
284222
223+ func (f * Handler ) updateFailedQueryCache (err error , queryExpressionNormalized string , queryExpressionRangeLength int , r * http.Request ) {
224+ // Extracting error code from error string.
225+ codeExtract := f .errorExtract .FindStringSubmatch (err .Error ())
226+
227+ // Checking if error code extracted successfully.
228+ if codeExtract == nil || len (codeExtract ) < 2 {
229+ level .Error (util_log .WithContext (r .Context (), f .log )).Log (
230+ "msg" , "Error string regex conversion error" )
231+ return
232+ }
233+
234+ // Converting error code to int.
235+ errCode , strConvError := strconv .Atoi (codeExtract [1 ])
236+
237+ // Checking if error code extracted properly from string.
238+ if strConvError != nil {
239+ level .Error (util_log .WithContext (r .Context (), f .log )).Log (
240+ "msg" , "String to int conversion error" )
241+ return
242+ }
243+
244+ // If error should be cached, store it in cache.
245+ if ! isCacheableError (errCode ) {
246+ level .Debug (util_log .WithContext (r .Context (), f .log )).Log (
247+ "msg" , "Query not cached due to non-cacheable error code" )
248+ return
249+ }
250+
251+ // Checks if queryExpression is already in cache, and updates time range length value to min of stored and new value.
252+ if contains , _ := f .lruCache .ContainsOrAdd (queryExpressionNormalized , queryExpressionRangeLength ); contains {
253+ if oldValue , ok := f .lruCache .Get (queryExpressionNormalized ); ok {
254+ queryExpressionRangeLength = min (queryExpressionRangeLength , oldValue .(int ))
255+ }
256+ f .lruCache .Add (queryExpressionNormalized , queryExpressionRangeLength )
257+ }
258+
259+ level .Debug (util_log .WithContext (r .Context (), f .log )).Log (
260+ "msg" , "Query cached" , "response " )
261+ }
262+
263+ // isCacheableError Returns true if response code is in pre-defined cacheable errors list, else returns false.
264+ func isCacheableError (statusCode int ) bool {
265+ for _ , errStatusCode := range cacheableResponseCodes {
266+ if errStatusCode == statusCode {
267+ return true
268+ }
269+ }
270+ return false
271+ }
272+
273+ // Time range length for queries, if either of "start" or "end" are not present, return 0.
274+ func getQueryRangeSeconds (r * http.Request ) int {
275+ start , err := strconv .Atoi (r .URL .Query ().Get ("start" ))
276+ if err != nil {
277+ return 0
278+ }
279+ end , err := strconv .Atoi (r .URL .Query ().Get ("end" ))
280+ if err != nil {
281+ return 0
282+ }
283+ return end - start
284+ }
285+
285286func (f * Handler ) reportFailedQuery (r * http.Request , queryString url.Values , err error ) {
286287 // NOTE(GiedriusS): see https://github.com/grafana/grafana/pull/60301 for more info.
287288 grafanaDashboardUID := "-"
0 commit comments