mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 10:15:54 +08:00
feat: trace view and list view for traces (#2847)
* feat: checkpoint * feat: add select columns support to list view * chore: add more error handling * feat: always return timestamp, spanID, traceID Always return timestamp, spanID, traceID in list view * test: update and add new tests * chore: remove deprecated const * chore: addressed review comments * fix: add support for timestamp ordering and fix logic related to timestamp orderBy * chore: remove unused variable * fix: edge case and more tests
This commit is contained in:
parent
b7c50cc76d
commit
bc400c2bcf
@ -4223,8 +4223,11 @@ func (r *ClickHouseReader) GetListResultV3(ctx context.Context, query string) ([
|
|||||||
for idx, v := range vars {
|
for idx, v := range vars {
|
||||||
if columnNames[idx] == "timestamp" {
|
if columnNames[idx] == "timestamp" {
|
||||||
t = time.Unix(0, int64(*v.(*uint64)))
|
t = time.Unix(0, int64(*v.(*uint64)))
|
||||||
|
} else if columnNames[idx] == "timestamp_datetime" {
|
||||||
|
t = *v.(*time.Time)
|
||||||
|
} else {
|
||||||
|
row[columnNames[idx]] = v
|
||||||
}
|
}
|
||||||
row[columnNames[idx]] = v
|
|
||||||
}
|
}
|
||||||
rowList = append(rowList, &v3.Row{Timestamp: t, Data: row})
|
rowList = append(rowList, &v3.Row{Timestamp: t, Data: row})
|
||||||
}
|
}
|
||||||
|
@ -2684,6 +2684,11 @@ func (aH *APIHandler) getSpanKeysV3(ctx context.Context, queryRangeParams *v3.Qu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Add timestamp as a span key to allow ordering by timestamp
|
||||||
|
spanKeys["timestamp"] = v3.AttributeKey{
|
||||||
|
Key: "timestamp",
|
||||||
|
IsColumn: true,
|
||||||
|
}
|
||||||
return spanKeys, nil
|
return spanKeys, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2725,7 +2730,7 @@ func (aH *APIHandler) queryRangeV3(ctx context.Context, queryRangeParams *v3.Que
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if queryRangeParams.CompositeQuery.PanelType == v3.PanelTypeList {
|
if queryRangeParams.CompositeQuery.PanelType == v3.PanelTypeList || queryRangeParams.CompositeQuery.PanelType == v3.PanelTypeTrace {
|
||||||
result, err, errQuriesByName = aH.execClickHouseListQueries(r.Context(), queries)
|
result, err, errQuriesByName = aH.execClickHouseListQueries(r.Context(), queries)
|
||||||
} else {
|
} else {
|
||||||
result, err, errQuriesByName = aH.execClickHouseGraphQueries(r.Context(), queries)
|
result, err, errQuriesByName = aH.execClickHouseGraphQueries(r.Context(), queries)
|
||||||
|
@ -95,7 +95,7 @@ func enrichKeyWithMetadata(key v3.AttributeKey, keys map[string]v3.AttributeKey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSelectLabels returns the select labels for the query based on groupBy and aggregateOperator
|
// getSelectLabels returns the select labels for the query based on groupBy and aggregateOperator
|
||||||
func getSelectLabels(aggregatorOperator v3.AggregateOperator, groupBy []v3.AttributeKey, keys map[string]v3.AttributeKey) (string, error) {
|
func getSelectLabels(aggregatorOperator v3.AggregateOperator, groupBy []v3.AttributeKey, keys map[string]v3.AttributeKey) string {
|
||||||
var selectLabels string
|
var selectLabels string
|
||||||
if aggregatorOperator == v3.AggregateOperatorNoOp {
|
if aggregatorOperator == v3.AggregateOperatorNoOp {
|
||||||
selectLabels = ""
|
selectLabels = ""
|
||||||
@ -105,7 +105,16 @@ func getSelectLabels(aggregatorOperator v3.AggregateOperator, groupBy []v3.Attri
|
|||||||
selectLabels += fmt.Sprintf(", %s as `%s`", filterName, tag.Key)
|
selectLabels += fmt.Sprintf(", %s as `%s`", filterName, tag.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return selectLabels, nil
|
return selectLabels
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSelectColumns(sc []v3.AttributeKey, keys map[string]v3.AttributeKey) string {
|
||||||
|
var columns []string
|
||||||
|
for _, tag := range sc {
|
||||||
|
columnName := getColumnName(tag, keys)
|
||||||
|
columns = append(columns, fmt.Sprintf("%s as `%s` ", columnName, tag.Key))
|
||||||
|
}
|
||||||
|
return strings.Join(columns, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getZerosForEpochNano returns the number of zeros to be appended to the epoch time for converting it to nanoseconds
|
// getZerosForEpochNano returns the number of zeros to be appended to the epoch time for converting it to nanoseconds
|
||||||
@ -208,7 +217,7 @@ func handleEmptyValuesInGroupBy(keys map[string]v3.AttributeKey, groupBy []v3.At
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName string, keys map[string]v3.AttributeKey) (string, error) {
|
func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName string, keys map[string]v3.AttributeKey, panelType v3.PanelType) (string, error) {
|
||||||
|
|
||||||
filterSubQuery, err := buildTracesFilterQuery(mq.Filters, keys)
|
filterSubQuery, err := buildTracesFilterQuery(mq.Filters, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -217,10 +226,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str
|
|||||||
// timerange will be sent in epoch millisecond
|
// timerange will be sent in epoch millisecond
|
||||||
spanIndexTableTimeFilter := fmt.Sprintf("(timestamp >= '%d' AND timestamp <= '%d')", start*getZerosForEpochNano(start), end*getZerosForEpochNano(end))
|
spanIndexTableTimeFilter := fmt.Sprintf("(timestamp >= '%d' AND timestamp <= '%d')", start*getZerosForEpochNano(start), end*getZerosForEpochNano(end))
|
||||||
|
|
||||||
selectLabels, err := getSelectLabels(mq.AggregateOperator, mq.GroupBy, keys)
|
selectLabels := getSelectLabels(mq.AggregateOperator, mq.GroupBy, keys)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
having := having(mq.Having)
|
having := having(mq.Having)
|
||||||
if having != "" {
|
if having != "" {
|
||||||
@ -234,7 +240,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str
|
|||||||
"from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME +
|
"from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME +
|
||||||
" where " + spanIndexTableTimeFilter + "%s " +
|
" where " + spanIndexTableTimeFilter + "%s " +
|
||||||
"group by %s%s " +
|
"group by %s%s " +
|
||||||
"order by %sts"
|
"order by %s"
|
||||||
|
|
||||||
emptyValuesInGroupByFilter, err := handleEmptyValuesInGroupBy(keys, mq.GroupBy)
|
emptyValuesInGroupByFilter, err := handleEmptyValuesInGroupBy(keys, mq.GroupBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -243,7 +249,8 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str
|
|||||||
filterSubQuery += emptyValuesInGroupByFilter
|
filterSubQuery += emptyValuesInGroupByFilter
|
||||||
|
|
||||||
groupBy := groupByAttributeKeyTags(keys, mq.GroupBy...)
|
groupBy := groupByAttributeKeyTags(keys, mq.GroupBy...)
|
||||||
orderBy := orderByAttributeKeyTags(mq.OrderBy, mq.GroupBy)
|
enrichedOrderBy := enrichOrderBy(mq.OrderBy, keys)
|
||||||
|
orderBy := orderByAttributeKeyTags(panelType, enrichedOrderBy, mq.GroupBy, keys)
|
||||||
|
|
||||||
aggregationKey := ""
|
aggregationKey := ""
|
||||||
if mq.AggregateAttribute.Key != "" {
|
if mq.AggregateAttribute.Key != "" {
|
||||||
@ -297,15 +304,48 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str
|
|||||||
query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy)
|
query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy)
|
||||||
return query, nil
|
return query, nil
|
||||||
case v3.AggregateOperatorNoOp:
|
case v3.AggregateOperatorNoOp:
|
||||||
// queryTmpl := constants.TracesSQLSelect + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + " where %s %s"
|
var query string
|
||||||
// query := fmt.Sprintf(queryTmpl, spanIndexTableTimeFilter, filterSubQuery)
|
if panelType == v3.PanelTypeTrace {
|
||||||
// return query, nil
|
withSubQuery := fmt.Sprintf(constants.TracesExplorerViewSQLSelectWithSubQuery, constants.SIGNOZ_TRACE_DBNAME, constants.SIGNOZ_SPAN_INDEX_TABLENAME, spanIndexTableTimeFilter, filterSubQuery)
|
||||||
return "", fmt.Errorf("not implemented, part of traces page")
|
withSubQuery = addLimitToQuery(withSubQuery, mq.Limit, panelType)
|
||||||
|
if mq.Offset != 0 {
|
||||||
|
withSubQuery = addOffsetToQuery(withSubQuery, mq.Offset)
|
||||||
|
}
|
||||||
|
query = withSubQuery + ") " + fmt.Sprintf(constants.TracesExplorerViewSQLSelectQuery, constants.SIGNOZ_TRACE_DBNAME, constants.SIGNOZ_SPAN_INDEX_TABLENAME, constants.SIGNOZ_SPAN_INDEX_TABLENAME)
|
||||||
|
} else if panelType == v3.PanelTypeList {
|
||||||
|
if len(mq.SelectColumns) == 0 {
|
||||||
|
return "", fmt.Errorf("select columns cannot be empty for panelType %s", panelType)
|
||||||
|
}
|
||||||
|
selectColumns := getSelectColumns(mq.SelectColumns, keys)
|
||||||
|
queryNoOpTmpl := fmt.Sprintf("SELECT timestamp as timestamp_datetime, spanID, traceID, "+"%s ", selectColumns) + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + " where %s %s" + " order by %s"
|
||||||
|
query = fmt.Sprintf(queryNoOpTmpl, spanIndexTableTimeFilter, filterSubQuery, orderBy)
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("unsupported aggregate operator %s for panelType %s", mq.AggregateOperator, panelType)
|
||||||
|
}
|
||||||
|
return query, nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("unsupported aggregate operator")
|
return "", fmt.Errorf("unsupported aggregate operator %s", mq.AggregateOperator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enrichOrderBy(items []v3.OrderBy, keys map[string]v3.AttributeKey) []v3.OrderBy {
|
||||||
|
enrichedItems := []v3.OrderBy{}
|
||||||
|
for i := 0; i < len(items); i++ {
|
||||||
|
attributeKey := enrichKeyWithMetadata(v3.AttributeKey{
|
||||||
|
Key: items[i].ColumnName,
|
||||||
|
}, keys)
|
||||||
|
enrichedItems = append(enrichedItems, v3.OrderBy{
|
||||||
|
ColumnName: items[i].ColumnName,
|
||||||
|
Order: items[i].Order,
|
||||||
|
Key: attributeKey.Key,
|
||||||
|
DataType: attributeKey.DataType,
|
||||||
|
Type: attributeKey.Type,
|
||||||
|
IsColumn: attributeKey.IsColumn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return enrichedItems
|
||||||
|
}
|
||||||
|
|
||||||
// groupBy returns a string of comma separated tags for group by clause
|
// groupBy returns a string of comma separated tags for group by clause
|
||||||
// `ts` is always added to the group by clause
|
// `ts` is always added to the group by clause
|
||||||
func groupBy(tags ...string) string {
|
func groupBy(tags ...string) string {
|
||||||
@ -322,41 +362,66 @@ func groupByAttributeKeyTags(keys map[string]v3.AttributeKey, tags ...v3.Attribu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// orderBy returns a string of comma separated tags for order by clause
|
// orderBy returns a string of comma separated tags for order by clause
|
||||||
|
// if there are remaining items which are not present in tags they are also added
|
||||||
// if the order is not specified, it defaults to ASC
|
// if the order is not specified, it defaults to ASC
|
||||||
func orderBy(items []v3.OrderBy, tags []string) string {
|
func orderBy(panelType v3.PanelType, items []v3.OrderBy, tags []string, keys map[string]v3.AttributeKey) []string {
|
||||||
var orderBy []string
|
var orderBy []string
|
||||||
|
|
||||||
|
// create a lookup
|
||||||
|
addedToOrderBy := map[string]bool{}
|
||||||
|
itemsLookup := map[string]v3.OrderBy{}
|
||||||
|
|
||||||
|
for i := 0; i < len(items); i++ {
|
||||||
|
addedToOrderBy[items[i].ColumnName] = false
|
||||||
|
itemsLookup[items[i].ColumnName] = items[i]
|
||||||
|
}
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
found := false
|
if item, ok := itemsLookup[tag]; ok {
|
||||||
for _, item := range items {
|
orderBy = append(orderBy, fmt.Sprintf("%s %s", item.ColumnName, item.Order))
|
||||||
if item.ColumnName == tag {
|
addedToOrderBy[item.ColumnName] = true
|
||||||
found = true
|
} else {
|
||||||
orderBy = append(orderBy, fmt.Sprintf("%s %s", item.ColumnName, item.Order))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
orderBy = append(orderBy, fmt.Sprintf("%s ASC", tag))
|
orderBy = append(orderBy, fmt.Sprintf("%s ASC", tag))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// users might want to order by value of aggreagation
|
// users might want to order by value of aggregation
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
if item.ColumnName == constants.SigNozOrderByValue {
|
if item.ColumnName == constants.SigNozOrderByValue {
|
||||||
orderBy = append(orderBy, fmt.Sprintf("value %s", item.Order))
|
orderBy = append(orderBy, fmt.Sprintf("value %s", item.Order))
|
||||||
|
addedToOrderBy[item.ColumnName] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.Join(orderBy, ",")
|
|
||||||
|
// add the remaining items
|
||||||
|
if panelType == v3.PanelTypeList {
|
||||||
|
for _, item := range items {
|
||||||
|
// since these are not present in tags we will have to select them correctly
|
||||||
|
// for list view there is no need to check if it was added since they wont be added yet but this is just for safety
|
||||||
|
if !addedToOrderBy[item.ColumnName] {
|
||||||
|
attr := v3.AttributeKey{Key: item.ColumnName, DataType: item.DataType, Type: item.Type, IsColumn: item.IsColumn}
|
||||||
|
name := getColumnName(attr, keys)
|
||||||
|
orderBy = append(orderBy, fmt.Sprintf("%s %s", name, item.Order))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orderBy
|
||||||
}
|
}
|
||||||
|
|
||||||
func orderByAttributeKeyTags(items []v3.OrderBy, tags []v3.AttributeKey) string {
|
func orderByAttributeKeyTags(panelType v3.PanelType, items []v3.OrderBy, tags []v3.AttributeKey, keys map[string]v3.AttributeKey) string {
|
||||||
var groupTags []string
|
var groupTags []string
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
groupTags = append(groupTags, tag.Key)
|
groupTags = append(groupTags, tag.Key)
|
||||||
}
|
}
|
||||||
str := orderBy(items, groupTags)
|
orderByArray := orderBy(panelType, items, groupTags, keys)
|
||||||
if len(str) > 0 {
|
|
||||||
str = str + ","
|
if panelType == v3.PanelTypeList && len(orderByArray) == 0 {
|
||||||
|
orderByArray = append(orderByArray, constants.TIMESTAMP+" DESC")
|
||||||
|
} else if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeTable {
|
||||||
|
orderByArray = append(orderByArray, "ts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str := strings.Join(orderByArray, ",")
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,10 +458,7 @@ func addLimitToQuery(query string, limit uint64, panelType v3.PanelType) string
|
|||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
limit = 100
|
limit = 100
|
||||||
}
|
}
|
||||||
if panelType == v3.PanelTypeList {
|
return fmt.Sprintf("%s LIMIT %d", query, limit)
|
||||||
return fmt.Sprintf("%s LIMIT %d", query, limit)
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addOffsetToQuery(query string, offset uint64) string {
|
func addOffsetToQuery(query string, offset uint64) string {
|
||||||
@ -404,17 +466,19 @@ func addOffsetToQuery(query string, offset uint64) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PrepareTracesQuery(start, end int64, queryType v3.QueryType, panelType v3.PanelType, mq *v3.BuilderQuery, keys map[string]v3.AttributeKey) (string, error) {
|
func PrepareTracesQuery(start, end int64, queryType v3.QueryType, panelType v3.PanelType, mq *v3.BuilderQuery, keys map[string]v3.AttributeKey) (string, error) {
|
||||||
query, err := buildTracesQuery(start, end, mq.StepInterval, mq, constants.SIGNOZ_SPAN_INDEX_TABLENAME, keys)
|
query, err := buildTracesQuery(start, end, mq.StepInterval, mq, constants.SIGNOZ_SPAN_INDEX_TABLENAME, keys, panelType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if panelType == v3.PanelTypeValue {
|
if panelType == v3.PanelTypeValue {
|
||||||
query, err = reduceToQuery(query, mq.ReduceTo, mq.AggregateOperator)
|
query, err = reduceToQuery(query, mq.ReduceTo, mq.AggregateOperator)
|
||||||
}
|
}
|
||||||
query = addLimitToQuery(query, mq.Limit, panelType)
|
if panelType == v3.PanelTypeList {
|
||||||
|
query = addLimitToQuery(query, mq.Limit, panelType)
|
||||||
|
|
||||||
if mq.Offset != 0 {
|
if mq.Offset != 0 {
|
||||||
query = addOffsetToQuery(query, mq.Offset)
|
query = addOffsetToQuery(query, mq.Offset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return query, err
|
return query, err
|
||||||
}
|
}
|
||||||
|
@ -244,13 +244,51 @@ var testGetSelectLabelsData = []struct {
|
|||||||
func TestGetSelectLabels(t *testing.T) {
|
func TestGetSelectLabels(t *testing.T) {
|
||||||
for _, tt := range testGetSelectLabelsData {
|
for _, tt := range testGetSelectLabelsData {
|
||||||
Convey("testGetSelectLabelsData", t, func() {
|
Convey("testGetSelectLabelsData", t, func() {
|
||||||
selectLabels, err := getSelectLabels(tt.AggregateOperator, tt.GroupByTags, map[string]v3.AttributeKey{})
|
selectLabels := getSelectLabels(tt.AggregateOperator, tt.GroupByTags, map[string]v3.AttributeKey{})
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(selectLabels, ShouldEqual, tt.SelectLabels)
|
So(selectLabels, ShouldEqual, tt.SelectLabels)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var testGetSelectColumnsData = []struct {
|
||||||
|
Name string
|
||||||
|
sc []v3.AttributeKey
|
||||||
|
SelectColumns string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "select columns attribute",
|
||||||
|
sc: []v3.AttributeKey{{Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
||||||
|
SelectColumns: "stringTagMap['user.name'] as `user.name` ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "select columns resource",
|
||||||
|
sc: []v3.AttributeKey{{Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}},
|
||||||
|
SelectColumns: "resourceTagsMap['user.name'] as `user.name` ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "select columns attribute and resource",
|
||||||
|
sc: []v3.AttributeKey{
|
||||||
|
{Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource},
|
||||||
|
{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
||||||
|
},
|
||||||
|
SelectColumns: "resourceTagsMap['user.name'] as `user.name` ,stringTagMap['host'] as `host` ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "select columns fixed column",
|
||||||
|
sc: []v3.AttributeKey{{Key: "host", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
||||||
|
SelectColumns: "host as `host` ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSelectColumns(t *testing.T) {
|
||||||
|
for _, tt := range testGetSelectColumnsData {
|
||||||
|
Convey("testGetSelectColumnsData", t, func() {
|
||||||
|
selectColumns := getSelectColumns(tt.sc, map[string]v3.AttributeKey{})
|
||||||
|
So(selectColumns, ShouldEqual, tt.SelectColumns)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var testGetZerosForEpochNanoData = []struct {
|
var testGetZerosForEpochNanoData = []struct {
|
||||||
Name string
|
Name string
|
||||||
Epoch int64
|
Epoch int64
|
||||||
@ -282,13 +320,15 @@ func TestGetZerosForEpochNano(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testOrderBy = []struct {
|
var testOrderBy = []struct {
|
||||||
Name string
|
Name string
|
||||||
Items []v3.OrderBy
|
PanelType v3.PanelType
|
||||||
Tags []string
|
Items []v3.OrderBy
|
||||||
Result string
|
Tags []string
|
||||||
|
Result []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "Test 1",
|
Name: "Test 1",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
Items: []v3.OrderBy{
|
Items: []v3.OrderBy{
|
||||||
{
|
{
|
||||||
ColumnName: "name",
|
ColumnName: "name",
|
||||||
@ -300,10 +340,11 @@ var testOrderBy = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tags: []string{"name"},
|
Tags: []string{"name"},
|
||||||
Result: "name asc,value desc",
|
Result: []string{"name asc", "value desc"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test 2",
|
Name: "Test 2",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
Items: []v3.OrderBy{
|
Items: []v3.OrderBy{
|
||||||
{
|
{
|
||||||
ColumnName: "name",
|
ColumnName: "name",
|
||||||
@ -315,10 +356,11 @@ var testOrderBy = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tags: []string{"name", "bytes"},
|
Tags: []string{"name", "bytes"},
|
||||||
Result: "name asc,bytes asc",
|
Result: []string{"name asc", "bytes asc"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test 3",
|
Name: "Test 3",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
Items: []v3.OrderBy{
|
Items: []v3.OrderBy{
|
||||||
{
|
{
|
||||||
ColumnName: "name",
|
ColumnName: "name",
|
||||||
@ -334,15 +376,62 @@ var testOrderBy = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tags: []string{"name", "bytes"},
|
Tags: []string{"name", "bytes"},
|
||||||
Result: "name asc,bytes asc,value asc",
|
Result: []string{"name asc", "bytes asc", "value asc"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test 4",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
|
Items: []v3.OrderBy{
|
||||||
|
{
|
||||||
|
ColumnName: "name",
|
||||||
|
Order: "asc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ColumnName: "bytes",
|
||||||
|
Order: "asc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ColumnName: "response_time",
|
||||||
|
Order: "desc",
|
||||||
|
Key: "response_time",
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
DataType: v3.AttributeKeyDataTypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: []string{"name", "bytes"},
|
||||||
|
Result: []string{"name asc", "bytes asc", "stringTagMap['response_time'] desc"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test 4",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
|
Items: []v3.OrderBy{
|
||||||
|
{
|
||||||
|
ColumnName: "name",
|
||||||
|
Order: "asc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ColumnName: "bytes",
|
||||||
|
Order: "asc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ColumnName: "response_time",
|
||||||
|
Order: "desc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: []string{},
|
||||||
|
Result: []string{"name asc", "bytes asc", "stringTagMap['response_time'] desc"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrderBy(t *testing.T) {
|
func TestOrderBy(t *testing.T) {
|
||||||
for _, tt := range testOrderBy {
|
for _, tt := range testOrderBy {
|
||||||
Convey("testOrderBy", t, func() {
|
Convey("testOrderBy", t, func() {
|
||||||
res := orderBy(tt.Items, tt.Tags)
|
res := orderBy(tt.PanelType, tt.Items, tt.Tags, map[string]v3.AttributeKey{
|
||||||
So(res, ShouldEqual, tt.Result)
|
"name": {Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
"bytes": {Key: "bytes", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
"response_time": {Key: "response_time", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: false},
|
||||||
|
})
|
||||||
|
So(res, ShouldResemble, tt.Result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,6 +446,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
TableName string
|
TableName string
|
||||||
AggregateOperator v3.AggregateOperator
|
AggregateOperator v3.AggregateOperator
|
||||||
ExpectedQuery string
|
ExpectedQuery string
|
||||||
|
PanelType v3.PanelType
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count on fixed column of float64 type",
|
Name: "Test aggregate count on fixed column of float64 type",
|
||||||
@ -373,6 +463,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" group by ts order by ts",
|
" group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate rate without aggregate attribute",
|
Name: "Test aggregate rate without aggregate attribute",
|
||||||
@ -388,6 +479,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, count()/60 as value from" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, count()/60 as value from" +
|
||||||
" signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <=" +
|
" signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <=" +
|
||||||
" '1680066458000000000') group by ts order by ts",
|
" '1680066458000000000') group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count on fixed column of float64 type with filter",
|
Name: "Test aggregate count on fixed column of float64 type with filter",
|
||||||
@ -406,6 +498,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
" toFloat64(count()) as value from signoz_traces.distributed_signoz_index_v2" +
|
" toFloat64(count()) as value from signoz_traces.distributed_signoz_index_v2" +
|
||||||
" where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" AND stringTagMap['customer_id'] = '10001' group by ts order by ts",
|
" AND stringTagMap['customer_id'] = '10001' group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count on fixed column of bool type",
|
Name: "Test aggregate count on fixed column of bool type",
|
||||||
@ -422,6 +515,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" group by ts order by ts",
|
" group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count on a attribute",
|
Name: "Test aggregate count on a attribute",
|
||||||
@ -438,6 +532,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" AND has(stringTagMap, 'user_name') group by ts order by ts",
|
" AND has(stringTagMap, 'user_name') group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count on a fixed column of string type",
|
Name: "Test aggregate count on a fixed column of string type",
|
||||||
@ -454,6 +549,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" AND name != '' group by ts order by ts",
|
" AND name != '' group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count with filter",
|
Name: "Test aggregate count with filter",
|
||||||
@ -473,6 +569,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" AND numberTagMap['bytes'] > 100.000000 AND has(stringTagMap, 'user_name') group by ts order by ts",
|
" AND numberTagMap['bytes'] > 100.000000 AND has(stringTagMap, 'user_name') group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count distinct and order by value",
|
Name: "Test aggregate count distinct and order by value",
|
||||||
@ -490,6 +587,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(name))) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(name))) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" group by ts order by value ASC,ts",
|
" group by ts order by value ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count distinct on string key",
|
Name: "Test aggregate count distinct on string key",
|
||||||
@ -506,6 +604,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name'])))" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name'])))" +
|
||||||
" as value from signoz_traces.distributed_signoz_index_v2 where" +
|
" as value from signoz_traces.distributed_signoz_index_v2 where" +
|
||||||
" (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') group by ts order by ts",
|
" (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') group by ts order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count distinct with filter and groupBy",
|
Name: "Test aggregate count distinct with filter and groupBy",
|
||||||
@ -533,6 +632,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['http.method'] = 'GET' AND resourceTagsMap['x'] != 'abc' " +
|
"AND stringTagMap['http.method'] = 'GET' AND resourceTagsMap['x'] != 'abc' " +
|
||||||
"AND has(stringTagMap, 'http.method') group by http.method,ts " +
|
"AND has(stringTagMap, 'http.method') group by http.method,ts " +
|
||||||
"order by http.method ASC,ts",
|
"order by http.method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate count with multiple filter,groupBy and orderBy",
|
Name: "Test aggregate count with multiple filter,groupBy and orderBy",
|
||||||
@ -564,6 +664,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['method'] = 'GET' AND resourceTagsMap['x'] != 'abc' " +
|
"AND stringTagMap['method'] = 'GET' AND resourceTagsMap['x'] != 'abc' " +
|
||||||
"AND has(stringTagMap, 'method') AND has(resourceTagsMap, 'x') group by method,x,ts " +
|
"AND has(stringTagMap, 'method') AND has(resourceTagsMap, 'x') group by method,x,ts " +
|
||||||
"order by method ASC,x ASC,ts",
|
"order by method ASC,x ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate avg",
|
Name: "Test aggregate avg",
|
||||||
@ -591,6 +692,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['method'] = 'GET' " +
|
"AND stringTagMap['method'] = 'GET' " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate sum",
|
Name: "Test aggregate sum",
|
||||||
@ -618,6 +720,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['method'] = 'GET' " +
|
"AND stringTagMap['method'] = 'GET' " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate min",
|
Name: "Test aggregate min",
|
||||||
@ -645,6 +748,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['method'] = 'GET' " +
|
"AND stringTagMap['method'] = 'GET' " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate max",
|
Name: "Test aggregate max",
|
||||||
@ -672,6 +776,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"AND stringTagMap['method'] = 'GET' " +
|
"AND stringTagMap['method'] = 'GET' " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate PXX",
|
Name: "Test aggregate PXX",
|
||||||
@ -695,6 +800,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate RateSum",
|
Name: "Test aggregate RateSum",
|
||||||
@ -715,6 +821,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
", sum(bytes)/60 as value from signoz_traces.distributed_signoz_index_v2 " +
|
", sum(bytes)/60 as value from signoz_traces.distributed_signoz_index_v2 " +
|
||||||
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" AND has(stringTagMap, 'method') group by method,ts order by method ASC,ts",
|
" AND has(stringTagMap, 'method') group by method,ts order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate rate",
|
Name: "Test aggregate rate",
|
||||||
@ -736,6 +843,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
"from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate RateSum without fixed column",
|
Name: "Test aggregate RateSum without fixed column",
|
||||||
@ -758,6 +866,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
"from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
"from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
||||||
"AND has(stringTagMap, 'method') group by method,ts " +
|
"AND has(stringTagMap, 'method') group by method,ts " +
|
||||||
"order by method ASC,ts",
|
"order by method ASC,ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test aggregate with having clause",
|
Name: "Test aggregate with having clause",
|
||||||
@ -781,6 +890,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name']))) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name']))) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
" group by ts having value > 10 order by ts",
|
" group by ts having value > 10 order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test count aggregate with having clause and filters",
|
Name: "Test count aggregate with having clause and filters",
|
||||||
@ -808,6 +918,7 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value from " +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value from " +
|
||||||
"signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
"signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
||||||
"AND stringTagMap['method'] = 'GET' AND has(stringTagMap, 'name') group by ts having value > 10 order by ts",
|
"AND stringTagMap['method'] = 'GET' AND has(stringTagMap, 'name') group by ts having value > 10 order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Test count distinct aggregate with having clause and filters",
|
Name: "Test count distinct aggregate with having clause and filters",
|
||||||
@ -835,32 +946,104 @@ var testBuildTracesQueryData = []struct {
|
|||||||
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name']))) as value" +
|
ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count(distinct(stringTagMap['name']))) as value" +
|
||||||
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
" from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
||||||
"AND stringTagMap['method'] = 'GET' group by ts having value > 10 order by ts",
|
"AND stringTagMap['method'] = 'GET' group by ts having value > 10 order by ts",
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test Noop list view",
|
||||||
|
Start: 1680066360726210000,
|
||||||
|
End: 1680066458000000000,
|
||||||
|
Step: 60,
|
||||||
|
BuilderQuery: &v3.BuilderQuery{
|
||||||
|
SelectColumns: []v3.AttributeKey{
|
||||||
|
{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
},
|
||||||
|
QueryName: "A",
|
||||||
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
||||||
|
Expression: "A",
|
||||||
|
Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}},
|
||||||
|
},
|
||||||
|
ExpectedQuery: "SELECT timestamp as timestamp_datetime, spanID, traceID," +
|
||||||
|
" name as `name` from signoz_traces.distributed_signoz_index_v2 where " +
|
||||||
|
"(timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') order by timestamp DESC",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test Noop list view with order by",
|
||||||
|
Start: 1680066360726210000,
|
||||||
|
End: 1680066458000000000,
|
||||||
|
Step: 60,
|
||||||
|
BuilderQuery: &v3.BuilderQuery{
|
||||||
|
SelectColumns: []v3.AttributeKey{
|
||||||
|
{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
},
|
||||||
|
QueryName: "A",
|
||||||
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
||||||
|
Expression: "A",
|
||||||
|
Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}},
|
||||||
|
OrderBy: []v3.OrderBy{{ColumnName: "name", Order: "ASC"}},
|
||||||
|
},
|
||||||
|
ExpectedQuery: "SELECT timestamp as timestamp_datetime, spanID, traceID," +
|
||||||
|
" name as `name` from signoz_traces.distributed_signoz_index_v2 where " +
|
||||||
|
"(timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') order by name ASC",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test Noop list view with order by and filter",
|
||||||
|
Start: 1680066360726210000,
|
||||||
|
End: 1680066458000000000,
|
||||||
|
Step: 60,
|
||||||
|
BuilderQuery: &v3.BuilderQuery{
|
||||||
|
SelectColumns: []v3.AttributeKey{
|
||||||
|
{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
},
|
||||||
|
QueryName: "A",
|
||||||
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
||||||
|
Expression: "A",
|
||||||
|
Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
||||||
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "GET", Operator: "="},
|
||||||
|
}},
|
||||||
|
OrderBy: []v3.OrderBy{{ColumnName: "name", Order: "ASC"}},
|
||||||
|
},
|
||||||
|
ExpectedQuery: "SELECT timestamp as timestamp_datetime, spanID, traceID," +
|
||||||
|
" name as `name` from signoz_traces.distributed_signoz_index_v2 where " +
|
||||||
|
"(timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')" +
|
||||||
|
" AND stringTagMap['method'] = 'GET' order by name ASC",
|
||||||
|
PanelType: v3.PanelTypeList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Test Noop trace view",
|
||||||
|
Start: 1680066360726210000,
|
||||||
|
End: 1680066458000000000,
|
||||||
|
Step: 60,
|
||||||
|
BuilderQuery: &v3.BuilderQuery{
|
||||||
|
QueryName: "A",
|
||||||
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
||||||
|
Expression: "A",
|
||||||
|
Filters: &v3.FilterSet{
|
||||||
|
Operator: "AND", Items: []v3.FilterItem{
|
||||||
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "GET", Operator: "="},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedQuery: "WITH subQuery AS (SELECT distinct on (traceID) traceID, durationNano, serviceName," +
|
||||||
|
" name FROM signoz_traces.distributed_signoz_index_v2 WHERE parentSpanID = '' AND (timestamp >= '1680066360726210000' AND " +
|
||||||
|
"timestamp <= '1680066458000000000') AND stringTagMap['method'] = 'GET' ORDER BY durationNano DESC LIMIT 100)" +
|
||||||
|
" SELECT subQuery.serviceName, subQuery.name, count() AS span_count, subQuery.durationNano, traceID" +
|
||||||
|
" FROM signoz_traces.distributed_signoz_index_v2 INNER JOIN subQuery ON distributed_signoz_index_v2.traceID" +
|
||||||
|
" = subQuery.traceID GROUP BY traceID, subQuery.durationNano, subQuery.name, subQuery.serviceName " +
|
||||||
|
"ORDER BY subQuery.durationNano desc;",
|
||||||
|
PanelType: v3.PanelTypeTrace,
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// Name: "Test Noop",
|
|
||||||
// Start: 1680066360726210000,
|
|
||||||
// End: 1680066458000000000,
|
|
||||||
// Step: 60,
|
|
||||||
// BuilderQuery: &v3.BuilderQuery{
|
|
||||||
// SelectColumns: []v3.AttributeKey{},
|
|
||||||
// QueryName: "A",
|
|
||||||
// AggregateOperator: v3.AggregateOperatorNoOp,
|
|
||||||
// Expression: "A",
|
|
||||||
// Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}},
|
|
||||||
// // GroupBy: []v3.AttributeKey{{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
||||||
// // OrderBy: []v3.OrderBy{{ColumnName: "method", Order: "ASC"}},
|
|
||||||
// },
|
|
||||||
// ExpectedQuery: "",
|
|
||||||
// },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildTracesQuery(t *testing.T) {
|
func TestBuildTracesQuery(t *testing.T) {
|
||||||
for _, tt := range testBuildTracesQueryData {
|
for _, tt := range testBuildTracesQueryData {
|
||||||
Convey("TestBuildTracesQuery", t, func() {
|
Convey("TestBuildTracesQuery", t, func() {
|
||||||
query, err := buildTracesQuery(tt.Start, tt.End, tt.Step, tt.BuilderQuery, tt.TableName, map[string]v3.AttributeKey{})
|
query, err := buildTracesQuery(tt.Start, tt.End, tt.Step, tt.BuilderQuery, tt.TableName, map[string]v3.AttributeKey{
|
||||||
|
"name": {Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
||||||
|
}, tt.PanelType)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(query, ShouldEqual, tt.ExpectedQuery)
|
So(query, ShouldEqual, tt.ExpectedQuery)
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +236,11 @@ const (
|
|||||||
"CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64," +
|
"CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64," +
|
||||||
"CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," +
|
"CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," +
|
||||||
"CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string "
|
"CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string "
|
||||||
|
TracesExplorerViewSQLSelectWithSubQuery = "WITH subQuery AS (SELECT distinct on (traceID) traceID, durationNano, " +
|
||||||
|
"serviceName, name FROM %s.%s WHERE parentSpanID = '' AND %s %s ORDER BY durationNano DESC "
|
||||||
|
TracesExplorerViewSQLSelectQuery = "SELECT subQuery.serviceName, subQuery.name, count() AS " +
|
||||||
|
"span_count, subQuery.durationNano, traceID FROM %s.%s INNER JOIN subQuery ON %s.traceID = subQuery.traceID GROUP " +
|
||||||
|
"BY traceID, subQuery.durationNano, subQuery.name, subQuery.serviceName ORDER BY subQuery.durationNano desc;"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReservedColumnTargetAliases identifies result value from a user
|
// ReservedColumnTargetAliases identifies result value from a user
|
||||||
|
@ -178,11 +178,12 @@ const (
|
|||||||
PanelTypeGraph PanelType = "graph"
|
PanelTypeGraph PanelType = "graph"
|
||||||
PanelTypeTable PanelType = "table"
|
PanelTypeTable PanelType = "table"
|
||||||
PanelTypeList PanelType = "list"
|
PanelTypeList PanelType = "list"
|
||||||
|
PanelTypeTrace PanelType = "trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p PanelType) Validate() error {
|
func (p PanelType) Validate() error {
|
||||||
switch p {
|
switch p {
|
||||||
case PanelTypeValue, PanelTypeGraph, PanelTypeTable, PanelTypeList:
|
case PanelTypeValue, PanelTypeGraph, PanelTypeTable, PanelTypeList, PanelTypeTrace:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid panel type: %s", p)
|
return fmt.Errorf("invalid panel type: %s", p)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user