Skip to content

Commit

Permalink
Allow users to sort traces (#8497)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccschmitz committed May 13, 2024
1 parent 7a2f541 commit 73d46ef
Show file tree
Hide file tree
Showing 17 changed files with 440 additions and 115 deletions.
17 changes: 6 additions & 11 deletions backend/clickhouse/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package clickhouse
import (
"context"
"fmt"
"github.com/openlyinc/pointy"
"math"
"strings"
"time"

"github.com/openlyinc/pointy"

"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
e "github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -36,6 +37,7 @@ var logKeysToColumns = map[modelInputs.ReservedLogKey]string{
modelInputs.ReservedLogKeyServiceVersion: "ServiceVersion",
modelInputs.ReservedLogKeyEnvironment: "Environment",
modelInputs.ReservedLogKeyMessage: "Body",
modelInputs.ReservedLogKeyTimestamp: "Timestamp",
}

// These keys show up as recommendations, but with no recommended values due to high cardinality
Expand Down Expand Up @@ -198,9 +200,8 @@ func (client *Client) ReadSessionLogs(ctx context.Context, projectID int, params
selectCols,
[]int{projectID},
params,
Pagination{},
OrderBackwardInverted,
OrderForwardInverted)
Pagination{Direction: modelInputs.SortDirectionAsc},
)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -251,9 +252,7 @@ func (client *Client) ReadLogsTotalCount(ctx context.Context, projectID int, par
[]string{"COUNT(*)"},
[]int{projectID},
params,
Pagination{CountOnly: true},
OrderBackwardNatural,
OrderForwardNatural)
Pagination{CountOnly: true})
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -340,8 +339,6 @@ func (client *Client) ReadLogsHistogram(ctx context.Context, projectID int, para
[]int{projectID},
params,
Pagination{CountOnly: true},
OrderBackwardNatural,
OrderForwardNatural,
)
} else {
fromSb, err = makeSelectBuilder(
Expand All @@ -350,8 +347,6 @@ func (client *Client) ReadLogsHistogram(ctx context.Context, projectID int, para
[]int{projectID},
params,
Pagination{CountOnly: true},
OrderBackwardNatural,
OrderForwardNatural,
)
}
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions backend/clickhouse/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func setupTest(tb testing.TB) (*Client, func(tb testing.TB)) {

err = client.conn.Exec(context.Background(), fmt.Sprintf("TRUNCATE TABLE %s", TracesTable))
assert.NoError(tb, err)

err = client.conn.Exec(context.Background(), fmt.Sprintf("TRUNCATE TABLE %s", TracesSamplingTable))
assert.NoError(tb, err)
}
}

