chore: remove metrics summary (#6510)
* chore: remove metrics summary * CHANGELOG
This commit is contained in:
+1
-1
@@ -39,7 +39,7 @@
|
||||
* [CHANGE] **BREAKING CHANGE** Remove ingesters and compactor alerts [#6369](https://github.com/grafana/tempo/pull/6369) (@javiermolinar)
|
||||
* [CHANGE] **BREAKING CHANGE** Removed `v2` block encoding and compactor component. [#6273](https://github.com/grafana/tempo/pull/6273) (@joe-elliott)
|
||||
This includes the removal of the following CLI commands which were `v2` specific: `list block`, `list index`, `view index`, `gen index`, `gen bloom`.
|
||||
* [CHANGE] **BREAKING CHANGE** SpanMetricsSummary is removed and querier code simplified [#6496](https://github.com/grafana/tempo/pull/6496) (@javiermolinar)
|
||||
* [CHANGE] **BREAKING CHANGE** SpanMetricsSummary is removed and querier code simplified [#6496](https://github.com/grafana/tempo/pull/6496) [#6510](https://github.com/grafana/tempo/pull/6510) (@javiermolinar)
|
||||
* [CHANGE] **BREAKING CHANGE** Sets the `all` target to be 3.0 compatible and removes the `scalable-single-binary` target [#6283](https://github.com/grafana/tempo/pull/6283) (@joe-elliott)
|
||||
* [CHANGE] **BREAKING CHANGE** Clean up enterprise jsonnet [#6505](https://github.com/grafana/tempo/pull/6505) (@javiermolinar)
|
||||
* [CHANGE] Expose otlp http and grpc ports for Docker examples [#6296](https://github.com/grafana/tempo/pull/6296) (@javiermolinar)
|
||||
|
||||
@@ -65,11 +65,6 @@ func (m *MockHTTPClient) GetOverrides() (*userconfigurableoverrides.Limits, stri
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
//nolint:all
|
||||
func (m *MockHTTPClient) MetricsSummary(_ string, _ string, _ int64, _ int64) (*tempopb.SpanMetricsSummaryResponse, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
//nolint:all
|
||||
func (m *MockHTTPClient) MetricsQueryRange(_ string, _, _ int64, _ string, _ int) (*tempopb.QueryRangeResponse, error) {
|
||||
if m.err != nil {
|
||||
|
||||
@@ -444,9 +444,6 @@ func (t *App) initQuerier() (services.Service, error) {
|
||||
searchTagValuesV2Handler := t.HTTPAuthMiddleware.Wrap(http.HandlerFunc(t.querier.SearchTagValuesV2Handler))
|
||||
t.Server.HTTPRouter().Handle(path.Join(api.PathPrefixQuerier, addHTTPAPIPrefix(&t.cfg, api.PathSearchTagValuesV2)), searchTagValuesV2Handler)
|
||||
|
||||
spanMetricsSummaryHandler := t.HTTPAuthMiddleware.Wrap(http.HandlerFunc(t.querier.SpanMetricsSummaryHandler))
|
||||
t.Server.HTTPRouter().Handle(path.Join(api.PathPrefixQuerier, addHTTPAPIPrefix(&t.cfg, api.PathSpanMetricsSummary)), spanMetricsSummaryHandler)
|
||||
|
||||
queryRangeHandler := t.HTTPAuthMiddleware.Wrap(http.HandlerFunc(t.querier.QueryRangeHandler))
|
||||
t.Server.HTTPRouter().Handle(path.Join(api.PathPrefixQuerier, addHTTPAPIPrefix(&t.cfg, api.PathMetricsQueryRange)), queryRangeHandler)
|
||||
|
||||
@@ -500,7 +497,6 @@ func (t *App) initQueryFrontend() (services.Service, error) {
|
||||
t.Server.HTTPRouter().Handle(addHTTPAPIPrefix(&t.cfg, api.PathSearchTagValuesV2), base.Wrap(queryFrontend.SearchTagsValuesV2Handler))
|
||||
|
||||
// http metrics endpoints
|
||||
t.Server.HTTPRouter().Handle(addHTTPAPIPrefix(&t.cfg, api.PathSpanMetricsSummary), base.Wrap(queryFrontend.MetricsSummaryHandler))
|
||||
t.Server.HTTPRouter().Handle(addHTTPAPIPrefix(&t.cfg, api.PathMetricsQueryInstant), base.Wrap(queryFrontend.MetricsQueryInstantHandler))
|
||||
t.Server.HTTPRouter().Handle(addHTTPAPIPrefix(&t.cfg, api.PathMetricsQueryRange), base.Wrap(queryFrontend.MetricsQueryRangeHandler))
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
---
|
||||
description: Learn how to use the metrics summary API in Tempo
|
||||
keywords:
|
||||
- Metrics summary
|
||||
- API
|
||||
title: Metrics summary API
|
||||
weight: 600
|
||||
---
|
||||
|
||||
# Metrics summary API
|
||||
|
||||
{{< admonition type="warning" >}}
|
||||
The metrics summary API is deprecated as of Tempo 2.7. Features powered by the metrics summary API, like the [Aggregate by table](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/query-editor/traceql-search/#optional-use-aggregate-by), are also deprecated in Grafana Cloud and Grafana 11.3 and later.
|
||||
It will be removed in a future release.
|
||||
{{< /admonition >}}
|
||||
|
||||
This document explains how to use the metrics summary API in Tempo.
|
||||
This API returns RED metrics (span count, erroring span count, and latency information) for `kind=server` spans sent to Tempo in the last hour, grouped by a user-specified attribute.
|
||||
|
||||
{{< youtube id="g97CjKOZqT4" >}}
|
||||
|
||||
## Deprecation in favor of TraceQL metrics
|
||||
|
||||
The metrics summary API is now redundant given the release of TraceQL metrics.
|
||||
This API is therefore being deprecated to reduce our maintenance burden.
|
||||
|
||||
TraceQL metrics queries are significantly more powerful than what metrics summary API provides.
|
||||
TraceQL metrics can look at arbitrary time windows (not just the last hour), return time series information (rather than just a single instant value over the past hour), and can look at all spans (not just `kind=server`).
|
||||
|
||||
To provide an example, if you were to aggregate by the attribute `resource.cloud.region` with the metrics summary API, you could get the same results with a couple TraceQL queries:
|
||||
|
||||
Rate of requests by `resource.cloud.region`
|
||||
```
|
||||
{ } | rate() by (resource.cloud.region)
|
||||
```
|
||||
|
||||
Error rate by `resource.cloud.region`
|
||||
```
|
||||
{ status=error } | rate() by (resource.cloud.region)
|
||||
```
|
||||
|
||||
The 50th, 90th, and 99th percentile latencies (for example, p99, p90, and p50) by `resource.cloud.region`:
|
||||
```
|
||||
{ } | quantile_over_time(duration, .99, .9, .5) by (resource.cloud.region)
|
||||
```
|
||||
|
||||
If you want something faster than typing these queries out in Explore's code mode, use [Grafana Traces Drilldown](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/explore/simplified-exploration/traces/), a queryless experience for navigating your trace data stored in Tempo and powered by TraceQL metrics queries under the hood.
|
||||
|
||||
## Activate metrics summary
|
||||
|
||||
To enable the deprecated) metrics summary API, you must turn on the local blocks processor in the metrics generator.
|
||||
Be aware that the generator uses considerably more resources, including disk space, if it's enabled:
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
defaults:
|
||||
metrics_generator:
|
||||
processors: [..., 'local-blocks']
|
||||
```
|
||||
|
||||
In Grafana and Grafana Cloud, the Metrics summary API is disabled by default.
|
||||
To enable it in Grafana Cloud, contact Grafana Support.
|
||||
|
||||
## Request
|
||||
|
||||
To make a request to this API, use the following endpoint on the query-frontend:
|
||||
|
||||
```
|
||||
GET http://<tempo>/api/metrics/summary
|
||||
```
|
||||
|
||||
### Query Parameters
|
||||
|
||||
All query parameters must be URL-encoded to preserve non-URL-safe characters in the query such as `&`.
|
||||
|
||||
| Name | Examples | Definition | Required? |
|
||||
| --------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
||||
| `q` | `{ resource.service.name = "foo" && span.http.status_code != 200 }` | The TraceQL query with full syntax. All spans matching this query are included in the calculations. Any valid TraceQL query is supported. | Yes |
|
||||
| `groupBy` | `name` <br /> `.foo` <br/> `resource.namespace` <br/> `span.http.url,span.http.status_code` <br> | One or more TraceQL values to group by. Any valid intrinsic or attribute with scope. To group by multiple values use a comma-delimited list. | Yes |
|
||||
| `start ` | 1672549200 | Start of time range in Unix seconds. If not specified, then all recent data is queried. | No |
|
||||
| `end` | 1672549200 | End of the time range in Unix seconds. If not specified, then all recent data is queried. | No |
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl "$URL/api/metrics/summary" --data-urlencode 'q={resource.service.name="checkout-service"}' --data-urlencode 'groupBy=name'
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
The Tempo response is a `SpanMetricsSummary` object defined in [tempo.proto](https://github.com/grafana/tempo/blob/main/pkg/tempopb/tempo.proto#L234), relevant section pasted below:
|
||||
|
||||
```
|
||||
message SpanMetricsSummaryResponse {
|
||||
repeated SpanMetricsSummary summaries = 1;
|
||||
}
|
||||
|
||||
message SpanMetricsSummary {
|
||||
uint64 spanCount = 1;
|
||||
uint64 errorSpanCount = 2;
|
||||
TraceQLStatic static = 3;
|
||||
uint64 p99 = 4;
|
||||
uint64 p95 = 5;
|
||||
uint64 p90 = 6;
|
||||
uint64 p50 = 7;
|
||||
}
|
||||
|
||||
message TraceQLStatic {
|
||||
int32 type = 1;
|
||||
int64 n = 2;
|
||||
double f = 3;
|
||||
string s = 4;
|
||||
bool b = 5;
|
||||
uint64 d = 6;
|
||||
int32 status = 7;
|
||||
int32 kind = 8;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The response is returned as JSON following [standard protobuf->JSON mapping rules](https://protobuf.dev/programming-guides/proto3/#json).
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
The `uint64` fields can't be fully expressed by JSON numeric values so the fields are serialized as strings.
|
||||
{{< /admonition >}}
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"summaries": [
|
||||
{
|
||||
"spanCount": "20",
|
||||
"series" : [
|
||||
{
|
||||
"key": ".attr1",
|
||||
"value": {
|
||||
"type": 5,
|
||||
"s": "foo"
|
||||
},
|
||||
},
|
||||
...
|
||||
],
|
||||
"p99": "68719476736",
|
||||
"p95": "1073741824",
|
||||
"p90": "1017990479",
|
||||
"p50": "664499239"
|
||||
},
|
||||
```
|
||||
|
||||
| Field | Notes |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `summaries` | The list of metrics per group. |
|
||||
| `.spanCount` | Number of spans in this group. |
|
||||
| `.errorSpanCount` | Number of spans with `status`=`error`. (This field isn't present if the value is `0`.) |
|
||||
| `.series` | The unique values for this group. A key/value pair is returned for each entry in `groupBy`. |
|
||||
| `.key` | Key name. |
|
||||
| `.value` | Value with TraceQL underlying type. |
|
||||
| `.type` | Data type `enum`` defined [here](https://github.com/grafana/tempo/blob/main/pkg/traceql/enum_statics.go#L8) (This field will not be present if the value is `0`.) <br/>0 = `nil`<br/>3 = `integer`<br/> 4 = `float` <br/> 5 = `string`<br/> 6 = `bool`<br/> 7 = `duration`<br/> 8 = span status<br/> 9 = span kind |
|
||||
| `.n` | Populated if this is an integer value. |
|
||||
| `.s` | Populated if this is a string value. |
|
||||
| `.f` | Populated if this is a float value. |
|
||||
| `.b` | Populated if this is a boolean value. |
|
||||
| `.d` | Populated if this is a duration value. |
|
||||
| `.status` | Populated if this is a span status value. |
|
||||
| `.kind` | Populated if this is a span kind value. |
|
||||
| `.p99` | The p99 latency of this group in nanoseconds. |
|
||||
| `.p95` | The p95 latency of this group in nanoseconds. |
|
||||
| `.p90` | The p90 latency of this group in nanoseconds. |
|
||||
| `.p50` | The p50 latency of this group in nanoseconds. |
|
||||
@@ -706,7 +706,7 @@ query_frontend:
|
||||
# Set a maximum timeout for all api queries at which point the frontend will cancel queued jobs
|
||||
# and return cleanly. HTTP will return a 503 and GRPC will return a context canceled error.
|
||||
# This timeout impacts all http and grpc streaming queries as part of the Tempo api surface such as
|
||||
# search, metrics summary, tags and tag values lookups, etc.
|
||||
# search, metrics queries, tags and tag values lookups, etc.
|
||||
# Generally it is preferred to let the client cancel context. This is a failsafe to prevent a client
|
||||
# from imposing more work on Tempo than desired.
|
||||
# (default: 0)
|
||||
|
||||
@@ -11,9 +11,8 @@ aliases:
|
||||
Metrics provide a powerful insight into the systems you are monitoring with your observability strategy.
|
||||
Instead of running an additional service to generate metrics, you can use Grafana Tempo to generate metrics from traces.
|
||||
|
||||
Grafana Tempo can generate metrics from tracing data using the metrics-generator, TraceQL metrics (experimental), and the metrics summary API (deprecated).
|
||||
Grafana Tempo can generate metrics from tracing data using the metrics-generator and TraceQL metrics.
|
||||
Refer to the table for a summary of these metrics and their capabilities.
|
||||
Metrics summary isn't included in the table because it's deprecated.
|
||||
|
||||
| | Metrics-generator | TraceQL metrics |
|
||||
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -95,22 +94,3 @@ Refer to these resources for additional information:
|
||||
- [Configure TraceQL metrics](https://grafana.com/docs/tempo/<TEMPO_VERSION>/metrics-from-traces/metrics-queries/configure-traceql-metrics/)
|
||||
- [TraceQL metrics queries](https://grafana.com/docs/tempo/<TEMPO_VERSION>/metrics-from-traces/metrics-queries/)
|
||||
- [TraceQL metrics functions](https://grafana.com/docs/tempo/<TEMPO_VERSION>/metrics-from-traces/metrics-queries/functions/)
|
||||
|
||||
## Metrics summary API (deprecated)
|
||||
|
||||
{{< admonition type="warning" >}}
|
||||
The metrics summary API is deprecated as of Tempo 2.7. Features powered by the metrics summary API, like the [Aggregate by table](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/query-editor/traceql-search/#optional-use-aggregate-by), are also deprecated in Grafana Cloud and Grafana 11.3 and later.
|
||||
It will be removed in a future release.
|
||||
{{< /admonition >}}
|
||||
|
||||
The metrics summary API was an early capability in Tempo for generating ad hoc RED metrics at query time.
|
||||
This data was displayed in the Aggregate by table in Grafana Explore, where you could see request rate, error rate, and latency values of your system over the last hour, computed from your trace data.
|
||||
Those values were broken down by any and all attributes attached to your traces.
|
||||
|
||||
When you used the “Aggregate by” option, Grafana made a call to Tempo’s metrics summary API, which returned these RED metrics based on spans of `kind=server` seen in the last hour.
|
||||
|
||||
The metrics summary API returns RED metrics for `kind=server` spans sent to Tempo in the last hour.
|
||||
The metrics summary feature creates metrics from trace data without using metrics-generator.
|
||||
|
||||
The metrics summary API and the Aggregate by table have been deprecated in favor of TraceQL metrics.
|
||||
For more information, refer to [Deprecation in favor of TraceQL metrics](https://grafana.com/docs/tempo/<TEMPO_VERSION>/api_docs/metrics-summary/#deprecation-in-favor-of-traceql-metrics).
|
||||
|
||||
@@ -19,7 +19,6 @@ Tempo supports multi-tenant queries for search, search-tags, and trace-by-ID sea
|
||||
TraceQL metrics queries (for example, query range and instant endpoints that use TraceQLMetrics) also support cross-tenant queries.
|
||||
|
||||
These operations can be federated across multiple tenants when you specify more than one tenant ID in the `X-Scope-OrgID` header.
|
||||
Metrics summary APIs remain single-tenant only, even when `multi_tenant_queries_enabled` is set to `true`.
|
||||
|
||||
To perform multi-tenant queries, send tenant IDs separated by a `|` character in the `X-Scope-OrgID` header, for example, `foo|bar`.
|
||||
|
||||
|
||||
@@ -123,9 +123,6 @@ func TestInvalidTenants(t *testing.T) {
|
||||
assertHTTP400(t, err)
|
||||
|
||||
if !tc.multitenant {
|
||||
_, err := apiClient.MetricsSummary("{}", "name", 0, 0)
|
||||
assertHTTP400(t, err)
|
||||
|
||||
_, err = apiClient.MetricsQueryRange("{} | count_over_time()", 0, 0, "", 0)
|
||||
assertHTTP400(t, err)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ package frontend
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
@@ -49,7 +47,7 @@ type (
|
||||
)
|
||||
|
||||
type QueryFrontend struct {
|
||||
TraceByIDHandler, TraceByIDHandlerV2, SearchHandler, MetricsSummaryHandler http.Handler
|
||||
TraceByIDHandler, TraceByIDHandlerV2, SearchHandler http.Handler
|
||||
SearchTagsHandler, SearchTagsV2Handler, SearchTagsValuesHandler, SearchTagsValuesV2Handler http.Handler
|
||||
MetricsQueryInstantHandler, MetricsQueryRangeHandler http.Handler
|
||||
MCPHandler http.Handler
|
||||
@@ -72,7 +70,6 @@ type DataAccessController interface {
|
||||
HandleHTTPTagValuesV2Req(r *http.Request) error
|
||||
HandleHTTPQueryRangeReq(r *http.Request) error
|
||||
HandleHTTPQueryInstantReq(r *http.Request) error
|
||||
HandleHTTPMetricsSummaryReq(r *http.Request) error
|
||||
HandleHTTPTraceByIDReq(r *http.Request) (combiner.TraceRedactor, error)
|
||||
|
||||
HandleGRPCSearchReq(c context.Context, r *tempopb.SearchRequest) error
|
||||
@@ -208,19 +205,6 @@ func New(cfg Config, next pipeline.RoundTripper, o overrides.Interface, reader t
|
||||
[]pipeline.Middleware{cacheWare, statusCodeWare, retryWare},
|
||||
next)
|
||||
|
||||
// metrics summary
|
||||
metricsPipeline := pipeline.Build(
|
||||
[]pipeline.AsyncMiddleware[combiner.PipelineResponse]{
|
||||
urlDenyListWare,
|
||||
adjustEndWareNanos,
|
||||
queryValidatorWare,
|
||||
pipeline.NewWeightRequestWare(pipeline.Default, cfg.Weights),
|
||||
multiTenantUnsupportedMiddleware(cfg, logger),
|
||||
tenantValidatorWare,
|
||||
},
|
||||
[]pipeline.Middleware{statusCodeWare, retryWare},
|
||||
next)
|
||||
|
||||
// traceql metrics
|
||||
queryRangePipeline := pipeline.Build(
|
||||
[]pipeline.AsyncMiddleware[combiner.PipelineResponse]{
|
||||
@@ -259,7 +243,6 @@ func New(cfg Config, next pipeline.RoundTripper, o overrides.Interface, reader t
|
||||
searchTagsV2 := newTagsV2HTTPHandler(cfg, searchTagsPipeline, o, logger, dataAccessController)
|
||||
searchTagValues := newTagValuesHTTPHandler(cfg, searchTagValuesPipeline, o, logger, dataAccessController)
|
||||
searchTagValuesV2 := newTagValuesV2HTTPHandler(cfg, searchTagValuesV2Pipeline, o, logger, dataAccessController)
|
||||
metrics := newMetricsSummaryHandler(metricsPipeline, logger, dataAccessController)
|
||||
queryInstant := newMetricsQueryInstantHTTPHandler(cfg, queryInstantPipeline, logger, dataAccessController) // Reuses the same pipeline
|
||||
queryRange := newMetricsQueryRangeHTTPHandler(cfg, queryRangePipeline, logger, dataAccessController)
|
||||
|
||||
@@ -272,7 +255,6 @@ func New(cfg Config, next pipeline.RoundTripper, o overrides.Interface, reader t
|
||||
SearchTagsV2Handler: newHandler(cfg.Config.LogQueryRequestHeaders, searchTagsV2, logger),
|
||||
SearchTagsValuesHandler: newHandler(cfg.Config.LogQueryRequestHeaders, searchTagValues, logger),
|
||||
SearchTagsValuesV2Handler: newHandler(cfg.Config.LogQueryRequestHeaders, searchTagValuesV2, logger),
|
||||
MetricsSummaryHandler: newHandler(cfg.Config.LogQueryRequestHeaders, metrics, logger),
|
||||
MetricsQueryInstantHandler: newHandler(cfg.Config.LogQueryRequestHeaders, queryInstant, logger),
|
||||
MetricsQueryRangeHandler: newHandler(cfg.Config.LogQueryRequestHeaders, queryRange, logger),
|
||||
|
||||
@@ -331,51 +313,6 @@ func (q *QueryFrontend) MetricsQueryInstant(req *tempopb.QueryInstantRequest, sr
|
||||
return q.streamingQueryInstant(req, srv)
|
||||
}
|
||||
|
||||
// newSpanMetricsMiddleware creates a new frontend middleware to handle metrics-generator requests.
|
||||
func newMetricsSummaryHandler(next pipeline.AsyncRoundTripper[combiner.PipelineResponse], logger log.Logger, dataAccessController DataAccessController) http.RoundTripper {
|
||||
return RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
tenant, err := user.ExtractOrgID(req.Context())
|
||||
if err != nil {
|
||||
level.Error(logger).Log("msg", "metrics summary: failed to extract tenant id", "err", err)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Status: http.StatusText(http.StatusBadRequest),
|
||||
Body: io.NopCloser(strings.NewReader(err.Error())),
|
||||
}, nil
|
||||
}
|
||||
if dataAccessController != nil {
|
||||
if err := dataAccessController.HandleHTTPMetricsSummaryReq(req); err != nil {
|
||||
level.Error(logger).Log("msg", "metrics summary: add filter failed", "err", err)
|
||||
return httpInvalidRequest(err), nil
|
||||
}
|
||||
}
|
||||
prepareRequestForQueriers(req, tenant)
|
||||
// This API is always json because it only ever has 1 job and this
|
||||
// lets us return the response as-is.
|
||||
req.Header.Set(api.HeaderAccept, api.HeaderAcceptJSON)
|
||||
|
||||
level.Info(logger).Log(
|
||||
"msg", "metrics summary request",
|
||||
"tenant", tenant,
|
||||
"path", req.URL.Path)
|
||||
|
||||
resps, err := next.RoundTrip(pipeline.NewHTTPRequest(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, _, err := resps.Next(req.Context()) // metrics path will only ever have one response
|
||||
|
||||
level.Info(logger).Log(
|
||||
"msg", "metrics summary response",
|
||||
"tenant", tenant,
|
||||
"path", req.URL.Path,
|
||||
"err", err)
|
||||
|
||||
return resp.HTTPResponse(), err
|
||||
})
|
||||
}
|
||||
|
||||
// cloneRequestforQueriers returns a cloned pipeline.Request from the passed pipeline.Request ready for queriers. The caller is given an opportunity
|
||||
// to modify the internal http.Request before it is returned using the modHTTP param. If modHTTP is nil, the internal http.Request is returned.
|
||||
func cloneRequestforQueriers(parent pipeline.Request, tenant string, modHTTP func(*http.Request) (*http.Request, error)) (pipeline.Request, error) {
|
||||
@@ -431,14 +368,6 @@ func multiTenantMiddleware(cfg Config, logger log.Logger) pipeline.AsyncMiddlewa
|
||||
return pipeline.NewNoopMiddleware()
|
||||
}
|
||||
|
||||
func multiTenantUnsupportedMiddleware(cfg Config, logger log.Logger) pipeline.AsyncMiddleware[combiner.PipelineResponse] {
|
||||
if cfg.MultiTenantQueriesEnabled {
|
||||
return pipeline.NewMultiTenantUnsupportedMiddleware(logger)
|
||||
}
|
||||
|
||||
return pipeline.NewNoopMiddleware()
|
||||
}
|
||||
|
||||
// blockMetasForSearch returns a list of blocks that are relevant to the search query.
|
||||
// start and end are unix timestamps in seconds. rf is the replication factor of the blocks to return.
|
||||
func blockMetasForSearch(allBlocks []*backend.BlockMeta, start, end time.Time, filterFn func(m *backend.BlockMeta) bool) []*backend.BlockMeta {
|
||||
|
||||
@@ -759,7 +759,9 @@ func (s *LiveStore) PushSpans(_ context.Context, _ *tempopb.PushSpansRequest) (*
|
||||
|
||||
// GetMetrics implements tempopb.MetricsGeneratorServer
|
||||
func (s *LiveStore) GetMetrics(_ context.Context, _ *tempopb.SpanMetricsRequest) (*tempopb.SpanMetricsResponse, error) {
|
||||
return nil, fmt.Errorf("GetMetrics not implemented in livestore") // todo: this is metrics summary, are we allowed to remove this or do we need to continue to support?
|
||||
// Keep this stub until r241 is fully rolled out. After that, we can remove
|
||||
// GetMetrics here by switching LiveStore from MetricsGenerator to MetricsService.
|
||||
return nil, fmt.Errorf("GetMetrics not implemented in livestore")
|
||||
}
|
||||
|
||||
// QueryRange implements tempopb.MetricsGeneratorServer
|
||||
|
||||
@@ -17,8 +17,6 @@ import (
|
||||
"github.com/grafana/tempo/pkg/api"
|
||||
"github.com/grafana/tempo/pkg/model/trace"
|
||||
"github.com/grafana/tempo/pkg/tempopb"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -331,33 +329,6 @@ func (q *Querier) SearchTagValuesV2Handler(w http.ResponseWriter, r *http.Reques
|
||||
writeFormattedContentForRequest(w, r, resp, span)
|
||||
}
|
||||
|
||||
func (q *Querier) SpanMetricsSummaryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Enforce the query timeout while querying backends
|
||||
ctx, cancel := context.WithDeadline(r.Context(), time.Now().Add(q.cfg.Search.QueryTimeout))
|
||||
defer cancel()
|
||||
|
||||
ctx, span := tracer.Start(ctx, "Querier.SpanMetricsSummaryHandler")
|
||||
defer span.End()
|
||||
|
||||
req, err := api.ParseSpanMetricsSummaryRequest(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := q.SpanMetricsSummary(ctx, req)
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
http.Error(w, err.Error(), http.StatusGone)
|
||||
return
|
||||
}
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
writeFormattedContentForRequest(w, r, resp, span)
|
||||
}
|
||||
|
||||
func (q *Querier) QueryRangeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
err error
|
||||
|
||||
@@ -38,8 +38,6 @@ import (
|
||||
"github.com/grafana/tempo/pkg/validation"
|
||||
"github.com/grafana/tempo/tempodb/backend"
|
||||
"github.com/grafana/tempo/tempodb/encoding/common"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var tracer = otel.Tracer("modules/querier")
|
||||
@@ -57,8 +55,6 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
const spanMetricsSummaryDeprecationMessage = "Span metrics summary endpoint is deprecated; use /api/metrics/query_range"
|
||||
|
||||
type (
|
||||
forEachFn func(ctx context.Context, client tempopb.QuerierClient) (any, error)
|
||||
forEachGeneratorFn func(ctx context.Context, client tempopb.MetricsGeneratorClient) (any, error)
|
||||
@@ -625,12 +621,6 @@ outer:
|
||||
return valuesToV2Response(distinctValues, inspectedBytes), nil
|
||||
}
|
||||
|
||||
func (q *Querier) SpanMetricsSummary(ctx context.Context, req *tempopb.SpanMetricsSummaryRequest) (*tempopb.SpanMetricsSummaryResponse, error) {
|
||||
_ = ctx
|
||||
_ = req
|
||||
return nil, status.Error(codes.Unimplemented, spanMetricsSummaryDeprecationMessage)
|
||||
}
|
||||
|
||||
func valuesToV2Response(distinctValues *collector.DistinctValue[tempopb.TagValue], bytesRead uint64) *tempopb.SearchTagValuesV2Response {
|
||||
resp := &tempopb.SearchTagValuesV2Response{
|
||||
Metrics: &tempopb.MetadataMetrics{InspectedBytes: bytesRead},
|
||||
|
||||
@@ -18,8 +18,6 @@ import (
|
||||
v1_trace "github.com/grafana/tempo/pkg/tempopb/trace/v1"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestVirtualTagsDoesntHitBackend(t *testing.T) {
|
||||
@@ -182,33 +180,3 @@ func TestFindTraceByID_ExternalMode(t *testing.T) {
|
||||
require.Len(t, resp.Trace.ResourceSpans[0].ScopeSpans[0].Spans, 1)
|
||||
require.Equal(t, "external-span", resp.Trace.ResourceSpans[0].ScopeSpans[0].Spans[0].Name)
|
||||
}
|
||||
|
||||
func TestSpanMetricsSummary_Deprecated(t *testing.T) {
|
||||
o, err := overrides.NewOverrides(overrides.Config{}, nil, prometheus.DefaultRegisterer)
|
||||
require.NoError(t, err)
|
||||
|
||||
q, err := New(Config{}, nil, generator_client.Config{}, nil, livestore_client.Config{}, nil, false, nil, o)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := q.SpanMetricsSummary(context.Background(), &tempopb.SpanMetricsSummaryRequest{})
|
||||
require.Nil(t, resp)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, codes.Unimplemented, status.Code(err))
|
||||
require.Contains(t, err.Error(), spanMetricsSummaryDeprecationMessage)
|
||||
}
|
||||
|
||||
func TestSpanMetricsSummaryHandler_Deprecated(t *testing.T) {
|
||||
o, err := overrides.NewOverrides(overrides.Config{}, nil, prometheus.DefaultRegisterer)
|
||||
require.NoError(t, err)
|
||||
|
||||
q, err := New(Config{Search: SearchConfig{QueryTimeout: time.Second}}, nil, generator_client.Config{}, nil, livestore_client.Config{}, nil, false, nil, o)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/metrics/summary?q={}", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
q.SpanMetricsSummaryHandler(rec, req)
|
||||
|
||||
require.Equal(t, http.StatusGone, rec.Code)
|
||||
require.Contains(t, rec.Body.String(), spanMetricsSummaryDeprecationMessage)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ const (
|
||||
PathBuildInfo = "/api/status/buildinfo"
|
||||
PathUsageStats = "/status/usage-stats"
|
||||
PathSpanMetrics = "/api/metrics"
|
||||
PathSpanMetricsSummary = "/api/metrics/summary"
|
||||
PathMetricsQueryInstant = "/api/metrics/query"
|
||||
PathMetricsQueryRange = "/api/metrics/query_range"
|
||||
PathMCP = "/api/mcp"
|
||||
@@ -335,44 +334,6 @@ func ParseSpanMetricsRequest(r *http.Request) (*tempopb.SpanMetricsRequest, erro
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func ParseSpanMetricsSummaryRequest(r *http.Request) (*tempopb.SpanMetricsSummaryRequest, error) {
|
||||
req := &tempopb.SpanMetricsSummaryRequest{}
|
||||
vals := r.URL.Query()
|
||||
|
||||
groupBy := vals.Get(urlParamGroupBy)
|
||||
req.GroupBy = groupBy
|
||||
|
||||
query := vals.Get(urlParamQuery)
|
||||
req.Query = query
|
||||
|
||||
l := vals.Get(urlParamLimit)
|
||||
if l != "" {
|
||||
limit, err := strconv.Atoi(l)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid limit: %w", err)
|
||||
}
|
||||
req.Limit = uint64(limit)
|
||||
}
|
||||
|
||||
if s, ok := extractQueryParam(vals, urlParamStart); ok {
|
||||
start, err := strconv.ParseInt(s, 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid start: %w", err)
|
||||
}
|
||||
req.Start = uint32(start)
|
||||
}
|
||||
|
||||
if s, ok := extractQueryParam(vals, urlParamEnd); ok {
|
||||
end, err := strconv.ParseInt(s, 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid end: %w", err)
|
||||
}
|
||||
req.End = uint32(end)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func ParseQueryInstantRequest(r *http.Request) (*tempopb.QueryInstantRequest, error) {
|
||||
req := &tempopb.QueryInstantRequest{}
|
||||
vals := r.URL.Query()
|
||||
|
||||
@@ -53,7 +53,6 @@ type TempoHTTPClient interface {
|
||||
SearchTraceQL(query string) (*tempopb.SearchResponse, error)
|
||||
SearchTraceQLWithRange(query string, start int64, end int64) (*tempopb.SearchResponse, error)
|
||||
SearchTraceQLWithRangeAndLimit(query string, start int64, end int64, limit int64, spss int64) (*tempopb.SearchResponse, error)
|
||||
MetricsSummary(query string, groupBy string, start int64, end int64) (*tempopb.SpanMetricsSummaryResponse, error)
|
||||
MetricsQueryRange(query string, start, end int64, step string, exemplars int) (*tempopb.QueryRangeResponse, error)
|
||||
MetricsQueryInstant(query string, start, end int64, exemplars int) (*tempopb.QueryInstantResponse, error)
|
||||
GetOverrides() (*userconfigurableoverrides.Limits, string, error)
|
||||
@@ -342,26 +341,6 @@ func (c *Client) SearchTraceQLWithRangeAndLimit(query string, start int64, end i
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *Client) MetricsSummary(query string, groupBy string, start int64, end int64) (*tempopb.SpanMetricsSummaryResponse, error) {
|
||||
joinURL, _ := url.Parse(c.BaseURL + api.PathSpanMetricsSummary + "?")
|
||||
q := joinURL.Query()
|
||||
if start != 0 && end != 0 {
|
||||
q.Set("start", strconv.FormatInt(start, 10))
|
||||
q.Set("end", strconv.FormatInt(end, 10))
|
||||
}
|
||||
q.Set("q", query)
|
||||
q.Set("groupBy", groupBy)
|
||||
joinURL.RawQuery = q.Encode()
|
||||
|
||||
m := &tempopb.SpanMetricsSummaryResponse{}
|
||||
_, err := c.getFor(fmt.Sprint(joinURL), m)
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *Client) buildSearchQueryURL(queryType string, query string, start int64, end int64, limit int64, spss int64, params map[string]string) string {
|
||||
joinURL, _ := url.Parse(c.BaseURL + "/api/search?")
|
||||
q := joinURL.Query()
|
||||
|
||||
+204
-1108
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,6 @@ service Querier {
|
||||
rpc SearchTagsV2(SearchTagsRequest) returns (SearchTagsV2Response) {}
|
||||
rpc SearchTagValues(SearchTagValuesRequest) returns (SearchTagValuesResponse) {}
|
||||
rpc SearchTagValuesV2(SearchTagValuesRequest) returns (SearchTagValuesV2Response) {}
|
||||
// rpc SpanMetricsSummary(SpanMetricsSummaryRequest) returns
|
||||
// (SpanMetricsSummaryResponse) {};
|
||||
}
|
||||
|
||||
service StreamingQuerier {
|
||||
@@ -339,14 +337,6 @@ message SpanMetricsRequest {
|
||||
uint32 end = 5;
|
||||
}
|
||||
|
||||
message SpanMetricsSummaryRequest {
|
||||
string query = 1;
|
||||
string groupBy = 2;
|
||||
uint64 limit = 3;
|
||||
uint32 start = 4;
|
||||
uint32 end = 5;
|
||||
}
|
||||
|
||||
message SpanMetricsResponse {
|
||||
bool estimated = 1;
|
||||
uint64 spanCount = 2;
|
||||
@@ -370,20 +360,6 @@ message SpanMetrics {
|
||||
uint64 errors = 3;
|
||||
}
|
||||
|
||||
message SpanMetricsSummary {
|
||||
uint64 spanCount = 1;
|
||||
uint64 errorSpanCount = 2;
|
||||
repeated KeyValue series = 3;
|
||||
uint64 p99 = 4;
|
||||
uint64 p95 = 5;
|
||||
uint64 p90 = 6;
|
||||
uint64 p50 = 7;
|
||||
}
|
||||
|
||||
message SpanMetricsSummaryResponse {
|
||||
repeated SpanMetricsSummary summaries = 1;
|
||||
}
|
||||
|
||||
message TraceQLStatic {
|
||||
int32 type = 1;
|
||||
int64 n = 2;
|
||||
|
||||
Reference in New Issue
Block a user