github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/codec.go (about) 1 package queryrange 2 3 import ( 4 "bytes" 5 "container/heap" 6 "context" 7 "errors" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 "net/url" 12 "sort" 13 strings "strings" 14 "time" 15 16 json "github.com/json-iterator/go" 17 "github.com/opentracing/opentracing-go" 18 otlog "github.com/opentracing/opentracing-go/log" 19 "github.com/prometheus/prometheus/model/timestamp" 20 "github.com/weaveworks/common/httpgrpc" 21 22 "github.com/grafana/loki/pkg/loghttp" 23 "github.com/grafana/loki/pkg/logproto" 24 "github.com/grafana/loki/pkg/logql" 25 "github.com/grafana/loki/pkg/logql/syntax" 26 "github.com/grafana/loki/pkg/logqlmodel" 27 "github.com/grafana/loki/pkg/logqlmodel/stats" 28 "github.com/grafana/loki/pkg/querier/queryrange/queryrangebase" 29 "github.com/grafana/loki/pkg/util" 30 "github.com/grafana/loki/pkg/util/httpreq" 31 "github.com/grafana/loki/pkg/util/marshal" 32 marshal_legacy "github.com/grafana/loki/pkg/util/marshal/legacy" 33 ) 34 35 var LokiCodec = &Codec{} 36 37 type Codec struct{} 38 39 func (r *LokiRequest) GetEnd() int64 { 40 return r.EndTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 41 } 42 43 func (r *LokiRequest) GetStart() int64 { 44 return r.StartTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 45 } 46 47 func (r *LokiRequest) WithStartEnd(s int64, e int64) queryrangebase.Request { 48 new := *r 49 new.StartTs = time.Unix(0, s*int64(time.Millisecond)) 50 new.EndTs = time.Unix(0, e*int64(time.Millisecond)) 51 return &new 52 } 53 54 func (r *LokiRequest) WithStartEndTime(s time.Time, e time.Time) *LokiRequest { 55 new := *r 56 new.StartTs = s 57 new.EndTs = e 58 return &new 59 } 60 61 func (r *LokiRequest) WithQuery(query string) queryrangebase.Request { 62 new := *r 63 new.Query = query 64 return &new 65 } 66 67 func (r *LokiRequest) WithShards(shards logql.Shards) *LokiRequest { 68 new := *r 69 new.Shards = shards.Encode() 70 return &new 71 } 72 73 func (r *LokiRequest) LogToSpan(sp opentracing.Span) { 74 sp.LogFields( 75 otlog.String("query", r.GetQuery()), 76 otlog.String("start", timestamp.Time(r.GetStart()).String()), 77 otlog.String("end", timestamp.Time(r.GetEnd()).String()), 78 otlog.Int64("step (ms)", r.GetStep()), 79 otlog.Int64("interval (ms)", r.GetInterval()), 80 otlog.Int64("limit", int64(r.GetLimit())), 81 otlog.String("direction", r.GetDirection().String()), 82 otlog.String("shards", strings.Join(r.GetShards(), ",")), 83 ) 84 } 85 86 func (*LokiRequest) GetCachingOptions() (res queryrangebase.CachingOptions) { return } 87 88 func (r *LokiInstantRequest) GetStep() int64 { 89 return 0 90 } 91 92 func (r *LokiInstantRequest) GetEnd() int64 { 93 return r.TimeTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 94 } 95 96 func (r *LokiInstantRequest) GetStart() int64 { 97 return r.TimeTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 98 } 99 100 func (r *LokiInstantRequest) WithStartEnd(s int64, e int64) queryrangebase.Request { 101 new := *r 102 new.TimeTs = time.Unix(0, s*int64(time.Millisecond)) 103 return &new 104 } 105 106 func (r *LokiInstantRequest) WithQuery(query string) queryrangebase.Request { 107 new := *r 108 new.Query = query 109 return &new 110 } 111 112 func (r *LokiInstantRequest) WithShards(shards logql.Shards) *LokiInstantRequest { 113 new := *r 114 new.Shards = shards.Encode() 115 return &new 116 } 117 118 func (r *LokiInstantRequest) LogToSpan(sp opentracing.Span) { 119 sp.LogFields( 120 otlog.String("query", r.GetQuery()), 121 otlog.String("ts", timestamp.Time(r.GetStart()).String()), 122 otlog.Int64("limit", int64(r.GetLimit())), 123 otlog.String("direction", r.GetDirection().String()), 124 otlog.String("shards", strings.Join(r.GetShards(), ",")), 125 ) 126 } 127 128 func (*LokiInstantRequest) GetCachingOptions() (res queryrangebase.CachingOptions) { return } 129 130 func (r *LokiSeriesRequest) GetEnd() int64 { 131 return r.EndTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 132 } 133 134 func (r *LokiSeriesRequest) GetStart() int64 { 135 return r.StartTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 136 } 137 138 func (r *LokiSeriesRequest) WithStartEnd(s int64, e int64) queryrangebase.Request { 139 new := *r 140 new.StartTs = time.Unix(0, s*int64(time.Millisecond)) 141 new.EndTs = time.Unix(0, e*int64(time.Millisecond)) 142 return &new 143 } 144 145 func (r *LokiSeriesRequest) WithQuery(query string) queryrangebase.Request { 146 new := *r 147 return &new 148 } 149 150 func (r *LokiSeriesRequest) GetQuery() string { 151 return "" 152 } 153 154 func (r *LokiSeriesRequest) GetStep() int64 { 155 return 0 156 } 157 158 func (r *LokiSeriesRequest) LogToSpan(sp opentracing.Span) { 159 sp.LogFields( 160 otlog.String("matchers", strings.Join(r.GetMatch(), ",")), 161 otlog.String("start", timestamp.Time(r.GetStart()).String()), 162 otlog.String("end", timestamp.Time(r.GetEnd()).String()), 163 otlog.String("shards", strings.Join(r.GetShards(), ",")), 164 ) 165 } 166 167 func (*LokiSeriesRequest) GetCachingOptions() (res queryrangebase.CachingOptions) { return } 168 169 func (r *LokiLabelNamesRequest) GetEnd() int64 { 170 return r.EndTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 171 } 172 173 func (r *LokiLabelNamesRequest) GetStart() int64 { 174 return r.StartTs.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 175 } 176 177 func (r *LokiLabelNamesRequest) WithStartEnd(s int64, e int64) queryrangebase.Request { 178 new := *r 179 new.StartTs = time.Unix(0, s*int64(time.Millisecond)) 180 new.EndTs = time.Unix(0, e*int64(time.Millisecond)) 181 return &new 182 } 183 184 func (r *LokiLabelNamesRequest) WithQuery(query string) queryrangebase.Request { 185 new := *r 186 return &new 187 } 188 189 func (r *LokiLabelNamesRequest) GetQuery() string { 190 return "" 191 } 192 193 func (r *LokiLabelNamesRequest) GetStep() int64 { 194 return 0 195 } 196 197 func (r *LokiLabelNamesRequest) LogToSpan(sp opentracing.Span) { 198 sp.LogFields( 199 otlog.String("start", timestamp.Time(r.GetStart()).String()), 200 otlog.String("end", timestamp.Time(r.GetEnd()).String()), 201 ) 202 } 203 204 func (*LokiLabelNamesRequest) GetCachingOptions() (res queryrangebase.CachingOptions) { return } 205 206 func (Codec) DecodeRequest(_ context.Context, r *http.Request, forwardHeaders []string) (queryrangebase.Request, error) { 207 if err := r.ParseForm(); err != nil { 208 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 209 } 210 211 switch op := getOperation(r.URL.Path); op { 212 case QueryRangeOp: 213 req, err := loghttp.ParseRangeQuery(r) 214 if err != nil { 215 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 216 } 217 return &LokiRequest{ 218 Query: req.Query, 219 Limit: req.Limit, 220 Direction: req.Direction, 221 StartTs: req.Start.UTC(), 222 EndTs: req.End.UTC(), 223 Step: req.Step.Milliseconds(), 224 Interval: req.Interval.Milliseconds(), 225 Path: r.URL.Path, 226 Shards: req.Shards, 227 }, nil 228 case InstantQueryOp: 229 req, err := loghttp.ParseInstantQuery(r) 230 if err != nil { 231 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 232 } 233 return &LokiInstantRequest{ 234 Query: req.Query, 235 Limit: req.Limit, 236 Direction: req.Direction, 237 TimeTs: req.Ts.UTC(), 238 Path: r.URL.Path, 239 Shards: req.Shards, 240 }, nil 241 case SeriesOp: 242 req, err := loghttp.ParseAndValidateSeriesQuery(r) 243 if err != nil { 244 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 245 } 246 return &LokiSeriesRequest{ 247 Match: req.Groups, 248 StartTs: req.Start.UTC(), 249 EndTs: req.End.UTC(), 250 Path: r.URL.Path, 251 Shards: req.Shards, 252 }, nil 253 case LabelNamesOp: 254 req, err := loghttp.ParseLabelQuery(r) 255 if err != nil { 256 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 257 } 258 return &LokiLabelNamesRequest{ 259 StartTs: *req.Start, 260 EndTs: *req.End, 261 Path: r.URL.Path, 262 }, nil 263 case IndexStatsOp: 264 req, err := loghttp.ParseIndexStatsQuery(r) 265 if err != nil { 266 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 267 } 268 from, through := util.RoundToMilliseconds(req.Start, req.End) 269 return &logproto.IndexStatsRequest{ 270 From: from, 271 Through: through, 272 Matchers: req.Query, 273 }, err 274 default: 275 return nil, httpgrpc.Errorf(http.StatusBadRequest, fmt.Sprintf("unknown request path: %s", r.URL.Path)) 276 } 277 } 278 279 func (Codec) EncodeRequest(ctx context.Context, r queryrangebase.Request) (*http.Request, error) { 280 header := make(http.Header) 281 queryTags := getQueryTags(ctx) 282 if queryTags != "" { 283 header.Set(string(httpreq.QueryTagsHTTPHeader), queryTags) 284 } 285 286 switch request := r.(type) { 287 case *LokiRequest: 288 params := url.Values{ 289 "start": []string{fmt.Sprintf("%d", request.StartTs.UnixNano())}, 290 "end": []string{fmt.Sprintf("%d", request.EndTs.UnixNano())}, 291 "query": []string{request.Query}, 292 "direction": []string{request.Direction.String()}, 293 "limit": []string{fmt.Sprintf("%d", request.Limit)}, 294 } 295 if len(request.Shards) > 0 { 296 params["shards"] = request.Shards 297 } 298 if request.Step != 0 { 299 params["step"] = []string{fmt.Sprintf("%f", float64(request.Step)/float64(1e3))} 300 } 301 if request.Interval != 0 { 302 params["interval"] = []string{fmt.Sprintf("%f", float64(request.Interval)/float64(1e3))} 303 } 304 u := &url.URL{ 305 // the request could come /api/prom/query but we want to only use the new api. 306 Path: "/loki/api/v1/query_range", 307 RawQuery: params.Encode(), 308 } 309 req := &http.Request{ 310 Method: "GET", 311 RequestURI: u.String(), // This is what the httpgrpc code looks at. 312 URL: u, 313 Body: http.NoBody, 314 Header: header, 315 } 316 317 return req.WithContext(ctx), nil 318 case *LokiSeriesRequest: 319 params := url.Values{ 320 "start": []string{fmt.Sprintf("%d", request.StartTs.UnixNano())}, 321 "end": []string{fmt.Sprintf("%d", request.EndTs.UnixNano())}, 322 "match[]": request.Match, 323 } 324 if len(request.Shards) > 0 { 325 params["shards"] = request.Shards 326 } 327 u := &url.URL{ 328 Path: "/loki/api/v1/series", 329 RawQuery: params.Encode(), 330 } 331 req := &http.Request{ 332 Method: "GET", 333 RequestURI: u.String(), // This is what the httpgrpc code looks at. 334 URL: u, 335 Body: http.NoBody, 336 Header: header, 337 } 338 return req.WithContext(ctx), nil 339 case *LokiLabelNamesRequest: 340 params := url.Values{ 341 "start": []string{fmt.Sprintf("%d", request.StartTs.UnixNano())}, 342 "end": []string{fmt.Sprintf("%d", request.EndTs.UnixNano())}, 343 } 344 345 u := &url.URL{ 346 Path: request.Path, // NOTE: this could be either /label or /label/{name}/values endpoint. So forward the original path as it is. 347 RawQuery: params.Encode(), 348 } 349 req := &http.Request{ 350 Method: "GET", 351 RequestURI: u.String(), // This is what the httpgrpc code looks at. 352 URL: u, 353 Body: http.NoBody, 354 Header: header, 355 } 356 return req.WithContext(ctx), nil 357 case *LokiInstantRequest: 358 params := url.Values{ 359 "query": []string{request.Query}, 360 "direction": []string{request.Direction.String()}, 361 "limit": []string{fmt.Sprintf("%d", request.Limit)}, 362 "time": []string{fmt.Sprintf("%d", request.TimeTs.UnixNano())}, 363 } 364 if len(request.Shards) > 0 { 365 params["shards"] = request.Shards 366 } 367 u := &url.URL{ 368 // the request could come /api/prom/query but we want to only use the new api. 369 Path: "/loki/api/v1/query", 370 RawQuery: params.Encode(), 371 } 372 req := &http.Request{ 373 Method: "GET", 374 RequestURI: u.String(), // This is what the httpgrpc code looks at. 375 URL: u, 376 Body: http.NoBody, 377 Header: header, 378 } 379 380 return req.WithContext(ctx), nil 381 case *logproto.IndexStatsRequest: 382 params := url.Values{ 383 "start": []string{fmt.Sprintf("%d", request.From.Time().UnixNano())}, 384 "end": []string{fmt.Sprintf("%d", request.Through.Time().UnixNano())}, 385 "query": []string{request.GetQuery()}, 386 } 387 u := &url.URL{ 388 Path: "/loki/api/v1/index/stats", 389 RawQuery: params.Encode(), 390 } 391 req := &http.Request{ 392 Method: "GET", 393 RequestURI: u.String(), // This is what the httpgrpc code looks at. 394 URL: u, 395 Body: http.NoBody, 396 Header: header, 397 } 398 return req.WithContext(ctx), nil 399 default: 400 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "invalid request format") 401 } 402 } 403 404 type Buffer interface { 405 Bytes() []byte 406 } 407 408 func (Codec) DecodeResponse(ctx context.Context, r *http.Response, req queryrangebase.Request) (queryrangebase.Response, error) { 409 if r.StatusCode/100 != 2 { 410 body, _ := ioutil.ReadAll(r.Body) 411 return nil, httpgrpc.Errorf(r.StatusCode, string(body)) 412 } 413 414 var buf []byte 415 var err error 416 if buffer, ok := r.Body.(Buffer); ok { 417 buf = buffer.Bytes() 418 } else { 419 buf, err = ioutil.ReadAll(r.Body) 420 if err != nil { 421 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err) 422 } 423 } 424 425 switch req := req.(type) { 426 case *LokiSeriesRequest: 427 var resp loghttp.SeriesResponse 428 if err := json.Unmarshal(buf, &resp); err != nil { 429 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err) 430 } 431 432 data := make([]logproto.SeriesIdentifier, 0, len(resp.Data)) 433 for _, label := range resp.Data { 434 d := logproto.SeriesIdentifier{ 435 Labels: label.Map(), 436 } 437 data = append(data, d) 438 } 439 440 return &LokiSeriesResponse{ 441 Status: resp.Status, 442 Version: uint32(loghttp.GetVersion(req.Path)), 443 Data: data, 444 Headers: httpResponseHeadersToPromResponseHeaders(r.Header), 445 }, nil 446 case *LokiLabelNamesRequest: 447 var resp loghttp.LabelResponse 448 if err := json.Unmarshal(buf, &resp); err != nil { 449 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err) 450 } 451 return &LokiLabelNamesResponse{ 452 Status: resp.Status, 453 Version: uint32(loghttp.GetVersion(req.Path)), 454 Data: resp.Data, 455 Headers: httpResponseHeadersToPromResponseHeaders(r.Header), 456 }, nil 457 case *logproto.IndexStatsRequest: 458 var resp logproto.IndexStatsResponse 459 if err := json.Unmarshal(buf, &resp); err != nil { 460 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err) 461 } 462 return &IndexStatsResponse{ 463 Response: &resp, 464 Headers: httpResponseHeadersToPromResponseHeaders(r.Header), 465 }, nil 466 default: 467 var resp loghttp.QueryResponse 468 if err := resp.UnmarshalJSON(buf); err != nil { 469 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err) 470 } 471 switch string(resp.Data.ResultType) { 472 case loghttp.ResultTypeMatrix: 473 return &LokiPromResponse{ 474 Response: &queryrangebase.PrometheusResponse{ 475 Status: resp.Status, 476 Data: queryrangebase.PrometheusData{ 477 ResultType: loghttp.ResultTypeMatrix, 478 Result: toProtoMatrix(resp.Data.Result.(loghttp.Matrix)), 479 }, 480 Headers: convertPrometheusResponseHeadersToPointers(httpResponseHeadersToPromResponseHeaders(r.Header)), 481 }, 482 Statistics: resp.Data.Statistics, 483 }, nil 484 case loghttp.ResultTypeStream: 485 // This is the same as in querysharding.go 486 params, err := paramsFromRequest(req) 487 if err != nil { 488 return nil, err 489 } 490 491 var path string 492 switch r := req.(type) { 493 case *LokiRequest: 494 path = r.GetPath() 495 case *LokiInstantRequest: 496 path = r.GetPath() 497 default: 498 return nil, fmt.Errorf("expected *LokiRequest or *LokiInstantRequest, got (%T)", r) 499 } 500 return &LokiResponse{ 501 Status: resp.Status, 502 Direction: params.Direction(), 503 Limit: params.Limit(), 504 Version: uint32(loghttp.GetVersion(path)), 505 Statistics: resp.Data.Statistics, 506 Data: LokiData{ 507 ResultType: loghttp.ResultTypeStream, 508 Result: resp.Data.Result.(loghttp.Streams).ToProto(), 509 }, 510 Headers: httpResponseHeadersToPromResponseHeaders(r.Header), 511 }, nil 512 case loghttp.ResultTypeVector: 513 return &LokiPromResponse{ 514 Response: &queryrangebase.PrometheusResponse{ 515 Status: resp.Status, 516 Data: queryrangebase.PrometheusData{ 517 ResultType: loghttp.ResultTypeVector, 518 Result: toProtoVector(resp.Data.Result.(loghttp.Vector)), 519 }, 520 Headers: convertPrometheusResponseHeadersToPointers(httpResponseHeadersToPromResponseHeaders(r.Header)), 521 }, 522 Statistics: resp.Data.Statistics, 523 }, nil 524 default: 525 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "unsupported response type, got (%s)", string(resp.Data.ResultType)) 526 } 527 } 528 } 529 530 func (Codec) EncodeResponse(ctx context.Context, res queryrangebase.Response) (*http.Response, error) { 531 sp, _ := opentracing.StartSpanFromContext(ctx, "codec.EncodeResponse") 532 defer sp.Finish() 533 var buf bytes.Buffer 534 535 switch response := res.(type) { 536 case *LokiPromResponse: 537 return response.encode(ctx) 538 case *LokiResponse: 539 streams := make([]logproto.Stream, len(response.Data.Result)) 540 541 for i, stream := range response.Data.Result { 542 streams[i] = logproto.Stream{ 543 Labels: stream.Labels, 544 Entries: stream.Entries, 545 } 546 } 547 result := logqlmodel.Result{ 548 Data: logqlmodel.Streams(streams), 549 Statistics: response.Statistics, 550 } 551 if loghttp.Version(response.Version) == loghttp.VersionLegacy { 552 if err := marshal_legacy.WriteQueryResponseJSON(result, &buf); err != nil { 553 return nil, err 554 } 555 } else { 556 if err := marshal.WriteQueryResponseJSON(result, &buf); err != nil { 557 return nil, err 558 } 559 } 560 561 case *LokiSeriesResponse: 562 result := logproto.SeriesResponse{ 563 Series: response.Data, 564 } 565 if err := marshal.WriteSeriesResponseJSON(result, &buf); err != nil { 566 return nil, err 567 } 568 case *LokiLabelNamesResponse: 569 if loghttp.Version(response.Version) == loghttp.VersionLegacy { 570 if err := marshal_legacy.WriteLabelResponseJSON(logproto.LabelResponse{Values: response.Data}, &buf); err != nil { 571 return nil, err 572 } 573 } else { 574 if err := marshal.WriteLabelResponseJSON(logproto.LabelResponse{Values: response.Data}, &buf); err != nil { 575 return nil, err 576 } 577 } 578 case *IndexStatsResponse: 579 if err := marshal.WriteIndexStatsResponseJSON(response.Response, &buf); err != nil { 580 return nil, err 581 } 582 583 default: 584 return nil, httpgrpc.Errorf(http.StatusInternalServerError, "invalid response format") 585 } 586 587 sp.LogFields(otlog.Int("bytes", buf.Len())) 588 589 resp := http.Response{ 590 Header: http.Header{ 591 "Content-Type": []string{"application/json"}, 592 }, 593 Body: ioutil.NopCloser(&buf), 594 StatusCode: http.StatusOK, 595 } 596 return &resp, nil 597 } 598 599 // NOTE: When we would start caching response from non-metric queries we would have to consider cache gen headers as well in 600 // MergeResponse implementation for Loki codecs same as it is done in Cortex at https://github.com/cortexproject/cortex/blob/21bad57b346c730d684d6d0205efef133422ab28/pkg/querier/queryrange/query_range.go#L170 601 func (Codec) MergeResponse(responses ...queryrangebase.Response) (queryrangebase.Response, error) { 602 if len(responses) == 0 { 603 return nil, errors.New("merging responses requires at least one response") 604 } 605 var mergedStats stats.Result 606 switch responses[0].(type) { 607 case *LokiPromResponse: 608 609 promResponses := make([]queryrangebase.Response, 0, len(responses)) 610 for _, res := range responses { 611 mergedStats.Merge(res.(*LokiPromResponse).Statistics) 612 promResponses = append(promResponses, res.(*LokiPromResponse).Response) 613 } 614 promRes, err := queryrangebase.PrometheusCodec.MergeResponse(promResponses...) 615 if err != nil { 616 return nil, err 617 } 618 return &LokiPromResponse{ 619 Response: promRes.(*queryrangebase.PrometheusResponse), 620 Statistics: mergedStats, 621 }, nil 622 case *LokiResponse: 623 return mergeLokiResponse(responses...), nil 624 case *LokiSeriesResponse: 625 lokiSeriesRes := responses[0].(*LokiSeriesResponse) 626 627 var lokiSeriesData []logproto.SeriesIdentifier 628 uniqueSeries := make(map[string]struct{}) 629 630 // only unique series should be merged 631 for _, res := range responses { 632 lokiResult := res.(*LokiSeriesResponse) 633 for _, series := range lokiResult.Data { 634 if _, ok := uniqueSeries[series.String()]; !ok { 635 lokiSeriesData = append(lokiSeriesData, series) 636 uniqueSeries[series.String()] = struct{}{} 637 } 638 } 639 } 640 641 return &LokiSeriesResponse{ 642 Status: lokiSeriesRes.Status, 643 Version: lokiSeriesRes.Version, 644 Data: lokiSeriesData, 645 }, nil 646 case *LokiLabelNamesResponse: 647 labelNameRes := responses[0].(*LokiLabelNamesResponse) 648 uniqueNames := make(map[string]struct{}) 649 names := []string{} 650 651 // only unique name should be merged 652 for _, res := range responses { 653 lokiResult := res.(*LokiLabelNamesResponse) 654 for _, labelName := range lokiResult.Data { 655 if _, ok := uniqueNames[labelName]; !ok { 656 names = append(names, labelName) 657 uniqueNames[labelName] = struct{}{} 658 } 659 } 660 } 661 662 return &LokiLabelNamesResponse{ 663 Status: labelNameRes.Status, 664 Version: labelNameRes.Version, 665 Data: names, 666 }, nil 667 default: 668 return nil, errors.New("unknown response in merging responses") 669 } 670 } 671 672 // mergeOrderedNonOverlappingStreams merges a set of ordered, nonoverlapping responses by concatenating matching streams then running them through a heap to pull out limit values 673 func mergeOrderedNonOverlappingStreams(resps []*LokiResponse, limit uint32, direction logproto.Direction) []logproto.Stream { 674 var total int 675 676 // turn resps -> map[labels] []entries 677 groups := make(map[string]*byDir) 678 for _, resp := range resps { 679 for _, stream := range resp.Data.Result { 680 s, ok := groups[stream.Labels] 681 if !ok { 682 s = &byDir{ 683 direction: direction, 684 labels: stream.Labels, 685 } 686 groups[stream.Labels] = s 687 } 688 689 s.markers = append(s.markers, stream.Entries) 690 total += len(stream.Entries) 691 } 692 693 // optimization: since limit has been reached, no need to append entries from subsequent responses 694 if total >= int(limit) { 695 break 696 } 697 } 698 699 keys := make([]string, 0, len(groups)) 700 for key := range groups { 701 keys = append(keys, key) 702 } 703 if direction == logproto.BACKWARD { 704 sort.Sort(sort.Reverse(sort.StringSlice(keys))) 705 } else { 706 sort.Strings(keys) 707 } 708 709 // escape hatch, can just return all the streams 710 if total <= int(limit) { 711 results := make([]logproto.Stream, 0, len(keys)) 712 for _, key := range keys { 713 results = append(results, logproto.Stream{ 714 Labels: key, 715 Entries: groups[key].merge(), 716 }) 717 } 718 return results 719 } 720 721 pq := &priorityqueue{ 722 direction: direction, 723 } 724 725 for _, key := range keys { 726 stream := &logproto.Stream{ 727 Labels: key, 728 Entries: groups[key].merge(), 729 } 730 if len(stream.Entries) > 0 { 731 pq.streams = append(pq.streams, stream) 732 } 733 } 734 735 heap.Init(pq) 736 737 resultDict := make(map[string]*logproto.Stream) 738 739 // we want the min(limit, num_entries) 740 for i := 0; i < int(limit) && pq.Len() > 0; i++ { 741 // grab the next entry off the queue. This will be a stream (to preserve labels) with one entry. 742 next := heap.Pop(pq).(*logproto.Stream) 743 744 s, ok := resultDict[next.Labels] 745 if !ok { 746 s = &logproto.Stream{ 747 Labels: next.Labels, 748 Entries: make([]logproto.Entry, 0, int(limit)/len(keys)), // allocation hack -- assume uniform distribution across labels 749 } 750 resultDict[next.Labels] = s 751 } 752 // TODO: make allocation friendly 753 s.Entries = append(s.Entries, next.Entries...) 754 } 755 756 results := make([]logproto.Stream, 0, len(resultDict)) 757 for _, key := range keys { 758 stream, ok := resultDict[key] 759 if ok { 760 results = append(results, *stream) 761 } 762 } 763 764 return results 765 } 766 767 func toProtoMatrix(m loghttp.Matrix) []queryrangebase.SampleStream { 768 res := make([]queryrangebase.SampleStream, 0, len(m)) 769 770 if len(m) == 0 { 771 return res 772 } 773 774 for _, stream := range m { 775 samples := make([]logproto.LegacySample, 0, len(stream.Values)) 776 for _, s := range stream.Values { 777 samples = append(samples, logproto.LegacySample{ 778 Value: float64(s.Value), 779 TimestampMs: int64(s.Timestamp), 780 }) 781 } 782 res = append(res, queryrangebase.SampleStream{ 783 Labels: logproto.FromMetricsToLabelAdapters(stream.Metric), 784 Samples: samples, 785 }) 786 } 787 return res 788 } 789 790 func toProtoVector(v loghttp.Vector) []queryrangebase.SampleStream { 791 res := make([]queryrangebase.SampleStream, 0, len(v)) 792 793 if len(v) == 0 { 794 return res 795 } 796 for _, s := range v { 797 res = append(res, queryrangebase.SampleStream{ 798 Samples: []logproto.LegacySample{{ 799 Value: float64(s.Value), 800 TimestampMs: int64(s.Timestamp), 801 }}, 802 Labels: logproto.FromMetricsToLabelAdapters(s.Metric), 803 }) 804 } 805 return res 806 } 807 808 func (res LokiResponse) Count() int64 { 809 var result int64 810 for _, s := range res.Data.Result { 811 result += int64(len(s.Entries)) 812 } 813 return result 814 } 815 816 func paramsFromRequest(req queryrangebase.Request) (logql.Params, error) { 817 switch r := req.(type) { 818 case *LokiRequest: 819 return ¶msRangeWrapper{ 820 LokiRequest: r, 821 }, nil 822 case *LokiInstantRequest: 823 return ¶msInstantWrapper{ 824 LokiInstantRequest: r, 825 }, nil 826 case *LokiSeriesRequest: 827 return ¶msSeriesWrapper{ 828 LokiSeriesRequest: r, 829 }, nil 830 case *LokiLabelNamesRequest: 831 return ¶msLabelNamesWrapper{ 832 LokiLabelNamesRequest: r, 833 }, nil 834 default: 835 return nil, fmt.Errorf("expected one of the *LokiRequest, *LokiInstantRequest, *LokiSeriesRequest, *LokiLabelNamesRequest, got (%T)", r) 836 } 837 } 838 839 type paramsRangeWrapper struct { 840 *LokiRequest 841 } 842 843 func (p paramsRangeWrapper) Query() string { 844 return p.GetQuery() 845 } 846 847 func (p paramsRangeWrapper) Start() time.Time { 848 return p.GetStartTs() 849 } 850 851 func (p paramsRangeWrapper) End() time.Time { 852 return p.GetEndTs() 853 } 854 855 func (p paramsRangeWrapper) Step() time.Duration { 856 return time.Duration(p.GetStep() * 1e6) 857 } 858 func (p paramsRangeWrapper) Interval() time.Duration { 859 return time.Duration(p.GetInterval() * 1e6) 860 } 861 func (p paramsRangeWrapper) Direction() logproto.Direction { 862 return p.GetDirection() 863 } 864 func (p paramsRangeWrapper) Limit() uint32 { return p.LokiRequest.Limit } 865 func (p paramsRangeWrapper) Shards() []string { 866 return p.GetShards() 867 } 868 869 type paramsInstantWrapper struct { 870 *LokiInstantRequest 871 } 872 873 func (p paramsInstantWrapper) Query() string { 874 return p.GetQuery() 875 } 876 877 func (p paramsInstantWrapper) Start() time.Time { 878 return p.LokiInstantRequest.GetTimeTs() 879 } 880 881 func (p paramsInstantWrapper) End() time.Time { 882 return p.LokiInstantRequest.GetTimeTs() 883 } 884 885 func (p paramsInstantWrapper) Step() time.Duration { 886 return time.Duration(p.GetStep() * 1e6) 887 } 888 func (p paramsInstantWrapper) Interval() time.Duration { return 0 } 889 func (p paramsInstantWrapper) Direction() logproto.Direction { 890 return p.GetDirection() 891 } 892 func (p paramsInstantWrapper) Limit() uint32 { return p.LokiInstantRequest.Limit } 893 func (p paramsInstantWrapper) Shards() []string { 894 return p.GetShards() 895 } 896 897 type paramsSeriesWrapper struct { 898 *LokiSeriesRequest 899 } 900 901 func (p paramsSeriesWrapper) Query() string { 902 return p.GetQuery() 903 } 904 905 func (p paramsSeriesWrapper) Start() time.Time { 906 return p.LokiSeriesRequest.GetStartTs() 907 } 908 909 func (p paramsSeriesWrapper) End() time.Time { 910 return p.LokiSeriesRequest.GetEndTs() 911 } 912 913 func (p paramsSeriesWrapper) Step() time.Duration { 914 return time.Duration(p.GetStep() * 1e6) 915 } 916 func (p paramsSeriesWrapper) Interval() time.Duration { return 0 } 917 func (p paramsSeriesWrapper) Direction() logproto.Direction { 918 return logproto.FORWARD 919 } 920 func (p paramsSeriesWrapper) Limit() uint32 { return 0 } 921 func (p paramsSeriesWrapper) Shards() []string { 922 return p.GetShards() 923 } 924 925 type paramsLabelNamesWrapper struct { 926 *LokiLabelNamesRequest 927 } 928 929 func (p paramsLabelNamesWrapper) Query() string { 930 return p.GetQuery() 931 } 932 933 func (p paramsLabelNamesWrapper) Start() time.Time { 934 return p.LokiLabelNamesRequest.GetStartTs() 935 } 936 937 func (p paramsLabelNamesWrapper) End() time.Time { 938 return p.LokiLabelNamesRequest.GetEndTs() 939 } 940 941 func (p paramsLabelNamesWrapper) Step() time.Duration { 942 return time.Duration(p.GetStep() * 1e6) 943 } 944 func (p paramsLabelNamesWrapper) Interval() time.Duration { return 0 } 945 func (p paramsLabelNamesWrapper) Direction() logproto.Direction { 946 return logproto.FORWARD 947 } 948 func (p paramsLabelNamesWrapper) Limit() uint32 { return 0 } 949 func (p paramsLabelNamesWrapper) Shards() []string { 950 return make([]string, 0) 951 } 952 953 func httpResponseHeadersToPromResponseHeaders(httpHeaders http.Header) []queryrangebase.PrometheusResponseHeader { 954 var promHeaders []queryrangebase.PrometheusResponseHeader 955 for h, hv := range httpHeaders { 956 promHeaders = append(promHeaders, queryrangebase.PrometheusResponseHeader{Name: h, Values: hv}) 957 } 958 959 return promHeaders 960 } 961 962 func getQueryTags(ctx context.Context) string { 963 v, _ := ctx.Value(httpreq.QueryTagsHTTPHeader).(string) // it's ok to be empty 964 return v 965 } 966 967 func NewEmptyResponse(r queryrangebase.Request) (queryrangebase.Response, error) { 968 switch req := r.(type) { 969 case *LokiSeriesRequest: 970 return &LokiSeriesResponse{ 971 Status: loghttp.QueryStatusSuccess, 972 Version: uint32(loghttp.GetVersion(req.Path)), 973 }, nil 974 case *LokiLabelNamesRequest: 975 return &LokiLabelNamesResponse{ 976 Status: loghttp.QueryStatusSuccess, 977 Version: uint32(loghttp.GetVersion(req.Path)), 978 }, nil 979 case *LokiInstantRequest: 980 // instant queries in the frontend are always metrics queries. 981 return &LokiPromResponse{ 982 Response: &queryrangebase.PrometheusResponse{ 983 Status: loghttp.QueryStatusSuccess, 984 Data: queryrangebase.PrometheusData{ 985 ResultType: loghttp.ResultTypeVector, 986 }, 987 }, 988 }, nil 989 case *LokiRequest: 990 // range query can either be metrics or logs 991 expr, err := syntax.ParseExpr(req.Query) 992 if err != nil { 993 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 994 } 995 if _, ok := expr.(syntax.SampleExpr); ok { 996 return &LokiPromResponse{ 997 Response: queryrangebase.NewEmptyPrometheusResponse(), 998 }, nil 999 } 1000 return &LokiResponse{ 1001 Status: loghttp.QueryStatusSuccess, 1002 Direction: req.Direction, 1003 Limit: req.Limit, 1004 Version: uint32(loghttp.GetVersion(req.Path)), 1005 Data: LokiData{ 1006 ResultType: loghttp.ResultTypeStream, 1007 }, 1008 }, nil 1009 default: 1010 return nil, fmt.Errorf("unsupported request type %T", req) 1011 } 1012 } 1013 1014 func mergeLokiResponse(responses ...queryrangebase.Response) *LokiResponse { 1015 if len(responses) == 0 { 1016 return nil 1017 } 1018 var ( 1019 lokiRes = responses[0].(*LokiResponse) 1020 mergedStats stats.Result 1021 lokiResponses = make([]*LokiResponse, 0, len(responses)) 1022 ) 1023 1024 for _, res := range responses { 1025 lokiResult := res.(*LokiResponse) 1026 mergedStats.Merge(lokiResult.Statistics) 1027 lokiResponses = append(lokiResponses, lokiResult) 1028 } 1029 1030 return &LokiResponse{ 1031 Status: loghttp.QueryStatusSuccess, 1032 Direction: lokiRes.Direction, 1033 Limit: lokiRes.Limit, 1034 Version: lokiRes.Version, 1035 ErrorType: lokiRes.ErrorType, 1036 Error: lokiRes.Error, 1037 Statistics: mergedStats, 1038 Data: LokiData{ 1039 ResultType: loghttp.ResultTypeStream, 1040 Result: mergeOrderedNonOverlappingStreams(lokiResponses, lokiRes.Limit, lokiRes.Direction), 1041 }, 1042 } 1043 }