Expand Down
64 changes: 40 additions & 24 deletions backend/clickhouse/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ func readObjects[TObj interface{}, TReservedKey ~string](ctx context.Context, cl
var err error
var args []interface{}

orderForward := OrderForwardNatural
orderBackward := OrderBackwardNatural
if pagination.Direction == modelInputs.SortDirectionAsc {
orderForward = OrderForwardInverted
orderBackward = OrderBackwardInverted
}
orderForward, _ := getSortOrders[TReservedKey](sb, pagination.Direction, config, params)

outerSelect := strings.Join(config.SelectColumns, ", ")
innerSelect := []string{"Timestamp", "UUID"}
Expand All @@ -58,9 +53,7 @@ func readObjects[TObj interface{}, TReservedKey ~string](ctx context.Context, cl
params,
Pagination{
Before: pagination.At,
},
orderBackward,
orderForward)
})
if err != nil {
return nil, err
}
Expand All @@ -73,9 +66,7 @@ func readObjects[TObj interface{}, TReservedKey ~string](ctx context.Context, cl
params,
Pagination{
At: pagination.At,
},
orderBackward,
orderForward)
})
if err != nil {
return nil, err
}
Expand All @@ -88,9 +79,7 @@ func readObjects[TObj interface{}, TReservedKey ~string](ctx context.Context, cl
params,
Pagination{
After: pagination.At,
},
orderBackward,
orderForward)
})
if err != nil {
return nil, err
}
Expand All @@ -109,9 +98,7 @@ func readObjects[TObj interface{}, TReservedKey ~string](ctx context.Context, cl
innerSelect,
[]int{projectID},
params,
pagination,
orderBackward,
orderForward)
pagination)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -163,11 +150,11 @@ func makeSelectBuilder[T ~string](
projectIDs []int,
params modelInputs.QueryInput,
pagination Pagination,
orderBackward string,
orderForward string,
) (*sqlbuilder.SelectBuilder, error) {
sb := sqlbuilder.NewSelectBuilder()

orderForward, orderBackward := getSortOrders[T](sb, pagination.Direction, config, params)

sb.Select(selectCols...)
sb.From(config.TableName)
sb.Where(sb.In("ProjectId", projectIDs))
Expand Down Expand Up @@ -612,8 +599,6 @@ func readWorkspaceMetrics[T ~string](ctx context.Context, client *Client, sample
projectIDs,
params,
Pagination{CountOnly: true},
OrderBackwardNatural,
OrderForwardNatural,
)

var col string
Expand Down Expand Up @@ -895,8 +880,6 @@ func logLines[T ~string](ctx context.Context, client *Client, tableConfig model.
[]int{projectID},
params,
Pagination{CountOnly: true},
OrderBackwardNatural,
OrderForwardNatural,
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -959,3 +942,36 @@ func repr(val reflect.Value) string {
return val.String()
}
}

func getSortOrders[TReservedKey ~string](
sb *sqlbuilder.SelectBuilder,
paginationDirection modelInputs.SortDirection,
config model.TableConfig[TReservedKey],
params modelInputs.QueryInput,
) (string, string) {
sortColumn := "timestamp"
sortDirection := modelInputs.SortDirectionDesc
if params.Sort != nil {
sortColumn = params.Sort.Column
sortDirection = params.Sort.Direction
}

if col, found := config.KeysToColumns[TReservedKey(sortColumn)]; found {
sortColumn = col
} else {
sortColumn = fmt.Sprintf("%s[%s]", config.AttributesColumn, sb.Var(sortColumn))
}

forwardDirection := "DESC"
backwardDirection := "ASC"
if paginationDirection == modelInputs.SortDirectionAsc || sortDirection == modelInputs.SortDirectionAsc {
forwardDirection = "ASC"
} else {
backwardDirection = "DESC"
}

orderForward := fmt.Sprintf("%s %s, UUID %s", sortColumn, forwardDirection, forwardDirection)
orderBackward := fmt.Sprintf("%s %s, UUID %s", sortColumn, backwardDirection, backwardDirection)

return orderForward, orderBackward
}
8 changes: 7 additions & 1 deletion backend/clickhouse/traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var traceKeysToColumns = map[modelInputs.ReservedTraceKey]string{
modelInputs.ReservedTraceKeyMetricValue: "MetricValue",
modelInputs.ReservedTraceKeyEnvironment: "Environment",
modelInputs.ReservedTraceKeyHasErrors: "HasErrors",
modelInputs.ReservedTraceKeyTimestamp: "Timestamp",
}

var traceColumns = []string{
Expand Down Expand Up @@ -268,7 +269,12 @@ func (client *Client) ReadTraces(ctx context.Context, projectID int, params mode
}, nil
}

conn, err := readObjects(ctx, client, TracesTableConfig, projectID, params, pagination, scanTrace)
tableConfig := TracesTableConfig
if params.Sort != nil {
tableConfig = tracesSamplingTableConfig
}

conn, err := readObjects(ctx, client, tableConfig, projectID, params, pagination, scanTrace)
if err != nil {
return nil, err
}
Expand Down
49 changes: 49 additions & 0 deletions backend/clickhouse/traces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package clickhouse

import (
"context"
"fmt"
"testing"
"time"

Expand Down Expand Up @@ -191,3 +192,51 @@ func TestReadTracesWithEnvironmentFilter(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, payload.Edges, 2)
}

func TestReadTracesWithSorting(t *testing.T) {
ctx := context.Background()
client, teardown := setupTest(t)
defer teardown(t)

now := time.Now()
rows := []*ClickhouseTraceRow{
NewTraceRow(now, 1).WithSpanName("Span A").WithDuration(now, now.Add(100*time.Nanosecond)).WithTraceAttributes(map[string]string{"host.name": "b"}).AsClickhouseTraceRow(),
NewTraceRow(now, 1).WithSpanName("Span B").WithDuration(now, now.Add(300*time.Nanosecond)).WithTraceAttributes(map[string]string{"host.name": "c"}).AsClickhouseTraceRow(),
NewTraceRow(now, 1).WithSpanName("Span C").WithDuration(now, now.Add(200*time.Nanosecond)).WithTraceAttributes(map[string]string{"host.name": "a"}).AsClickhouseTraceRow(),
}

assert.NoError(t, client.BatchWriteTraceRows(ctx, rows))

payload, err := client.ReadTraces(ctx, 1, modelInputs.QueryInput{
DateRange: makeDateWithinRange(now),
Query: "",
Sort: &modelInputs.SortInput{
Column: "duration",
Direction: "DESC",
},
}, Pagination{})
assert.NoError(t, err)
assert.Len(t, payload.Edges, 3)

assert.Equal(t, "Span B", payload.Edges[0].Node.SpanName)
assert.Equal(t, "Span C", payload.Edges[1].Node.SpanName)
assert.Equal(t, "Span A", payload.Edges[2].Node.SpanName)

payload, err = client.ReadTraces(ctx, 1, modelInputs.QueryInput{
DateRange: makeDateWithinRange(now),
Query: "",
Sort: &modelInputs.SortInput{
Column: "host.name",
Direction: "DESC",
},
}, Pagination{})
assert.NoError(t, err)
assert.Len(t, payload.Edges, 3)

for i, edge := range payload.Edges {
fmt.Printf("Edge %d: %v\n", i, edge.Node)
}
assert.Equal(t, "Span B", payload.Edges[0].Node.SpanName)
assert.Equal(t, "Span A", payload.Edges[1].Node.SpanName)
assert.Equal(t, "Span C", payload.Edges[2].Node.SpanName)
}
Loading

0 comments on commit 73d46ef

Please sign in to comment.