mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 02:39:04 +08:00
feat: add attrs filters autocomplete endpoints (#2264)
This commit is contained in:
parent
59497ed53c
commit
9af991e424
@ -3700,6 +3700,73 @@ func (r *ClickHouseReader) GetMetricAggregateAttributes(ctx context.Context, req
|
|||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ClickHouseReader) GetMetricAttributeKeys(ctx context.Context, req *v3.FilterAttributeKeyRequest) (*v3.FilterAttributeKeyResponse, error) {
|
||||||
|
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
var rows driver.Rows
|
||||||
|
var response v3.FilterAttributeKeyResponse
|
||||||
|
|
||||||
|
// skips the internal attributes i.e attributes starting with __
|
||||||
|
query = fmt.Sprintf("SELECT DISTINCT arrayJoin(tagKeys) as distinctTagKey from (SELECT DISTINCT(JSONExtractKeys(labels)) tagKeys from %s.%s WHERE metric_name=$1) WHERE distinctTagKey ILIKE $2 AND distinctTagKey NOT LIKE '\\_\\_%%'", signozMetricDBName, signozTSTableName)
|
||||||
|
if req.Limit != 0 {
|
||||||
|
query = query + fmt.Sprintf(" LIMIT %d;", req.Limit)
|
||||||
|
}
|
||||||
|
rows, err = r.db.Query(ctx, query, req.AggregateAttribute, fmt.Sprintf("%%%s%%", req.SearchText))
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Error(err)
|
||||||
|
return nil, fmt.Errorf("error while executing query: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var attributeKey string
|
||||||
|
for rows.Next() {
|
||||||
|
if err := rows.Scan(&attributeKey); err != nil {
|
||||||
|
return nil, fmt.Errorf("error while scanning rows: %s", err.Error())
|
||||||
|
}
|
||||||
|
key := v3.AttributeKey{
|
||||||
|
Key: attributeKey,
|
||||||
|
DataType: v3.AttributeKeyDataTypeString, // https://github.com/OpenObservability/OpenMetrics/blob/main/proto/openmetrics_data_model.proto#L64-L72.
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
}
|
||||||
|
response.AttributeKeys = append(response.AttributeKeys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ClickHouseReader) GetMetricAttributeValues(ctx context.Context, req *v3.FilterAttributeValueRequest) (*v3.FilterAttributeValueResponse, error) {
|
||||||
|
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
var rows driver.Rows
|
||||||
|
var attributeValues v3.FilterAttributeValueResponse
|
||||||
|
|
||||||
|
query = fmt.Sprintf("SELECT DISTINCT(JSONExtractString(labels, $1)) from %s.%s WHERE metric_name=$2 AND JSONExtractString(labels, $3) ILIKE $4", signozMetricDBName, signozTSTableName)
|
||||||
|
if req.Limit != 0 {
|
||||||
|
query = query + fmt.Sprintf(" LIMIT %d;", req.Limit)
|
||||||
|
}
|
||||||
|
rows, err = r.db.Query(ctx, query, req.FilterAttributeKey, req.AggregateAttribute, req.FilterAttributeKey, fmt.Sprintf("%%%s%%", req.SearchText))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Error(err)
|
||||||
|
return nil, fmt.Errorf("error while executing query: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var atrributeValue string
|
||||||
|
for rows.Next() {
|
||||||
|
if err := rows.Scan(&atrributeValue); err != nil {
|
||||||
|
return nil, fmt.Errorf("error while scanning rows: %s", err.Error())
|
||||||
|
}
|
||||||
|
// https://github.com/OpenObservability/OpenMetrics/blob/main/proto/openmetrics_data_model.proto#L64-L72
|
||||||
|
// this may change in future if we use OTLP as the data model
|
||||||
|
attributeValues.StringAttributeValues = append(attributeValues.StringAttributeValues, atrributeValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &attributeValues, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ClickHouseReader) CheckClickHouse(ctx context.Context) error {
|
func (r *ClickHouseReader) CheckClickHouse(ctx context.Context) error {
|
||||||
rows, err := r.db.Query(ctx, "SELECT 1")
|
rows, err := r.db.Query(ctx, "SELECT 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -242,6 +242,8 @@ func (aH *APIHandler) RegisterMetricsRoutes(router *mux.Router, am *AuthMiddlewa
|
|||||||
func (aH *APIHandler) RegisterQueryRangeV3Routes(router *mux.Router, am *AuthMiddleware) {
|
func (aH *APIHandler) RegisterQueryRangeV3Routes(router *mux.Router, am *AuthMiddleware) {
|
||||||
subRouter := router.PathPrefix("/api/v3").Subrouter()
|
subRouter := router.PathPrefix("/api/v3").Subrouter()
|
||||||
subRouter.HandleFunc("/autocomplete/aggregate_attributes", am.ViewAccess(aH.autocompleteAggregateAttributes)).Methods(http.MethodGet)
|
subRouter.HandleFunc("/autocomplete/aggregate_attributes", am.ViewAccess(aH.autocompleteAggregateAttributes)).Methods(http.MethodGet)
|
||||||
|
subRouter.HandleFunc("/autocomplete/attribute_keys", am.ViewAccess(aH.autoCompleteAttributeKeys)).Methods(http.MethodGet)
|
||||||
|
subRouter.HandleFunc("/autocomplete/attribute_values", am.ViewAccess(aH.autoCompleteAttributeValues)).Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aH *APIHandler) Respond(w http.ResponseWriter, data interface{}) {
|
func (aH *APIHandler) Respond(w http.ResponseWriter, data interface{}) {
|
||||||
@ -2364,3 +2366,61 @@ func (aH *APIHandler) autocompleteAggregateAttributes(w http.ResponseWriter, r *
|
|||||||
|
|
||||||
aH.Respond(w, response)
|
aH.Respond(w, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aH *APIHandler) autoCompleteAttributeKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var response *v3.FilterAttributeKeyResponse
|
||||||
|
req, err := parseFilterAttributeKeyRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.DataSource {
|
||||||
|
case v3.DataSourceMetrics:
|
||||||
|
response, err = aH.reader.GetMetricAttributeKeys(r.Context(), req)
|
||||||
|
case v3.DataSourceLogs:
|
||||||
|
// TODO: implement
|
||||||
|
case v3.DataSourceTraces:
|
||||||
|
// TODO: implement
|
||||||
|
default:
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("invalid data source")}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aH.Respond(w, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aH *APIHandler) autoCompleteAttributeValues(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var response *v3.FilterAttributeValueResponse
|
||||||
|
req, err := parseFilterAttributeValueRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.DataSource {
|
||||||
|
case v3.DataSourceMetrics:
|
||||||
|
response, err = aH.reader.GetMetricAttributeValues(r.Context(), req)
|
||||||
|
case v3.DataSourceLogs:
|
||||||
|
// TODO: implement
|
||||||
|
case v3.DataSourceTraces:
|
||||||
|
// TODO: implement
|
||||||
|
default:
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("invalid data source")}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aH.Respond(w, response)
|
||||||
|
}
|
||||||
|
@ -841,3 +841,64 @@ func parseAggregateAttributeRequest(r *http.Request) (*v3.AggregateAttributeRequ
|
|||||||
}
|
}
|
||||||
return &req, nil
|
return &req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFilterAttributeKeyRequest(r *http.Request) (*v3.FilterAttributeKeyRequest, error) {
|
||||||
|
var req v3.FilterAttributeKeyRequest
|
||||||
|
|
||||||
|
dataSource := v3.DataSource(r.URL.Query().Get("dataSource"))
|
||||||
|
aggregateOperator := v3.AggregateOperator(r.URL.Query().Get("aggregateOperator"))
|
||||||
|
aggregateAttribute := r.URL.Query().Get("aggregateAttribute")
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
limit = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dataSource.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := aggregateOperator.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req = v3.FilterAttributeKeyRequest{
|
||||||
|
DataSource: dataSource,
|
||||||
|
AggregateOperator: aggregateOperator,
|
||||||
|
AggregateAttribute: aggregateAttribute,
|
||||||
|
Limit: limit,
|
||||||
|
SearchText: r.URL.Query().Get("searchText"),
|
||||||
|
}
|
||||||
|
return &req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFilterAttributeValueRequest(r *http.Request) (*v3.FilterAttributeValueRequest, error) {
|
||||||
|
|
||||||
|
var req v3.FilterAttributeValueRequest
|
||||||
|
|
||||||
|
dataSource := v3.DataSource(r.URL.Query().Get("dataSource"))
|
||||||
|
aggregateOperator := v3.AggregateOperator(r.URL.Query().Get("aggregateOperator"))
|
||||||
|
aggregateAttribute := r.URL.Query().Get("aggregateAttribute")
|
||||||
|
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
limit = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dataSource.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := aggregateOperator.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req = v3.FilterAttributeValueRequest{
|
||||||
|
DataSource: dataSource,
|
||||||
|
AggregateOperator: aggregateOperator,
|
||||||
|
AggregateAttribute: aggregateAttribute,
|
||||||
|
Limit: limit,
|
||||||
|
SearchText: r.URL.Query().Get("searchText"),
|
||||||
|
FilterAttributeKey: r.URL.Query().Get("attributeKey"),
|
||||||
|
}
|
||||||
|
return &req, nil
|
||||||
|
}
|
||||||
|
@ -147,3 +147,193 @@ func TestParseAggregateAttrReques(t *testing.T) {
|
|||||||
assert.Equal(t, reqCase.expectedSearchText, aggregateAttrRequest.SearchText)
|
assert.Equal(t, reqCase.expectedSearchText, aggregateAttrRequest.SearchText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseFilterAttributeKeyRequest(t *testing.T) {
|
||||||
|
reqCases := []struct {
|
||||||
|
desc string
|
||||||
|
queryString string
|
||||||
|
expectedOperator v3.AggregateOperator
|
||||||
|
expectedDataSource v3.DataSource
|
||||||
|
expectedAggAttr string
|
||||||
|
expectedLimit int
|
||||||
|
expectedSearchText string
|
||||||
|
expectErr bool
|
||||||
|
errMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source",
|
||||||
|
queryString: "aggregateOperator=sum&dataSource=metrics&aggregateAttribute=metric_name&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorSum,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedAggAttr: "metric_name",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and data source as logs",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=logs&aggregateAttribute=bytes&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceLogs,
|
||||||
|
expectedAggAttr: "bytes",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and with default search text and limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=metrics&aggregateAttribute=metric_name",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedAggAttr: "metric_name",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source with limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&aggregateAttribute=http.req.duration&limit=10",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedAggAttr: "http.req.duration",
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 10,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid operator",
|
||||||
|
queryString: "aggregateOperator=avg1&dataSource=traces&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid operator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid data source",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces1&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid data source",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&limit=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 50,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, reqCase := range reqCases {
|
||||||
|
r := httptest.NewRequest("GET", "/api/v3/autocomplete/filter_attributes?"+reqCase.queryString, nil)
|
||||||
|
filterAttrRequest, err := parseFilterAttributeKeyRequest(r)
|
||||||
|
if reqCase.expectErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error: %s", reqCase.errMsg)
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), reqCase.errMsg) {
|
||||||
|
t.Errorf("expected error to contain: %s, got: %s", reqCase.errMsg, err.Error())
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, reqCase.expectedOperator, filterAttrRequest.AggregateOperator)
|
||||||
|
assert.Equal(t, reqCase.expectedDataSource, filterAttrRequest.DataSource)
|
||||||
|
assert.Equal(t, reqCase.expectedAggAttr, filterAttrRequest.AggregateAttribute)
|
||||||
|
assert.Equal(t, reqCase.expectedLimit, filterAttrRequest.Limit)
|
||||||
|
assert.Equal(t, reqCase.expectedSearchText, filterAttrRequest.SearchText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseFilterAttributeValueRequest(t *testing.T) {
|
||||||
|
reqCases := []struct {
|
||||||
|
desc string
|
||||||
|
queryString string
|
||||||
|
expectedOperator v3.AggregateOperator
|
||||||
|
expectedDataSource v3.DataSource
|
||||||
|
expectedAggAttr string
|
||||||
|
expectedFilterAttr string
|
||||||
|
expectedLimit int
|
||||||
|
expectedSearchText string
|
||||||
|
expectErr bool
|
||||||
|
errMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source",
|
||||||
|
queryString: "aggregateOperator=sum&dataSource=metrics&aggregateAttribute=metric_name&attributeKey=service_name&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorSum,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedAggAttr: "metric_name",
|
||||||
|
expectedFilterAttr: "service_name",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and data source as logs",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=logs&aggregateAttribute=bytes&attributeKey=service_name&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceLogs,
|
||||||
|
expectedAggAttr: "bytes",
|
||||||
|
expectedFilterAttr: "service_name",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and with default search text and limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=metrics&aggregateAttribute=metric_name&attributeKey=service_name",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedAggAttr: "metric_name",
|
||||||
|
expectedFilterAttr: "service_name",
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source with limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&aggregateAttribute=http.req.duration&attributeKey=service_name&limit=10",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedAggAttr: "http.req.duration",
|
||||||
|
expectedFilterAttr: "service_name",
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 10,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid operator",
|
||||||
|
queryString: "aggregateOperator=avg1&dataSource=traces&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid operator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid data source",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces1&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid data source",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&limit=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 50,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, reqCase := range reqCases {
|
||||||
|
r := httptest.NewRequest("GET", "/api/v3/autocomplete/filter_attribute_values?"+reqCase.queryString, nil)
|
||||||
|
filterAttrRequest, err := parseFilterAttributeValueRequest(r)
|
||||||
|
if reqCase.expectErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error: %s", reqCase.errMsg)
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), reqCase.errMsg) {
|
||||||
|
t.Errorf("expected error to contain: %s, got: %s", reqCase.errMsg, err.Error())
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, reqCase.expectedOperator, filterAttrRequest.AggregateOperator)
|
||||||
|
assert.Equal(t, reqCase.expectedDataSource, filterAttrRequest.DataSource)
|
||||||
|
assert.Equal(t, reqCase.expectedAggAttr, filterAttrRequest.AggregateAttribute)
|
||||||
|
assert.Equal(t, reqCase.expectedFilterAttr, filterAttrRequest.FilterAttributeKey)
|
||||||
|
assert.Equal(t, reqCase.expectedLimit, filterAttrRequest.Limit)
|
||||||
|
assert.Equal(t, reqCase.expectedSearchText, filterAttrRequest.SearchText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -58,6 +58,8 @@ type Reader interface {
|
|||||||
GetMetricResult(ctx context.Context, query string) ([]*model.Series, error)
|
GetMetricResult(ctx context.Context, query string) ([]*model.Series, error)
|
||||||
GetMetricResultEE(ctx context.Context, query string) ([]*model.Series, string, error)
|
GetMetricResultEE(ctx context.Context, query string) ([]*model.Series, string, error)
|
||||||
GetMetricAggregateAttributes(ctx context.Context, req *v3.AggregateAttributeRequest) (*v3.AggregateAttributeResponse, error)
|
GetMetricAggregateAttributes(ctx context.Context, req *v3.AggregateAttributeRequest) (*v3.AggregateAttributeResponse, error)
|
||||||
|
GetMetricAttributeKeys(ctx context.Context, req *v3.FilterAttributeKeyRequest) (*v3.FilterAttributeKeyResponse, error)
|
||||||
|
GetMetricAttributeValues(ctx context.Context, req *v3.FilterAttributeValueRequest) (*v3.FilterAttributeValueResponse, error)
|
||||||
|
|
||||||
GetTotalSpans(ctx context.Context) (uint64, error)
|
GetTotalSpans(ctx context.Context) (uint64, error)
|
||||||
GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error)
|
GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user