From 31ada18c6f280d5005a8e9de41281cf89f8229f1 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Tue, 19 Nov 2019 15:03:51 -0500 Subject: [PATCH 01/12] Create new cassandra table "operation_names_v2" with "spanKind" column for operation name index - add migration script - read from the latest table if available, otherwise fail back to previous table Signed-off-by: Jun Guo --- plugin/storage/cassandra/factory_test.go | 2 +- .../cassandra/schema/migration/V002toV003.sh | 100 +++++++++ plugin/storage/cassandra/schema/v003.cql.tmpl | 204 ++++++++++++++++++ .../cassandra/spanstore/operation_names.go | 149 +++++++++++-- .../spanstore/operation_names_test.go | 104 ++++++--- .../cassandra/spanstore/reader_test.go | 4 + .../cassandra/spanstore/writer_test.go | 5 + 7 files changed, 513 insertions(+), 55 deletions(-) create mode 100644 plugin/storage/cassandra/schema/migration/V002toV003.sh create mode 100644 plugin/storage/cassandra/schema/v003.cql.tmpl diff --git a/plugin/storage/cassandra/factory_test.go b/plugin/storage/cassandra/factory_test.go index 6671203b187..2b739a71b3a 100644 --- a/plugin/storage/cassandra/factory_test.go +++ b/plugin/storage/cassandra/factory_test.go @@ -91,7 +91,7 @@ func TestCassandraFactory(t *testing.T) { _, err = f.CreateArchiveSpanWriter() assert.EqualError(t, err, "archive storage not configured") - f.archiveConfig = &mockSessionBuilder{} + f.archiveConfig = newMockSessionBuilder(session, nil) assert.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) _, err = f.CreateArchiveSpanReader() diff --git a/plugin/storage/cassandra/schema/migration/V002toV003.sh b/plugin/storage/cassandra/schema/migration/V002toV003.sh new file mode 100644 index 00000000000..9d53b06ca07 --- /dev/null +++ b/plugin/storage/cassandra/schema/migration/V002toV003.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# Create a new operation_names_v2 table and copy all data from operation_names table +# Sample usage: KEYSPACE=jaeger_v1_test TIMEOUT=1000 ./plugin/storage/cassandra/schema/migration/v002tov003.sh + +set -euo pipefail + +function usage { + >&2 echo "Error: $1" + >&2 echo "" + >&2 echo "Usage: KEYSPACE={keyspace} TTL={ttl} $0" + >&2 echo "" + >&2 echo "The following parameters can be set via environment:" + >&2 echo " KEYSPACE - keyspace" + >&2 echo "" + exit 1 +} + +confirm() { + read -r -p "${1:-Continue? [y/N]} " response + case "$response" in + [yY][eE][sS]|[yY]) + true + ;; + *) + exit 1 + ;; + esac +} + +if [[ ${KEYSPACE} == "" ]]; then + usage "missing KEYSPACE parameter" +fi + +if [[ ${KEYSPACE} =~ [^a-zA-Z0-9_] ]]; then + usage "invalid characters in KEYSPACE=$KEYSPACE parameter, please use letters, digits or underscores" +fi + +keyspace=${KEYSPACE} +old_table=operation_names +new_table=operation_names_v2 +cqlsh_cmd=cqlsh + +row_count=$(${cqlsh_cmd} -e "select count(*) from $keyspace.$old_table;"|head -4|tail -1| tr -d ' ') + +echo "About to copy $row_count rows to new table..." + +confirm + +${cqlsh_cmd} -e "COPY $keyspace.$old_table (service_name, operation_name) to '$old_table.csv';" + +if [[ ! -f ${old_table}.csv ]]; then + echo "Could not find $old_table.csv. Backup from cassandra was probably not successful" + exit 1 +fi + +csv_rows=$(wc -l ${old_table}.csv | tr -dc '0-9') + +if [[ ${row_count} -ne ${csv_rows} ]]; then + echo "Number of rows: $csv_rows in file is not equal to number of rows: $row_count in cassandra" + exit 1 +fi + +echo "Generating data for new table..." +while IFS="," read service_name operation_name; do + echo "$service_name,,$operation_name" +done < ${old_table}.csv > ${new_table}.csv + +ttl=$(${cqlsh_cmd} -e "select default_time_to_live from system_schema.tables WHERE keyspace_name='$keyspace' AND table_name='$old_table';"|head -4|tail -1|tr -d ' ') + +echo "Creating new table $new_table with ttl: $ttl" + +${cqlsh_cmd} -e "CREATE TABLE IF NOT EXISTS $keyspace.$new_table ( + service_name text, + span_kind text, + operation_name text, + PRIMARY KEY ((service_name), span_kind, operation_name) +) + WITH compaction = { + 'min_threshold': '4', + 'max_threshold': '32', + 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = $ttl + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800;" + +echo "Import data to new table: $keyspace.$new_table from $new_table.csv" + +# empty string will be inserted as empty string instead of null +${cqlsh_cmd} -e "COPY $keyspace.$new_table (service_name, span_kind, operation_name) + FROM '$new_table.csv' + WITH NULL='NIL';" + +echo "Data from old table are successfully imported to new table!" + +echo "Before finish, do you want to delete old table: $keyspace.$old_table?" +confirm +${cqlsh_cmd} -e "DROP TABLE IF EXISTS $keyspace.$old_table;" \ No newline at end of file diff --git a/plugin/storage/cassandra/schema/v003.cql.tmpl b/plugin/storage/cassandra/schema/v003.cql.tmpl new file mode 100644 index 00000000000..b1b664d3dd0 --- /dev/null +++ b/plugin/storage/cassandra/schema/v003.cql.tmpl @@ -0,0 +1,204 @@ +-- +-- Creates Cassandra keyspace with tables for traces and dependencies. +-- +-- Required parameters: +-- +-- keyspace +-- name of the keyspace +-- replication +-- replication strategy for the keyspace, such as +-- for prod environments +-- {'class': 'NetworkTopologyStrategy', '$datacenter': '${replication_factor}' } +-- for test environments +-- {'class': 'SimpleStrategy', 'replication_factor': '1'} +-- trace_ttl +-- default time to live for trace data, in seconds +-- dependencies_ttl +-- default time to live for dependencies data, in seconds (0 for no TTL) +-- +-- Non-configurable settings: +-- gc_grace_seconds is non-zero, see: http://www.uberobert.com/cassandra_gc_grace_disables_hinted_handoff/ +-- For TTL of 2 days, compaction window is 1 hour, rule of thumb here: http://thelastpickle.com/blog/2016/12/08/TWCS-part1.html + +CREATE KEYSPACE IF NOT EXISTS ${keyspace} WITH replication = ${replication}; + +CREATE TYPE IF NOT EXISTS ${keyspace}.keyvalue ( + key text, + value_type text, + value_string text, + value_bool boolean, + value_long bigint, + value_double double, + value_binary blob, +); + +CREATE TYPE IF NOT EXISTS ${keyspace}.log ( + ts bigint, + fields list>, +); + +CREATE TYPE IF NOT EXISTS ${keyspace}.span_ref ( + ref_type text, + trace_id blob, + span_id bigint, +); + +CREATE TYPE IF NOT EXISTS ${keyspace}.process ( + service_name text, + tags list>, +); + +-- Notice we have span_hash. This exists only for zipkin backwards compat. Zipkin allows spans with the same ID. +-- Note: Cassandra re-orders non-PK columns alphabetically, so the table looks differently in CQLSH "describe table". +-- start_time is bigint instead of timestamp as we require microsecond precision +CREATE TABLE IF NOT EXISTS ${keyspace}.traces ( + trace_id blob, + span_id bigint, + span_hash bigint, + parent_id bigint, + operation_name text, + flags int, + start_time bigint, + duration bigint, + tags list>, + logs list>, + refs list>, + process frozen, + PRIMARY KEY (trace_id, span_id, span_hash) +) + WITH compaction = { + 'compaction_window_size': '1', + 'compaction_window_unit': 'HOURS', + 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +CREATE TABLE IF NOT EXISTS ${keyspace}.service_names ( + service_name text, + PRIMARY KEY (service_name) +) + WITH compaction = { + 'min_threshold': '4', + 'max_threshold': '32', + 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +CREATE TABLE IF NOT EXISTS ${keyspace}.operation_names_v2 ( + service_name text, + span_kind text, + operation_name text, + PRIMARY KEY ((service_name), span_kind, operation_name) +) + WITH compaction = { + 'min_threshold': '4', + 'max_threshold': '32', + 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +-- index of trace IDs by service + operation names, sorted by span start_time. +CREATE TABLE IF NOT EXISTS ${keyspace}.service_operation_index ( + service_name text, + operation_name text, + start_time bigint, + trace_id blob, + PRIMARY KEY ((service_name, operation_name), start_time) +) WITH CLUSTERING ORDER BY (start_time DESC) + AND compaction = { + 'compaction_window_size': '1', + 'compaction_window_unit': 'HOURS', + 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +CREATE TABLE IF NOT EXISTS ${keyspace}.service_name_index ( + service_name text, + bucket int, + start_time bigint, + trace_id blob, + PRIMARY KEY ((service_name, bucket), start_time) +) WITH CLUSTERING ORDER BY (start_time DESC) + AND compaction = { + 'compaction_window_size': '1', + 'compaction_window_unit': 'HOURS', + 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +CREATE TABLE IF NOT EXISTS ${keyspace}.duration_index ( + service_name text, // service name + operation_name text, // operation name, or blank for queries without span name + bucket timestamp, // time bucket, - the start_time of the given span rounded to an hour + duration bigint, // span duration, in microseconds + start_time bigint, + trace_id blob, + PRIMARY KEY ((service_name, operation_name, bucket), duration, start_time, trace_id) +) WITH CLUSTERING ORDER BY (duration DESC, start_time DESC) + AND compaction = { + 'compaction_window_size': '1', + 'compaction_window_unit': 'HOURS', + 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +-- a bucketing strategy may have to be added for tag queries +-- we can make this table even better by adding a timestamp to it +CREATE TABLE IF NOT EXISTS ${keyspace}.tag_index ( + service_name text, + tag_key text, + tag_value text, + start_time bigint, + trace_id blob, + span_id bigint, + PRIMARY KEY ((service_name, tag_key, tag_value), start_time, trace_id, span_id) +) + WITH CLUSTERING ORDER BY (start_time DESC) + AND compaction = { + 'compaction_window_size': '1', + 'compaction_window_unit': 'HOURS', + 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy' + } + AND dclocal_read_repair_chance = 0.0 + AND default_time_to_live = ${trace_ttl} + AND speculative_retry = 'NONE' + AND gc_grace_seconds = 10800; -- 3 hours of downtime acceptable on nodes + +CREATE TYPE IF NOT EXISTS ${keyspace}.dependency ( + parent text, + child text, + call_count bigint, + source text, +); + +-- compaction strategy is intentionally different as compared to other tables due to the size of dependencies data +CREATE TABLE IF NOT EXISTS ${keyspace}.dependencies_v2 ( + ts_bucket timestamp, + ts timestamp, + dependencies list>, + PRIMARY KEY (ts_bucket, ts) +) WITH CLUSTERING ORDER BY (ts DESC) + AND compaction = { + 'min_threshold': '4', + 'max_threshold': '32', + 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy' + } + AND default_time_to_live = ${dependencies_ttl}; \ No newline at end of file diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index de73cf4347e..8a2f993a693 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -16,6 +16,7 @@ package spanstore import ( + "fmt" "time" "github.com/pkg/errors" @@ -25,23 +26,51 @@ import ( "github.com/jaegertracing/jaeger/pkg/cache" "github.com/jaegertracing/jaeger/pkg/cassandra" casMetrics "github.com/jaegertracing/jaeger/pkg/cassandra/metrics" + "github.com/jaegertracing/jaeger/storage/spanstore" ) const ( - insertOperationName = `INSERT INTO operation_names(service_name, operation_name) VALUES (?, ?)` - queryOperationNames = `SELECT operation_name FROM operation_names WHERE service_name = ?` + // LatestVersion latest version of operation_names table schema, increase the version if your table schema changes require code change + LatestVersion = 1 + // TableQueryStmt the query statement used to check if a table exists or not + TableQueryStmt = "SELECT * from %s limit 1" ) +type schemaMeta struct { + TableName string + InsertStmt string + QueryByKindStmt string + QueryStmt string +} + +var schemas = []schemaMeta{ + { + TableName: "operation_names", + InsertStmt: "INSERT INTO %s(service_name, operation_name) VALUES (?, ?)", + QueryByKindStmt: "SELECT operation_name FROM %s WHERE service_name = ?", + QueryStmt: "SELECT operation_name FROM %s WHERE service_name = ?", + }, + { + TableName: "operation_names_v2", + InsertStmt: "INSERT INTO %s(service_name, span_kind, operation_name) VALUES (?, ?, ?)", + QueryByKindStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ? AND span_kind = ?", + QueryStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ?", + }, +} + // OperationNamesStorage stores known operation names by service. type OperationNamesStorage struct { // CQL statements are public so that Cassandra2 storage can override them - InsertStmt string - QueryStmt string - session cassandra.Session - writeCacheTTL time.Duration - metrics *casMetrics.Table - operationNames cache.Cache - logger *zap.Logger + SchemaVersion int + TableName string + InsertStmt string + QueryStmt string + QueryByKindStmt string + session cassandra.Session + writeCacheTTL time.Duration + metrics *casMetrics.Table + operationNames cache.Cache + logger *zap.Logger } // NewOperationNamesStorage returns a new OperationNamesStorage @@ -51,13 +80,23 @@ func NewOperationNamesStorage( metricsFactory metrics.Factory, logger *zap.Logger, ) *OperationNamesStorage { + + schemaVersion := LatestVersion + + if !tableExist(session, schemas[schemaVersion].TableName) { + schemaVersion = schemaVersion - 1 + } + return &OperationNamesStorage{ - session: session, - InsertStmt: insertOperationName, - QueryStmt: queryOperationNames, - metrics: casMetrics.NewTable(metricsFactory, "operation_names"), - writeCacheTTL: writeCacheTTL, - logger: logger, + session: session, + TableName: schemas[schemaVersion].TableName, + SchemaVersion: schemaVersion, + InsertStmt: fmt.Sprintf(schemas[schemaVersion].InsertStmt, schemas[schemaVersion].TableName), + QueryByKindStmt: fmt.Sprintf(schemas[schemaVersion].QueryByKindStmt, schemas[schemaVersion].TableName), + QueryStmt: fmt.Sprintf(schemas[schemaVersion].QueryStmt, schemas[schemaVersion].TableName), + metrics: casMetrics.NewTable(metricsFactory, schemas[schemaVersion].TableName), + writeCacheTTL: writeCacheTTL, + logger: logger, operationNames: cache.NewLRUWithOptions( 100000, &cache.Options{ @@ -67,12 +106,27 @@ func NewOperationNamesStorage( } } +func tableExist(session cassandra.Session, tableName string) bool { + query := session.Query(fmt.Sprintf(TableQueryStmt, tableName)) + err := query.Exec() + return err == nil +} + // Write saves Operation and Service name tuples func (s *OperationNamesStorage) Write(serviceName string, operationName string) error { var err error + //TODO: take spanKind from args + spanKind := "" query := s.session.Query(s.InsertStmt) - if inCache := checkWriteCache(serviceName+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { - q := query.Bind(serviceName, operationName) + if inCache := checkWriteCache(serviceName+"|"+spanKind+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { + var q cassandra.Query + switch s.SchemaVersion { + case 1: + q = query.Bind(serviceName, spanKind, operationName) + case 0: + q = query.Bind(serviceName, operationName) + } + err2 := s.metrics.Exec(q, s.logger) if err2 != nil { err = err2 @@ -83,16 +137,73 @@ func (s *OperationNamesStorage) Write(serviceName string, operationName string) // GetOperations returns all operations for a specific service traced by Jaeger func (s *OperationNamesStorage) GetOperations(service string) ([]string, error) { + var operations []*spanstore.Operation + var err error + + switch s.SchemaVersion { + case 1: + operations, err = getOperationsV1(s, &spanstore.OperationQueryParameters{ + ServiceName: service, + }) + case 0: + operations, err = getOperationsV0(s, service) + } + + if err != nil { + return nil, err + } + operationNames := make([]string, len(operations)) + for idx, operation := range operations { + operationNames[idx] = operation.Name + } + return operationNames, err +} + +func getOperationsV0(s *OperationNamesStorage, service string) ([]*spanstore.Operation, error) { iter := s.session.Query(s.QueryStmt, service).Iter() var operation string - var operations []string + var operationNames []string for iter.Scan(&operation) { - operations = append(operations, operation) + operationNames = append(operationNames, operation) } if err := iter.Close(); err != nil { err = errors.Wrap(err, "Error reading operation_names from storage") return nil, err } + + operations := make([]*spanstore.Operation, len(operationNames)) + for idx, name := range operationNames { + operations[idx] = &spanstore.Operation{ + Name: name, + } + } + return operations, nil +} + +func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + var casQuery cassandra.Query + if query.SpanKind == "" { + // Get operations for all spanKind + casQuery = s.session.Query(s.QueryStmt, query.ServiceName) + } else { + // Get operations for given spanKind + casQuery = s.session.Query(s.QueryByKindStmt, query.ServiceName, query.SpanKind) + } + iter := casQuery.Iter() + + var operationName string + var spanKind string + var operations []*spanstore.Operation + for iter.Scan(&spanKind, &operationName) { + operations = append(operations, &spanstore.Operation{ + Name: operationName, + SpanKind: spanKind, + }) + } + if err := iter.Close(); err != nil { + err = errors.Wrap(err, fmt.Sprintf("Error reading %s from storage", s.TableName)) + return nil, err + } return operations, nil } diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index ca8357542f8..86c257cf789 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -30,6 +30,12 @@ import ( "github.com/jaegertracing/jaeger/pkg/testutils" ) +type test struct { + ttl time.Duration + schemaVersion int + expErr error +} + type operationNameStorageTest struct { session *mocks.Session writeCacheTTL time.Duration @@ -39,10 +45,18 @@ type operationNameStorageTest struct { storage *OperationNamesStorage } -func withOperationNamesStorage(writeCacheTTL time.Duration, fn func(s *operationNameStorageTest)) { +func withOperationNamesStorage(writeCacheTTL time.Duration, schemaVersion int, fn func(s *operationNameStorageTest)) { session := &mocks.Session{} logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) + query := &mocks.Query{} + session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) + if schemaVersion != LatestVersion { + query.On("Exec").Return(errors.New("new table does not exist")) + } else { + query.On("Exec").Return(nil) + } + s := &operationNameStorageTest{ session: session, writeCacheTTL: writeCacheTTL, @@ -55,38 +69,49 @@ func withOperationNamesStorage(writeCacheTTL time.Duration, fn func(s *operation } func TestOperationNamesStorageWrite(t *testing.T) { - for _, ttl := range []time.Duration{0, time.Minute} { - writeCacheTTL := ttl // capture loop var - t.Run(fmt.Sprintf("writeCacheTTL=%v", writeCacheTTL), func(t *testing.T) { - withOperationNamesStorage(writeCacheTTL, func(s *operationNameStorageTest) { + for _, test := range []test{ + {0, 0, nil}, + {time.Minute, 0, nil}, + {0, 1, nil}, + {time.Minute, 1, nil}, + } { + writeCacheTTL := test.ttl // capture loop var + t.Run(fmt.Sprintf("test %#v", test), func(t *testing.T) { + withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { var execError = errors.New("exec error") query := &mocks.Query{} query1 := &mocks.Query{} query2 := &mocks.Query{} - query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) - query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) + + if test.schemaVersion == 0 { + query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) + } else { + query.On("Bind", []interface{}{"service-a", "", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "", "operation-d"}).Return(query2) + } + query1.On("Exec").Return(nil) query2.On("Exec").Return(execError) - query2.On("String").Return("select from operation_names") + query2.On("String").Return("select from " + schemas[test.schemaVersion].TableName) - var emptyArgs []interface{} - s.session.On("Query", mock.AnythingOfType("string"), emptyArgs).Return(query) + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) err := s.storage.Write("service-a", "Operation-b") assert.NoError(t, err) err = s.storage.Write("service-c", "operation-d") - assert.EqualError(t, err, "failed to Exec query 'select from operation_names': exec error") + assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].TableName+"': exec error") assert.Equal(t, map[string]string{ "level": "error", "msg": "Failed to exec query", - "query": "select from operation_names", + "query": "select from " + schemas[test.schemaVersion].TableName, "error": "exec error", }, s.logBuffer.JSONLine(0)) counts, _ := s.metricsFactory.Snapshot() assert.Equal(t, map[string]int64{ - "attempts|table=operation_names": 2, "inserts|table=operation_names": 1, "errors|table=operation_names": 1, + "attempts|table=" + schemas[test.schemaVersion].TableName: 2, "inserts|table=" + schemas[test.schemaVersion].TableName: 1, "errors|table=" + schemas[test.schemaVersion].TableName: 1, }, counts, "after first two writes") // write again @@ -97,8 +122,8 @@ func TestOperationNamesStorageWrite(t *testing.T) { expCounts := counts if writeCacheTTL == 0 { // without write cache, the second write must succeed - expCounts["attempts|table=operation_names"]++ - expCounts["inserts|table=operation_names"]++ + expCounts["attempts|table="+schemas[test.schemaVersion].TableName]++ + expCounts["inserts|table="+schemas[test.schemaVersion].TableName]++ } assert.Equal(t, expCounts, counts2) }) @@ -118,28 +143,37 @@ func TestOperationNamesStorageGetServices(t *testing.T) { return true }) matchEverything := mock.MatchedBy(func(v []interface{}) bool { return true }) - for _, expErr := range []error{nil, scanError} { - withOperationNamesStorage(writeCacheTTL, func(s *operationNameStorageTest) { - iter := &mocks.Iterator{} - iter.On("Scan", matchOnce).Return(true) - iter.On("Scan", matchEverything).Return(false) // false to stop the loop - iter.On("Close").Return(expErr) + for _, test := range []test{ + {0, 0, nil}, + {0, 0, scanError}, + {0, 1, nil}, + {0, 1, scanError}, + } { + t.Run(fmt.Sprintf("test %#v", test), func(t *testing.T) { + withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { + iter := &mocks.Iterator{} + iter.On("Scan", matchOnce).Return(true) + iter.On("Scan", matchEverything).Return(false) // false to stop the loop + iter.On("Close").Return(test.expErr) - query := &mocks.Query{} - query.On("Iter").Return(iter) - - s.session.On("Query", mock.AnythingOfType("string"), []interface{}{"service-a"}).Return(query) - - services, err := s.storage.GetOperations("service-a") - if expErr == nil { - assert.NoError(t, err) - // expect empty string because mock iter.Scan(&placeholder) does not write to `placeholder` - assert.Equal(t, []string{""}, services) - } else { - assert.EqualError(t, err, "Error reading operation_names from storage: "+expErr.Error()) - } + query := &mocks.Query{} + query.On("Iter").Return(iter) + + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) + services, err := s.storage.GetOperations("service-a") + if test.expErr == nil { + assert.NoError(t, err) + if test.schemaVersion == 0 { + // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` + assert.Equal(t, []string{""}, services) + } else { + assert.Equal(t, []string{}, services) + } + } else { + assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].TableName, test.expErr.Error())) + } + }) }) - } } diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index 5f60eeff361..95596731ca8 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -18,6 +18,7 @@ package spanstore import ( "context" "errors" + "fmt" "strings" "testing" "time" @@ -45,6 +46,9 @@ type spanReaderTest struct { func withSpanReader(fn func(r *spanReaderTest)) { session := &mocks.Session{} + query := &mocks.Query{} + session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) + query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) r := &spanReaderTest{ diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index e911d117bae..4d5ce7706c8 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -17,11 +17,13 @@ package spanstore import ( "errors" + "fmt" "strings" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/uber/jaeger-lib/metrics/metricstest" "go.uber.org/zap" @@ -42,6 +44,9 @@ type spanWriterTest struct { func withSpanWriter(writeCacheTTL time.Duration, fn func(w *spanWriterTest), options ...Option, ) { session := &mocks.Session{} + query := &mocks.Query{} + session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) + query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) w := &spanWriterTest{ From b9f7c2e0b47134286b0fa5a193edee982bf5c832 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Wed, 20 Nov 2019 16:39:10 -0500 Subject: [PATCH 02/12] Refactor schema versions Signed-off-by: Jun Guo --- .../cassandra/spanstore/operation_names.go | 152 +++++++------- .../spanstore/operation_names_test.go | 185 +++++++++--------- .../cassandra/spanstore/reader_test.go | 2 +- .../cassandra/spanstore/writer_test.go | 2 +- 4 files changed, 171 insertions(+), 170 deletions(-) diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index 8a2f993a693..5900e85fb4a 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -30,47 +30,66 @@ import ( ) const ( - // LatestVersion latest version of operation_names table schema, increase the version if your table schema changes require code change - LatestVersion = 1 - // TableQueryStmt the query statement used to check if a table exists or not - TableQueryStmt = "SELECT * from %s limit 1" + // latestVersion of operation_names table + // increase the version if your table schema changes require code change + latestVersion = "v2" + + // previous version of operation_names table + // if latest version does not work, will fail back to use previous version + previousVersion = "v1" + + // tableCheckStmt the query statement used to check if a table exists or not + tableCheckStmt = "SELECT * from %s limit 1" ) -type schemaMeta struct { - TableName string - InsertStmt string - QueryByKindStmt string - QueryStmt string +type tableMeta struct { + tableName string + insertStmt string + queryByKindStmt string + queryStmt string + createWriteQuery func(query cassandra.Query, service, kind, opName string) cassandra.Query + getOperations func(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) +} + +func (t *tableMeta) materialize() { + t.insertStmt = fmt.Sprintf(t.insertStmt, t.tableName) + t.queryByKindStmt = fmt.Sprintf(t.queryByKindStmt, t.tableName) + t.queryStmt = fmt.Sprintf(t.queryStmt, t.tableName) } -var schemas = []schemaMeta{ - { - TableName: "operation_names", - InsertStmt: "INSERT INTO %s(service_name, operation_name) VALUES (?, ?)", - QueryByKindStmt: "SELECT operation_name FROM %s WHERE service_name = ?", - QueryStmt: "SELECT operation_name FROM %s WHERE service_name = ?", +var schemas = map[string]*tableMeta{ + "v1": { + tableName: "operation_names", + insertStmt: "INSERT INTO %s(service_name, operation_name) VALUES (?, ?)", + queryByKindStmt: "SELECT operation_name FROM %s WHERE service_name = ?", + queryStmt: "SELECT operation_name FROM %s WHERE service_name = ?", + getOperations: getOperationsV1, + createWriteQuery: func(query cassandra.Query, service, kind, opName string) cassandra.Query { + return query.Bind(service, opName) + }, }, - { - TableName: "operation_names_v2", - InsertStmt: "INSERT INTO %s(service_name, span_kind, operation_name) VALUES (?, ?, ?)", - QueryByKindStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ? AND span_kind = ?", - QueryStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ?", + "v2": { + tableName: "operation_names_v2", + insertStmt: "INSERT INTO %s(service_name, span_kind, operation_name) VALUES (?, ?, ?)", + queryByKindStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ? AND span_kind = ?", + queryStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ?", + getOperations: getOperationsV2, + createWriteQuery: func(query cassandra.Query, service, kind, opName string) cassandra.Query { + return query.Bind(service, kind, opName) + }, }, } // OperationNamesStorage stores known operation names by service. type OperationNamesStorage struct { // CQL statements are public so that Cassandra2 storage can override them - SchemaVersion int - TableName string - InsertStmt string - QueryStmt string - QueryByKindStmt string - session cassandra.Session - writeCacheTTL time.Duration - metrics *casMetrics.Table - operationNames cache.Cache - logger *zap.Logger + schemaVersion string + table *tableMeta + session cassandra.Session + writeCacheTTL time.Duration + metrics *casMetrics.Table + operationNames cache.Cache + logger *zap.Logger } // NewOperationNamesStorage returns a new OperationNamesStorage @@ -81,22 +100,20 @@ func NewOperationNamesStorage( logger *zap.Logger, ) *OperationNamesStorage { - schemaVersion := LatestVersion - - if !tableExist(session, schemas[schemaVersion].TableName) { - schemaVersion = schemaVersion - 1 + schemaVersion := latestVersion + if !tableExist(session, schemas[schemaVersion].tableName) { + schemaVersion = previousVersion } + table := schemas[schemaVersion] + table.materialize() return &OperationNamesStorage{ - session: session, - TableName: schemas[schemaVersion].TableName, - SchemaVersion: schemaVersion, - InsertStmt: fmt.Sprintf(schemas[schemaVersion].InsertStmt, schemas[schemaVersion].TableName), - QueryByKindStmt: fmt.Sprintf(schemas[schemaVersion].QueryByKindStmt, schemas[schemaVersion].TableName), - QueryStmt: fmt.Sprintf(schemas[schemaVersion].QueryStmt, schemas[schemaVersion].TableName), - metrics: casMetrics.NewTable(metricsFactory, schemas[schemaVersion].TableName), - writeCacheTTL: writeCacheTTL, - logger: logger, + session: session, + schemaVersion: schemaVersion, + table: table, + metrics: casMetrics.NewTable(metricsFactory, schemas[schemaVersion].tableName), + writeCacheTTL: writeCacheTTL, + logger: logger, operationNames: cache.NewLRUWithOptions( 100000, &cache.Options{ @@ -106,27 +123,14 @@ func NewOperationNamesStorage( } } -func tableExist(session cassandra.Session, tableName string) bool { - query := session.Query(fmt.Sprintf(TableQueryStmt, tableName)) - err := query.Exec() - return err == nil -} - // Write saves Operation and Service name tuples func (s *OperationNamesStorage) Write(serviceName string, operationName string) error { var err error //TODO: take spanKind from args spanKind := "" - query := s.session.Query(s.InsertStmt) - if inCache := checkWriteCache(serviceName+"|"+spanKind+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { - var q cassandra.Query - switch s.SchemaVersion { - case 1: - q = query.Bind(serviceName, spanKind, operationName) - case 0: - q = query.Bind(serviceName, operationName) - } + if inCache := checkWriteCache(serviceName+"|"+spanKind+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { + q := s.table.createWriteQuery(s.session.Query(s.table.insertStmt), serviceName, spanKind, operationName) err2 := s.metrics.Exec(q, s.logger) if err2 != nil { err = err2 @@ -137,17 +141,9 @@ func (s *OperationNamesStorage) Write(serviceName string, operationName string) // GetOperations returns all operations for a specific service traced by Jaeger func (s *OperationNamesStorage) GetOperations(service string) ([]string, error) { - var operations []*spanstore.Operation - var err error - - switch s.SchemaVersion { - case 1: - operations, err = getOperationsV1(s, &spanstore.OperationQueryParameters{ - ServiceName: service, - }) - case 0: - operations, err = getOperationsV0(s, service) - } + operations, err := s.table.getOperations(s, &spanstore.OperationQueryParameters{ + ServiceName: service, + }) if err != nil { return nil, err @@ -159,8 +155,14 @@ func (s *OperationNamesStorage) GetOperations(service string) ([]string, error) return operationNames, err } -func getOperationsV0(s *OperationNamesStorage, service string) ([]*spanstore.Operation, error) { - iter := s.session.Query(s.QueryStmt, service).Iter() +func tableExist(session cassandra.Session, tableName string) bool { + query := session.Query(fmt.Sprintf(tableCheckStmt, tableName)) + err := query.Exec() + return err == nil +} + +func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + iter := s.session.Query(s.table.queryStmt, query.ServiceName).Iter() var operation string var operationNames []string @@ -181,14 +183,14 @@ func getOperationsV0(s *OperationNamesStorage, service string) ([]*spanstore.Ope return operations, nil } -func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func getOperationsV2(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { var casQuery cassandra.Query if query.SpanKind == "" { // Get operations for all spanKind - casQuery = s.session.Query(s.QueryStmt, query.ServiceName) + casQuery = s.session.Query(s.table.queryStmt, query.ServiceName) } else { // Get operations for given spanKind - casQuery = s.session.Query(s.QueryByKindStmt, query.ServiceName, query.SpanKind) + casQuery = s.session.Query(s.table.queryByKindStmt, query.ServiceName, query.SpanKind) } iter := casQuery.Iter() @@ -202,7 +204,7 @@ func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryPa }) } if err := iter.Close(); err != nil { - err = errors.Wrap(err, fmt.Sprintf("Error reading %s from storage", s.TableName)) + err = errors.Wrap(err, fmt.Sprintf("Error reading %s from storage", s.table.tableName)) return nil, err } return operations, nil diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 86c257cf789..e348b4a0a56 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -30,12 +30,6 @@ import ( "github.com/jaegertracing/jaeger/pkg/testutils" ) -type test struct { - ttl time.Duration - schemaVersion int - expErr error -} - type operationNameStorageTest struct { session *mocks.Session writeCacheTTL time.Duration @@ -45,13 +39,13 @@ type operationNameStorageTest struct { storage *OperationNamesStorage } -func withOperationNamesStorage(writeCacheTTL time.Duration, schemaVersion int, fn func(s *operationNameStorageTest)) { +func withOperationNamesStorage(writeCacheTTL time.Duration, schemaVersion string, fn func(s *operationNameStorageTest)) { session := &mocks.Session{} logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) query := &mocks.Query{} - session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) - if schemaVersion != LatestVersion { + session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) + if schemaVersion != latestVersion { query.On("Exec").Return(errors.New("new table does not exist")) } else { query.On("Exec").Return(nil) @@ -69,71 +63,73 @@ func withOperationNamesStorage(writeCacheTTL time.Duration, schemaVersion int, f } func TestOperationNamesStorageWrite(t *testing.T) { - for _, test := range []test{ - {0, 0, nil}, - {time.Minute, 0, nil}, - {0, 1, nil}, - {time.Minute, 1, nil}, + for _, test := range []struct { + name string + ttl time.Duration + schemaVersion string + }{ + {name: "test old schema with 0 ttl", ttl: 0, schemaVersion: previousVersion}, + {name: "test old schema with 1min ttl", ttl: time.Minute, schemaVersion: previousVersion}, + {name: "test new schema with 0 ttl", ttl: 0, schemaVersion: latestVersion}, + {name: "test new schema with 1min ttl", ttl: time.Minute, schemaVersion: latestVersion}, } { + fmt.Printf(test.name) writeCacheTTL := test.ttl // capture loop var - t.Run(fmt.Sprintf("test %#v", test), func(t *testing.T) { - withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { - var execError = errors.New("exec error") - query := &mocks.Query{} - query1 := &mocks.Query{} - query2 := &mocks.Query{} - - if test.schemaVersion == 0 { - query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) - query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) - } else { - query.On("Bind", []interface{}{"service-a", "", "Operation-b"}).Return(query1) - query.On("Bind", []interface{}{"service-c", "", "operation-d"}).Return(query2) - } - - query1.On("Exec").Return(nil) - query2.On("Exec").Return(execError) - query2.On("String").Return("select from " + schemas[test.schemaVersion].TableName) - - s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - - err := s.storage.Write("service-a", "Operation-b") - assert.NoError(t, err) - - err = s.storage.Write("service-c", "operation-d") - assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].TableName+"': exec error") - assert.Equal(t, map[string]string{ - "level": "error", - "msg": "Failed to exec query", - "query": "select from " + schemas[test.schemaVersion].TableName, - "error": "exec error", - }, s.logBuffer.JSONLine(0)) - - counts, _ := s.metricsFactory.Snapshot() - assert.Equal(t, map[string]int64{ - "attempts|table=" + schemas[test.schemaVersion].TableName: 2, "inserts|table=" + schemas[test.schemaVersion].TableName: 1, "errors|table=" + schemas[test.schemaVersion].TableName: 1, - }, counts, "after first two writes") - - // write again - err = s.storage.Write("service-a", "Operation-b") - assert.NoError(t, err) - - counts2, _ := s.metricsFactory.Snapshot() - expCounts := counts - if writeCacheTTL == 0 { - // without write cache, the second write must succeed - expCounts["attempts|table="+schemas[test.schemaVersion].TableName]++ - expCounts["inserts|table="+schemas[test.schemaVersion].TableName]++ - } - assert.Equal(t, expCounts, counts2) - }) + withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { + var execError = errors.New("exec error") + query := &mocks.Query{} + query1 := &mocks.Query{} + query2 := &mocks.Query{} + + if test.schemaVersion == previousVersion { + query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) + } else { + query.On("Bind", []interface{}{"service-a", "", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "", "operation-d"}).Return(query2) + } + + query1.On("Exec").Return(nil) + query2.On("Exec").Return(execError) + query2.On("String").Return("select from " + schemas[test.schemaVersion].tableName) + + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) + + err := s.storage.Write("service-a", "Operation-b") + assert.NoError(t, err) + + err = s.storage.Write("service-c", "operation-d") + assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") + assert.Equal(t, map[string]string{ + "level": "error", + "msg": "Failed to exec query", + "query": "select from " + schemas[test.schemaVersion].tableName, + "error": "exec error", + }, s.logBuffer.JSONLine(0)) + + counts, _ := s.metricsFactory.Snapshot() + assert.Equal(t, map[string]int64{ + "attempts|table=" + schemas[test.schemaVersion].tableName: 2, "inserts|table=" + schemas[test.schemaVersion].tableName: 1, "errors|table=" + schemas[test.schemaVersion].tableName: 1, + }, counts, "after first two writes") + + // write again + err = s.storage.Write("service-a", "Operation-b") + assert.NoError(t, err) + + counts2, _ := s.metricsFactory.Snapshot() + expCounts := counts + if writeCacheTTL == 0 { + // without write cache, the second write must succeed + expCounts["attempts|table="+schemas[test.schemaVersion].tableName]++ + expCounts["inserts|table="+schemas[test.schemaVersion].tableName]++ + } + assert.Equal(t, expCounts, counts2) }) } } func TestOperationNamesStorageGetServices(t *testing.T) { var scanError = errors.New("scan error") - var writeCacheTTL time.Duration var matched bool matchOnce := mock.MatchedBy(func(v []interface{}) bool { if matched { @@ -143,36 +139,39 @@ func TestOperationNamesStorageGetServices(t *testing.T) { return true }) matchEverything := mock.MatchedBy(func(v []interface{}) bool { return true }) - for _, test := range []test{ - {0, 0, nil}, - {0, 0, scanError}, - {0, 1, nil}, - {0, 1, scanError}, + for _, test := range []struct { + name string + schemaVersion string + expErr error + }{ + {name: "test old schema without error", schemaVersion: previousVersion, expErr: nil}, + {name: "test old schema with scan error", schemaVersion: previousVersion, expErr: scanError}, + {name: "test new schema without error", schemaVersion: latestVersion, expErr: nil}, + {name: "test new schema with scan error", schemaVersion: latestVersion, expErr: scanError}, } { - t.Run(fmt.Sprintf("test %#v", test), func(t *testing.T) { - withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { - iter := &mocks.Iterator{} - iter.On("Scan", matchOnce).Return(true) - iter.On("Scan", matchEverything).Return(false) // false to stop the loop - iter.On("Close").Return(test.expErr) - - query := &mocks.Query{} - query.On("Iter").Return(iter) - - s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - services, err := s.storage.GetOperations("service-a") - if test.expErr == nil { - assert.NoError(t, err) - if test.schemaVersion == 0 { - // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` - assert.Equal(t, []string{""}, services) - } else { - assert.Equal(t, []string{}, services) - } + fmt.Printf(test.name) + withOperationNamesStorage(0, test.schemaVersion, func(s *operationNameStorageTest) { + iter := &mocks.Iterator{} + iter.On("Scan", matchOnce).Return(true) + iter.On("Scan", matchEverything).Return(false) // false to stop the loop + iter.On("Close").Return(test.expErr) + + query := &mocks.Query{} + query.On("Iter").Return(iter) + + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) + services, err := s.storage.GetOperations("service-a") + if test.expErr == nil { + assert.NoError(t, err) + if test.schemaVersion == previousVersion { + // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` + assert.Equal(t, []string{""}, services) } else { - assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].TableName, test.expErr.Error())) + assert.Equal(t, []string{}, services) } - }) + } else { + assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].tableName, test.expErr.Error())) + } }) } diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index 95596731ca8..24e2af007cf 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -47,7 +47,7 @@ type spanReaderTest struct { func withSpanReader(fn func(r *spanReaderTest)) { session := &mocks.Session{} query := &mocks.Query{} - session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) + session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index 4d5ce7706c8..460125e42ac 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -45,7 +45,7 @@ func withSpanWriter(writeCacheTTL time.Duration, fn func(w *spanWriterTest), opt ) { session := &mocks.Session{} query := &mocks.Query{} - session.On("Query", fmt.Sprintf(TableQueryStmt, schemas[LatestVersion].TableName), mock.Anything).Return(query) + session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) From 6539d277f88611210373c3dfa468d9fe9b9ae223 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Thu, 21 Nov 2019 19:11:48 -0500 Subject: [PATCH 03/12] Using typed constant for schemaVersion Signed-off-by: Jun Guo --- .../cassandra/spanstore/operation_names.go | 27 ++- .../spanstore/operation_names_test.go | 176 +++++++++--------- 2 files changed, 105 insertions(+), 98 deletions(-) diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index 5900e85fb4a..71a8215c4ed 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -32,16 +32,18 @@ import ( const ( // latestVersion of operation_names table // increase the version if your table schema changes require code change - latestVersion = "v2" + latestVersion = schemaVersion("v2") // previous version of operation_names table // if latest version does not work, will fail back to use previous version - previousVersion = "v1" + previousVersion = schemaVersion("v1") // tableCheckStmt the query statement used to check if a table exists or not tableCheckStmt = "SELECT * from %s limit 1" ) +type schemaVersion string + type tableMeta struct { tableName string insertStmt string @@ -57,8 +59,8 @@ func (t *tableMeta) materialize() { t.queryStmt = fmt.Sprintf(t.queryStmt, t.tableName) } -var schemas = map[string]*tableMeta{ - "v1": { +var schemas = map[schemaVersion]*tableMeta{ + previousVersion: { tableName: "operation_names", insertStmt: "INSERT INTO %s(service_name, operation_name) VALUES (?, ?)", queryByKindStmt: "SELECT operation_name FROM %s WHERE service_name = ?", @@ -68,7 +70,7 @@ var schemas = map[string]*tableMeta{ return query.Bind(service, opName) }, }, - "v2": { + latestVersion: { tableName: "operation_names_v2", insertStmt: "INSERT INTO %s(service_name, span_kind, operation_name) VALUES (?, ?, ?)", queryByKindStmt: "SELECT span_kind, operation_name FROM %s WHERE service_name = ? AND span_kind = ?", @@ -83,7 +85,7 @@ var schemas = map[string]*tableMeta{ // OperationNamesStorage stores known operation names by service. type OperationNamesStorage struct { // CQL statements are public so that Cassandra2 storage can override them - schemaVersion string + schemaVersion schemaVersion table *tableMeta session cassandra.Session writeCacheTTL time.Duration @@ -148,6 +150,7 @@ func (s *OperationNamesStorage) GetOperations(service string) ([]string, error) if err != nil { return nil, err } + //TODO: return operations instead of list of string operationNames := make([]string, len(operations)) for idx, operation := range operations { operationNames[idx] = operation.Name @@ -165,21 +168,17 @@ func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryPa iter := s.session.Query(s.table.queryStmt, query.ServiceName).Iter() var operation string - var operationNames []string + var operations []*spanstore.Operation for iter.Scan(&operation) { - operationNames = append(operationNames, operation) + operations = append(operations, &spanstore.Operation{ + Name: operation, + }) } if err := iter.Close(); err != nil { err = errors.Wrap(err, "Error reading operation_names from storage") return nil, err } - operations := make([]*spanstore.Operation, len(operationNames)) - for idx, name := range operationNames { - operations[idx] = &spanstore.Operation{ - Name: name, - } - } return operations, nil } diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index e348b4a0a56..920831f4586 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -39,12 +39,16 @@ type operationNameStorageTest struct { storage *OperationNamesStorage } -func withOperationNamesStorage(writeCacheTTL time.Duration, schemaVersion string, fn func(s *operationNameStorageTest)) { +func withOperationNamesStorage(writeCacheTTL time.Duration, + schemaVersion schemaVersion, + fn func(s *operationNameStorageTest)) { + session := &mocks.Session{} logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) query := &mocks.Query{} - session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) + session.On("Query", + fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) if schemaVersion != latestVersion { query.On("Exec").Return(errors.New("new table does not exist")) } else { @@ -66,7 +70,7 @@ func TestOperationNamesStorageWrite(t *testing.T) { for _, test := range []struct { name string ttl time.Duration - schemaVersion string + schemaVersion schemaVersion }{ {name: "test old schema with 0 ttl", ttl: 0, schemaVersion: previousVersion}, {name: "test old schema with 1min ttl", ttl: time.Minute, schemaVersion: previousVersion}, @@ -74,74 +78,69 @@ func TestOperationNamesStorageWrite(t *testing.T) { {name: "test new schema with 1min ttl", ttl: time.Minute, schemaVersion: latestVersion}, } { fmt.Printf(test.name) - writeCacheTTL := test.ttl // capture loop var - withOperationNamesStorage(writeCacheTTL, test.schemaVersion, func(s *operationNameStorageTest) { - var execError = errors.New("exec error") - query := &mocks.Query{} - query1 := &mocks.Query{} - query2 := &mocks.Query{} - - if test.schemaVersion == previousVersion { - query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) - query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) - } else { - query.On("Bind", []interface{}{"service-a", "", "Operation-b"}).Return(query1) - query.On("Bind", []interface{}{"service-c", "", "operation-d"}).Return(query2) - } - - query1.On("Exec").Return(nil) - query2.On("Exec").Return(execError) - query2.On("String").Return("select from " + schemas[test.schemaVersion].tableName) - - s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - - err := s.storage.Write("service-a", "Operation-b") - assert.NoError(t, err) - - err = s.storage.Write("service-c", "operation-d") - assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") - assert.Equal(t, map[string]string{ - "level": "error", - "msg": "Failed to exec query", - "query": "select from " + schemas[test.schemaVersion].tableName, - "error": "exec error", - }, s.logBuffer.JSONLine(0)) - - counts, _ := s.metricsFactory.Snapshot() - assert.Equal(t, map[string]int64{ - "attempts|table=" + schemas[test.schemaVersion].tableName: 2, "inserts|table=" + schemas[test.schemaVersion].tableName: 1, "errors|table=" + schemas[test.schemaVersion].tableName: 1, - }, counts, "after first two writes") - - // write again - err = s.storage.Write("service-a", "Operation-b") - assert.NoError(t, err) - - counts2, _ := s.metricsFactory.Snapshot() - expCounts := counts - if writeCacheTTL == 0 { - // without write cache, the second write must succeed - expCounts["attempts|table="+schemas[test.schemaVersion].tableName]++ - expCounts["inserts|table="+schemas[test.schemaVersion].tableName]++ - } - assert.Equal(t, expCounts, counts2) + t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) { + withOperationNamesStorage(test.ttl, test.schemaVersion, func(s *operationNameStorageTest) { + var execError = errors.New("exec error") + query := &mocks.Query{} + query1 := &mocks.Query{} + query2 := &mocks.Query{} + + if test.schemaVersion == previousVersion { + query.On("Bind", []interface{}{"service-a", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "operation-d"}).Return(query2) + } else { + query.On("Bind", []interface{}{"service-a", "", "Operation-b"}).Return(query1) + query.On("Bind", []interface{}{"service-c", "", "operation-d"}).Return(query2) + } + + query1.On("Exec").Return(nil) + query2.On("Exec").Return(execError) + query2.On("String").Return("select from " + schemas[test.schemaVersion].tableName) + + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) + + err := s.storage.Write("service-a", "Operation-b") + assert.NoError(t, err) + + err = s.storage.Write("service-c", "operation-d") + assert.EqualError(t, err, + "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") + assert.Equal(t, map[string]string{ + "level": "error", + "msg": "Failed to exec query", + "query": "select from " + schemas[test.schemaVersion].tableName, + "error": "exec error", + }, s.logBuffer.JSONLine(0)) + + counts, _ := s.metricsFactory.Snapshot() + assert.Equal(t, map[string]int64{ + "attempts|table=" + schemas[test.schemaVersion].tableName: 2, + "inserts|table=" + schemas[test.schemaVersion].tableName: 1, + "errors|table=" + schemas[test.schemaVersion].tableName: 1, + }, counts, "after first two writes") + + // write again + err = s.storage.Write("service-a", "Operation-b") + assert.NoError(t, err) + + counts2, _ := s.metricsFactory.Snapshot() + expCounts := counts + if test.ttl == 0 { + // without write cache, the second write must succeed + expCounts["attempts|table="+schemas[test.schemaVersion].tableName]++ + expCounts["inserts|table="+schemas[test.schemaVersion].tableName]++ + } + assert.Equal(t, expCounts, counts2) + }) }) } } func TestOperationNamesStorageGetServices(t *testing.T) { var scanError = errors.New("scan error") - var matched bool - matchOnce := mock.MatchedBy(func(v []interface{}) bool { - if matched { - return false - } - matched = true - return true - }) - matchEverything := mock.MatchedBy(func(v []interface{}) bool { return true }) for _, test := range []struct { name string - schemaVersion string + schemaVersion schemaVersion expErr error }{ {name: "test old schema without error", schemaVersion: previousVersion, expErr: nil}, @@ -149,30 +148,39 @@ func TestOperationNamesStorageGetServices(t *testing.T) { {name: "test new schema without error", schemaVersion: latestVersion, expErr: nil}, {name: "test new schema with scan error", schemaVersion: latestVersion, expErr: scanError}, } { - fmt.Printf(test.name) - withOperationNamesStorage(0, test.schemaVersion, func(s *operationNameStorageTest) { - iter := &mocks.Iterator{} - iter.On("Scan", matchOnce).Return(true) - iter.On("Scan", matchEverything).Return(false) // false to stop the loop - iter.On("Close").Return(test.expErr) - - query := &mocks.Query{} - query.On("Iter").Return(iter) - - s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - services, err := s.storage.GetOperations("service-a") - if test.expErr == nil { - assert.NoError(t, err) - if test.schemaVersion == previousVersion { - // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` + t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) { + withOperationNamesStorage(0, test.schemaVersion, func(s *operationNameStorageTest) { + var matched bool + matchOnce := mock.MatchedBy(func(v []interface{}) bool { + if matched { + return false + } + matched = true + return true + }) + matchEverything := mock.MatchedBy(func(v []interface{}) bool { return true }) + + iter := &mocks.Iterator{} + iter.On("Scan", matchOnce).Return(true) + iter.On("Scan", matchEverything).Return(false) // false to stop the loop + iter.On("Close").Return(test.expErr) + + query := &mocks.Query{} + query.On("Iter").Return(iter) + + s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) + services, err := s.storage.GetOperations("service-a") + if test.expErr == nil { + assert.NoError(t, err) + // expect empty string because mock iter.Scan(&placeholder) does not write to `placeholder` assert.Equal(t, []string{""}, services) } else { - assert.Equal(t, []string{}, services) + assert.EqualError(t, err, + fmt.Sprintf("Error reading %s from storage: %s", + schemas[test.schemaVersion].tableName, + test.expErr.Error())) } - } else { - assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].tableName, test.expErr.Error())) - } + }) }) } - } From 7e1880667e8d7bbb8711803fb7424fe1335c96b2 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Fri, 22 Nov 2019 14:11:14 -0500 Subject: [PATCH 04/12] Fix travis build error Signed-off-by: Jun Guo --- plugin/storage/cassandra/spanstore/operation_names_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 920831f4586..91b0e812e2e 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -77,8 +77,7 @@ func TestOperationNamesStorageWrite(t *testing.T) { {name: "test new schema with 0 ttl", ttl: 0, schemaVersion: latestVersion}, {name: "test new schema with 1min ttl", ttl: time.Minute, schemaVersion: latestVersion}, } { - fmt.Printf(test.name) - t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { withOperationNamesStorage(test.ttl, test.schemaVersion, func(s *operationNameStorageTest) { var execError = errors.New("exec error") query := &mocks.Query{} @@ -148,7 +147,7 @@ func TestOperationNamesStorageGetServices(t *testing.T) { {name: "test new schema without error", schemaVersion: latestVersion, expErr: nil}, {name: "test new schema with scan error", schemaVersion: latestVersion, expErr: scanError}, } { - t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { withOperationNamesStorage(0, test.schemaVersion, func(s *operationNameStorageTest) { var matched bool matchOnce := mock.MatchedBy(func(v []interface{}) bool { From e199801499efd285bc02dae1a322f90360979a10 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Wed, 20 Nov 2019 19:07:15 -0500 Subject: [PATCH 05/12] Update storage api to support query operations by spanKind Signed-off-by: Jun Guo --- cmd/query/app/grpc_handler_test.go | 11 +- cmd/query/app/http_handler_test.go | 33 +- cmd/query/app/querysvc/query_service.go | 13 +- cmd/query/app/querysvc/query_service_test.go | 9 +- plugin/storage/badger/spanstore/cache.go | 17 +- .../badger/spanstore/read_write_test.go | 2 +- plugin/storage/badger/spanstore/reader.go | 4 +- .../cassandra/spanstore/operation_names.go | 21 +- .../spanstore/operation_names_test.go | 30 +- plugin/storage/cassandra/spanstore/reader.go | 6 +- .../cassandra/spanstore/reader_test.go | 13 +- plugin/storage/cassandra/spanstore/writer.go | 9 +- .../cassandra/spanstore/writer_test.go | 16 +- plugin/storage/es/spanstore/reader.go | 17 +- plugin/storage/es/spanstore/reader_test.go | 21 +- .../es/spanstore/service_operation_test.go | 3 +- plugin/storage/grpc/proto/storage.proto | 8 +- plugin/storage/grpc/shared/grpc_client.go | 14 +- .../storage/grpc/shared/grpc_client_test.go | 6 +- plugin/storage/grpc/shared/grpc_server.go | 11 +- .../storage/grpc/shared/grpc_server_test.go | 6 +- .../storage/integration/integration_test.go | 7 +- plugin/storage/integration/kafka_test.go | 2 +- plugin/storage/memory/memory.go | 30 +- plugin/storage/memory/memory_test.go | 29 +- proto-gen/storage_v1/storage.pb.go | 452 ++++++++++++++---- storage/spanstore/interface.go | 2 +- storage/spanstore/metrics/decorator.go | 4 +- storage/spanstore/metrics/decorator_test.go | 10 +- storage/spanstore/mocks/Reader.go | 28 +- 30 files changed, 617 insertions(+), 217 deletions(-) diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index 63a2bd3d11c..a3ce84f8f08 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -415,20 +415,23 @@ func TestGetServicesFailureGRPC(t *testing.T) { func TestGetOperationsSuccessGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { - expectedOperations := []string{"", "get"} - server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperations, nil).Once() + expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() res, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ Service: "abc/trifle", }) assert.NoError(t, err) - assert.Equal(t, expectedOperations, res.Operations) + assert.Equal(t, len(expectedOperations), len(res.Operations)) + for idx, actualOp := range res.Operations { + assert.Equal(t, expectedOperations[idx].Name, actualOp) + } }) } func TestGetOperationsFailureGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { - server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "trifle").Return(nil, errStorageGRPC).Once() + server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "trifle"}).Return(nil, errStorageGRPC).Once() _, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ Service: "trifle", diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index 444106636ec..42a0198f9ee 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -483,17 +483,16 @@ func TestGetServicesStorageFailure(t *testing.T) { func TestGetOperationsSuccess(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() - expectedOperations := []string{"", "get"} - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperations, nil).Once() + expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() var response structuredResponse err := getJSON(server.URL+"/api/operations?service=abc%2Ftrifle", &response) assert.NoError(t, err) - actualOperations := make([]string, len(expectedOperations)) for i, s := range response.Data.([]interface{}) { - actualOperations[i] = s.(string) + assert.Equal(t, expectedOperations[i].Name, s.(string)) } - assert.Equal(t, expectedOperations, actualOperations) + } func TestGetOperationsNoServiceName(t *testing.T) { @@ -506,9 +505,12 @@ func TestGetOperationsNoServiceName(t *testing.T) { } func TestGetOperationsStorageFailure(t *testing.T) { - server, reaMock, _ := initializeTestServer() + server, readMock, _ := initializeTestServer() defer server.Close() - reaMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "trifle").Return(nil, errStorage).Once() + readMock.On( + "GetOperations", + mock.AnythingOfType("*context.valueCtx"), + mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() var response structuredResponse err := getJSON(server.URL+"/api/operations?service=trifle", &response) @@ -518,8 +520,13 @@ func TestGetOperationsStorageFailure(t *testing.T) { func TestGetOperationsLegacySuccess(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() - expectedOperations := []string{"", "get"} - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperations, nil).Once() + expectedOperationNames := []string{"", "get"} + expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperationNames, nil).Once() + readMock.On( + "GetOperations", + mock.AnythingOfType("*context.valueCtx"), + mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() var response structuredResponse err := getJSON(server.URL+"/api/services/abc%2Ftrifle/operations", &response) @@ -528,14 +535,16 @@ func TestGetOperationsLegacySuccess(t *testing.T) { for i, s := range response.Data.([]interface{}) { actualOperations[i] = s.(string) } - assert.Equal(t, expectedOperations, actualOperations) + assert.Equal(t, expectedOperationNames, actualOperations) } func TestGetOperationsLegacyStorageFailure(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "trifle").Return(nil, errStorage).Once() - + readMock.On( + "GetOperations", + mock.AnythingOfType("*context.valueCtx"), + mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() var response structuredResponse err := getJSON(server.URL+"/api/services/trifle/operations", &response) assert.Error(t, err) diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index 05c38647cf7..ddc34c295ed 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -80,7 +80,18 @@ func (qs QueryService) GetServices(ctx context.Context) ([]string, error) { // GetOperations is the queryService implementation of spanstore.Reader.GetOperations func (qs QueryService) GetOperations(ctx context.Context, service string) ([]string, error) { - return qs.spanReader.GetOperations(ctx, service) + operations, err := qs.spanReader.GetOperations(ctx, &spanstore.OperationQueryParameters{ + ServiceName: service, + }) + if err != nil { + return nil, err + } + + names := make([]string, len(operations)) + for idx, operation := range operations { + names[idx] = operation.Name + } + return names, err } // FindTraces is the queryService implementation of spanstore.Reader.FindTraces diff --git a/cmd/query/app/querysvc/query_service_test.go b/cmd/query/app/querysvc/query_service_test.go index 05a84810aa4..fdd0c742f6c 100644 --- a/cmd/query/app/querysvc/query_service_test.go +++ b/cmd/query/app/querysvc/query_service_test.go @@ -147,14 +147,17 @@ func TestGetServices(t *testing.T) { // Test QueryService.GetOperations() for success. func TestGetOperations(t *testing.T) { qs, readMock, _ := initializeTestService() - expectedOperations := []string{"", "get"} - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperations, nil).Once() + expectedOperationNames := []string{"", "get"} + expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + readMock.On("GetOperations", + mock.AnythingOfType("*context.valueCtx"), + mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() type contextKey string ctx := context.Background() actualOperations, err := qs.GetOperations(context.WithValue(ctx, contextKey("foo"), "bar"), "abc/trifle") assert.NoError(t, err) - assert.Equal(t, expectedOperations, actualOperations) + assert.Equal(t, expectedOperationNames, actualOperations) } // Test QueryService.FindTraces() for success. diff --git a/plugin/storage/badger/spanstore/cache.go b/plugin/storage/badger/spanstore/cache.go index 36f1bb6d044..9aac7c6d944 100644 --- a/plugin/storage/badger/spanstore/cache.go +++ b/plugin/storage/badger/spanstore/cache.go @@ -20,6 +20,8 @@ import ( "time" "github.com/dgraph-io/badger" + + "github.com/jaegertracing/jaeger/storage/spanstore" ) // CacheStore saves expensive calculations from the K/V store @@ -125,8 +127,8 @@ func (c *CacheStore) Update(service, operation string, expireTime uint64) { c.cacheLock.Unlock() } -// GetOperations returns all operations for a specific service traced by Jaeger -func (c *CacheStore) GetOperations(service string) ([]string, error) { +// GetOperations returns all operations for a specific service & spanKind traced by Jaeger +func (c *CacheStore) GetOperations(service string) ([]*spanstore.Operation, error) { operations := make([]string, 0, len(c.services)) t := uint64(time.Now().Unix()) c.cacheLock.Lock() @@ -137,7 +139,7 @@ func (c *CacheStore) GetOperations(service string) ([]string, error) { // Expired, remove delete(c.services, service) delete(c.operations, service) - return operations, nil // empty slice rather than nil + return []*spanstore.Operation{}, nil // empty slice rather than nil } for o, e := range c.operations[service] { if e > t { @@ -150,7 +152,14 @@ func (c *CacheStore) GetOperations(service string) ([]string, error) { sort.Strings(operations) - return operations, nil + //TODO: return the operations with actual spanKind + result := make([]*spanstore.Operation, 0, len(operations)) + for _, op := range operations { + result = append(result, &spanstore.Operation{ + Name: op, + }) + } + return result, nil } // GetServices returns all services traced by Jaeger diff --git a/plugin/storage/badger/spanstore/read_write_test.go b/plugin/storage/badger/spanstore/read_write_test.go index d6422edc6ef..922b3fbd6e9 100644 --- a/plugin/storage/badger/spanstore/read_write_test.go +++ b/plugin/storage/badger/spanstore/read_write_test.go @@ -331,7 +331,7 @@ func TestMenuSeeks(t *testing.T) { } } - operations, err := sr.GetOperations(context.Background(), "service-1") + operations, err := sr.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-1", SpanKind: ""}) assert.NoError(t, err) serviceList, err := sr.GetServices(context.Background()) diff --git a/plugin/storage/badger/spanstore/reader.go b/plugin/storage/badger/spanstore/reader.go index a329e98e6f3..ec8629dde22 100644 --- a/plugin/storage/badger/spanstore/reader.go +++ b/plugin/storage/badger/spanstore/reader.go @@ -237,8 +237,8 @@ func (r *TraceReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations fetches operations in the service and empty slice if service does not exists -func (r *TraceReader) GetOperations(ctx context.Context, service string) ([]string, error) { - return r.cache.GetOperations(service) +func (r *TraceReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + return r.cache.GetOperations(query.ServiceName) } // setQueryDefaults alters the query with defaults if certain parameters are not set diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index 71a8215c4ed..f222bc86510 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -126,10 +126,8 @@ func NewOperationNamesStorage( } // Write saves Operation and Service name tuples -func (s *OperationNamesStorage) Write(serviceName string, operationName string) error { +func (s *OperationNamesStorage) Write(serviceName, operationName, spanKind string) error { var err error - //TODO: take spanKind from args - spanKind := "" if inCache := checkWriteCache(serviceName+"|"+spanKind+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { q := s.table.createWriteQuery(s.session.Query(s.table.insertStmt), serviceName, spanKind, operationName) @@ -142,20 +140,11 @@ func (s *OperationNamesStorage) Write(serviceName string, operationName string) } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *OperationNamesStorage) GetOperations(service string) ([]string, error) { - operations, err := s.table.getOperations(s, &spanstore.OperationQueryParameters{ - ServiceName: service, +func (s *OperationNamesStorage) GetOperations(query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + return s.table.getOperations(s, &spanstore.OperationQueryParameters{ + ServiceName: query.ServiceName, + SpanKind: query.SpanKind, }) - - if err != nil { - return nil, err - } - //TODO: return operations instead of list of string - operationNames := make([]string, len(operations)) - for idx, operation := range operations { - operationNames[idx] = operation.Name - } - return operationNames, err } func tableExist(session cassandra.Session, tableName string) bool { diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 91b0e812e2e..b005512b276 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -28,6 +28,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/cassandra/mocks" "github.com/jaegertracing/jaeger/pkg/testutils" + "github.com/jaegertracing/jaeger/storage/spanstore" ) type operationNameStorageTest struct { @@ -98,10 +99,10 @@ func TestOperationNamesStorageWrite(t *testing.T) { s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - err := s.storage.Write("service-a", "Operation-b") + err := s.storage.Write("service-a", "Operation-b", "") assert.NoError(t, err) - err = s.storage.Write("service-c", "operation-d") + err = s.storage.Write("service-c", "operation-d", "") assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") assert.Equal(t, map[string]string{ @@ -110,6 +111,14 @@ func TestOperationNamesStorageWrite(t *testing.T) { "query": "select from " + schemas[test.schemaVersion].tableName, "error": "exec error", }, s.logBuffer.JSONLine(0)) + err = s.storage.Write("service-c", "operation-d", "") + assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") + assert.Equal(t, map[string]string{ + "level": "error", + "msg": "Failed to exec query", + "query": "select from " + schemas[test.schemaVersion].tableName, + "error": "exec error", + }, s.logBuffer.JSONLine(0)) counts, _ := s.metricsFactory.Snapshot() assert.Equal(t, map[string]int64{ @@ -118,9 +127,9 @@ func TestOperationNamesStorageWrite(t *testing.T) { "errors|table=" + schemas[test.schemaVersion].tableName: 1, }, counts, "after first two writes") - // write again - err = s.storage.Write("service-a", "Operation-b") - assert.NoError(t, err) + // write again + err = s.storage.Write("service-a", "Operation-b", "") + assert.NoError(t, err) counts2, _ := s.metricsFactory.Snapshot() expCounts := counts @@ -168,16 +177,13 @@ func TestOperationNamesStorageGetServices(t *testing.T) { query.On("Iter").Return(iter) s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - services, err := s.storage.GetOperations("service-a") + services, err := s.storage.GetOperations(&spanstore.OperationQueryParameters{ServiceName: "service-a"}) if test.expErr == nil { assert.NoError(t, err) - // expect empty string because mock iter.Scan(&placeholder) does not write to `placeholder` - assert.Equal(t, []string{""}, services) + // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` + assert.Equal(t, []*spanstore.Operation{{}}, services) } else { - assert.EqualError(t, err, - fmt.Sprintf("Error reading %s from storage: %s", - schemas[test.schemaVersion].tableName, - test.expErr.Error())) + assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].tableName, test.expErr.Error())) } }) }) diff --git a/plugin/storage/cassandra/spanstore/reader.go b/plugin/storage/cassandra/spanstore/reader.go index f89026d480e..98dea522229 100644 --- a/plugin/storage/cassandra/spanstore/reader.go +++ b/plugin/storage/cassandra/spanstore/reader.go @@ -91,7 +91,7 @@ var ( type serviceNamesReader func() ([]string, error) -type operationNamesReader func(service string) ([]string, error) +type operationNamesReader func(query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) type spanReaderMetrics struct { readTraces *casMetrics.Table @@ -143,8 +143,8 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, service string) ([]string, error) { - return s.operationNamesReader(service) +func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + return s.operationNamesReader(query) } func (s *SpanReader) readTrace(ctx context.Context, traceID dbmodel.TraceID) (*model.Trace, error) { diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index 24e2af007cf..90c1f0d2439 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -73,10 +73,17 @@ func TestSpanReaderGetServices(t *testing.T) { func TestSpanReaderGetOperations(t *testing.T) { withSpanReader(func(r *spanReaderTest) { - r.reader.operationNamesReader = func(string) ([]string, error) { return []string{"operation-a"}, nil } - s, err := r.reader.GetOperations(context.Background(), "service-x") + r.reader.operationNamesReader = func(parameters *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + return []*spanstore.Operation{ + { + Name: "operation-a", + SpanKind: "server", + }, + }, nil + } + s, err := r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) assert.NoError(t, err) - assert.Equal(t, []string{"operation-a"}, s) + assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) }) } diff --git a/plugin/storage/cassandra/spanstore/writer.go b/plugin/storage/cassandra/spanstore/writer.go index 712ad53ba3d..3ea10e75482 100644 --- a/plugin/storage/cassandra/spanstore/writer.go +++ b/plugin/storage/cassandra/spanstore/writer.go @@ -73,7 +73,7 @@ const ( type storageMode uint8 type serviceNamesWriter func(serviceName string) error -type operationNamesWriter func(serviceName, operationName string) error +type operationNamesWriter func(serviceName, operationName, spanKind string) error type spanWriterMetrics struct { traces *casMetrics.Table @@ -172,7 +172,8 @@ func (s *SpanWriter) writeSpan(span *model.Span, ds *dbmodel.Span) error { } func (s *SpanWriter) writeIndexes(span *model.Span, ds *dbmodel.Span) error { - if err := s.saveServiceNameAndOperationName(ds.ServiceName, ds.OperationName); err != nil { + spanKind, _ := span.GetSpanKind() + if err := s.saveServiceNameAndOperationName(ds.ServiceName, ds.OperationName, spanKind); err != nil { // should this be a soft failure? return s.logError(ds, err, "Failed to insert service name and operation name", s.logger) } @@ -274,9 +275,9 @@ func (s *SpanWriter) logError(span *dbmodel.Span, err error, msg string, logger return errors.Wrap(err, msg) } -func (s *SpanWriter) saveServiceNameAndOperationName(serviceName, operationName string) error { +func (s *SpanWriter) saveServiceNameAndOperationName(serviceName, operationName, spanKind string) error { if err := s.serviceNamesWriter(serviceName); err != nil { return err } - return s.operationNamesWriter(serviceName, operationName) + return s.operationNamesWriter(serviceName, operationName, spanKind) } diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index 460125e42ac..58c954e7855 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -198,7 +198,7 @@ func TestSpanWriter(t *testing.T) { w.session.On("Query", stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) w.writer.serviceNamesWriter = func(serviceName string) error { return testCase.serviceNameError } - w.writer.operationNamesWriter = func(serviceName, operationName string) error { return testCase.serviceNameError } + w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return testCase.serviceNameError } err := w.writer.WriteSpan(span) if testCase.expectedError == "" { @@ -226,16 +226,16 @@ func TestSpanWriterSaveServiceNameAndOperationName(t *testing.T) { }{ { serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(serviceName, operationName string) error { return nil }, + operationNamesWriter: func(serviceName, operationName, spanKind string) error { return nil }, }, { serviceNamesWriter: func(serviceName string) error { return expectedErr }, - operationNamesWriter: func(serviceName, operationName string) error { return nil }, + operationNamesWriter: func(serviceName, operationName, spanKind string) error { return nil }, expectedError: "some error", }, { serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(serviceName, operationName string) error { return expectedErr }, + operationNamesWriter: func(serviceName, operationName, spanKind string) error { return expectedErr }, expectedError: "some error", }, } @@ -244,7 +244,7 @@ func TestSpanWriterSaveServiceNameAndOperationName(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = testCase.serviceNamesWriter w.writer.operationNamesWriter = testCase.operationNamesWriter - err := w.writer.saveServiceNameAndOperationName("service", "operation") + err := w.writer.saveServiceNameAndOperationName("service", "operation", "") if testCase.expectedError == "" { assert.NoError(t, err) } else { @@ -285,7 +285,7 @@ func TestStorageMode_IndexOnly(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName string) error { return nil } + w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ @@ -328,7 +328,7 @@ func TestStorageMode_IndexOnly_WithFilter(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.indexFilter = filterEverything w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName string) error { return nil } + w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ @@ -348,7 +348,7 @@ func TestStorageMode_IndexOnly_FirehoseSpan(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName string) error { return nil } + w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ diff --git a/plugin/storage/es/spanstore/reader.go b/plugin/storage/es/spanstore/reader.go index 1303155c551..893151c4005 100644 --- a/plugin/storage/es/spanstore/reader.go +++ b/plugin/storage/es/spanstore/reader.go @@ -245,12 +245,25 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, service string) ([]string, error) { +func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { span, ctx := opentracing.StartSpanFromContext(ctx, "GetOperations") defer span.Finish() currentTime := time.Now() jaegerIndices := s.timeRangeIndices(s.serviceIndexPrefix, currentTime.Add(-s.maxSpanAge), currentTime) - return s.serviceOperationStorage.getOperations(ctx, jaegerIndices, service) + operations, err := s.serviceOperationStorage.getOperations(ctx, jaegerIndices, query.ServiceName) + if err != nil { + return nil, err + } + + //TODO: return the operations with actual span kind that meet requirement + var result []*spanstore.Operation + for _, operation := range operations { + result = append(result, &spanstore.Operation{ + Name: operation, + SpanKind: "", + }) + } + return result, err } func bucketToStringArray(buckets []*elastic.AggregationBucketKeyItem) ([]string, error) { diff --git a/plugin/storage/es/spanstore/reader_test.go b/plugin/storage/es/spanstore/reader_test.go index 7f12d94cd87..9f352f05386 100644 --- a/plugin/storage/es/spanstore/reader_test.go +++ b/plugin/storage/es/spanstore/reader_test.go @@ -488,12 +488,11 @@ func testGet(typ string, t *testing.T) { searchResult *elastic.SearchResult searchError error expectedError string - expectedOutput []string + expectedOutput interface{} }{ { - caption: typ + " full behavior", - searchResult: &elastic.SearchResult{Aggregations: elastic.Aggregations(goodAggregations)}, - expectedOutput: []string{"123"}, + caption: typ + " full behavior", + searchResult: &elastic.SearchResult{Aggregations: elastic.Aggregations(goodAggregations)}, }, { caption: typ + " search error", @@ -506,6 +505,16 @@ func testGet(typ string, t *testing.T) { expectedError: "Could not find aggregation of " + typ, }, } + if typ == operationsAggregation { + testCases[0].expectedOutput = []*spanstore.Operation{ + { + Name: "123", + SpanKind: "", + }, + } + } else { + testCases[0].expectedOutput = []string{"123"} + } for _, tc := range testCases { testCase := tc t.Run(testCase.caption, func(t *testing.T) { @@ -525,11 +534,11 @@ func testGet(typ string, t *testing.T) { } } -func returnSearchFunc(typ string, r *spanReaderTest) ([]string, error) { +func returnSearchFunc(typ string, r *spanReaderTest) (interface{}, error) { if typ == servicesAggregation { return r.reader.GetServices(context.Background()) } else if typ == operationsAggregation { - return r.reader.GetOperations(context.Background(), "someService") + return r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "someService", SpanKind: ""}) } else if typ == traceIDAggregation { return r.reader.findTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) } diff --git a/plugin/storage/es/spanstore/service_operation_test.go b/plugin/storage/es/spanstore/service_operation_test.go index 6ebbf194502..258e5a38597 100644 --- a/plugin/storage/es/spanstore/service_operation_test.go +++ b/plugin/storage/es/spanstore/service_operation_test.go @@ -26,6 +26,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/es/mocks" "github.com/jaegertracing/jaeger/plugin/storage/es/spanstore/dbmodel" + "github.com/jaegertracing/jaeger/storage/spanstore" ) func TestWriteService(t *testing.T) { @@ -121,7 +122,7 @@ func TestSpanReader_GetOperationsEmptyIndex(t *testing.T) { Return(&elastic.MultiSearchResult{ Responses: []*elastic.SearchResult{}, }, nil) - services, err := r.reader.GetOperations(context.Background(), "foo") + services, err := r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "foo", SpanKind: ""}) require.NoError(t, err) assert.Empty(t, services) }) diff --git a/plugin/storage/grpc/proto/storage.proto b/plugin/storage/grpc/proto/storage.proto index 0c347883dcf..8a8ca57057a 100644 --- a/plugin/storage/grpc/proto/storage.proto +++ b/plugin/storage/grpc/proto/storage.proto @@ -76,10 +76,16 @@ message GetServicesResponse { message GetOperationsRequest { string service = 1; + string span_kind = 2; +} + +message Operation { + string name = 1; + string span_kind = 2; } message GetOperationsResponse { - repeated string operations = 1; + repeated Operation operations = 1; } message TraceQueryParameters { diff --git a/plugin/storage/grpc/shared/grpc_client.go b/plugin/storage/grpc/shared/grpc_client.go index 89fe9e9dc86..2cb73f6923d 100644 --- a/plugin/storage/grpc/shared/grpc_client.go +++ b/plugin/storage/grpc/shared/grpc_client.go @@ -104,15 +104,23 @@ func (c *grpcClient) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (c *grpcClient) GetOperations(ctx context.Context, service string) ([]string, error) { +func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { resp, err := c.readerClient.GetOperations(upgradeContextWithBearerToken(ctx), &storage_v1.GetOperationsRequest{ - Service: service, + Service: query.ServiceName, + SpanKind: query.SpanKind, }) if err != nil { return nil, errors.Wrap(err, "plugin error") } - return resp.Operations, nil + operations := make([]*spanstore.Operation, len(resp.Operations)) + for idx, operation := range resp.Operations { + operations[idx] = &spanstore.Operation{ + Name: operation.Name, + SpanKind: operation.SpanKind, + } + } + return operations, nil } // FindTraces retrieves traces that match the traceQuery diff --git a/plugin/storage/grpc/shared/grpc_client_test.go b/plugin/storage/grpc/shared/grpc_client_test.go index 6adacf3e27c..0ad47c6cb85 100644 --- a/plugin/storage/grpc/shared/grpc_client_test.go +++ b/plugin/storage/grpc/shared/grpc_client_test.go @@ -124,12 +124,12 @@ func TestGRPCClientGetOperations(t *testing.T) { r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ Service: "service-a", }).Return(&storage_v1.GetOperationsResponse{ - Operations: []string{"operation-a"}, + Operations: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}, }, nil) - s, err := r.client.GetOperations(context.Background(), "service-a") + s, err := r.client.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-a"}) assert.NoError(t, err) - assert.Equal(t, []string{"operation-a"}, s) + assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, s) }) } diff --git a/plugin/storage/grpc/shared/grpc_server.go b/plugin/storage/grpc/shared/grpc_server.go index 1db0ee1aa28..21faf85329c 100644 --- a/plugin/storage/grpc/shared/grpc_server.go +++ b/plugin/storage/grpc/shared/grpc_server.go @@ -79,12 +79,19 @@ func (s *grpcServer) GetServices(ctx context.Context, r *storage_v1.GetServicesR // GetOperations returns the operations of a given service func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperationsRequest) (*storage_v1.GetOperationsResponse, error) { - operations, err := s.Impl.SpanReader().GetOperations(ctx, r.Service) + operations, err := s.Impl.SpanReader().GetOperations(ctx, &spanstore.OperationQueryParameters{ServiceName: r.Service, SpanKind: r.SpanKind}) if err != nil { return nil, err } + grpcOperation := make([]*storage_v1.Operation, len(operations)) + for idx, operation := range operations { + grpcOperation[idx] = &storage_v1.Operation{ + Name: operation.Name, + SpanKind: operation.SpanKind, + } + } return &storage_v1.GetOperationsResponse{ - Operations: operations, + Operations: grpcOperation, }, nil } diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index 01f4f2d23e2..6515d69e4f4 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -87,14 +87,14 @@ func TestGRPCServerGetServices(t *testing.T) { func TestGRPCServerGetOperations(t *testing.T) { withGRPCServer(func(r *grpcServerTest) { - r.impl.spanReader.On("GetOperations", mock.Anything, "service-a"). - Return([]string{"operation-a"}, nil) + r.impl.spanReader.On("GetOperations", mock.Anything, &spanstore.OperationQueryParameters{ServiceName: "service-a"}). + Return([]*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, nil) s, err := r.server.GetOperations(context.Background(), &storage_v1.GetOperationsRequest{ Service: "service-a", }) assert.NoError(t, err) - assert.Equal(t, &storage_v1.GetOperationsResponse{Operations: []string{"operation-a"}}, s) + assert.Equal(t, &storage_v1.GetOperationsResponse{Operations: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}}, s) }) } diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index 147f01ef0f0..ae2fdb58b73 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -149,14 +149,15 @@ func (s *StorageIntegration) testGetLargeSpan(t *testing.T) { func (s *StorageIntegration) testGetOperations(t *testing.T) { defer s.cleanUp(t) - expected := []string{"example-operation-1", "example-operation-3", "example-operation-4"} + expected := []*spanstore.Operation{ + {Name: "example-operation-1", SpanKind: ""}, {Name: "example-operation-3", SpanKind: ""}, {Name: "example-operation-4", SpanKind: ""}} s.loadParseAndWriteExampleTrace(t) s.refresh(t) - var actual []string + var actual []*spanstore.Operation found := s.waitForCondition(t, func(t *testing.T) bool { var err error - actual, err = s.SpanReader.GetOperations(context.Background(), "example-service-1") + actual, err = s.SpanReader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "example-service-1", SpanKind: ""}) require.NoError(t, err) return assert.ObjectsAreEqualValues(expected, actual) }) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index c0ec5f3b757..3acde074848 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -119,7 +119,7 @@ func (r *ingester) GetServices(ctx context.Context) ([]string, error) { return nil, nil } -func (r *ingester) GetOperations(ctx context.Context, service string) ([]string, error) { +func (r *ingester) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { return nil, nil } diff --git a/plugin/storage/memory/memory.go b/plugin/storage/memory/memory.go index d4aaa4c98da..0356c64e8b9 100644 --- a/plugin/storage/memory/memory.go +++ b/plugin/storage/memory/memory.go @@ -34,7 +34,7 @@ type Store struct { ids []*model.TraceID traces map[model.TraceID]*model.Trace services map[string]struct{} - operations map[string]map[string]struct{} + operations map[string]map[string]map[string]struct{} deduper adjuster.Adjuster config config.Configuration index int @@ -51,7 +51,7 @@ func WithConfiguration(configuration config.Configuration) *Store { ids: make([]*model.TraceID, configuration.MaxTraces), traces: map[model.TraceID]*model.Trace{}, services: map[string]struct{}{}, - operations: map[string]map[string]struct{}{}, + operations: map[string]map[string]map[string]struct{}{}, deduper: adjuster.SpanIDDeduper(), config: configuration, } @@ -118,9 +118,14 @@ func (m *Store) WriteSpan(span *model.Span) error { m.Lock() defer m.Unlock() if _, ok := m.operations[span.Process.ServiceName]; !ok { - m.operations[span.Process.ServiceName] = map[string]struct{}{} + m.operations[span.Process.ServiceName] = map[string]map[string]struct{}{} } - m.operations[span.Process.ServiceName][span.OperationName] = struct{}{} + if _, ok := m.operations[span.Process.ServiceName][span.OperationName]; !ok { + m.operations[span.Process.ServiceName][span.OperationName] = map[string]struct{}{} + } + + spanKind, _ := span.GetSpanKind() + m.operations[span.Process.ServiceName][span.OperationName][spanKind] = struct{}{} m.services[span.Process.ServiceName] = struct{}{} if _, ok := m.traces[span.TraceID]; !ok { m.traces[span.TraceID] = &model.Trace{} @@ -177,13 +182,20 @@ func (m *Store) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (m *Store) GetOperations(ctx context.Context, service string) ([]string, error) { +func (m *Store) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { m.RLock() defer m.RUnlock() - var retMe []string - if operations, ok := m.operations[service]; ok { - for ops := range operations { - retMe = append(retMe, ops) + var retMe []*spanstore.Operation + if operations, ok := m.operations[query.ServiceName]; ok { + for operationName, kinds := range operations { + for kind := range kinds { + if query.SpanKind == "" || query.SpanKind == kind { + retMe = append(retMe, &spanstore.Operation{ + Name: operationName, + SpanKind: kind, + }) + } + } } } return retMe, nil diff --git a/plugin/storage/memory/memory_test.go b/plugin/storage/memory/memory_test.go index 497606bacd2..b3034ccbffd 100644 --- a/plugin/storage/memory/memory_test.go +++ b/plugin/storage/memory/memory_test.go @@ -39,6 +39,7 @@ var testingSpan = &model.Span{ OperationName: "operationName", Tags: model.KeyValues{ model.String("tagKey", "tagValue"), + model.String("span.kind", "client"), }, Logs: []model.Log{ { @@ -63,6 +64,7 @@ var childSpan1 = &model.Span{ OperationName: "childOperationName", Tags: model.KeyValues{ model.String("tagKey", "tagValue"), + model.String("span.kind", "server"), }, Logs: []model.Log{ { @@ -87,6 +89,7 @@ var childSpan2 = &model.Span{ OperationName: "childOperationName", Tags: model.KeyValues{ model.String("tagKey", "tagValue"), + model.String("span.kind", "local"), }, Logs: []model.Log{ { @@ -224,18 +227,36 @@ func TestStoreGetServices(t *testing.T) { }) } -func TestStoreGetOperationsFound(t *testing.T) { +func TestStoreGetAllOperationsFound(t *testing.T) { withPopulatedMemoryStore(func(store *Store) { - operations, err := store.GetOperations(context.Background(), testingSpan.Process.ServiceName) + assert.NoError(t, store.WriteSpan(testingSpan)) + assert.NoError(t, store.WriteSpan(childSpan1)) + assert.NoError(t, store.WriteSpan(childSpan2)) + assert.NoError(t, store.WriteSpan(childSpan2_1)) + operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: ""}) + assert.NoError(t, err) + assert.Len(t, operations, 3) + assert.EqualValues(t, childSpan1.OperationName, (*operations[0]).Name) + }) +} + +func TestStoreGetServerOperationsFound(t *testing.T) { + withPopulatedMemoryStore(func(store *Store) { + assert.NoError(t, store.WriteSpan(testingSpan)) + assert.NoError(t, store.WriteSpan(childSpan1)) + assert.NoError(t, store.WriteSpan(childSpan2)) + assert.NoError(t, store.WriteSpan(childSpan2_1)) + operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: "server"}) assert.NoError(t, err) assert.Len(t, operations, 1) - assert.EqualValues(t, testingSpan.OperationName, operations[0]) + assert.EqualValues(t, childSpan1.OperationName, operations[0].Name) + assert.EqualValues(t, "server", operations[0].SpanKind) }) } func TestStoreGetOperationsNotFound(t *testing.T) { withPopulatedMemoryStore(func(store *Store) { - operations, err := store.GetOperations(context.Background(), "notAService") + operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "notAService", SpanKind: ""}) assert.NoError(t, err) assert.Len(t, operations, 0) }) diff --git a/proto-gen/storage_v1/storage.pb.go b/proto-gen/storage_v1/storage.pb.go index 4452ef3c715..d7bcf52fb40 100644 --- a/proto-gen/storage_v1/storage.pb.go +++ b/proto-gen/storage_v1/storage.pb.go @@ -6,6 +6,10 @@ package storage_v1 import ( context "context" fmt "fmt" + io "io" + math "math" + time "time" + _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "github.com/gogo/protobuf/types" @@ -14,9 +18,6 @@ import ( github_com_jaegertracing_jaeger_model "github.com/jaegertracing/jaeger/model" model "github.com/jaegertracing/jaeger/model" grpc "google.golang.org/grpc" - io "io" - math "math" - time "time" ) // Reference imports to suppress errors if they are not otherwise used. @@ -349,6 +350,7 @@ func (m *GetServicesResponse) GetServices() []string { type GetOperationsRequest struct { Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + SpanKind string `protobuf:"bytes,2,opt,name=span_kind,json=spanKind,proto3" json:"span_kind,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -394,18 +396,80 @@ func (m *GetOperationsRequest) GetService() string { return "" } -type GetOperationsResponse struct { - Operations []string `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` +func (m *GetOperationsRequest) GetSpanKind() string { + if m != nil { + return m.SpanKind + } + return "" +} + +type Operation struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + SpanKind string `protobuf:"bytes,2,opt,name=span_kind,json=spanKind,proto3" json:"span_kind,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } +func (m *Operation) Reset() { *m = Operation{} } +func (m *Operation) String() string { return proto.CompactTextString(m) } +func (*Operation) ProtoMessage() {} +func (*Operation) Descriptor() ([]byte, []int) { + return fileDescriptor_0d2c4ccf1453ffdb, []int{8} +} +func (m *Operation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Operation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Operation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Operation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Operation.Merge(m, src) +} +func (m *Operation) XXX_Size() int { + return m.Size() +} +func (m *Operation) XXX_DiscardUnknown() { + xxx_messageInfo_Operation.DiscardUnknown(m) +} + +var xxx_messageInfo_Operation proto.InternalMessageInfo + +func (m *Operation) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Operation) GetSpanKind() string { + if m != nil { + return m.SpanKind + } + return "" +} + +type GetOperationsResponse struct { + Operations []*Operation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + func (m *GetOperationsResponse) Reset() { *m = GetOperationsResponse{} } func (m *GetOperationsResponse) String() string { return proto.CompactTextString(m) } func (*GetOperationsResponse) ProtoMessage() {} func (*GetOperationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{8} + return fileDescriptor_0d2c4ccf1453ffdb, []int{9} } func (m *GetOperationsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -434,7 +498,7 @@ func (m *GetOperationsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_GetOperationsResponse proto.InternalMessageInfo -func (m *GetOperationsResponse) GetOperations() []string { +func (m *GetOperationsResponse) GetOperations() []*Operation { if m != nil { return m.Operations } @@ -459,7 +523,7 @@ func (m *TraceQueryParameters) Reset() { *m = TraceQueryParameters{} } func (m *TraceQueryParameters) String() string { return proto.CompactTextString(m) } func (*TraceQueryParameters) ProtoMessage() {} func (*TraceQueryParameters) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{9} + return fileDescriptor_0d2c4ccf1453ffdb, []int{10} } func (m *TraceQueryParameters) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -555,7 +619,7 @@ func (m *FindTracesRequest) Reset() { *m = FindTracesRequest{} } func (m *FindTracesRequest) String() string { return proto.CompactTextString(m) } func (*FindTracesRequest) ProtoMessage() {} func (*FindTracesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{10} + return fileDescriptor_0d2c4ccf1453ffdb, []int{11} } func (m *FindTracesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -602,7 +666,7 @@ func (m *SpansResponseChunk) Reset() { *m = SpansResponseChunk{} } func (m *SpansResponseChunk) String() string { return proto.CompactTextString(m) } func (*SpansResponseChunk) ProtoMessage() {} func (*SpansResponseChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{11} + return fileDescriptor_0d2c4ccf1453ffdb, []int{12} } func (m *SpansResponseChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -649,7 +713,7 @@ func (m *FindTraceIDsRequest) Reset() { *m = FindTraceIDsRequest{} } func (m *FindTraceIDsRequest) String() string { return proto.CompactTextString(m) } func (*FindTraceIDsRequest) ProtoMessage() {} func (*FindTraceIDsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{12} + return fileDescriptor_0d2c4ccf1453ffdb, []int{13} } func (m *FindTraceIDsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -696,7 +760,7 @@ func (m *FindTraceIDsResponse) Reset() { *m = FindTraceIDsResponse{} } func (m *FindTraceIDsResponse) String() string { return proto.CompactTextString(m) } func (*FindTraceIDsResponse) ProtoMessage() {} func (*FindTraceIDsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0d2c4ccf1453ffdb, []int{13} + return fileDescriptor_0d2c4ccf1453ffdb, []int{14} } func (m *FindTraceIDsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -742,6 +806,8 @@ func init() { golang_proto.RegisterType((*GetServicesResponse)(nil), "jaeger.storage.v1.GetServicesResponse") proto.RegisterType((*GetOperationsRequest)(nil), "jaeger.storage.v1.GetOperationsRequest") golang_proto.RegisterType((*GetOperationsRequest)(nil), "jaeger.storage.v1.GetOperationsRequest") + proto.RegisterType((*Operation)(nil), "jaeger.storage.v1.Operation") + golang_proto.RegisterType((*Operation)(nil), "jaeger.storage.v1.Operation") proto.RegisterType((*GetOperationsResponse)(nil), "jaeger.storage.v1.GetOperationsResponse") golang_proto.RegisterType((*GetOperationsResponse)(nil), "jaeger.storage.v1.GetOperationsResponse") proto.RegisterType((*TraceQueryParameters)(nil), "jaeger.storage.v1.TraceQueryParameters") @@ -762,64 +828,66 @@ func init() { proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffd func init() { golang_proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffdb) } var fileDescriptor_0d2c4ccf1453ffdb = []byte{ - // 905 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0xe3, 0x44, - 0x14, 0xc7, 0x6d, 0xb2, 0x71, 0x5e, 0xd2, 0xa5, 0x9d, 0x06, 0x30, 0x16, 0x9b, 0x14, 0x43, 0xb7, - 0x05, 0x09, 0x67, 0x1b, 0x0e, 0x8b, 0x40, 0x08, 0xc8, 0xa6, 0x1b, 0x15, 0xf1, 0x67, 0xf1, 0x46, - 0xac, 0xc4, 0x22, 0xac, 0x49, 0x3c, 0xb8, 0xde, 0xc6, 0x63, 0xaf, 0x3d, 0x8e, 0x92, 0x3b, 0x1f, - 0x80, 0x23, 0x27, 0xae, 0x7c, 0x0d, 0x8e, 0x7b, 0xe4, 0xcc, 0xa1, 0xa0, 0x70, 0xe4, 0x4b, 0x20, - 0xcf, 0x8c, 0xdd, 0xfc, 0xb1, 0xb6, 0xdd, 0x8a, 0x9b, 0xe7, 0xcd, 0xef, 0xfd, 0xde, 0x9b, 0xf7, - 0xe7, 0x97, 0xc0, 0x56, 0xcc, 0x82, 0x08, 0xbb, 0xc4, 0x0c, 0xa3, 0x80, 0x05, 0x68, 0xe7, 0x09, - 0x26, 0x2e, 0x89, 0xcc, 0xcc, 0x3a, 0x39, 0xd2, 0x1b, 0x6e, 0xe0, 0x06, 0xfc, 0xb6, 0x9d, 0x7e, - 0x09, 0xa0, 0xde, 0x72, 0x83, 0xc0, 0x1d, 0x93, 0x36, 0x3f, 0x0d, 0x93, 0x1f, 0xdb, 0xcc, 0xf3, - 0x49, 0xcc, 0xb0, 0x1f, 0x4a, 0x40, 0x73, 0x15, 0xe0, 0x24, 0x11, 0x66, 0x5e, 0x40, 0xe5, 0x7d, - 0xcd, 0x0f, 0x1c, 0x32, 0x16, 0x07, 0xe3, 0x57, 0x05, 0x5e, 0xed, 0x13, 0xd6, 0x23, 0x21, 0xa1, - 0x0e, 0xa1, 0x23, 0x8f, 0xc4, 0x16, 0x79, 0x9a, 0x90, 0x98, 0xa1, 0x7b, 0x00, 0x31, 0xc3, 0x11, - 0xb3, 0xd3, 0x00, 0x9a, 0xb2, 0xa7, 0x1c, 0xd6, 0x3a, 0xba, 0x29, 0xc8, 0xcd, 0x8c, 0xdc, 0x1c, - 0x64, 0xd1, 0xbb, 0xea, 0xb3, 0xf3, 0xd6, 0x4b, 0x3f, 0xff, 0xd5, 0x52, 0xac, 0x2a, 0xf7, 0x4b, - 0x6f, 0xd0, 0x27, 0xa0, 0x12, 0xea, 0x08, 0x8a, 0x8d, 0x17, 0xa0, 0xa8, 0x10, 0xea, 0xa4, 0x76, - 0x63, 0x08, 0xaf, 0xad, 0xe5, 0x17, 0x87, 0x01, 0x8d, 0x09, 0xea, 0x43, 0xdd, 0x59, 0xb0, 0x6b, - 0xca, 0xde, 0xe6, 0x61, 0xad, 0x73, 0xcb, 0x94, 0x95, 0xc4, 0xa1, 0x67, 0x4f, 0x3a, 0x66, 0xee, - 0x3a, 0xfb, 0xc2, 0xa3, 0x67, 0xdd, 0x52, 0x1a, 0xc2, 0x5a, 0x72, 0x34, 0x3e, 0x82, 0xed, 0x47, - 0x91, 0xc7, 0xc8, 0xc3, 0x10, 0xd3, 0xec, 0xf5, 0x07, 0x50, 0x8a, 0x43, 0x4c, 0xe5, 0xbb, 0x77, - 0x57, 0x48, 0x39, 0x92, 0x03, 0x8c, 0x5d, 0xd8, 0x59, 0x70, 0x16, 0xa9, 0x19, 0x14, 0x5e, 0xee, - 0x13, 0x36, 0x88, 0xf0, 0x88, 0x64, 0x84, 0x8f, 0x41, 0x65, 0xe9, 0xd9, 0xf6, 0x1c, 0x4e, 0x5a, - 0xef, 0x7e, 0x9a, 0xa6, 0xf2, 0xe7, 0x79, 0xeb, 0x3d, 0xd7, 0x63, 0xa7, 0xc9, 0xd0, 0x1c, 0x05, - 0x7e, 0x5b, 0x84, 0x49, 0x81, 0x1e, 0x75, 0xe5, 0xa9, 0x2d, 0x1a, 0xc6, 0xd9, 0x4e, 0x7a, 0xf3, - 0xf3, 0x56, 0x45, 0x7e, 0x5a, 0x15, 0xce, 0x78, 0xe2, 0x18, 0x0d, 0x40, 0x7d, 0xc2, 0x1e, 0x92, - 0x68, 0xe2, 0x8d, 0xf2, 0x0e, 0x1a, 0x47, 0xb0, 0xbb, 0x64, 0x95, 0x75, 0xd3, 0x41, 0x8d, 0xa5, - 0x8d, 0xd7, 0xac, 0x6a, 0xe5, 0x67, 0xe3, 0x0e, 0x34, 0xfa, 0x84, 0x7d, 0x1d, 0x12, 0x31, 0x32, - 0xf9, 0x30, 0x68, 0x50, 0x91, 0x18, 0x9e, 0x7c, 0xd5, 0xca, 0x8e, 0xc6, 0x5d, 0x78, 0x65, 0xc5, - 0x43, 0x86, 0x69, 0x02, 0x04, 0xb9, 0x55, 0x06, 0x5a, 0xb0, 0x18, 0xbf, 0x95, 0xa0, 0xc1, 0x1f, - 0xf2, 0x4d, 0x42, 0xa2, 0xd9, 0x03, 0x1c, 0x61, 0x9f, 0x30, 0x12, 0xc5, 0xe8, 0x4d, 0xa8, 0x4b, - 0x72, 0x9b, 0x62, 0x3f, 0x0b, 0x58, 0x93, 0xb6, 0xaf, 0xb0, 0x4f, 0xd0, 0x3e, 0xdc, 0xcc, 0x99, - 0x04, 0x68, 0x83, 0x83, 0xb6, 0x72, 0x2b, 0x87, 0x1d, 0x43, 0x89, 0x61, 0x37, 0xd6, 0x36, 0xf9, - 0x64, 0x1c, 0x99, 0x6b, 0x3b, 0x66, 0x16, 0x25, 0x60, 0x0e, 0xb0, 0x1b, 0x1f, 0x53, 0x16, 0xcd, - 0x2c, 0xee, 0x8e, 0x3e, 0x87, 0x9b, 0x17, 0x9b, 0x60, 0xfb, 0x1e, 0xd5, 0x4a, 0x2f, 0x30, 0xca, - 0xf5, 0x7c, 0x1b, 0xbe, 0xf4, 0xe8, 0x2a, 0x17, 0x9e, 0x6a, 0xe5, 0xeb, 0x71, 0xe1, 0x29, 0xba, - 0x0f, 0xf5, 0x6c, 0xb7, 0x79, 0x56, 0x37, 0x38, 0xd3, 0xeb, 0x6b, 0x4c, 0x3d, 0x09, 0x12, 0x44, - 0xbf, 0xa4, 0x44, 0xb5, 0xcc, 0x31, 0xcd, 0x69, 0x89, 0x07, 0x4f, 0xb5, 0xca, 0x75, 0x78, 0xf0, - 0x14, 0xdd, 0x02, 0xa0, 0x89, 0x6f, 0xf3, 0xa1, 0x8c, 0x35, 0x75, 0x4f, 0x39, 0x2c, 0x5b, 0x55, - 0x9a, 0xf8, 0xbc, 0xc8, 0xb1, 0x7e, 0x17, 0xaa, 0x79, 0x65, 0xd1, 0x36, 0x6c, 0x9e, 0x91, 0x99, - 0xec, 0x6d, 0xfa, 0x89, 0x1a, 0x50, 0x9e, 0xe0, 0x71, 0x92, 0xb5, 0x52, 0x1c, 0x3e, 0xdc, 0xf8, - 0x40, 0x31, 0x2c, 0xd8, 0xb9, 0xef, 0x51, 0x47, 0xd0, 0x64, 0x13, 0xf9, 0x31, 0x94, 0x9f, 0xa6, - 0x7d, 0x93, 0x1b, 0x7a, 0x70, 0xc5, 0xe6, 0x5a, 0xc2, 0xcb, 0x38, 0x06, 0x94, 0x6e, 0x6c, 0x3e, - 0xae, 0xf7, 0x4e, 0x13, 0x7a, 0x86, 0xda, 0x50, 0x4e, 0x97, 0x3a, 0xd3, 0x92, 0xa2, 0xb5, 0x97, - 0x0a, 0x22, 0x70, 0xc6, 0x00, 0x76, 0xf3, 0xd4, 0x4e, 0x7a, 0xff, 0x57, 0x72, 0x13, 0x68, 0x2c, - 0xb3, 0xca, 0x95, 0xfa, 0x01, 0xaa, 0x99, 0x86, 0x88, 0x14, 0xeb, 0xdd, 0xcf, 0xae, 0x2b, 0x22, - 0x6a, 0xce, 0xae, 0x4a, 0x15, 0x89, 0x3b, 0x4f, 0x60, 0x3b, 0x7d, 0x22, 0xd7, 0xb3, 0xe8, 0xc1, - 0x38, 0x71, 0x3d, 0x8a, 0xbe, 0x85, 0x6a, 0xae, 0x6f, 0xe8, 0xad, 0x82, 0x87, 0xac, 0x4a, 0xa7, - 0xfe, 0xf6, 0xf3, 0x41, 0xe2, 0x2d, 0x9d, 0x7f, 0x37, 0x45, 0x30, 0x8b, 0x60, 0x27, 0x0f, 0xf6, - 0x08, 0xd4, 0x4c, 0x37, 0x91, 0x51, 0x40, 0xb3, 0x22, 0xaa, 0xfa, 0x7e, 0x01, 0x66, 0xbd, 0xad, - 0x77, 0x14, 0xf4, 0x3d, 0xd4, 0x16, 0xa4, 0x10, 0xed, 0x17, 0x73, 0xaf, 0x08, 0xa8, 0x7e, 0xfb, - 0x32, 0x98, 0xec, 0xcb, 0x10, 0xb6, 0x96, 0x34, 0x10, 0x1d, 0x14, 0x3b, 0xae, 0xe9, 0xaa, 0x7e, - 0x78, 0x39, 0x50, 0xc6, 0x78, 0x0c, 0x70, 0xb1, 0x04, 0xa8, 0xa8, 0xc6, 0x6b, 0x3b, 0x72, 0xf5, - 0xf2, 0xd8, 0x50, 0x5f, 0x1c, 0x38, 0x74, 0xfb, 0x79, 0xf4, 0x17, 0x73, 0xae, 0x1f, 0x5c, 0x8a, - 0x93, 0xdd, 0xfe, 0x49, 0x01, 0x6d, 0xf9, 0x47, 0x7c, 0xa1, 0xeb, 0xa7, 0xfc, 0xd7, 0x72, 0xf1, - 0x1a, 0xbd, 0x53, 0x5c, 0x97, 0x82, 0xff, 0x29, 0xfa, 0xbb, 0x57, 0x81, 0x8a, 0x34, 0xba, 0x6f, - 0x3c, 0x9b, 0x37, 0x95, 0x3f, 0xe6, 0x4d, 0xe5, 0xef, 0x79, 0x53, 0xf9, 0xfd, 0x9f, 0xa6, 0xf2, - 0x1d, 0x48, 0x2f, 0x7b, 0x72, 0x34, 0xbc, 0xc1, 0x95, 0xee, 0xfd, 0xff, 0x02, 0x00, 0x00, 0xff, - 0xff, 0x7d, 0x2c, 0x50, 0x42, 0x9b, 0x09, 0x00, 0x00, + // 941 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x73, 0xdb, 0x44, + 0x14, 0x46, 0x8d, 0x5d, 0x5b, 0xcf, 0x4e, 0x49, 0x36, 0x06, 0x84, 0x68, 0xed, 0x20, 0x48, 0x13, + 0x98, 0x41, 0x26, 0xe6, 0x00, 0x03, 0x65, 0x00, 0x37, 0xa9, 0x27, 0x40, 0xa1, 0xa8, 0x81, 0xce, + 0x50, 0x06, 0xcd, 0x3a, 0x5a, 0x14, 0x35, 0xd1, 0x4a, 0x95, 0x56, 0x9e, 0xe4, 0xce, 0x1f, 0xc0, + 0x91, 0x13, 0x57, 0xfe, 0x0d, 0x8e, 0x3d, 0x72, 0xe6, 0x10, 0x18, 0x73, 0xe4, 0x9f, 0x60, 0xf6, + 0x87, 0x14, 0xff, 0xd0, 0xe4, 0xd7, 0xf4, 0xa6, 0x7d, 0xfb, 0xbd, 0x6f, 0xbf, 0x7d, 0x6f, 0xdf, + 0x67, 0xc3, 0x62, 0xca, 0xa2, 0x04, 0xfb, 0xc4, 0x8e, 0x93, 0x88, 0x45, 0x68, 0xf9, 0x09, 0x26, + 0x3e, 0x49, 0xec, 0x3c, 0x3a, 0xda, 0x34, 0x5b, 0x7e, 0xe4, 0x47, 0x62, 0xb7, 0xcb, 0xbf, 0x24, + 0xd0, 0xec, 0xf8, 0x51, 0xe4, 0x1f, 0x92, 0xae, 0x58, 0x0d, 0xb3, 0x9f, 0xba, 0x2c, 0x08, 0x49, + 0xca, 0x70, 0x18, 0x2b, 0x40, 0x7b, 0x16, 0xe0, 0x65, 0x09, 0x66, 0x41, 0x44, 0xd5, 0x7e, 0x23, + 0x8c, 0x3c, 0x72, 0x28, 0x17, 0xd6, 0x6f, 0x1a, 0xbc, 0x3c, 0x20, 0x6c, 0x8b, 0xc4, 0x84, 0x7a, + 0x84, 0xee, 0x05, 0x24, 0x75, 0xc8, 0xd3, 0x8c, 0xa4, 0x0c, 0xdd, 0x05, 0x48, 0x19, 0x4e, 0x98, + 0xcb, 0x0f, 0x30, 0xb4, 0x55, 0x6d, 0xa3, 0xd1, 0x33, 0x6d, 0x49, 0x6e, 0xe7, 0xe4, 0xf6, 0x6e, + 0x7e, 0x7a, 0xbf, 0xfe, 0xec, 0xa4, 0xf3, 0xc2, 0x2f, 0x7f, 0x77, 0x34, 0x47, 0x17, 0x79, 0x7c, + 0x07, 0x7d, 0x02, 0x75, 0x42, 0x3d, 0x49, 0x71, 0xed, 0x12, 0x14, 0x35, 0x42, 0x3d, 0x1e, 0xb7, + 0x86, 0xf0, 0xca, 0x9c, 0xbe, 0x34, 0x8e, 0x68, 0x4a, 0xd0, 0x00, 0x9a, 0xde, 0x44, 0xdc, 0xd0, + 0x56, 0x17, 0x36, 0x1a, 0xbd, 0x5b, 0xb6, 0xaa, 0x24, 0x8e, 0x03, 0x77, 0xd4, 0xb3, 0x8b, 0xd4, + 0xe3, 0x2f, 0x03, 0x7a, 0xd0, 0xaf, 0xf0, 0x23, 0x9c, 0xa9, 0x44, 0xeb, 0x23, 0x58, 0x7a, 0x94, + 0x04, 0x8c, 0x3c, 0x8c, 0x31, 0xcd, 0x6f, 0xbf, 0x0e, 0x95, 0x34, 0xc6, 0x54, 0xdd, 0x7b, 0x65, + 0x86, 0x54, 0x20, 0x05, 0xc0, 0x5a, 0x81, 0xe5, 0x89, 0x64, 0x29, 0xcd, 0xa2, 0xf0, 0xe2, 0x80, + 0xb0, 0xdd, 0x04, 0xef, 0x91, 0x9c, 0xf0, 0x31, 0xd4, 0x19, 0x5f, 0xbb, 0x81, 0x27, 0x48, 0x9b, + 0xfd, 0x4f, 0xb9, 0x94, 0xbf, 0x4e, 0x3a, 0xef, 0xf8, 0x01, 0xdb, 0xcf, 0x86, 0xf6, 0x5e, 0x14, + 0x76, 0xe5, 0x31, 0x1c, 0x18, 0x50, 0x5f, 0xad, 0xba, 0xb2, 0x61, 0x82, 0x6d, 0x67, 0x6b, 0x7c, + 0xd2, 0xa9, 0xa9, 0x4f, 0xa7, 0x26, 0x18, 0x77, 0x3c, 0xab, 0x05, 0x68, 0x40, 0xd8, 0x43, 0x92, + 0x8c, 0x82, 0xbd, 0xa2, 0x83, 0xd6, 0x26, 0xac, 0x4c, 0x45, 0x55, 0xdd, 0x4c, 0xa8, 0xa7, 0x2a, + 0x26, 0x6a, 0xa6, 0x3b, 0xc5, 0xda, 0xba, 0x0f, 0xad, 0x01, 0x61, 0x5f, 0xc7, 0x44, 0x3e, 0x99, + 0xe2, 0x31, 0x18, 0x50, 0x53, 0x18, 0x21, 0x5e, 0x77, 0xf2, 0x25, 0x7a, 0x0d, 0x74, 0x5e, 0x07, + 0xf7, 0x20, 0xa0, 0x9e, 0x68, 0x31, 0xa7, 0x8b, 0x31, 0xfd, 0x22, 0xa0, 0x9e, 0x75, 0x07, 0xf4, + 0x82, 0x0b, 0x21, 0xa8, 0x50, 0x1c, 0xe6, 0x04, 0xe2, 0xfb, 0xec, 0xec, 0x6f, 0xe1, 0xa5, 0x19, + 0x31, 0xea, 0x06, 0x77, 0x00, 0xa2, 0x22, 0xaa, 0xfa, 0x7e, 0xd3, 0x9e, 0x9b, 0x20, 0xbb, 0x48, + 0x75, 0x26, 0xf0, 0xd6, 0xef, 0x15, 0x68, 0x89, 0x0a, 0x7e, 0x93, 0x91, 0xe4, 0xf8, 0x01, 0x4e, + 0x70, 0x48, 0x18, 0x49, 0x52, 0xf4, 0x3a, 0x34, 0xd5, 0xad, 0xdc, 0x09, 0xa1, 0x0d, 0x15, 0xfb, + 0x8a, 0xeb, 0x5d, 0x83, 0x1b, 0x05, 0x93, 0x04, 0x49, 0xd1, 0x8b, 0x45, 0x54, 0xc0, 0xb6, 0xa1, + 0xc2, 0xb0, 0x9f, 0x1a, 0x0b, 0x42, 0xda, 0x66, 0x89, 0xb4, 0x32, 0x01, 0xf6, 0x2e, 0xf6, 0xd3, + 0x6d, 0xca, 0x92, 0x63, 0x47, 0xa4, 0xa3, 0xcf, 0xe1, 0xc6, 0xe9, 0x08, 0xba, 0x61, 0x40, 0x8d, + 0xca, 0x25, 0x66, 0xa8, 0x59, 0x8c, 0xe1, 0xfd, 0x80, 0xce, 0x72, 0xe1, 0x23, 0xa3, 0x7a, 0x35, + 0x2e, 0x7c, 0x84, 0xee, 0x41, 0x33, 0x37, 0x15, 0xa1, 0xea, 0xba, 0x60, 0x7a, 0x75, 0x8e, 0x69, + 0x4b, 0x81, 0x24, 0xd1, 0xaf, 0x9c, 0xa8, 0x91, 0x27, 0x72, 0x4d, 0x53, 0x3c, 0xf8, 0xc8, 0xa8, + 0x5d, 0x85, 0x07, 0x1f, 0xa1, 0x5b, 0x00, 0x34, 0x0b, 0x5d, 0x31, 0x0d, 0xa9, 0x51, 0x5f, 0xd5, + 0x36, 0xaa, 0x8e, 0x4e, 0xb3, 0x50, 0x14, 0x39, 0x35, 0xdf, 0x07, 0xbd, 0xa8, 0x2c, 0x5a, 0x82, + 0x85, 0x03, 0x72, 0xac, 0x7a, 0xcb, 0x3f, 0x51, 0x0b, 0xaa, 0x23, 0x7c, 0x98, 0xe5, 0xad, 0x94, + 0x8b, 0x0f, 0xaf, 0x7d, 0xa0, 0x59, 0x0e, 0x2c, 0xdf, 0x0b, 0xa8, 0x27, 0x69, 0xf2, 0x51, 0xf8, + 0x18, 0xaa, 0x4f, 0x79, 0xdf, 0x94, 0x35, 0xac, 0x5f, 0xb0, 0xb9, 0x8e, 0xcc, 0xb2, 0xb6, 0x01, + 0x71, 0xab, 0x28, 0x1e, 0xf3, 0xdd, 0xfd, 0x8c, 0x1e, 0xa0, 0x2e, 0x54, 0xf9, 0xb3, 0xcf, 0x1f, + 0x73, 0x99, 0xdf, 0x28, 0xeb, 0x92, 0x38, 0x6b, 0x17, 0x56, 0x0a, 0x69, 0x3b, 0x5b, 0xcf, 0x4b, + 0xdc, 0x08, 0x5a, 0xd3, 0xac, 0x6a, 0xe0, 0x7e, 0x04, 0x3d, 0x37, 0x2f, 0x29, 0xb1, 0xd9, 0xff, + 0xec, 0xaa, 0xee, 0x55, 0x2f, 0xd8, 0xeb, 0xca, 0xbe, 0xd2, 0xde, 0x13, 0x58, 0xe2, 0x57, 0x14, + 0x46, 0x9a, 0x3c, 0x38, 0xcc, 0xfc, 0x80, 0xa2, 0xef, 0x40, 0x2f, 0x8c, 0x15, 0xbd, 0x51, 0x72, + 0x91, 0x59, 0xcf, 0x36, 0xdf, 0x3c, 0x1b, 0x24, 0xef, 0xd2, 0xfb, 0x6f, 0x41, 0x1e, 0xe6, 0x10, + 0xec, 0x15, 0x87, 0x3d, 0x82, 0x7a, 0x6e, 0xd8, 0xc8, 0x2a, 0xa1, 0x99, 0x71, 0x73, 0x73, 0xad, + 0x04, 0x33, 0xdf, 0xd6, 0x77, 0x35, 0xf4, 0x03, 0x34, 0x26, 0x3c, 0x18, 0xad, 0x95, 0x73, 0xcf, + 0x38, 0xb7, 0x79, 0xfb, 0x3c, 0x98, 0xea, 0xcb, 0x10, 0x16, 0xa7, 0x1c, 0x12, 0xad, 0x97, 0x27, + 0xce, 0x19, 0xba, 0xb9, 0x71, 0x3e, 0x50, 0x9d, 0xf1, 0x18, 0xe0, 0x74, 0x08, 0x50, 0x59, 0x8d, + 0xe7, 0x66, 0xe4, 0xe2, 0xe5, 0x71, 0xa1, 0x39, 0xf9, 0xe0, 0xd0, 0xed, 0xb3, 0xe8, 0x4f, 0xdf, + 0xb9, 0xb9, 0x7e, 0x2e, 0x4e, 0x75, 0xfb, 0x67, 0x0d, 0x8c, 0xe9, 0x7f, 0x0f, 0x13, 0x5d, 0xdf, + 0x17, 0x3f, 0xd3, 0x93, 0xdb, 0xe8, 0xad, 0xf2, 0xba, 0x94, 0xfc, 0x41, 0x32, 0xdf, 0xbe, 0x08, + 0x54, 0xca, 0xe8, 0xdf, 0x7c, 0x36, 0x6e, 0x6b, 0x7f, 0x8e, 0xdb, 0xda, 0x3f, 0xe3, 0xb6, 0xf6, + 0xc7, 0xbf, 0x6d, 0xed, 0x7b, 0x50, 0x59, 0xee, 0x68, 0x73, 0x78, 0x5d, 0x38, 0xdd, 0x7b, 0xff, + 0x07, 0x00, 0x00, 0xff, 0xff, 0x80, 0x63, 0x86, 0x8e, 0x14, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1444,6 +1512,45 @@ func (m *GetOperationsRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintStorage(dAtA, i, uint64(len(m.Service))) i += copy(dAtA[i:], m.Service) } + if len(m.SpanKind) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintStorage(dAtA, i, uint64(len(m.SpanKind))) + i += copy(dAtA[i:], m.SpanKind) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Operation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Operation) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintStorage(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.SpanKind) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintStorage(dAtA, i, uint64(len(m.SpanKind))) + i += copy(dAtA[i:], m.SpanKind) + } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -1466,18 +1573,15 @@ func (m *GetOperationsResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if len(m.Operations) > 0 { - for _, s := range m.Operations { + for _, msg := range m.Operations { dAtA[i] = 0xa i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ + i = encodeVarintStorage(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) + i += n } } if m.XXX_unrecognized != nil { @@ -1826,6 +1930,30 @@ func (m *GetOperationsRequest) Size() (n int) { if l > 0 { n += 1 + l + sovStorage(uint64(l)) } + l = len(m.SpanKind) + if l > 0 { + n += 1 + l + sovStorage(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Operation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovStorage(uint64(l)) + } + l = len(m.SpanKind) + if l > 0 { + n += 1 + l + sovStorage(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -1839,8 +1967,8 @@ func (m *GetOperationsResponse) Size() (n int) { var l int _ = l if len(m.Operations) > 0 { - for _, s := range m.Operations { - l = len(s) + for _, e := range m.Operations { + l = e.Size() n += 1 + l + sovStorage(uint64(l)) } } @@ -2610,6 +2738,38 @@ func (m *GetOperationsRequest) Unmarshal(dAtA []byte) error { } m.Service = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanKind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStorage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStorage + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStorage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanKind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStorage(dAtA[iNdEx:]) @@ -2635,7 +2795,7 @@ func (m *GetOperationsRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { +func (m *Operation) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2658,15 +2818,47 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GetOperationsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: Operation: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GetOperationsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Operation: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStorage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStorage + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStorage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanKind", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2694,7 +2886,95 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Operations = append(m.Operations, string(dAtA[iNdEx:postIndex])) + m.SpanKind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStorage(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStorage + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthStorage + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStorage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetOperationsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetOperationsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStorage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStorage + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStorage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operations = append(m.Operations, &Operation{}) + if err := m.Operations[len(m.Operations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex diff --git a/storage/spanstore/interface.go b/storage/spanstore/interface.go index 6b08b58d4e3..4b1a2ba3ff2 100644 --- a/storage/spanstore/interface.go +++ b/storage/spanstore/interface.go @@ -37,7 +37,7 @@ var ( type Reader interface { GetTrace(ctx context.Context, traceID model.TraceID) (*model.Trace, error) GetServices(ctx context.Context) ([]string, error) - GetOperations(ctx context.Context, service string) ([]string, error) + GetOperations(ctx context.Context, query *OperationQueryParameters) ([]*Operation, error) FindTraces(ctx context.Context, query *TraceQueryParameters) ([]*model.Trace, error) FindTraceIDs(ctx context.Context, query *TraceQueryParameters) ([]model.TraceID, error) } diff --git a/storage/spanstore/metrics/decorator.go b/storage/spanstore/metrics/decorator.go index fcf614d93f6..10128c34533 100644 --- a/storage/spanstore/metrics/decorator.go +++ b/storage/spanstore/metrics/decorator.go @@ -106,9 +106,9 @@ func (m *ReadMetricsDecorator) GetServices(ctx context.Context) ([]string, error } // GetOperations implements spanstore.Reader#GetOperations -func (m *ReadMetricsDecorator) GetOperations(ctx context.Context, service string) ([]string, error) { +func (m *ReadMetricsDecorator) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { start := time.Now() - retMe, err := m.spanReader.GetOperations(ctx, service) + retMe, err := m.spanReader.GetOperations(ctx, query) m.getOperationsMetrics.emit(err, time.Since(start), len(retMe)) return retMe, err } diff --git a/storage/spanstore/metrics/decorator_test.go b/storage/spanstore/metrics/decorator_test.go index 4f0ea790a0c..9c876fa0b23 100644 --- a/storage/spanstore/metrics/decorator_test.go +++ b/storage/spanstore/metrics/decorator_test.go @@ -36,8 +36,9 @@ func TestSuccessfulUnderlyingCalls(t *testing.T) { mrs := NewReadMetricsDecorator(&mockReader, mf) mockReader.On("GetServices", context.Background()).Return([]string{}, nil) mrs.GetServices(context.Background()) - mockReader.On("GetOperations", context.Background(), "something").Return([]string{}, nil) - mrs.GetOperations(context.Background(), "something") + operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} + mockReader.On("GetOperations", context.Background(), operationQuery).Return([]*spanstore.Operation{}, nil) + mrs.GetOperations(context.Background(), operationQuery) mockReader.On("GetTrace", context.Background(), model.TraceID{}).Return(&model.Trace{}, nil) mrs.GetTrace(context.Background(), model.TraceID{}) mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}).Return([]*model.Trace{}, nil) @@ -93,8 +94,9 @@ func TestFailingUnderlyingCalls(t *testing.T) { mrs := NewReadMetricsDecorator(&mockReader, mf) mockReader.On("GetServices", context.Background()).Return(nil, errors.New("Failure")) mrs.GetServices(context.Background()) - mockReader.On("GetOperations", context.Background(), "something").Return(nil, errors.New("Failure")) - mrs.GetOperations(context.Background(), "something") + operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} + mockReader.On("GetOperations", context.Background(), operationQuery).Return(nil, errors.New("Failure")) + mrs.GetOperations(context.Background(), operationQuery) mockReader.On("GetTrace", context.Background(), model.TraceID{}).Return(nil, errors.New("Failure")) mrs.GetTrace(context.Background(), model.TraceID{}) mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}).Return(nil, errors.New("Failure")) diff --git a/storage/spanstore/mocks/Reader.go b/storage/spanstore/mocks/Reader.go index 0ce7ecc64c9..8cc305243f2 100644 --- a/storage/spanstore/mocks/Reader.go +++ b/storage/spanstore/mocks/Reader.go @@ -15,10 +15,12 @@ package mocks -import context "context" -import mock "github.com/stretchr/testify/mock" -import model "github.com/jaegertracing/jaeger/model" -import spanstore "github.com/jaegertracing/jaeger/storage/spanstore" +import ( + "context" +) +import "github.com/stretchr/testify/mock" +import "github.com/jaegertracing/jaeger/model" +import "github.com/jaegertracing/jaeger/storage/spanstore" // Reader is an autogenerated mock type for the Reader type type Reader struct { @@ -71,22 +73,22 @@ func (_m *Reader) FindTraces(ctx context.Context, query *spanstore.TraceQueryPar return r0, r1 } -// GetOperations provides a mock function with given fields: ctx, service -func (_m *Reader) GetOperations(ctx context.Context, service string) ([]string, error) { - ret := _m.Called(ctx, service) +// GetOperations provides a mock function with given fields: ctx, query +func (_m *Reader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + ret := _m.Called(ctx, query) - var r0 []string - if rf, ok := ret.Get(0).(func(context.Context, string) []string); ok { - r0 = rf(ctx, service) + var r0 []*spanstore.Operation + if rf, ok := ret.Get(0).(func(context.Context, *spanstore.OperationQueryParameters) []*spanstore.Operation); ok { + r0 = rf(ctx, query) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) + r0 = ret.Get(0).([]*spanstore.Operation) } } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, service) + if rf, ok := ret.Get(1).(func(context.Context, *spanstore.OperationQueryParameters) error); ok { + r1 = rf(ctx, query) } else { r1 = ret.Error(1) } From 66c4389a29ef0dde0866c4680db1e357ced6525a Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Thu, 21 Nov 2019 14:37:01 -0500 Subject: [PATCH 06/12] Wrap long lines and update proto to be backwards compatible Signed-off-by: Jun Guo --- cmd/query/app/grpc_handler_test.go | 10 +- cmd/query/app/http_handler_test.go | 10 +- .../badger/spanstore/read_write_test.go | 3 +- plugin/storage/badger/spanstore/reader.go | 3 +- .../cassandra/spanstore/operation_names.go | 3 +- .../spanstore/operation_names_test.go | 6 +- plugin/storage/cassandra/spanstore/reader.go | 3 +- .../cassandra/spanstore/reader_test.go | 54 +++-- .../cassandra/spanstore/writer_test.go | 29 ++- plugin/storage/es/spanstore/reader.go | 3 +- plugin/storage/es/spanstore/reader_test.go | 3 +- .../es/spanstore/service_operation_test.go | 3 +- plugin/storage/grpc/proto/storage.proto | 3 +- plugin/storage/grpc/shared/grpc_client.go | 7 +- .../storage/grpc/shared/grpc_client_test.go | 5 +- plugin/storage/grpc/shared/grpc_server.go | 10 +- .../storage/grpc/shared/grpc_server_test.go | 7 +- .../storage/integration/integration_test.go | 7 +- plugin/storage/integration/kafka_test.go | 3 +- plugin/storage/memory/memory.go | 3 +- plugin/storage/memory/memory_test.go | 9 +- proto-gen/storage_v1/storage.pb.go | 201 ++++++++++++------ storage/spanstore/metrics/decorator.go | 3 +- storage/spanstore/metrics/decorator_test.go | 31 ++- storage/spanstore/mocks/Reader.go | 6 +- 25 files changed, 288 insertions(+), 137 deletions(-) diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index a3ce84f8f08..f7c29595eb9 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -416,7 +416,10 @@ func TestGetOperationsSuccessGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} - server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() + server.spanReader.On("GetOperations", + mock.AnythingOfType("*context.valueCtx"), + &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}, + ).Return(expectedOperations, nil).Once() res, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ Service: "abc/trifle", @@ -431,7 +434,10 @@ func TestGetOperationsSuccessGRPC(t *testing.T) { func TestGetOperationsFailureGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { - server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "trifle"}).Return(nil, errStorageGRPC).Once() + server.spanReader.On("GetOperations", + mock.AnythingOfType("*context.valueCtx"), + &spanstore.OperationQueryParameters{ServiceName: "trifle"}, + ).Return(nil, errStorageGRPC).Once() _, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ Service: "trifle", diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index 42a0198f9ee..986dcb5a746 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -32,7 +32,7 @@ import ( testHttp "github.com/stretchr/testify/http" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - jaeger "github.com/uber/jaeger-client-go" + "github.com/uber/jaeger-client-go" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -484,7 +484,8 @@ func TestGetOperationsSuccess(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() + readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), + &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() var response structuredResponse err := getJSON(server.URL+"/api/operations?service=abc%2Ftrifle", &response) @@ -522,7 +523,10 @@ func TestGetOperationsLegacySuccess(t *testing.T) { defer server.Close() expectedOperationNames := []string{"", "get"} expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} - readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle").Return(expectedOperationNames, nil).Once() + readMock.On("GetOperations", + mock.AnythingOfType("*context.valueCtx"), + "abc/trifle", + ).Return(expectedOperationNames, nil).Once() readMock.On( "GetOperations", mock.AnythingOfType("*context.valueCtx"), diff --git a/plugin/storage/badger/spanstore/read_write_test.go b/plugin/storage/badger/spanstore/read_write_test.go index 922b3fbd6e9..59fbe92a455 100644 --- a/plugin/storage/badger/spanstore/read_write_test.go +++ b/plugin/storage/badger/spanstore/read_write_test.go @@ -331,7 +331,8 @@ func TestMenuSeeks(t *testing.T) { } } - operations, err := sr.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-1", SpanKind: ""}) + operations, err := sr.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "service-1", SpanKind: ""}) assert.NoError(t, err) serviceList, err := sr.GetServices(context.Background()) diff --git a/plugin/storage/badger/spanstore/reader.go b/plugin/storage/badger/spanstore/reader.go index ec8629dde22..1249eec645a 100644 --- a/plugin/storage/badger/spanstore/reader.go +++ b/plugin/storage/badger/spanstore/reader.go @@ -237,7 +237,8 @@ func (r *TraceReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations fetches operations in the service and empty slice if service does not exists -func (r *TraceReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (r *TraceReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { return r.cache.GetOperations(query.ServiceName) } diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index f222bc86510..f3c8d5f9b8f 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -50,7 +50,8 @@ type tableMeta struct { queryByKindStmt string queryStmt string createWriteQuery func(query cassandra.Query, service, kind, opName string) cassandra.Query - getOperations func(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) + getOperations func(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) } func (t *tableMeta) materialize() { diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index b005512b276..71bce39b008 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -50,6 +50,9 @@ func withOperationNamesStorage(writeCacheTTL time.Duration, query := &mocks.Query{} session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) + session.On("Query", + fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), + mock.Anything).Return(query) if schemaVersion != latestVersion { query.On("Exec").Return(errors.New("new table does not exist")) } else { @@ -112,7 +115,8 @@ func TestOperationNamesStorageWrite(t *testing.T) { "error": "exec error", }, s.logBuffer.JSONLine(0)) err = s.storage.Write("service-c", "operation-d", "") - assert.EqualError(t, err, "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") + assert.EqualError(t, err, + "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") assert.Equal(t, map[string]string{ "level": "error", "msg": "Failed to exec query", diff --git a/plugin/storage/cassandra/spanstore/reader.go b/plugin/storage/cassandra/spanstore/reader.go index 98dea522229..3cdbff48220 100644 --- a/plugin/storage/cassandra/spanstore/reader.go +++ b/plugin/storage/cassandra/spanstore/reader.go @@ -143,7 +143,8 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { return s.operationNamesReader(query) } diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index 90c1f0d2439..a8090a82a19 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -47,7 +47,9 @@ type spanReaderTest struct { func withSpanReader(fn func(r *spanReaderTest)) { session := &mocks.Session{} query := &mocks.Query{} - session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) + session.On("Query", + fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), + mock.Anything).Return(query) query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) @@ -73,15 +75,17 @@ func TestSpanReaderGetServices(t *testing.T) { func TestSpanReaderGetOperations(t *testing.T) { withSpanReader(func(r *spanReaderTest) { - r.reader.operationNamesReader = func(parameters *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { - return []*spanstore.Operation{ - { - Name: "operation-a", - SpanKind: "server", - }, - }, nil - } - s, err := r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) + r.reader.operationNamesReader = + func(parameters *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + return []*spanstore.Operation{ + { + Name: "operation-a", + SpanKind: "server", + }, + }, nil + } + s, err := r.reader.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) assert.NoError(t, err) assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) }) @@ -340,12 +344,24 @@ func TestSpanReaderFindTraces(t *testing.T) { return loadQuery } - r.session.On("Query", stringMatcher(queryByServiceName), matchEverything()).Return(mainQuery) - r.session.On("Query", stringMatcher(queryByTag), matchEverything()).Return(tagsQuery) - r.session.On("Query", stringMatcher(queryByServiceAndOperationName), matchEverything()).Return(operationQuery) - r.session.On("Query", stringMatcher(queryByDuration), matchEverything()).Return(durationQuery) - r.session.On("Query", stringMatcher("SELECT trace_id"), matchOnce()).Return(makeLoadQuery()) - r.session.On("Query", stringMatcher("SELECT trace_id"), matchEverything()).Return(makeLoadQuery()) + r.session.On("Query", + stringMatcher(queryByServiceName), + matchEverything()).Return(mainQuery) + r.session.On("Query", + stringMatcher(queryByTag), + matchEverything()).Return(tagsQuery) + r.session.On("Query", + stringMatcher(queryByServiceAndOperationName), + matchEverything()).Return(operationQuery) + r.session.On("Query", + stringMatcher(queryByDuration), + matchEverything()).Return(durationQuery) + r.session.On("Query", + stringMatcher("SELECT trace_id"), + matchOnce()).Return(makeLoadQuery()) + r.session.On("Query", + stringMatcher("SELECT trace_id"), + matchEverything()).Return(makeLoadQuery()) queryParams := &spanstore.TraceQueryParameters{ ServiceName: "service-a", @@ -375,7 +391,11 @@ func TestSpanReaderFindTraces(t *testing.T) { assert.EqualError(t, err, testCase.expectedError) } for _, expectedLog := range testCase.expectedLogs { - assert.True(t, strings.Contains(r.logBuffer.String(), expectedLog), "Log must contain %s, but was %s", expectedLog, r.logBuffer.String()) + assert.True(t, + strings.Contains(r.logBuffer.String(), expectedLog), + "Log must contain %s, "+"but was %s", + expectedLog, + r.logBuffer.String()) } if len(testCase.expectedLogs) == 0 { assert.Equal(t, "", r.logBuffer.String()) diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index 58c954e7855..6e1bb136b55 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -45,7 +45,9 @@ func withSpanWriter(writeCacheTTL time.Duration, fn func(w *spanWriterTest), opt ) { session := &mocks.Session{} query := &mocks.Query{} - session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) + session.On("Query", + fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), + mock.Anything).Return(query) query.On("Exec").Return(nil) logger, logBuffer := testutils.NewLogger() metricsFactory := metricstest.NewFactory(0) @@ -192,13 +194,20 @@ func TestSpanWriter(t *testing.T) { // note: using matchOnce below because we only want one tag to be inserted w.session.On("Query", stringMatcher(insertTag), matchOnce()).Return(tagsQuery) - w.session.On("Query", stringMatcher(serviceNameIndex), matchEverything()).Return(serviceNameQuery) - w.session.On("Query", stringMatcher(serviceOperationIndex), matchEverything()).Return(serviceOperationNameQuery) + w.session.On("Query", + stringMatcher(serviceNameIndex), + matchEverything()).Return(serviceNameQuery) + w.session.On("Query", + stringMatcher(serviceOperationIndex), + matchEverything()).Return(serviceOperationNameQuery) - w.session.On("Query", stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) + w.session.On("Query", + stringMatcher(durationIndex), + matchOnce()).Return(durationNoOperationQuery) w.writer.serviceNamesWriter = func(serviceName string) error { return testCase.serviceNameError } - w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return testCase.serviceNameError } + w.writer.operationNamesWriter = + func(serviceName, operationName, spanKind string) error { return testCase.serviceNameError } err := w.writer.WriteSpan(span) if testCase.expectedError == "" { @@ -207,7 +216,11 @@ func TestSpanWriter(t *testing.T) { assert.EqualError(t, err, testCase.expectedError) } for _, expectedLog := range testCase.expectedLogs { - assert.True(t, strings.Contains(w.logBuffer.String(), expectedLog), "Log must contain %s, but was %s", expectedLog, w.logBuffer.String()) + assert.True(t, + strings.Contains(w.logBuffer.String(), expectedLog), + "Log must contain %s, but was %s", + expectedLog, + w.logBuffer.String()) } if len(testCase.expectedLogs) == 0 { assert.Equal(t, "", w.logBuffer.String()) @@ -306,7 +319,9 @@ func TestStorageMode_IndexOnly(t *testing.T) { durationNoOperationQuery.On("Exec").Return(nil) w.session.On("Query", stringMatcher(serviceNameIndex), matchEverything()).Return(serviceNameQuery) - w.session.On("Query", stringMatcher(serviceOperationIndex), matchEverything()).Return(serviceOperationNameQuery) + w.session.On("Query", + stringMatcher(serviceOperationIndex), + matchEverything()).Return(serviceOperationNameQuery) w.session.On("Query", stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) err := w.writer.WriteSpan(span) diff --git a/plugin/storage/es/spanstore/reader.go b/plugin/storage/es/spanstore/reader.go index 893151c4005..f8b80a097bf 100644 --- a/plugin/storage/es/spanstore/reader.go +++ b/plugin/storage/es/spanstore/reader.go @@ -245,7 +245,8 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { span, ctx := opentracing.StartSpanFromContext(ctx, "GetOperations") defer span.Finish() currentTime := time.Now() diff --git a/plugin/storage/es/spanstore/reader_test.go b/plugin/storage/es/spanstore/reader_test.go index 9f352f05386..5e3ac56e687 100644 --- a/plugin/storage/es/spanstore/reader_test.go +++ b/plugin/storage/es/spanstore/reader_test.go @@ -538,7 +538,8 @@ func returnSearchFunc(typ string, r *spanReaderTest) (interface{}, error) { if typ == servicesAggregation { return r.reader.GetServices(context.Background()) } else if typ == operationsAggregation { - return r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "someService", SpanKind: ""}) + return r.reader.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "someService", SpanKind: ""}) } else if typ == traceIDAggregation { return r.reader.findTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) } diff --git a/plugin/storage/es/spanstore/service_operation_test.go b/plugin/storage/es/spanstore/service_operation_test.go index 258e5a38597..2b16c8597bf 100644 --- a/plugin/storage/es/spanstore/service_operation_test.go +++ b/plugin/storage/es/spanstore/service_operation_test.go @@ -122,7 +122,8 @@ func TestSpanReader_GetOperationsEmptyIndex(t *testing.T) { Return(&elastic.MultiSearchResult{ Responses: []*elastic.SearchResult{}, }, nil) - services, err := r.reader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "foo", SpanKind: ""}) + services, err := r.reader.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "foo", SpanKind: ""}) require.NoError(t, err) assert.Empty(t, services) }) diff --git a/plugin/storage/grpc/proto/storage.proto b/plugin/storage/grpc/proto/storage.proto index 8a8ca57057a..a77ae63b65d 100644 --- a/plugin/storage/grpc/proto/storage.proto +++ b/plugin/storage/grpc/proto/storage.proto @@ -85,7 +85,8 @@ message Operation { } message GetOperationsResponse { - repeated Operation operations = 1; + repeated string operations = 1; // deprecated + repeated Operation operations_v2 = 2; } message TraceQueryParameters { diff --git a/plugin/storage/grpc/shared/grpc_client.go b/plugin/storage/grpc/shared/grpc_client.go index 2cb73f6923d..cb6147906c3 100644 --- a/plugin/storage/grpc/shared/grpc_client.go +++ b/plugin/storage/grpc/shared/grpc_client.go @@ -104,7 +104,8 @@ func (c *grpcClient) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { resp, err := c.readerClient.GetOperations(upgradeContextWithBearerToken(ctx), &storage_v1.GetOperationsRequest{ Service: query.ServiceName, SpanKind: query.SpanKind, @@ -113,8 +114,8 @@ func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.Operati return nil, errors.Wrap(err, "plugin error") } - operations := make([]*spanstore.Operation, len(resp.Operations)) - for idx, operation := range resp.Operations { + operations := make([]*spanstore.Operation, len(resp.OperationsV2)) + for idx, operation := range resp.OperationsV2 { operations[idx] = &spanstore.Operation{ Name: operation.Name, SpanKind: operation.SpanKind, diff --git a/plugin/storage/grpc/shared/grpc_client_test.go b/plugin/storage/grpc/shared/grpc_client_test.go index 0ad47c6cb85..17cc2ea4e9b 100644 --- a/plugin/storage/grpc/shared/grpc_client_test.go +++ b/plugin/storage/grpc/shared/grpc_client_test.go @@ -124,10 +124,11 @@ func TestGRPCClientGetOperations(t *testing.T) { r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ Service: "service-a", }).Return(&storage_v1.GetOperationsResponse{ - Operations: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}, + OperationsV2: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}, }, nil) - s, err := r.client.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-a"}) + s, err := r.client.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "service-a"}) assert.NoError(t, err) assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, s) }) diff --git a/plugin/storage/grpc/shared/grpc_server.go b/plugin/storage/grpc/shared/grpc_server.go index 21faf85329c..2681d578a94 100644 --- a/plugin/storage/grpc/shared/grpc_server.go +++ b/plugin/storage/grpc/shared/grpc_server.go @@ -78,8 +78,12 @@ func (s *grpcServer) GetServices(ctx context.Context, r *storage_v1.GetServicesR } // GetOperations returns the operations of a given service -func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperationsRequest) (*storage_v1.GetOperationsResponse, error) { - operations, err := s.Impl.SpanReader().GetOperations(ctx, &spanstore.OperationQueryParameters{ServiceName: r.Service, SpanKind: r.SpanKind}) +func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperationsRequest) ( + *storage_v1.GetOperationsResponse, error) { + operations, err := s.Impl.SpanReader().GetOperations(ctx, &spanstore.OperationQueryParameters{ + ServiceName: r.Service, + SpanKind: r.SpanKind, + }) if err != nil { return nil, err } @@ -91,7 +95,7 @@ func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperati } } return &storage_v1.GetOperationsResponse{ - Operations: grpcOperation, + OperationsV2: grpcOperation, }, nil } diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index 6515d69e4f4..27c93fb1e6b 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -87,14 +87,17 @@ func TestGRPCServerGetServices(t *testing.T) { func TestGRPCServerGetOperations(t *testing.T) { withGRPCServer(func(r *grpcServerTest) { - r.impl.spanReader.On("GetOperations", mock.Anything, &spanstore.OperationQueryParameters{ServiceName: "service-a"}). + r.impl.spanReader.On("GetOperations", + mock.Anything, + &spanstore.OperationQueryParameters{ServiceName: "service-a"}). Return([]*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, nil) s, err := r.server.GetOperations(context.Background(), &storage_v1.GetOperationsRequest{ Service: "service-a", }) assert.NoError(t, err) - assert.Equal(t, &storage_v1.GetOperationsResponse{Operations: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}}, s) + assert.Equal(t, &storage_v1.GetOperationsResponse{OperationsV2: []*storage_v1.Operation{{Name: "operation-a", + SpanKind: ""}}}, s) }) } diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index ae2fdb58b73..5054f3a45bc 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -150,14 +150,17 @@ func (s *StorageIntegration) testGetOperations(t *testing.T) { defer s.cleanUp(t) expected := []*spanstore.Operation{ - {Name: "example-operation-1", SpanKind: ""}, {Name: "example-operation-3", SpanKind: ""}, {Name: "example-operation-4", SpanKind: ""}} + {Name: "example-operation-1", SpanKind: ""}, + {Name: "example-operation-3", SpanKind: ""}, + {Name: "example-operation-4", SpanKind: ""}} s.loadParseAndWriteExampleTrace(t) s.refresh(t) var actual []*spanstore.Operation found := s.waitForCondition(t, func(t *testing.T) bool { var err error - actual, err = s.SpanReader.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "example-service-1", SpanKind: ""}) + actual, err = s.SpanReader.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "example-service-1", SpanKind: ""}) require.NoError(t, err) return assert.ObjectsAreEqualValues(expected, actual) }) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index 3acde074848..dffb41642fa 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -119,7 +119,8 @@ func (r *ingester) GetServices(ctx context.Context) ([]string, error) { return nil, nil } -func (r *ingester) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (r *ingester) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { return nil, nil } diff --git a/plugin/storage/memory/memory.go b/plugin/storage/memory/memory.go index 0356c64e8b9..c4eb84f99d7 100644 --- a/plugin/storage/memory/memory.go +++ b/plugin/storage/memory/memory.go @@ -182,7 +182,8 @@ func (m *Store) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (m *Store) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (m *Store) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { m.RLock() defer m.RUnlock() var retMe []*spanstore.Operation diff --git a/plugin/storage/memory/memory_test.go b/plugin/storage/memory/memory_test.go index b3034ccbffd..40ebf952b23 100644 --- a/plugin/storage/memory/memory_test.go +++ b/plugin/storage/memory/memory_test.go @@ -233,7 +233,8 @@ func TestStoreGetAllOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan1)) assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) - operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: ""}) + operations, err := store.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: ""}) assert.NoError(t, err) assert.Len(t, operations, 3) assert.EqualValues(t, childSpan1.OperationName, (*operations[0]).Name) @@ -246,7 +247,8 @@ func TestStoreGetServerOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan1)) assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) - operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: "server"}) + operations, err := store.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: "server"}) assert.NoError(t, err) assert.Len(t, operations, 1) assert.EqualValues(t, childSpan1.OperationName, operations[0].Name) @@ -256,7 +258,8 @@ func TestStoreGetServerOperationsFound(t *testing.T) { func TestStoreGetOperationsNotFound(t *testing.T) { withPopulatedMemoryStore(func(store *Store) { - operations, err := store.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "notAService", SpanKind: ""}) + operations, err := store.GetOperations(context.Background(), + &spanstore.OperationQueryParameters{ServiceName: "notAService", SpanKind: ""}) assert.NoError(t, err) assert.Len(t, operations, 0) }) diff --git a/proto-gen/storage_v1/storage.pb.go b/proto-gen/storage_v1/storage.pb.go index d7bcf52fb40..db6137ee4f5 100644 --- a/proto-gen/storage_v1/storage.pb.go +++ b/proto-gen/storage_v1/storage.pb.go @@ -6,10 +6,6 @@ package storage_v1 import ( context "context" fmt "fmt" - io "io" - math "math" - time "time" - _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "github.com/gogo/protobuf/types" @@ -18,6 +14,9 @@ import ( github_com_jaegertracing_jaeger_model "github.com/jaegertracing/jaeger/model" model "github.com/jaegertracing/jaeger/model" grpc "google.golang.org/grpc" + io "io" + math "math" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. @@ -459,7 +458,8 @@ func (m *Operation) GetSpanKind() string { } type GetOperationsResponse struct { - Operations []*Operation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` + Operations []string `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` + OperationsV2 []*Operation `protobuf:"bytes,2,rep,name=operations_v2,json=operationsV2,proto3" json:"operations_v2,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -498,13 +498,20 @@ func (m *GetOperationsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_GetOperationsResponse proto.InternalMessageInfo -func (m *GetOperationsResponse) GetOperations() []*Operation { +func (m *GetOperationsResponse) GetOperations() []string { if m != nil { return m.Operations } return nil } +func (m *GetOperationsResponse) GetOperationsV2() []*Operation { + if m != nil { + return m.OperationsV2 + } + return nil +} + type TraceQueryParameters struct { ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` OperationName string `protobuf:"bytes,2,opt,name=operation_name,json=operationName,proto3" json:"operation_name,omitempty"` @@ -828,66 +835,67 @@ func init() { proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffd func init() { golang_proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffdb) } var fileDescriptor_0d2c4ccf1453ffdb = []byte{ - // 941 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x73, 0xdb, 0x44, - 0x14, 0x46, 0x8d, 0x5d, 0x5b, 0xcf, 0x4e, 0x49, 0x36, 0x06, 0x84, 0x68, 0xed, 0x20, 0x48, 0x13, - 0x98, 0x41, 0x26, 0xe6, 0x00, 0x03, 0x65, 0x00, 0x37, 0xa9, 0x27, 0x40, 0xa1, 0xa8, 0x81, 0xce, - 0x50, 0x06, 0xcd, 0x3a, 0x5a, 0x14, 0x35, 0xd1, 0x4a, 0x95, 0x56, 0x9e, 0xe4, 0xce, 0x1f, 0xc0, - 0x91, 0x13, 0x57, 0xfe, 0x0d, 0x8e, 0x3d, 0x72, 0xe6, 0x10, 0x18, 0x73, 0xe4, 0x9f, 0x60, 0xf6, - 0x87, 0x14, 0xff, 0xd0, 0xe4, 0xd7, 0xf4, 0xa6, 0x7d, 0xfb, 0xbd, 0x6f, 0xbf, 0x7d, 0x6f, 0xdf, - 0x67, 0xc3, 0x62, 0xca, 0xa2, 0x04, 0xfb, 0xc4, 0x8e, 0x93, 0x88, 0x45, 0x68, 0xf9, 0x09, 0x26, - 0x3e, 0x49, 0xec, 0x3c, 0x3a, 0xda, 0x34, 0x5b, 0x7e, 0xe4, 0x47, 0x62, 0xb7, 0xcb, 0xbf, 0x24, - 0xd0, 0xec, 0xf8, 0x51, 0xe4, 0x1f, 0x92, 0xae, 0x58, 0x0d, 0xb3, 0x9f, 0xba, 0x2c, 0x08, 0x49, - 0xca, 0x70, 0x18, 0x2b, 0x40, 0x7b, 0x16, 0xe0, 0x65, 0x09, 0x66, 0x41, 0x44, 0xd5, 0x7e, 0x23, - 0x8c, 0x3c, 0x72, 0x28, 0x17, 0xd6, 0x6f, 0x1a, 0xbc, 0x3c, 0x20, 0x6c, 0x8b, 0xc4, 0x84, 0x7a, - 0x84, 0xee, 0x05, 0x24, 0x75, 0xc8, 0xd3, 0x8c, 0xa4, 0x0c, 0xdd, 0x05, 0x48, 0x19, 0x4e, 0x98, - 0xcb, 0x0f, 0x30, 0xb4, 0x55, 0x6d, 0xa3, 0xd1, 0x33, 0x6d, 0x49, 0x6e, 0xe7, 0xe4, 0xf6, 0x6e, - 0x7e, 0x7a, 0xbf, 0xfe, 0xec, 0xa4, 0xf3, 0xc2, 0x2f, 0x7f, 0x77, 0x34, 0x47, 0x17, 0x79, 0x7c, - 0x07, 0x7d, 0x02, 0x75, 0x42, 0x3d, 0x49, 0x71, 0xed, 0x12, 0x14, 0x35, 0x42, 0x3d, 0x1e, 0xb7, - 0x86, 0xf0, 0xca, 0x9c, 0xbe, 0x34, 0x8e, 0x68, 0x4a, 0xd0, 0x00, 0x9a, 0xde, 0x44, 0xdc, 0xd0, - 0x56, 0x17, 0x36, 0x1a, 0xbd, 0x5b, 0xb6, 0xaa, 0x24, 0x8e, 0x03, 0x77, 0xd4, 0xb3, 0x8b, 0xd4, - 0xe3, 0x2f, 0x03, 0x7a, 0xd0, 0xaf, 0xf0, 0x23, 0x9c, 0xa9, 0x44, 0xeb, 0x23, 0x58, 0x7a, 0x94, - 0x04, 0x8c, 0x3c, 0x8c, 0x31, 0xcd, 0x6f, 0xbf, 0x0e, 0x95, 0x34, 0xc6, 0x54, 0xdd, 0x7b, 0x65, - 0x86, 0x54, 0x20, 0x05, 0xc0, 0x5a, 0x81, 0xe5, 0x89, 0x64, 0x29, 0xcd, 0xa2, 0xf0, 0xe2, 0x80, - 0xb0, 0xdd, 0x04, 0xef, 0x91, 0x9c, 0xf0, 0x31, 0xd4, 0x19, 0x5f, 0xbb, 0x81, 0x27, 0x48, 0x9b, - 0xfd, 0x4f, 0xb9, 0x94, 0xbf, 0x4e, 0x3a, 0xef, 0xf8, 0x01, 0xdb, 0xcf, 0x86, 0xf6, 0x5e, 0x14, - 0x76, 0xe5, 0x31, 0x1c, 0x18, 0x50, 0x5f, 0xad, 0xba, 0xb2, 0x61, 0x82, 0x6d, 0x67, 0x6b, 0x7c, - 0xd2, 0xa9, 0xa9, 0x4f, 0xa7, 0x26, 0x18, 0x77, 0x3c, 0xab, 0x05, 0x68, 0x40, 0xd8, 0x43, 0x92, - 0x8c, 0x82, 0xbd, 0xa2, 0x83, 0xd6, 0x26, 0xac, 0x4c, 0x45, 0x55, 0xdd, 0x4c, 0xa8, 0xa7, 0x2a, - 0x26, 0x6a, 0xa6, 0x3b, 0xc5, 0xda, 0xba, 0x0f, 0xad, 0x01, 0x61, 0x5f, 0xc7, 0x44, 0x3e, 0x99, - 0xe2, 0x31, 0x18, 0x50, 0x53, 0x18, 0x21, 0x5e, 0x77, 0xf2, 0x25, 0x7a, 0x0d, 0x74, 0x5e, 0x07, - 0xf7, 0x20, 0xa0, 0x9e, 0x68, 0x31, 0xa7, 0x8b, 0x31, 0xfd, 0x22, 0xa0, 0x9e, 0x75, 0x07, 0xf4, - 0x82, 0x0b, 0x21, 0xa8, 0x50, 0x1c, 0xe6, 0x04, 0xe2, 0xfb, 0xec, 0xec, 0x6f, 0xe1, 0xa5, 0x19, - 0x31, 0xea, 0x06, 0x77, 0x00, 0xa2, 0x22, 0xaa, 0xfa, 0x7e, 0xd3, 0x9e, 0x9b, 0x20, 0xbb, 0x48, - 0x75, 0x26, 0xf0, 0xd6, 0xef, 0x15, 0x68, 0x89, 0x0a, 0x7e, 0x93, 0x91, 0xe4, 0xf8, 0x01, 0x4e, - 0x70, 0x48, 0x18, 0x49, 0x52, 0xf4, 0x3a, 0x34, 0xd5, 0xad, 0xdc, 0x09, 0xa1, 0x0d, 0x15, 0xfb, - 0x8a, 0xeb, 0x5d, 0x83, 0x1b, 0x05, 0x93, 0x04, 0x49, 0xd1, 0x8b, 0x45, 0x54, 0xc0, 0xb6, 0xa1, - 0xc2, 0xb0, 0x9f, 0x1a, 0x0b, 0x42, 0xda, 0x66, 0x89, 0xb4, 0x32, 0x01, 0xf6, 0x2e, 0xf6, 0xd3, - 0x6d, 0xca, 0x92, 0x63, 0x47, 0xa4, 0xa3, 0xcf, 0xe1, 0xc6, 0xe9, 0x08, 0xba, 0x61, 0x40, 0x8d, - 0xca, 0x25, 0x66, 0xa8, 0x59, 0x8c, 0xe1, 0xfd, 0x80, 0xce, 0x72, 0xe1, 0x23, 0xa3, 0x7a, 0x35, - 0x2e, 0x7c, 0x84, 0xee, 0x41, 0x33, 0x37, 0x15, 0xa1, 0xea, 0xba, 0x60, 0x7a, 0x75, 0x8e, 0x69, - 0x4b, 0x81, 0x24, 0xd1, 0xaf, 0x9c, 0xa8, 0x91, 0x27, 0x72, 0x4d, 0x53, 0x3c, 0xf8, 0xc8, 0xa8, - 0x5d, 0x85, 0x07, 0x1f, 0xa1, 0x5b, 0x00, 0x34, 0x0b, 0x5d, 0x31, 0x0d, 0xa9, 0x51, 0x5f, 0xd5, - 0x36, 0xaa, 0x8e, 0x4e, 0xb3, 0x50, 0x14, 0x39, 0x35, 0xdf, 0x07, 0xbd, 0xa8, 0x2c, 0x5a, 0x82, - 0x85, 0x03, 0x72, 0xac, 0x7a, 0xcb, 0x3f, 0x51, 0x0b, 0xaa, 0x23, 0x7c, 0x98, 0xe5, 0xad, 0x94, - 0x8b, 0x0f, 0xaf, 0x7d, 0xa0, 0x59, 0x0e, 0x2c, 0xdf, 0x0b, 0xa8, 0x27, 0x69, 0xf2, 0x51, 0xf8, - 0x18, 0xaa, 0x4f, 0x79, 0xdf, 0x94, 0x35, 0xac, 0x5f, 0xb0, 0xb9, 0x8e, 0xcc, 0xb2, 0xb6, 0x01, - 0x71, 0xab, 0x28, 0x1e, 0xf3, 0xdd, 0xfd, 0x8c, 0x1e, 0xa0, 0x2e, 0x54, 0xf9, 0xb3, 0xcf, 0x1f, - 0x73, 0x99, 0xdf, 0x28, 0xeb, 0x92, 0x38, 0x6b, 0x17, 0x56, 0x0a, 0x69, 0x3b, 0x5b, 0xcf, 0x4b, - 0xdc, 0x08, 0x5a, 0xd3, 0xac, 0x6a, 0xe0, 0x7e, 0x04, 0x3d, 0x37, 0x2f, 0x29, 0xb1, 0xd9, 0xff, - 0xec, 0xaa, 0xee, 0x55, 0x2f, 0xd8, 0xeb, 0xca, 0xbe, 0xd2, 0xde, 0x13, 0x58, 0xe2, 0x57, 0x14, - 0x46, 0x9a, 0x3c, 0x38, 0xcc, 0xfc, 0x80, 0xa2, 0xef, 0x40, 0x2f, 0x8c, 0x15, 0xbd, 0x51, 0x72, - 0x91, 0x59, 0xcf, 0x36, 0xdf, 0x3c, 0x1b, 0x24, 0xef, 0xd2, 0xfb, 0x6f, 0x41, 0x1e, 0xe6, 0x10, - 0xec, 0x15, 0x87, 0x3d, 0x82, 0x7a, 0x6e, 0xd8, 0xc8, 0x2a, 0xa1, 0x99, 0x71, 0x73, 0x73, 0xad, - 0x04, 0x33, 0xdf, 0xd6, 0x77, 0x35, 0xf4, 0x03, 0x34, 0x26, 0x3c, 0x18, 0xad, 0x95, 0x73, 0xcf, - 0x38, 0xb7, 0x79, 0xfb, 0x3c, 0x98, 0xea, 0xcb, 0x10, 0x16, 0xa7, 0x1c, 0x12, 0xad, 0x97, 0x27, - 0xce, 0x19, 0xba, 0xb9, 0x71, 0x3e, 0x50, 0x9d, 0xf1, 0x18, 0xe0, 0x74, 0x08, 0x50, 0x59, 0x8d, - 0xe7, 0x66, 0xe4, 0xe2, 0xe5, 0x71, 0xa1, 0x39, 0xf9, 0xe0, 0xd0, 0xed, 0xb3, 0xe8, 0x4f, 0xdf, - 0xb9, 0xb9, 0x7e, 0x2e, 0x4e, 0x75, 0xfb, 0x67, 0x0d, 0x8c, 0xe9, 0x7f, 0x0f, 0x13, 0x5d, 0xdf, - 0x17, 0x3f, 0xd3, 0x93, 0xdb, 0xe8, 0xad, 0xf2, 0xba, 0x94, 0xfc, 0x41, 0x32, 0xdf, 0xbe, 0x08, - 0x54, 0xca, 0xe8, 0xdf, 0x7c, 0x36, 0x6e, 0x6b, 0x7f, 0x8e, 0xdb, 0xda, 0x3f, 0xe3, 0xb6, 0xf6, - 0xc7, 0xbf, 0x6d, 0xed, 0x7b, 0x50, 0x59, 0xee, 0x68, 0x73, 0x78, 0x5d, 0x38, 0xdd, 0x7b, 0xff, - 0x07, 0x00, 0x00, 0xff, 0xff, 0x80, 0x63, 0x86, 0x8e, 0x14, 0x0a, 0x00, 0x00, + // 957 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4b, 0x73, 0xdb, 0x54, + 0x14, 0x46, 0x89, 0x5d, 0x5b, 0xc7, 0x4e, 0x49, 0x6e, 0x0c, 0x08, 0xd1, 0xda, 0x41, 0x90, 0x26, + 0x30, 0x83, 0x4c, 0xcc, 0x02, 0x86, 0xc7, 0x40, 0xdd, 0xa4, 0x9e, 0x00, 0x85, 0xa2, 0x66, 0xda, + 0x19, 0xca, 0xa0, 0xb9, 0x8e, 0x2e, 0x8a, 0x9a, 0xe8, 0x4a, 0x95, 0xae, 0x3c, 0x09, 0x6b, 0x7e, + 0x00, 0x4b, 0x56, 0x6c, 0xf9, 0x1b, 0x2c, 0xbb, 0x64, 0xcd, 0x22, 0x30, 0x61, 0xc9, 0x9f, 0x60, + 0xee, 0x43, 0xf2, 0x4b, 0x93, 0xa4, 0x19, 0x76, 0x3a, 0xe7, 0x7e, 0xe7, 0xbb, 0xe7, 0x71, 0xcf, + 0x67, 0xc3, 0x52, 0xca, 0xa2, 0x04, 0xfb, 0xc4, 0x8e, 0x93, 0x88, 0x45, 0x68, 0xe5, 0x09, 0x26, + 0x3e, 0x49, 0xec, 0xdc, 0x3b, 0xda, 0x32, 0x5b, 0x7e, 0xe4, 0x47, 0xe2, 0xb4, 0xcb, 0xbf, 0x24, + 0xd0, 0xec, 0xf8, 0x51, 0xe4, 0x1f, 0x91, 0xae, 0xb0, 0x86, 0xd9, 0x0f, 0x5d, 0x16, 0x84, 0x24, + 0x65, 0x38, 0x8c, 0x15, 0xa0, 0x3d, 0x0b, 0xf0, 0xb2, 0x04, 0xb3, 0x20, 0xa2, 0xea, 0xbc, 0x11, + 0x46, 0x1e, 0x39, 0x92, 0x86, 0xf5, 0xab, 0x06, 0x2f, 0x0f, 0x08, 0xdb, 0x26, 0x31, 0xa1, 0x1e, + 0xa1, 0xfb, 0x01, 0x49, 0x1d, 0xf2, 0x34, 0x23, 0x29, 0x43, 0x77, 0x00, 0x52, 0x86, 0x13, 0xe6, + 0xf2, 0x0b, 0x0c, 0x6d, 0x4d, 0xdb, 0x6c, 0xf4, 0x4c, 0x5b, 0x92, 0xdb, 0x39, 0xb9, 0xbd, 0x97, + 0xdf, 0xde, 0xaf, 0x3f, 0x3b, 0xed, 0xbc, 0xf0, 0xf3, 0x5f, 0x1d, 0xcd, 0xd1, 0x45, 0x1c, 0x3f, + 0x41, 0x9f, 0x42, 0x9d, 0x50, 0x4f, 0x52, 0x2c, 0x3c, 0x07, 0x45, 0x8d, 0x50, 0x8f, 0xfb, 0xad, + 0x21, 0xbc, 0x32, 0x97, 0x5f, 0x1a, 0x47, 0x34, 0x25, 0x68, 0x00, 0x4d, 0x6f, 0xc2, 0x6f, 0x68, + 0x6b, 0x8b, 0x9b, 0x8d, 0xde, 0x4d, 0x5b, 0x75, 0x12, 0xc7, 0x81, 0x3b, 0xea, 0xd9, 0x45, 0xe8, + 0xc9, 0x97, 0x01, 0x3d, 0xec, 0x57, 0xf8, 0x15, 0xce, 0x54, 0xa0, 0xf5, 0x11, 0x2c, 0x3f, 0x4a, + 0x02, 0x46, 0x1e, 0xc4, 0x98, 0xe6, 0xd5, 0x6f, 0x40, 0x25, 0x8d, 0x31, 0x55, 0x75, 0xaf, 0xce, + 0x90, 0x0a, 0xa4, 0x00, 0x58, 0xab, 0xb0, 0x32, 0x11, 0x2c, 0x53, 0xb3, 0x28, 0xbc, 0x38, 0x20, + 0x6c, 0x2f, 0xc1, 0xfb, 0x24, 0x27, 0x7c, 0x0c, 0x75, 0xc6, 0x6d, 0x37, 0xf0, 0x04, 0x69, 0xb3, + 0xff, 0x19, 0x4f, 0xe5, 0xcf, 0xd3, 0xce, 0x3b, 0x7e, 0xc0, 0x0e, 0xb2, 0xa1, 0xbd, 0x1f, 0x85, + 0x5d, 0x79, 0x0d, 0x07, 0x06, 0xd4, 0x57, 0x56, 0x57, 0x0e, 0x4c, 0xb0, 0xed, 0x6e, 0x9f, 0x9d, + 0x76, 0x6a, 0xea, 0xd3, 0xa9, 0x09, 0xc6, 0x5d, 0xcf, 0x6a, 0x01, 0x1a, 0x10, 0xf6, 0x80, 0x24, + 0xa3, 0x60, 0xbf, 0x98, 0xa0, 0xb5, 0x05, 0xab, 0x53, 0x5e, 0xd5, 0x37, 0x13, 0xea, 0xa9, 0xf2, + 0x89, 0x9e, 0xe9, 0x4e, 0x61, 0x5b, 0xf7, 0xa0, 0x35, 0x20, 0xec, 0xeb, 0x98, 0xc8, 0x27, 0x53, + 0x3c, 0x06, 0x03, 0x6a, 0x0a, 0x23, 0x92, 0xd7, 0x9d, 0xdc, 0x44, 0xaf, 0x81, 0xce, 0xfb, 0xe0, + 0x1e, 0x06, 0xd4, 0x13, 0x23, 0xe6, 0x74, 0x31, 0xa6, 0x5f, 0x04, 0xd4, 0xb3, 0x3e, 0x06, 0xbd, + 0xe0, 0x42, 0x08, 0x2a, 0x14, 0x87, 0x39, 0x81, 0xf8, 0x3e, 0x3f, 0xfa, 0x47, 0x78, 0x69, 0x26, + 0x19, 0x55, 0x41, 0x1b, 0x20, 0x2a, 0xbc, 0xaa, 0x86, 0x09, 0x0f, 0xba, 0x0d, 0x4b, 0x63, 0xcb, + 0x1d, 0xf5, 0x8c, 0x05, 0xf1, 0x34, 0x6e, 0xd8, 0x73, 0x4b, 0x66, 0x17, 0xec, 0x4e, 0x73, 0x1c, + 0xf2, 0xb0, 0x67, 0xfd, 0x56, 0x81, 0x96, 0x68, 0xf3, 0x37, 0x19, 0x49, 0x4e, 0xee, 0xe3, 0x04, + 0x87, 0x84, 0x91, 0x24, 0x45, 0xaf, 0x43, 0x53, 0x95, 0xee, 0x4e, 0x54, 0xd3, 0x50, 0xbe, 0xaf, + 0x78, 0x51, 0xeb, 0x70, 0xbd, 0xe0, 0x92, 0x20, 0x59, 0xd9, 0x38, 0x29, 0x01, 0xdb, 0x81, 0x0a, + 0xc3, 0x7e, 0x6a, 0x2c, 0x8a, 0xe4, 0xb6, 0x4a, 0x92, 0x2b, 0x4b, 0xc0, 0xde, 0xc3, 0x7e, 0xba, + 0x43, 0x59, 0x72, 0xe2, 0x88, 0x70, 0xf4, 0x39, 0x5c, 0x1f, 0xef, 0xa9, 0x1b, 0x06, 0xd4, 0xa8, + 0x3c, 0xc7, 0xa2, 0x35, 0x8b, 0x5d, 0xbd, 0x17, 0xd0, 0x59, 0x2e, 0x7c, 0x6c, 0x54, 0xaf, 0xc6, + 0x85, 0x8f, 0xd1, 0x5d, 0x68, 0xe6, 0xca, 0x23, 0xb2, 0xba, 0x26, 0x98, 0x5e, 0x9d, 0x63, 0xda, + 0x56, 0x20, 0x49, 0xf4, 0x0b, 0x27, 0x6a, 0xe4, 0x81, 0x3c, 0xa7, 0x29, 0x1e, 0x7c, 0x6c, 0xd4, + 0xae, 0xc2, 0x83, 0x8f, 0xd1, 0x4d, 0x00, 0x9a, 0x85, 0xae, 0x58, 0x99, 0xd4, 0xa8, 0xaf, 0x69, + 0x9b, 0x55, 0x47, 0xa7, 0x59, 0x28, 0x9a, 0x9c, 0x9a, 0xef, 0x83, 0x5e, 0x74, 0x16, 0x2d, 0xc3, + 0xe2, 0x21, 0x39, 0x51, 0xb3, 0xe5, 0x9f, 0xa8, 0x05, 0xd5, 0x11, 0x3e, 0xca, 0xf2, 0x51, 0x4a, + 0xe3, 0xc3, 0x85, 0x0f, 0x34, 0xcb, 0x81, 0x95, 0xbb, 0x01, 0xf5, 0x24, 0x4d, 0xbe, 0x2f, 0x9f, + 0x40, 0xf5, 0x29, 0x9f, 0x9b, 0xd2, 0x8f, 0x8d, 0x4b, 0x0e, 0xd7, 0x91, 0x51, 0xd6, 0x0e, 0x20, + 0xae, 0x27, 0xc5, 0x8b, 0xbf, 0x73, 0x90, 0xd1, 0x43, 0xd4, 0x85, 0x2a, 0xdf, 0x8d, 0x5c, 0xe9, + 0xca, 0x44, 0x49, 0xe9, 0x9b, 0xc4, 0x59, 0x7b, 0xb0, 0x5a, 0xa4, 0xb6, 0xbb, 0xfd, 0x7f, 0x25, + 0x37, 0x82, 0xd6, 0x34, 0xab, 0xda, 0xca, 0xef, 0x41, 0xcf, 0x15, 0x4e, 0xa6, 0xd8, 0xec, 0xdf, + 0xbe, 0xaa, 0xc4, 0xd5, 0x0b, 0xf6, 0xba, 0xd2, 0xb8, 0xb4, 0xf7, 0x04, 0x96, 0x79, 0x89, 0x42, + 0x6d, 0x93, 0xfb, 0x47, 0x99, 0x1f, 0x50, 0xf4, 0x10, 0xf4, 0x42, 0x7d, 0xd1, 0x1b, 0x25, 0x85, + 0xcc, 0x0a, 0xbb, 0xf9, 0xe6, 0xf9, 0x20, 0x59, 0x4b, 0xef, 0xdf, 0x45, 0x79, 0x99, 0x43, 0xb0, + 0x57, 0x5c, 0xf6, 0x08, 0xea, 0xb9, 0xaa, 0x23, 0xab, 0x84, 0x66, 0x46, 0xf2, 0xcd, 0xf5, 0x12, + 0xcc, 0xfc, 0x58, 0xdf, 0xd5, 0xd0, 0x77, 0xd0, 0x98, 0x10, 0x6a, 0xb4, 0x5e, 0xce, 0x3d, 0x23, + 0xef, 0xe6, 0xad, 0x8b, 0x60, 0x6a, 0x2e, 0x43, 0x58, 0x9a, 0x92, 0x51, 0xb4, 0x51, 0x1e, 0x38, + 0xa7, 0xfa, 0xe6, 0xe6, 0xc5, 0x40, 0x75, 0xc7, 0x63, 0x80, 0xf1, 0x12, 0xa0, 0xb2, 0x1e, 0xcf, + 0xed, 0xc8, 0xe5, 0xdb, 0xe3, 0x42, 0x73, 0xf2, 0xc1, 0xa1, 0x5b, 0xe7, 0xd1, 0x8f, 0xdf, 0xb9, + 0xb9, 0x71, 0x21, 0x4e, 0x4d, 0xfb, 0x27, 0x0d, 0x8c, 0xe9, 0xbf, 0x18, 0x13, 0x53, 0x3f, 0x10, + 0xbf, 0xe5, 0x93, 0xc7, 0xe8, 0xad, 0xf2, 0xbe, 0x94, 0xfc, 0x8b, 0x32, 0xdf, 0xbe, 0x0c, 0x54, + 0xa6, 0xd1, 0xbf, 0xf1, 0xec, 0xac, 0xad, 0xfd, 0x71, 0xd6, 0xd6, 0xfe, 0x3e, 0x6b, 0x6b, 0xbf, + 0xff, 0xd3, 0xd6, 0xbe, 0x05, 0x15, 0xe5, 0x8e, 0xb6, 0x86, 0xd7, 0x84, 0xd2, 0xbd, 0xf7, 0x5f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0xf7, 0xe6, 0x31, 0x39, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1573,9 +1581,24 @@ func (m *GetOperationsResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if len(m.Operations) > 0 { - for _, msg := range m.Operations { + for _, s := range m.Operations { dAtA[i] = 0xa i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + if len(m.OperationsV2) > 0 { + for _, msg := range m.OperationsV2 { + dAtA[i] = 0x12 + i++ i = encodeVarintStorage(dAtA, i, uint64(msg.Size())) n, err := msg.MarshalTo(dAtA[i:]) if err != nil { @@ -1967,7 +1990,13 @@ func (m *GetOperationsResponse) Size() (n int) { var l int _ = l if len(m.Operations) > 0 { - for _, e := range m.Operations { + for _, s := range m.Operations { + l = len(s) + n += 1 + l + sovStorage(uint64(l)) + } + } + if len(m.OperationsV2) > 0 { + for _, e := range m.OperationsV2 { l = e.Size() n += 1 + l + sovStorage(uint64(l)) } @@ -2946,6 +2975,38 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStorage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStorage + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStorage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operations = append(m.Operations, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperationsV2", wireType) + } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { @@ -2971,8 +3032,8 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Operations = append(m.Operations, &Operation{}) - if err := m.Operations[len(m.Operations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.OperationsV2 = append(m.OperationsV2, &Operation{}) + if err := m.OperationsV2[len(m.OperationsV2)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/storage/spanstore/metrics/decorator.go b/storage/spanstore/metrics/decorator.go index 10128c34533..907fa39ea3c 100644 --- a/storage/spanstore/metrics/decorator.go +++ b/storage/spanstore/metrics/decorator.go @@ -106,7 +106,8 @@ func (m *ReadMetricsDecorator) GetServices(ctx context.Context) ([]string, error } // GetOperations implements spanstore.Reader#GetOperations -func (m *ReadMetricsDecorator) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (m *ReadMetricsDecorator) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { start := time.Now() retMe, err := m.spanReader.GetOperations(ctx, query) m.getOperationsMetrics.emit(err, time.Since(start), len(retMe)) diff --git a/storage/spanstore/metrics/decorator_test.go b/storage/spanstore/metrics/decorator_test.go index 9c876fa0b23..f69c5b624b2 100644 --- a/storage/spanstore/metrics/decorator_test.go +++ b/storage/spanstore/metrics/decorator_test.go @@ -37,13 +37,16 @@ func TestSuccessfulUnderlyingCalls(t *testing.T) { mockReader.On("GetServices", context.Background()).Return([]string{}, nil) mrs.GetServices(context.Background()) operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} - mockReader.On("GetOperations", context.Background(), operationQuery).Return([]*spanstore.Operation{}, nil) + mockReader.On("GetOperations", context.Background(), operationQuery). + Return([]*spanstore.Operation{}, nil) mrs.GetOperations(context.Background(), operationQuery) mockReader.On("GetTrace", context.Background(), model.TraceID{}).Return(&model.Trace{}, nil) mrs.GetTrace(context.Background(), model.TraceID{}) - mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}).Return([]*model.Trace{}, nil) + mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}). + Return([]*model.Trace{}, nil) mrs.FindTraces(context.Background(), &spanstore.TraceQueryParameters{}) - mockReader.On("FindTraceIDs", context.Background(), &spanstore.TraceQueryParameters{}).Return([]model.TraceID{}, nil) + mockReader.On("FindTraceIDs", context.Background(), &spanstore.TraceQueryParameters{}). + Return([]model.TraceID{}, nil) mrs.FindTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) counters, gauges := mf.Snapshot() expecteds := map[string]int64{ @@ -71,7 +74,12 @@ func TestSuccessfulUnderlyingCalls(t *testing.T) { checkExpectedExistingAndNonExistentCounters(t, counters, expecteds, gauges, existingKeys, nonExistentKeys) } -func checkExpectedExistingAndNonExistentCounters(t *testing.T, actualCounters, expectedCounters, actualGauges map[string]int64, existingKeys, nonExistentKeys []string) { +func checkExpectedExistingAndNonExistentCounters(t *testing.T, + actualCounters, + expectedCounters, + actualGauges map[string]int64, + existingKeys, + nonExistentKeys []string) { for k, v := range expectedCounters { assert.EqualValues(t, v, actualCounters[k], k) } @@ -92,16 +100,21 @@ func TestFailingUnderlyingCalls(t *testing.T) { mockReader := mocks.Reader{} mrs := NewReadMetricsDecorator(&mockReader, mf) - mockReader.On("GetServices", context.Background()).Return(nil, errors.New("Failure")) + mockReader.On("GetServices", context.Background()). + Return(nil, errors.New("Failure")) mrs.GetServices(context.Background()) operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} - mockReader.On("GetOperations", context.Background(), operationQuery).Return(nil, errors.New("Failure")) + mockReader.On("GetOperations", context.Background(), operationQuery). + Return(nil, errors.New("Failure")) mrs.GetOperations(context.Background(), operationQuery) - mockReader.On("GetTrace", context.Background(), model.TraceID{}).Return(nil, errors.New("Failure")) + mockReader.On("GetTrace", context.Background(), model.TraceID{}). + Return(nil, errors.New("Failure")) mrs.GetTrace(context.Background(), model.TraceID{}) - mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}).Return(nil, errors.New("Failure")) + mockReader.On("FindTraces", context.Background(), &spanstore.TraceQueryParameters{}). + Return(nil, errors.New("Failure")) mrs.FindTraces(context.Background(), &spanstore.TraceQueryParameters{}) - mockReader.On("FindTraceIDs", context.Background(), &spanstore.TraceQueryParameters{}).Return(nil, errors.New("Failure")) + mockReader.On("FindTraceIDs", context.Background(), &spanstore.TraceQueryParameters{}). + Return(nil, errors.New("Failure")) mrs.FindTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) counters, gauges := mf.Snapshot() expecteds := map[string]int64{ diff --git a/storage/spanstore/mocks/Reader.go b/storage/spanstore/mocks/Reader.go index 8cc305243f2..135f576c802 100644 --- a/storage/spanstore/mocks/Reader.go +++ b/storage/spanstore/mocks/Reader.go @@ -74,11 +74,13 @@ func (_m *Reader) FindTraces(ctx context.Context, query *spanstore.TraceQueryPar } // GetOperations provides a mock function with given fields: ctx, query -func (_m *Reader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (_m *Reader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { ret := _m.Called(ctx, query) var r0 []*spanstore.Operation - if rf, ok := ret.Get(0).(func(context.Context, *spanstore.OperationQueryParameters) []*spanstore.Operation); ok { + if rf, ok := ret.Get(0).(func(context.Context, + *spanstore.OperationQueryParameters) []*spanstore.Operation); ok { r0 = rf(ctx, query) } else { if ret.Get(0) != nil { From 1392f39c06d4db28ee5cbca659e891127c219dec Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Thu, 21 Nov 2019 19:38:04 -0500 Subject: [PATCH 07/12] Merge branch 1921-2 Signed-off-by: Jun Guo --- .../spanstore/operation_names_test.go | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 71bce39b008..1f7ac373f8c 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -107,22 +107,15 @@ func TestOperationNamesStorageWrite(t *testing.T) { err = s.storage.Write("service-c", "operation-d", "") assert.EqualError(t, err, - "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") + "failed to Exec query 'select from "+ + schemas[test.schemaVersion].tableName+ + "': exec error") assert.Equal(t, map[string]string{ "level": "error", "msg": "Failed to exec query", "query": "select from " + schemas[test.schemaVersion].tableName, "error": "exec error", }, s.logBuffer.JSONLine(0)) - err = s.storage.Write("service-c", "operation-d", "") - assert.EqualError(t, err, - "failed to Exec query 'select from "+schemas[test.schemaVersion].tableName+"': exec error") - assert.Equal(t, map[string]string{ - "level": "error", - "msg": "Failed to exec query", - "query": "select from " + schemas[test.schemaVersion].tableName, - "error": "exec error", - }, s.logBuffer.JSONLine(0)) counts, _ := s.metricsFactory.Snapshot() assert.Equal(t, map[string]int64{ @@ -131,9 +124,9 @@ func TestOperationNamesStorageWrite(t *testing.T) { "errors|table=" + schemas[test.schemaVersion].tableName: 1, }, counts, "after first two writes") - // write again - err = s.storage.Write("service-a", "Operation-b", "") - assert.NoError(t, err) + // write again + err = s.storage.Write("service-a", "Operation-b", "") + assert.NoError(t, err) counts2, _ := s.metricsFactory.Snapshot() expCounts := counts @@ -181,13 +174,22 @@ func TestOperationNamesStorageGetServices(t *testing.T) { query.On("Iter").Return(iter) s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - services, err := s.storage.GetOperations(&spanstore.OperationQueryParameters{ServiceName: "service-a"}) + services, err := s.storage.GetOperations(&spanstore.OperationQueryParameters{ + ServiceName: "service-a", + }) if test.expErr == nil { assert.NoError(t, err) - // expect one empty operation result because mock iter.Scan(&placeholder) does not write to `placeholder` + // expect one empty operation result + // because mock iter.Scan(&placeholder) does not write to `placeholder` assert.Equal(t, []*spanstore.Operation{{}}, services) } else { - assert.EqualError(t, err, fmt.Sprintf("Error reading %s from storage: %s", schemas[test.schemaVersion].tableName, test.expErr.Error())) + assert.EqualError( + t, + err, + fmt.Sprintf("Error reading %s from storage: %s", + schemas[test.schemaVersion].tableName, + test.expErr.Error()), + ) } }) }) From 17d9a785d5f36fadf30f88e10379483146d7f883 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Fri, 22 Nov 2019 15:01:10 -0500 Subject: [PATCH 08/12] Fix line wrapping Signed-off-by: Jun Guo --- plugin/storage/cassandra/spanstore/operation_names.go | 3 ++- plugin/storage/grpc/shared/grpc_server_test.go | 10 ++++++++-- plugin/storage/memory/memory_test.go | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index f3c8d5f9b8f..e069118274f 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -141,7 +141,8 @@ func (s *OperationNamesStorage) Write(serviceName, operationName, spanKind strin } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *OperationNamesStorage) GetOperations(query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func (s *OperationNamesStorage) GetOperations(query *spanstore.OperationQueryParameters) ( + []*spanstore.Operation, error) { return s.table.getOperations(s, &spanstore.OperationQueryParameters{ ServiceName: query.ServiceName, SpanKind: query.SpanKind, diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index 27c93fb1e6b..1141a1eb5e7 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -96,8 +96,14 @@ func TestGRPCServerGetOperations(t *testing.T) { Service: "service-a", }) assert.NoError(t, err) - assert.Equal(t, &storage_v1.GetOperationsResponse{OperationsV2: []*storage_v1.Operation{{Name: "operation-a", - SpanKind: ""}}}, s) + assert.Equal( + t, + &storage_v1.GetOperationsResponse{ + OperationsV2: []*storage_v1.Operation{ + {Name: "operation-a", SpanKind: ""}, + }, + }, + s) }) } diff --git a/plugin/storage/memory/memory_test.go b/plugin/storage/memory/memory_test.go index 40ebf952b23..8df50d99c55 100644 --- a/plugin/storage/memory/memory_test.go +++ b/plugin/storage/memory/memory_test.go @@ -248,7 +248,10 @@ func TestStoreGetServerOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: "server"}) + &spanstore.OperationQueryParameters{ + ServiceName: childSpan1.Process.ServiceName, + SpanKind: "server", + }) assert.NoError(t, err) assert.Len(t, operations, 1) assert.EqualValues(t, childSpan1.OperationName, operations[0].Name) From 3646ad97c3220833d56b7c3423a430e80273b3e8 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Fri, 22 Nov 2019 16:30:26 -0500 Subject: [PATCH 09/12] Address comment - shorten var names and wrap lines - make grpc server backward compatible - write struct instead of list of strings for operation_names Signed-off-by: Jun Guo --- cmd/query/app/grpc_handler_test.go | 4 +- cmd/query/app/querysvc/query_service.go | 4 +- plugin/storage/badger/spanstore/cache.go | 3 +- .../badger/spanstore/read_write_test.go | 2 +- plugin/storage/badger/spanstore/reader.go | 6 ++- .../cassandra/spanstore/dbmodel/operation.go | 23 ++++++++++ .../cassandra/spanstore/operation_names.go | 32 +++++++++----- .../spanstore/operation_names_test.go | 16 +++++-- plugin/storage/cassandra/spanstore/writer.go | 14 +++--- .../cassandra/spanstore/writer_test.go | 43 ++++++++++++------- plugin/storage/es/spanstore/reader.go | 6 +-- plugin/storage/es/spanstore/reader_test.go | 5 +-- .../es/spanstore/service_operation_test.go | 2 +- plugin/storage/grpc/shared/grpc_client.go | 4 +- .../storage/grpc/shared/grpc_client_test.go | 4 +- plugin/storage/grpc/shared/grpc_server.go | 17 ++++++-- .../storage/grpc/shared/grpc_server_test.go | 26 ++++++----- .../storage/integration/integration_test.go | 8 ++-- plugin/storage/integration/kafka_test.go | 5 ++- plugin/storage/memory/memory_test.go | 4 +- storage/spanstore/metrics/decorator.go | 6 ++- storage/spanstore/metrics/decorator_test.go | 4 +- 22 files changed, 159 insertions(+), 79 deletions(-) create mode 100644 plugin/storage/cassandra/spanstore/dbmodel/operation.go diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index f7c29595eb9..6b7e2e5c3df 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -426,8 +426,8 @@ func TestGetOperationsSuccessGRPC(t *testing.T) { }) assert.NoError(t, err) assert.Equal(t, len(expectedOperations), len(res.Operations)) - for idx, actualOp := range res.Operations { - assert.Equal(t, expectedOperations[idx].Name, actualOp) + for i, actualOp := range res.Operations { + assert.Equal(t, expectedOperations[i].Name, actualOp) } }) } diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index ddc34c295ed..46fce1c7e95 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -88,8 +88,8 @@ func (qs QueryService) GetOperations(ctx context.Context, service string) ([]str } names := make([]string, len(operations)) - for idx, operation := range operations { - names[idx] = operation.Name + for i, operation := range operations { + names[i] = operation.Name } return names, err } diff --git a/plugin/storage/badger/spanstore/cache.go b/plugin/storage/badger/spanstore/cache.go index 9aac7c6d944..6c0e9b127ee 100644 --- a/plugin/storage/badger/spanstore/cache.go +++ b/plugin/storage/badger/spanstore/cache.go @@ -152,7 +152,8 @@ func (c *CacheStore) GetOperations(service string) ([]*spanstore.Operation, erro sort.Strings(operations) - //TODO: return the operations with actual spanKind + // TODO: https://github.com/jaegertracing/jaeger/issues/1922 + // - return the operations with actual spanKind result := make([]*spanstore.Operation, 0, len(operations)) for _, op := range operations { result = append(result, &spanstore.Operation{ diff --git a/plugin/storage/badger/spanstore/read_write_test.go b/plugin/storage/badger/spanstore/read_write_test.go index 59fbe92a455..fd7d289d37d 100644 --- a/plugin/storage/badger/spanstore/read_write_test.go +++ b/plugin/storage/badger/spanstore/read_write_test.go @@ -332,7 +332,7 @@ func TestMenuSeeks(t *testing.T) { } operations, err := sr.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "service-1", SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: "service-1"}) assert.NoError(t, err) serviceList, err := sr.GetServices(context.Background()) diff --git a/plugin/storage/badger/spanstore/reader.go b/plugin/storage/badger/spanstore/reader.go index 1249eec645a..523e48ea383 100644 --- a/plugin/storage/badger/spanstore/reader.go +++ b/plugin/storage/badger/spanstore/reader.go @@ -237,8 +237,10 @@ func (r *TraceReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations fetches operations in the service and empty slice if service does not exists -func (r *TraceReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (r *TraceReader) GetOperations( + ctx context.Context, + query *spanstore.OperationQueryParameters, +) ([]*spanstore.Operation, error) { return r.cache.GetOperations(query.ServiceName) } diff --git a/plugin/storage/cassandra/spanstore/dbmodel/operation.go b/plugin/storage/cassandra/spanstore/dbmodel/operation.go new file mode 100644 index 00000000000..29e9f66b17a --- /dev/null +++ b/plugin/storage/cassandra/spanstore/dbmodel/operation.go @@ -0,0 +1,23 @@ +// Copyright (c) 2019 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbmodel + +// Operation defines schema for records saved in operation_names_v2 table +type Operation struct { + ServiceName string + SpanKind string + OperationName string +} diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index e069118274f..fee76453b0d 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -26,6 +26,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/cache" "github.com/jaegertracing/jaeger/pkg/cassandra" casMetrics "github.com/jaegertracing/jaeger/pkg/cassandra/metrics" + "github.com/jaegertracing/jaeger/plugin/storage/cassandra/spanstore/dbmodel" "github.com/jaegertracing/jaeger/storage/spanstore" ) @@ -127,22 +128,31 @@ func NewOperationNamesStorage( } // Write saves Operation and Service name tuples -func (s *OperationNamesStorage) Write(serviceName, operationName, spanKind string) error { - var err error - - if inCache := checkWriteCache(serviceName+"|"+spanKind+"|"+operationName, s.operationNames, s.writeCacheTTL); !inCache { - q := s.table.createWriteQuery(s.session.Query(s.table.insertStmt), serviceName, spanKind, operationName) - err2 := s.metrics.Exec(q, s.logger) - if err2 != nil { - err = err2 +func (s *OperationNamesStorage) Write(operation dbmodel.Operation) error { + key := fmt.Sprintf("%s|%s|%s", + operation.ServiceName, + operation.SpanKind, + operation.OperationName, + ) + if inCache := checkWriteCache(key, s.operationNames, s.writeCacheTTL); !inCache { + q := s.table.createWriteQuery( + s.session.Query(s.table.insertStmt), + operation.ServiceName, + operation.SpanKind, + operation.OperationName, + ) + err := s.metrics.Exec(q, s.logger) + if err != nil { + return err } } - return err + return nil } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *OperationNamesStorage) GetOperations(query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (s *OperationNamesStorage) GetOperations( + query *spanstore.OperationQueryParameters, +) ([]*spanstore.Operation, error) { return s.table.getOperations(s, &spanstore.OperationQueryParameters{ ServiceName: query.ServiceName, SpanKind: query.SpanKind, diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 0b777829072..57c81ad1776 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -28,6 +28,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/cassandra/mocks" "github.com/jaegertracing/jaeger/pkg/testutils" + "github.com/jaegertracing/jaeger/plugin/storage/cassandra/spanstore/dbmodel" "github.com/jaegertracing/jaeger/storage/spanstore" ) @@ -102,10 +103,16 @@ func TestOperationNamesStorageWrite(t *testing.T) { s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - err := s.storage.Write("service-a", "Operation-b", "") + err := s.storage.Write(dbmodel.Operation{ + ServiceName: "service-a", + OperationName: "Operation-b", + }) assert.NoError(t, err) - err = s.storage.Write("service-c", "operation-d", "") + err = s.storage.Write(dbmodel.Operation{ + ServiceName: "service-c", + OperationName: "operation-d", + }) assert.EqualError(t, err, "failed to Exec query 'select from "+ schemas[test.schemaVersion].tableName+ @@ -125,7 +132,10 @@ func TestOperationNamesStorageWrite(t *testing.T) { }, counts, "after first two writes") // write again - err = s.storage.Write("service-a", "Operation-b", "") + err = s.storage.Write(dbmodel.Operation{ + ServiceName: "service-a", + OperationName: "Operation-b", + }) assert.NoError(t, err) counts2, _ := s.metricsFactory.Snapshot() diff --git a/plugin/storage/cassandra/spanstore/writer.go b/plugin/storage/cassandra/spanstore/writer.go index 3ea10e75482..364ef593cc7 100644 --- a/plugin/storage/cassandra/spanstore/writer.go +++ b/plugin/storage/cassandra/spanstore/writer.go @@ -73,7 +73,7 @@ const ( type storageMode uint8 type serviceNamesWriter func(serviceName string) error -type operationNamesWriter func(serviceName, operationName, spanKind string) error +type operationNamesWriter func(operation dbmodel.Operation) error type spanWriterMetrics struct { traces *casMetrics.Table @@ -173,7 +173,11 @@ func (s *SpanWriter) writeSpan(span *model.Span, ds *dbmodel.Span) error { func (s *SpanWriter) writeIndexes(span *model.Span, ds *dbmodel.Span) error { spanKind, _ := span.GetSpanKind() - if err := s.saveServiceNameAndOperationName(ds.ServiceName, ds.OperationName, spanKind); err != nil { + if err := s.saveServiceNameAndOperationName(dbmodel.Operation{ + ServiceName: ds.ServiceName, + SpanKind: spanKind, + OperationName: ds.OperationName, + }); err != nil { // should this be a soft failure? return s.logError(ds, err, "Failed to insert service name and operation name", s.logger) } @@ -275,9 +279,9 @@ func (s *SpanWriter) logError(span *dbmodel.Span, err error, msg string, logger return errors.Wrap(err, msg) } -func (s *SpanWriter) saveServiceNameAndOperationName(serviceName, operationName, spanKind string) error { - if err := s.serviceNamesWriter(serviceName); err != nil { +func (s *SpanWriter) saveServiceNameAndOperationName(operation dbmodel.Operation) error { + if err := s.serviceNamesWriter(operation.ServiceName); err != nil { return err } - return s.operationNamesWriter(serviceName, operationName, spanKind) + return s.operationNamesWriter(operation) } diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index 6e1bb136b55..3204501dcc2 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -205,9 +205,12 @@ func TestSpanWriter(t *testing.T) { stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) - w.writer.serviceNamesWriter = func(serviceName string) error { return testCase.serviceNameError } - w.writer.operationNamesWriter = - func(serviceName, operationName, spanKind string) error { return testCase.serviceNameError } + w.writer.serviceNamesWriter = func(serviceName string) error { + return testCase.serviceNameError + } + w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { + return testCase.serviceNameError + } err := w.writer.WriteSpan(span) if testCase.expectedError == "" { @@ -238,18 +241,24 @@ func TestSpanWriterSaveServiceNameAndOperationName(t *testing.T) { expectedError string }{ { - serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(serviceName, operationName, spanKind string) error { return nil }, + serviceNamesWriter: func(serviceName string) error { return nil }, + operationNamesWriter: func(operation dbmodel.Operation) error { + return nil + }, }, { - serviceNamesWriter: func(serviceName string) error { return expectedErr }, - operationNamesWriter: func(serviceName, operationName, spanKind string) error { return nil }, - expectedError: "some error", + serviceNamesWriter: func(serviceName string) error { return expectedErr }, + operationNamesWriter: func(operation dbmodel.Operation) error { + return nil + }, + expectedError: "some error", }, { - serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(serviceName, operationName, spanKind string) error { return expectedErr }, - expectedError: "some error", + serviceNamesWriter: func(serviceName string) error { return nil }, + operationNamesWriter: func(operation dbmodel.Operation) error { + return expectedErr + }, + expectedError: "some error", }, } for _, tc := range testCases { @@ -257,7 +266,11 @@ func TestSpanWriterSaveServiceNameAndOperationName(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = testCase.serviceNamesWriter w.writer.operationNamesWriter = testCase.operationNamesWriter - err := w.writer.saveServiceNameAndOperationName("service", "operation", "") + err := w.writer.saveServiceNameAndOperationName( + dbmodel.Operation{ + ServiceName: "service", + OperationName: "operation", + }) if testCase.expectedError == "" { assert.NoError(t, err) } else { @@ -298,7 +311,7 @@ func TestStorageMode_IndexOnly(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } + w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ @@ -343,7 +356,7 @@ func TestStorageMode_IndexOnly_WithFilter(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.indexFilter = filterEverything w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } + w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ @@ -363,7 +376,7 @@ func TestStorageMode_IndexOnly_FirehoseSpan(t *testing.T) { withSpanWriter(0, func(w *spanWriterTest) { w.writer.serviceNamesWriter = func(serviceName string) error { return nil } - w.writer.operationNamesWriter = func(serviceName, operationName, spanKind string) error { return nil } + w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { return nil } span := &model.Span{ TraceID: model.NewTraceID(0, 1), Process: &model.Process{ diff --git a/plugin/storage/es/spanstore/reader.go b/plugin/storage/es/spanstore/reader.go index f8b80a097bf..bf244fc278c 100644 --- a/plugin/storage/es/spanstore/reader.go +++ b/plugin/storage/es/spanstore/reader.go @@ -256,12 +256,12 @@ func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.Operati return nil, err } - //TODO: return the operations with actual span kind that meet requirement + // TODO: https://github.com/jaegertracing/jaeger/issues/1923 + // - return the operations with actual span kind that meet requirement var result []*spanstore.Operation for _, operation := range operations { result = append(result, &spanstore.Operation{ - Name: operation, - SpanKind: "", + Name: operation, }) } return result, err diff --git a/plugin/storage/es/spanstore/reader_test.go b/plugin/storage/es/spanstore/reader_test.go index 5e3ac56e687..bc955283dab 100644 --- a/plugin/storage/es/spanstore/reader_test.go +++ b/plugin/storage/es/spanstore/reader_test.go @@ -508,8 +508,7 @@ func testGet(typ string, t *testing.T) { if typ == operationsAggregation { testCases[0].expectedOutput = []*spanstore.Operation{ { - Name: "123", - SpanKind: "", + Name: "123", }, } } else { @@ -539,7 +538,7 @@ func returnSearchFunc(typ string, r *spanReaderTest) (interface{}, error) { return r.reader.GetServices(context.Background()) } else if typ == operationsAggregation { return r.reader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "someService", SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: "someService"}) } else if typ == traceIDAggregation { return r.reader.findTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) } diff --git a/plugin/storage/es/spanstore/service_operation_test.go b/plugin/storage/es/spanstore/service_operation_test.go index 2b16c8597bf..635a64948b1 100644 --- a/plugin/storage/es/spanstore/service_operation_test.go +++ b/plugin/storage/es/spanstore/service_operation_test.go @@ -123,7 +123,7 @@ func TestSpanReader_GetOperationsEmptyIndex(t *testing.T) { Responses: []*elastic.SearchResult{}, }, nil) services, err := r.reader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "foo", SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: "foo"}) require.NoError(t, err) assert.Empty(t, services) }) diff --git a/plugin/storage/grpc/shared/grpc_client.go b/plugin/storage/grpc/shared/grpc_client.go index cb6147906c3..695b82e75be 100644 --- a/plugin/storage/grpc/shared/grpc_client.go +++ b/plugin/storage/grpc/shared/grpc_client.go @@ -115,8 +115,8 @@ func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.Operati } operations := make([]*spanstore.Operation, len(resp.OperationsV2)) - for idx, operation := range resp.OperationsV2 { - operations[idx] = &spanstore.Operation{ + for i, operation := range resp.OperationsV2 { + operations[i] = &spanstore.Operation{ Name: operation.Name, SpanKind: operation.SpanKind, } diff --git a/plugin/storage/grpc/shared/grpc_client_test.go b/plugin/storage/grpc/shared/grpc_client_test.go index 17cc2ea4e9b..03a603b95d2 100644 --- a/plugin/storage/grpc/shared/grpc_client_test.go +++ b/plugin/storage/grpc/shared/grpc_client_test.go @@ -124,13 +124,13 @@ func TestGRPCClientGetOperations(t *testing.T) { r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ Service: "service-a", }).Return(&storage_v1.GetOperationsResponse{ - OperationsV2: []*storage_v1.Operation{{Name: "operation-a", SpanKind: ""}}, + OperationsV2: []*storage_v1.Operation{{Name: "operation-a"}}, }, nil) s, err := r.client.GetOperations(context.Background(), &spanstore.OperationQueryParameters{ServiceName: "service-a"}) assert.NoError(t, err) - assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, s) + assert.Equal(t, []*spanstore.Operation{{Name: "operation-a"}}, s) }) } diff --git a/plugin/storage/grpc/shared/grpc_server.go b/plugin/storage/grpc/shared/grpc_server.go index 2681d578a94..a93c802cef4 100644 --- a/plugin/storage/grpc/shared/grpc_server.go +++ b/plugin/storage/grpc/shared/grpc_server.go @@ -78,8 +78,10 @@ func (s *grpcServer) GetServices(ctx context.Context, r *storage_v1.GetServicesR } // GetOperations returns the operations of a given service -func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperationsRequest) ( - *storage_v1.GetOperationsResponse, error) { +func (s *grpcServer) GetOperations( + ctx context.Context, + r *storage_v1.GetOperationsRequest, +) (*storage_v1.GetOperationsResponse, error) { operations, err := s.Impl.SpanReader().GetOperations(ctx, &spanstore.OperationQueryParameters{ ServiceName: r.Service, SpanKind: r.SpanKind, @@ -88,13 +90,20 @@ func (s *grpcServer) GetOperations(ctx context.Context, r *storage_v1.GetOperati return nil, err } grpcOperation := make([]*storage_v1.Operation, len(operations)) - for idx, operation := range operations { - grpcOperation[idx] = &storage_v1.Operation{ + operationNameSet := make(map[string]struct{}) + for i, operation := range operations { + grpcOperation[i] = &storage_v1.Operation{ Name: operation.Name, SpanKind: operation.SpanKind, } + operationNameSet[operation.Name] = struct{}{} + } + var uniqueNames []string + for name := range operationNameSet { + uniqueNames = append(uniqueNames, name) } return &storage_v1.GetOperationsResponse{ + Operations: uniqueNames, OperationsV2: grpcOperation, }, nil } diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index 1141a1eb5e7..6a04b698ba5 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -87,23 +87,29 @@ func TestGRPCServerGetServices(t *testing.T) { func TestGRPCServerGetOperations(t *testing.T) { withGRPCServer(func(r *grpcServerTest) { + expOperations := []*spanstore.Operation{ + {Name: "operation-a", SpanKind: "client"}, + {Name: "operation-a", SpanKind: "server"}, + {Name: "operation-b", SpanKind: "client"}, + } + expOperationNames := []string{ + "operation-a", + "operation-b", + } r.impl.spanReader.On("GetOperations", mock.Anything, &spanstore.OperationQueryParameters{ServiceName: "service-a"}). - Return([]*spanstore.Operation{{Name: "operation-a", SpanKind: ""}}, nil) + Return(expOperations, nil) - s, err := r.server.GetOperations(context.Background(), &storage_v1.GetOperationsRequest{ + resp, err := r.server.GetOperations(context.Background(), &storage_v1.GetOperationsRequest{ Service: "service-a", }) assert.NoError(t, err) - assert.Equal( - t, - &storage_v1.GetOperationsResponse{ - OperationsV2: []*storage_v1.Operation{ - {Name: "operation-a", SpanKind: ""}, - }, - }, - s) + for i, operationV2 := range resp.OperationsV2 { + assert.Equal(t, expOperations[i].Name, operationV2.Name) + assert.Equal(t, expOperations[i].SpanKind, operationV2.SpanKind) + } + assert.Equal(t, expOperationNames, resp.Operations) }) } diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index 5054f3a45bc..32b05e1b317 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -150,9 +150,9 @@ func (s *StorageIntegration) testGetOperations(t *testing.T) { defer s.cleanUp(t) expected := []*spanstore.Operation{ - {Name: "example-operation-1", SpanKind: ""}, - {Name: "example-operation-3", SpanKind: ""}, - {Name: "example-operation-4", SpanKind: ""}} + {Name: "example-operation-1"}, + {Name: "example-operation-3"}, + {Name: "example-operation-4"}} s.loadParseAndWriteExampleTrace(t) s.refresh(t) @@ -160,7 +160,7 @@ func (s *StorageIntegration) testGetOperations(t *testing.T) { found := s.waitForCondition(t, func(t *testing.T) bool { var err error actual, err = s.SpanReader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "example-service-1", SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: "example-service-1"}) require.NoError(t, err) return assert.ObjectsAreEqualValues(expected, actual) }) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index dffb41642fa..c1455368918 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -119,8 +119,9 @@ func (r *ingester) GetServices(ctx context.Context) ([]string, error) { return nil, nil } -func (r *ingester) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (r *ingester) GetOperations( + ctx context.Context, + query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { return nil, nil } diff --git a/plugin/storage/memory/memory_test.go b/plugin/storage/memory/memory_test.go index 8df50d99c55..868b01f828a 100644 --- a/plugin/storage/memory/memory_test.go +++ b/plugin/storage/memory/memory_test.go @@ -234,7 +234,7 @@ func TestStoreGetAllOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName, SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName}) assert.NoError(t, err) assert.Len(t, operations, 3) assert.EqualValues(t, childSpan1.OperationName, (*operations[0]).Name) @@ -262,7 +262,7 @@ func TestStoreGetServerOperationsFound(t *testing.T) { func TestStoreGetOperationsNotFound(t *testing.T) { withPopulatedMemoryStore(func(store *Store) { operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "notAService", SpanKind: ""}) + &spanstore.OperationQueryParameters{ServiceName: "notAService"}) assert.NoError(t, err) assert.Len(t, operations, 0) }) diff --git a/storage/spanstore/metrics/decorator.go b/storage/spanstore/metrics/decorator.go index 907fa39ea3c..c62807dec98 100644 --- a/storage/spanstore/metrics/decorator.go +++ b/storage/spanstore/metrics/decorator.go @@ -106,8 +106,10 @@ func (m *ReadMetricsDecorator) GetServices(ctx context.Context) ([]string, error } // GetOperations implements spanstore.Reader#GetOperations -func (m *ReadMetricsDecorator) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (m *ReadMetricsDecorator) GetOperations( + ctx context.Context, + query *spanstore.OperationQueryParameters, +) ([]*spanstore.Operation, error) { start := time.Now() retMe, err := m.spanReader.GetOperations(ctx, query) m.getOperationsMetrics.emit(err, time.Since(start), len(retMe)) diff --git a/storage/spanstore/metrics/decorator_test.go b/storage/spanstore/metrics/decorator_test.go index f69c5b624b2..4848d8350a7 100644 --- a/storage/spanstore/metrics/decorator_test.go +++ b/storage/spanstore/metrics/decorator_test.go @@ -36,7 +36,7 @@ func TestSuccessfulUnderlyingCalls(t *testing.T) { mrs := NewReadMetricsDecorator(&mockReader, mf) mockReader.On("GetServices", context.Background()).Return([]string{}, nil) mrs.GetServices(context.Background()) - operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} + operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something"} mockReader.On("GetOperations", context.Background(), operationQuery). Return([]*spanstore.Operation{}, nil) mrs.GetOperations(context.Background(), operationQuery) @@ -103,7 +103,7 @@ func TestFailingUnderlyingCalls(t *testing.T) { mockReader.On("GetServices", context.Background()). Return(nil, errors.New("Failure")) mrs.GetServices(context.Background()) - operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something", SpanKind: ""} + operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something"} mockReader.On("GetOperations", context.Background(), operationQuery). Return(nil, errors.New("Failure")) mrs.GetOperations(context.Background(), operationQuery) From ecf10f410bca2b3fef1441bf3fc37d07e76b4e1c Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Fri, 22 Nov 2019 18:51:34 -0500 Subject: [PATCH 10/12] - Pass by value instead of by pointer for GetOperations - Backward compatibility for grpc client Signed-off-by: Jun Guo --- cmd/query/app/grpc_handler_test.go | 6 +- cmd/query/app/http_handler_test.go | 12 +- cmd/query/app/querysvc/query_service.go | 2 +- cmd/query/app/querysvc/query_service_test.go | 4 +- plugin/storage/badger/spanstore/cache.go | 8 +- .../badger/spanstore/read_write_test.go | 6 +- plugin/storage/badger/spanstore/reader.go | 4 +- .../cassandra/spanstore/dbmodel/operation.go | 1 - .../cassandra/spanstore/operation_names.go | 33 ++-- .../spanstore/operation_names_test.go | 7 +- plugin/storage/cassandra/spanstore/reader.go | 8 +- .../cassandra/spanstore/reader_test.go | 15 +- .../cassandra/spanstore/writer_test.go | 56 ++---- plugin/storage/es/spanstore/reader.go | 10 +- plugin/storage/es/spanstore/reader_test.go | 28 ++- .../es/spanstore/service_operation_test.go | 6 +- plugin/storage/grpc/proto/storage.proto | 4 +- plugin/storage/grpc/shared/grpc_client.go | 24 ++- .../storage/grpc/shared/grpc_client_test.go | 23 ++- plugin/storage/grpc/shared/grpc_server.go | 11 +- .../storage/grpc/shared/grpc_server_test.go | 16 +- .../storage/integration/integration_test.go | 6 +- plugin/storage/integration/kafka_test.go | 3 +- plugin/storage/memory/memory.go | 10 +- plugin/storage/memory/memory_test.go | 22 ++- proto-gen/storage_v1/storage.pb.go | 160 +++++++++--------- storage/spanstore/interface.go | 2 +- storage/spanstore/metrics/decorator.go | 4 +- storage/spanstore/metrics/decorator_test.go | 6 +- storage/spanstore/mocks/Reader.go | 18 +- 30 files changed, 261 insertions(+), 254 deletions(-) diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index 6b7e2e5c3df..47e2f4ac0d3 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -415,10 +415,10 @@ func TestGetServicesFailureGRPC(t *testing.T) { func TestGetOperationsSuccessGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { - expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + expectedOperations := []spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), - &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}, + spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}, ).Return(expectedOperations, nil).Once() res, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ @@ -436,7 +436,7 @@ func TestGetOperationsFailureGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { server.spanReader.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), - &spanstore.OperationQueryParameters{ServiceName: "trifle"}, + spanstore.OperationQueryParameters{ServiceName: "trifle"}, ).Return(nil, errStorageGRPC).Once() _, err := client.GetOperations(context.Background(), &api_v2.GetOperationsRequest{ diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index 986dcb5a746..dd60fde1b6a 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -483,9 +483,9 @@ func TestGetServicesStorageFailure(t *testing.T) { func TestGetOperationsSuccess(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() - expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + expectedOperations := []spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), - &spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() + spanstore.OperationQueryParameters{ServiceName: "abc/trifle"}).Return(expectedOperations, nil).Once() var response structuredResponse err := getJSON(server.URL+"/api/operations?service=abc%2Ftrifle", &response) @@ -511,7 +511,7 @@ func TestGetOperationsStorageFailure(t *testing.T) { readMock.On( "GetOperations", mock.AnythingOfType("*context.valueCtx"), - mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() + mock.AnythingOfType("spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() var response structuredResponse err := getJSON(server.URL+"/api/operations?service=trifle", &response) @@ -522,7 +522,7 @@ func TestGetOperationsLegacySuccess(t *testing.T) { server, readMock, _ := initializeTestServer() defer server.Close() expectedOperationNames := []string{"", "get"} - expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + expectedOperations := []spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), "abc/trifle", @@ -530,7 +530,7 @@ func TestGetOperationsLegacySuccess(t *testing.T) { readMock.On( "GetOperations", mock.AnythingOfType("*context.valueCtx"), - mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() + mock.AnythingOfType("spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() var response structuredResponse err := getJSON(server.URL+"/api/services/abc%2Ftrifle/operations", &response) @@ -548,7 +548,7 @@ func TestGetOperationsLegacyStorageFailure(t *testing.T) { readMock.On( "GetOperations", mock.AnythingOfType("*context.valueCtx"), - mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() + mock.AnythingOfType("spanstore.OperationQueryParameters")).Return(nil, errStorage).Once() var response structuredResponse err := getJSON(server.URL+"/api/services/trifle/operations", &response) assert.Error(t, err) diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index 46fce1c7e95..bf462db667a 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -80,7 +80,7 @@ func (qs QueryService) GetServices(ctx context.Context) ([]string, error) { // GetOperations is the queryService implementation of spanstore.Reader.GetOperations func (qs QueryService) GetOperations(ctx context.Context, service string) ([]string, error) { - operations, err := qs.spanReader.GetOperations(ctx, &spanstore.OperationQueryParameters{ + operations, err := qs.spanReader.GetOperations(ctx, spanstore.OperationQueryParameters{ ServiceName: service, }) if err != nil { diff --git a/cmd/query/app/querysvc/query_service_test.go b/cmd/query/app/querysvc/query_service_test.go index fdd0c742f6c..240316da26c 100644 --- a/cmd/query/app/querysvc/query_service_test.go +++ b/cmd/query/app/querysvc/query_service_test.go @@ -148,10 +148,10 @@ func TestGetServices(t *testing.T) { func TestGetOperations(t *testing.T) { qs, readMock, _ := initializeTestService() expectedOperationNames := []string{"", "get"} - expectedOperations := []*spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} + expectedOperations := []spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} readMock.On("GetOperations", mock.AnythingOfType("*context.valueCtx"), - mock.AnythingOfType("*spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() + mock.AnythingOfType("spanstore.OperationQueryParameters")).Return(expectedOperations, nil).Once() type contextKey string ctx := context.Background() diff --git a/plugin/storage/badger/spanstore/cache.go b/plugin/storage/badger/spanstore/cache.go index 6c0e9b127ee..b43750d9ea7 100644 --- a/plugin/storage/badger/spanstore/cache.go +++ b/plugin/storage/badger/spanstore/cache.go @@ -128,7 +128,7 @@ func (c *CacheStore) Update(service, operation string, expireTime uint64) { } // GetOperations returns all operations for a specific service & spanKind traced by Jaeger -func (c *CacheStore) GetOperations(service string) ([]*spanstore.Operation, error) { +func (c *CacheStore) GetOperations(service string) ([]spanstore.Operation, error) { operations := make([]string, 0, len(c.services)) t := uint64(time.Now().Unix()) c.cacheLock.Lock() @@ -139,7 +139,7 @@ func (c *CacheStore) GetOperations(service string) ([]*spanstore.Operation, erro // Expired, remove delete(c.services, service) delete(c.operations, service) - return []*spanstore.Operation{}, nil // empty slice rather than nil + return []spanstore.Operation{}, nil // empty slice rather than nil } for o, e := range c.operations[service] { if e > t { @@ -154,9 +154,9 @@ func (c *CacheStore) GetOperations(service string) ([]*spanstore.Operation, erro // TODO: https://github.com/jaegertracing/jaeger/issues/1922 // - return the operations with actual spanKind - result := make([]*spanstore.Operation, 0, len(operations)) + result := make([]spanstore.Operation, 0, len(operations)) for _, op := range operations { - result = append(result, &spanstore.Operation{ + result = append(result, spanstore.Operation{ Name: op, }) } diff --git a/plugin/storage/badger/spanstore/read_write_test.go b/plugin/storage/badger/spanstore/read_write_test.go index fd7d289d37d..0399e48a5f1 100644 --- a/plugin/storage/badger/spanstore/read_write_test.go +++ b/plugin/storage/badger/spanstore/read_write_test.go @@ -331,8 +331,10 @@ func TestMenuSeeks(t *testing.T) { } } - operations, err := sr.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "service-1"}) + operations, err := sr.GetOperations( + context.Background(), + spanstore.OperationQueryParameters{ServiceName: "service-1"}, + ) assert.NoError(t, err) serviceList, err := sr.GetServices(context.Background()) diff --git a/plugin/storage/badger/spanstore/reader.go b/plugin/storage/badger/spanstore/reader.go index 523e48ea383..9f1723c70e8 100644 --- a/plugin/storage/badger/spanstore/reader.go +++ b/plugin/storage/badger/spanstore/reader.go @@ -239,8 +239,8 @@ func (r *TraceReader) GetServices(ctx context.Context) ([]string, error) { // GetOperations fetches operations in the service and empty slice if service does not exists func (r *TraceReader) GetOperations( ctx context.Context, - query *spanstore.OperationQueryParameters, -) ([]*spanstore.Operation, error) { + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { return r.cache.GetOperations(query.ServiceName) } diff --git a/plugin/storage/cassandra/spanstore/dbmodel/operation.go b/plugin/storage/cassandra/spanstore/dbmodel/operation.go index 29e9f66b17a..14f75b22595 100644 --- a/plugin/storage/cassandra/spanstore/dbmodel/operation.go +++ b/plugin/storage/cassandra/spanstore/dbmodel/operation.go @@ -1,5 +1,4 @@ // Copyright (c) 2019 The Jaeger Authors. -// Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/plugin/storage/cassandra/spanstore/operation_names.go b/plugin/storage/cassandra/spanstore/operation_names.go index fee76453b0d..525f4a3af49 100644 --- a/plugin/storage/cassandra/spanstore/operation_names.go +++ b/plugin/storage/cassandra/spanstore/operation_names.go @@ -51,8 +51,10 @@ type tableMeta struct { queryByKindStmt string queryStmt string createWriteQuery func(query cassandra.Query, service, kind, opName string) cassandra.Query - getOperations func(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) + getOperations func( + s *OperationNamesStorage, + query spanstore.OperationQueryParameters, + ) ([]spanstore.Operation, error) } func (t *tableMeta) materialize() { @@ -151,12 +153,9 @@ func (s *OperationNamesStorage) Write(operation dbmodel.Operation) error { // GetOperations returns all operations for a specific service traced by Jaeger func (s *OperationNamesStorage) GetOperations( - query *spanstore.OperationQueryParameters, -) ([]*spanstore.Operation, error) { - return s.table.getOperations(s, &spanstore.OperationQueryParameters{ - ServiceName: query.ServiceName, - SpanKind: query.SpanKind, - }) + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { + return s.table.getOperations(s, query) } func tableExist(session cassandra.Session, tableName string) bool { @@ -165,13 +164,16 @@ func tableExist(session cassandra.Session, tableName string) bool { return err == nil } -func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func getOperationsV1( + s *OperationNamesStorage, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { iter := s.session.Query(s.table.queryStmt, query.ServiceName).Iter() var operation string - var operations []*spanstore.Operation + var operations []spanstore.Operation for iter.Scan(&operation) { - operations = append(operations, &spanstore.Operation{ + operations = append(operations, spanstore.Operation{ Name: operation, }) } @@ -183,7 +185,10 @@ func getOperationsV1(s *OperationNamesStorage, query *spanstore.OperationQueryPa return operations, nil } -func getOperationsV2(s *OperationNamesStorage, query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { +func getOperationsV2( + s *OperationNamesStorage, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { var casQuery cassandra.Query if query.SpanKind == "" { // Get operations for all spanKind @@ -196,9 +201,9 @@ func getOperationsV2(s *OperationNamesStorage, query *spanstore.OperationQueryPa var operationName string var spanKind string - var operations []*spanstore.Operation + var operations []spanstore.Operation for iter.Scan(&spanKind, &operationName) { - operations = append(operations, &spanstore.Operation{ + operations = append(operations, spanstore.Operation{ Name: operationName, SpanKind: spanKind, }) diff --git a/plugin/storage/cassandra/spanstore/operation_names_test.go b/plugin/storage/cassandra/spanstore/operation_names_test.go index 57c81ad1776..56a0a84cc7d 100644 --- a/plugin/storage/cassandra/spanstore/operation_names_test.go +++ b/plugin/storage/cassandra/spanstore/operation_names_test.go @@ -51,9 +51,6 @@ func withOperationNamesStorage(writeCacheTTL time.Duration, query := &mocks.Query{} session.On("Query", fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), mock.Anything).Return(query) - session.On("Query", - fmt.Sprintf(tableCheckStmt, schemas[latestVersion].tableName), - mock.Anything).Return(query) if schemaVersion != latestVersion { query.On("Exec").Return(errors.New("new table does not exist")) } else { @@ -184,14 +181,14 @@ func TestOperationNamesStorageGetServices(t *testing.T) { query.On("Iter").Return(iter) s.session.On("Query", mock.AnythingOfType("string"), mock.Anything).Return(query) - services, err := s.storage.GetOperations(&spanstore.OperationQueryParameters{ + services, err := s.storage.GetOperations(spanstore.OperationQueryParameters{ ServiceName: "service-a", }) if test.expErr == nil { assert.NoError(t, err) // expect one empty operation result // because mock iter.Scan(&placeholder) does not write to `placeholder` - assert.Equal(t, []*spanstore.Operation{{}}, services) + assert.Equal(t, []spanstore.Operation{{}}, services) } else { assert.EqualError( t, diff --git a/plugin/storage/cassandra/spanstore/reader.go b/plugin/storage/cassandra/spanstore/reader.go index 3cdbff48220..e2dc16e299a 100644 --- a/plugin/storage/cassandra/spanstore/reader.go +++ b/plugin/storage/cassandra/spanstore/reader.go @@ -91,7 +91,7 @@ var ( type serviceNamesReader func() ([]string, error) -type operationNamesReader func(query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) +type operationNamesReader func(query spanstore.OperationQueryParameters) ([]spanstore.Operation, error) type spanReaderMetrics struct { readTraces *casMetrics.Table @@ -143,8 +143,10 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (s *SpanReader) GetOperations( + ctx context.Context, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { return s.operationNamesReader(query) } diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index a8090a82a19..5e5837cc438 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -19,7 +19,6 @@ import ( "context" "errors" "fmt" - "strings" "testing" "time" @@ -76,8 +75,8 @@ func TestSpanReaderGetServices(t *testing.T) { func TestSpanReaderGetOperations(t *testing.T) { withSpanReader(func(r *spanReaderTest) { r.reader.operationNamesReader = - func(parameters *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { - return []*spanstore.Operation{ + func(parameters spanstore.OperationQueryParameters) ([]spanstore.Operation, error) { + return []spanstore.Operation{ { Name: "operation-a", SpanKind: "server", @@ -85,9 +84,9 @@ func TestSpanReaderGetOperations(t *testing.T) { }, nil } s, err := r.reader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) + spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) assert.NoError(t, err) - assert.Equal(t, []*spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) + assert.Equal(t, []spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) }) } @@ -391,11 +390,7 @@ func TestSpanReaderFindTraces(t *testing.T) { assert.EqualError(t, err, testCase.expectedError) } for _, expectedLog := range testCase.expectedLogs { - assert.True(t, - strings.Contains(r.logBuffer.String(), expectedLog), - "Log must contain %s, "+"but was %s", - expectedLog, - r.logBuffer.String()) + assert.Contains(t, r.logBuffer.String(), expectedLog) } if len(testCase.expectedLogs) == 0 { assert.Equal(t, "", r.logBuffer.String()) diff --git a/plugin/storage/cassandra/spanstore/writer_test.go b/plugin/storage/cassandra/spanstore/writer_test.go index 3204501dcc2..414050d8f69 100644 --- a/plugin/storage/cassandra/spanstore/writer_test.go +++ b/plugin/storage/cassandra/spanstore/writer_test.go @@ -194,23 +194,13 @@ func TestSpanWriter(t *testing.T) { // note: using matchOnce below because we only want one tag to be inserted w.session.On("Query", stringMatcher(insertTag), matchOnce()).Return(tagsQuery) - w.session.On("Query", - stringMatcher(serviceNameIndex), - matchEverything()).Return(serviceNameQuery) - w.session.On("Query", - stringMatcher(serviceOperationIndex), - matchEverything()).Return(serviceOperationNameQuery) - - w.session.On("Query", - stringMatcher(durationIndex), - matchOnce()).Return(durationNoOperationQuery) - - w.writer.serviceNamesWriter = func(serviceName string) error { - return testCase.serviceNameError - } - w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { - return testCase.serviceNameError - } + w.session.On("Query", stringMatcher(serviceNameIndex), matchEverything()).Return(serviceNameQuery) + w.session.On("Query", stringMatcher(serviceOperationIndex), matchEverything()).Return(serviceOperationNameQuery) + + w.session.On("Query", stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) + + w.writer.serviceNamesWriter = func(serviceName string) error { return testCase.serviceNameError } + w.writer.operationNamesWriter = func(operation dbmodel.Operation) error { return testCase.serviceNameError } err := w.writer.WriteSpan(span) if testCase.expectedError == "" { @@ -219,11 +209,7 @@ func TestSpanWriter(t *testing.T) { assert.EqualError(t, err, testCase.expectedError) } for _, expectedLog := range testCase.expectedLogs { - assert.True(t, - strings.Contains(w.logBuffer.String(), expectedLog), - "Log must contain %s, but was %s", - expectedLog, - w.logBuffer.String()) + assert.Contains(t, w.logBuffer.String(), expectedLog) } if len(testCase.expectedLogs) == 0 { assert.Equal(t, "", w.logBuffer.String()) @@ -241,24 +227,18 @@ func TestSpanWriterSaveServiceNameAndOperationName(t *testing.T) { expectedError string }{ { - serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(operation dbmodel.Operation) error { - return nil - }, + serviceNamesWriter: func(serviceName string) error { return nil }, + operationNamesWriter: func(operation dbmodel.Operation) error { return nil }, }, { - serviceNamesWriter: func(serviceName string) error { return expectedErr }, - operationNamesWriter: func(operation dbmodel.Operation) error { - return nil - }, - expectedError: "some error", + serviceNamesWriter: func(serviceName string) error { return expectedErr }, + operationNamesWriter: func(operation dbmodel.Operation) error { return nil }, + expectedError: "some error", }, { - serviceNamesWriter: func(serviceName string) error { return nil }, - operationNamesWriter: func(operation dbmodel.Operation) error { - return expectedErr - }, - expectedError: "some error", + serviceNamesWriter: func(serviceName string) error { return nil }, + operationNamesWriter: func(operation dbmodel.Operation) error { return expectedErr }, + expectedError: "some error", }, } for _, tc := range testCases { @@ -332,9 +312,7 @@ func TestStorageMode_IndexOnly(t *testing.T) { durationNoOperationQuery.On("Exec").Return(nil) w.session.On("Query", stringMatcher(serviceNameIndex), matchEverything()).Return(serviceNameQuery) - w.session.On("Query", - stringMatcher(serviceOperationIndex), - matchEverything()).Return(serviceOperationNameQuery) + w.session.On("Query", stringMatcher(serviceOperationIndex), matchEverything()).Return(serviceOperationNameQuery) w.session.On("Query", stringMatcher(durationIndex), matchOnce()).Return(durationNoOperationQuery) err := w.writer.WriteSpan(span) diff --git a/plugin/storage/es/spanstore/reader.go b/plugin/storage/es/spanstore/reader.go index bf244fc278c..a2163ed9afb 100644 --- a/plugin/storage/es/spanstore/reader.go +++ b/plugin/storage/es/spanstore/reader.go @@ -245,8 +245,10 @@ func (s *SpanReader) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns all operations for a specific service traced by Jaeger -func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (s *SpanReader) GetOperations( + ctx context.Context, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { span, ctx := opentracing.StartSpanFromContext(ctx, "GetOperations") defer span.Finish() currentTime := time.Now() @@ -258,9 +260,9 @@ func (s *SpanReader) GetOperations(ctx context.Context, query *spanstore.Operati // TODO: https://github.com/jaegertracing/jaeger/issues/1923 // - return the operations with actual span kind that meet requirement - var result []*spanstore.Operation + var result []spanstore.Operation for _, operation := range operations { - result = append(result, &spanstore.Operation{ + result = append(result, spanstore.Operation{ Name: operation, }) } diff --git a/plugin/storage/es/spanstore/reader_test.go b/plugin/storage/es/spanstore/reader_test.go index bc955283dab..d95f99f34b1 100644 --- a/plugin/storage/es/spanstore/reader_test.go +++ b/plugin/storage/es/spanstore/reader_test.go @@ -488,11 +488,15 @@ func testGet(typ string, t *testing.T) { searchResult *elastic.SearchResult searchError error expectedError string - expectedOutput interface{} + expectedOutput map[string]interface{} }{ { caption: typ + " full behavior", searchResult: &elastic.SearchResult{Aggregations: elastic.Aggregations(goodAggregations)}, + expectedOutput: map[string]interface{}{ + operationsAggregation: []spanstore.Operation{{Name: "123"}}, + "default": []string{"123"}, + }, }, { caption: typ + " search error", @@ -505,28 +509,20 @@ func testGet(typ string, t *testing.T) { expectedError: "Could not find aggregation of " + typ, }, } - if typ == operationsAggregation { - testCases[0].expectedOutput = []*spanstore.Operation{ - { - Name: "123", - }, - } - } else { - testCases[0].expectedOutput = []string{"123"} - } + for _, tc := range testCases { testCase := tc t.Run(testCase.caption, func(t *testing.T) { withSpanReader(func(r *spanReaderTest) { mockSearchService(r).Return(testCase.searchResult, testCase.searchError) - actual, err := returnSearchFunc(typ, r) if testCase.expectedError != "" { require.EqualError(t, err, testCase.expectedError) assert.Nil(t, actual) + } else if expectedOutput, ok := testCase.expectedOutput[typ]; ok { + assert.EqualValues(t, expectedOutput, actual) } else { - require.NoError(t, err) - assert.EqualValues(t, testCase.expectedOutput, actual) + assert.EqualValues(t, testCase.expectedOutput["default"], actual) } }) }) @@ -537,8 +533,10 @@ func returnSearchFunc(typ string, r *spanReaderTest) (interface{}, error) { if typ == servicesAggregation { return r.reader.GetServices(context.Background()) } else if typ == operationsAggregation { - return r.reader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "someService"}) + return r.reader.GetOperations( + context.Background(), + spanstore.OperationQueryParameters{ServiceName: "someService"}, + ) } else if typ == traceIDAggregation { return r.reader.findTraceIDs(context.Background(), &spanstore.TraceQueryParameters{}) } diff --git a/plugin/storage/es/spanstore/service_operation_test.go b/plugin/storage/es/spanstore/service_operation_test.go index 635a64948b1..ac3f548985f 100644 --- a/plugin/storage/es/spanstore/service_operation_test.go +++ b/plugin/storage/es/spanstore/service_operation_test.go @@ -122,8 +122,10 @@ func TestSpanReader_GetOperationsEmptyIndex(t *testing.T) { Return(&elastic.MultiSearchResult{ Responses: []*elastic.SearchResult{}, }, nil) - services, err := r.reader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "foo"}) + services, err := r.reader.GetOperations( + context.Background(), + spanstore.OperationQueryParameters{ServiceName: "foo"}, + ) require.NoError(t, err) assert.Empty(t, services) }) diff --git a/plugin/storage/grpc/proto/storage.proto b/plugin/storage/grpc/proto/storage.proto index a77ae63b65d..bd85d263948 100644 --- a/plugin/storage/grpc/proto/storage.proto +++ b/plugin/storage/grpc/proto/storage.proto @@ -85,8 +85,8 @@ message Operation { } message GetOperationsResponse { - repeated string operations = 1; // deprecated - repeated Operation operations_v2 = 2; + repeated string operationNames = 1; // deprecated + repeated Operation operations = 2; } message TraceQueryParameters { diff --git a/plugin/storage/grpc/shared/grpc_client.go b/plugin/storage/grpc/shared/grpc_client.go index 695b82e75be..8616509cb68 100644 --- a/plugin/storage/grpc/shared/grpc_client.go +++ b/plugin/storage/grpc/shared/grpc_client.go @@ -104,8 +104,10 @@ func (c *grpcClient) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (c *grpcClient) GetOperations( + ctx context.Context, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { resp, err := c.readerClient.GetOperations(upgradeContextWithBearerToken(ctx), &storage_v1.GetOperationsRequest{ Service: query.ServiceName, SpanKind: query.SpanKind, @@ -114,11 +116,19 @@ func (c *grpcClient) GetOperations(ctx context.Context, query *spanstore.Operati return nil, errors.Wrap(err, "plugin error") } - operations := make([]*spanstore.Operation, len(resp.OperationsV2)) - for i, operation := range resp.OperationsV2 { - operations[i] = &spanstore.Operation{ - Name: operation.Name, - SpanKind: operation.SpanKind, + var operations []spanstore.Operation + if resp.Operations != nil { + for _, operation := range resp.Operations { + operations = append(operations, spanstore.Operation{ + Name: operation.Name, + SpanKind: operation.SpanKind, + }) + } + } else { + for _, name := range resp.OperationNames { + operations = append(operations, spanstore.Operation{ + Name: name, + }) } } return operations, nil diff --git a/plugin/storage/grpc/shared/grpc_client_test.go b/plugin/storage/grpc/shared/grpc_client_test.go index 03a603b95d2..13747547006 100644 --- a/plugin/storage/grpc/shared/grpc_client_test.go +++ b/plugin/storage/grpc/shared/grpc_client_test.go @@ -119,18 +119,33 @@ func TestGRPCClientGetServices(t *testing.T) { }) } -func TestGRPCClientGetOperations(t *testing.T) { +func TestGRPCClientGetOperationsV1(t *testing.T) { withGRPCClient(func(r *grpcClientTest) { r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ Service: "service-a", }).Return(&storage_v1.GetOperationsResponse{ - OperationsV2: []*storage_v1.Operation{{Name: "operation-a"}}, + OperationNames: []string{"operation-a"}, }, nil) s, err := r.client.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "service-a"}) + spanstore.OperationQueryParameters{ServiceName: "service-a"}) assert.NoError(t, err) - assert.Equal(t, []*spanstore.Operation{{Name: "operation-a"}}, s) + assert.Equal(t, []spanstore.Operation{{Name: "operation-a"}}, s) + }) +} + +func TestGRPCClientGetOperationsV2(t *testing.T) { + withGRPCClient(func(r *grpcClientTest) { + r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ + Service: "service-a", + }).Return(&storage_v1.GetOperationsResponse{ + Operations: []*storage_v1.Operation{{Name: "operation-a"}}, + }, nil) + + s, err := r.client.GetOperations(context.Background(), + spanstore.OperationQueryParameters{ServiceName: "service-a"}) + assert.NoError(t, err) + assert.Equal(t, []spanstore.Operation{{Name: "operation-a"}}, s) }) } diff --git a/plugin/storage/grpc/shared/grpc_server.go b/plugin/storage/grpc/shared/grpc_server.go index a93c802cef4..abf6597f5cd 100644 --- a/plugin/storage/grpc/shared/grpc_server.go +++ b/plugin/storage/grpc/shared/grpc_server.go @@ -82,7 +82,7 @@ func (s *grpcServer) GetOperations( ctx context.Context, r *storage_v1.GetOperationsRequest, ) (*storage_v1.GetOperationsResponse, error) { - operations, err := s.Impl.SpanReader().GetOperations(ctx, &spanstore.OperationQueryParameters{ + operations, err := s.Impl.SpanReader().GetOperations(ctx, spanstore.OperationQueryParameters{ ServiceName: r.Service, SpanKind: r.SpanKind, }) @@ -90,21 +90,14 @@ func (s *grpcServer) GetOperations( return nil, err } grpcOperation := make([]*storage_v1.Operation, len(operations)) - operationNameSet := make(map[string]struct{}) for i, operation := range operations { grpcOperation[i] = &storage_v1.Operation{ Name: operation.Name, SpanKind: operation.SpanKind, } - operationNameSet[operation.Name] = struct{}{} - } - var uniqueNames []string - for name := range operationNameSet { - uniqueNames = append(uniqueNames, name) } return &storage_v1.GetOperationsResponse{ - Operations: uniqueNames, - OperationsV2: grpcOperation, + Operations: grpcOperation, }, nil } diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index 6a04b698ba5..d632e28602f 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -87,29 +87,25 @@ func TestGRPCServerGetServices(t *testing.T) { func TestGRPCServerGetOperations(t *testing.T) { withGRPCServer(func(r *grpcServerTest) { - expOperations := []*spanstore.Operation{ + expOperations := []spanstore.Operation{ {Name: "operation-a", SpanKind: "client"}, {Name: "operation-a", SpanKind: "server"}, {Name: "operation-b", SpanKind: "client"}, } - expOperationNames := []string{ - "operation-a", - "operation-b", - } + r.impl.spanReader.On("GetOperations", mock.Anything, - &spanstore.OperationQueryParameters{ServiceName: "service-a"}). + spanstore.OperationQueryParameters{ServiceName: "service-a"}). Return(expOperations, nil) resp, err := r.server.GetOperations(context.Background(), &storage_v1.GetOperationsRequest{ Service: "service-a", }) assert.NoError(t, err) - for i, operationV2 := range resp.OperationsV2 { - assert.Equal(t, expOperations[i].Name, operationV2.Name) - assert.Equal(t, expOperations[i].SpanKind, operationV2.SpanKind) + for i, operation := range resp.Operations { + assert.Equal(t, expOperations[i].Name, operation.Name) + assert.Equal(t, expOperations[i].SpanKind, operation.SpanKind) } - assert.Equal(t, expOperationNames, resp.Operations) }) } diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index 32b05e1b317..17ae8b24201 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -149,18 +149,18 @@ func (s *StorageIntegration) testGetLargeSpan(t *testing.T) { func (s *StorageIntegration) testGetOperations(t *testing.T) { defer s.cleanUp(t) - expected := []*spanstore.Operation{ + expected := []spanstore.Operation{ {Name: "example-operation-1"}, {Name: "example-operation-3"}, {Name: "example-operation-4"}} s.loadParseAndWriteExampleTrace(t) s.refresh(t) - var actual []*spanstore.Operation + var actual []spanstore.Operation found := s.waitForCondition(t, func(t *testing.T) bool { var err error actual, err = s.SpanReader.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "example-service-1"}) + spanstore.OperationQueryParameters{ServiceName: "example-service-1"}) require.NoError(t, err) return assert.ObjectsAreEqualValues(expected, actual) }) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index c1455368918..667646d81f7 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -121,7 +121,8 @@ func (r *ingester) GetServices(ctx context.Context) ([]string, error) { func (r *ingester) GetOperations( ctx context.Context, - query *spanstore.OperationQueryParameters) ([]*spanstore.Operation, error) { + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { return nil, nil } diff --git a/plugin/storage/memory/memory.go b/plugin/storage/memory/memory.go index c4eb84f99d7..5ea25bbba75 100644 --- a/plugin/storage/memory/memory.go +++ b/plugin/storage/memory/memory.go @@ -182,16 +182,18 @@ func (m *Store) GetServices(ctx context.Context) ([]string, error) { } // GetOperations returns the operations of a given service -func (m *Store) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (m *Store) GetOperations( + ctx context.Context, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { m.RLock() defer m.RUnlock() - var retMe []*spanstore.Operation + var retMe []spanstore.Operation if operations, ok := m.operations[query.ServiceName]; ok { for operationName, kinds := range operations { for kind := range kinds { if query.SpanKind == "" || query.SpanKind == kind { - retMe = append(retMe, &spanstore.Operation{ + retMe = append(retMe, spanstore.Operation{ Name: operationName, SpanKind: kind, }) diff --git a/plugin/storage/memory/memory_test.go b/plugin/storage/memory/memory_test.go index 868b01f828a..e9ab800c798 100644 --- a/plugin/storage/memory/memory_test.go +++ b/plugin/storage/memory/memory_test.go @@ -233,11 +233,13 @@ func TestStoreGetAllOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan1)) assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) - operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName}) + operations, err := store.GetOperations( + context.Background(), + spanstore.OperationQueryParameters{ServiceName: childSpan1.Process.ServiceName}, + ) assert.NoError(t, err) assert.Len(t, operations, 3) - assert.EqualValues(t, childSpan1.OperationName, (*operations[0]).Name) + assert.EqualValues(t, childSpan1.OperationName, operations[0].Name) }) } @@ -247,22 +249,26 @@ func TestStoreGetServerOperationsFound(t *testing.T) { assert.NoError(t, store.WriteSpan(childSpan1)) assert.NoError(t, store.WriteSpan(childSpan2)) assert.NoError(t, store.WriteSpan(childSpan2_1)) + expected := []spanstore.Operation{ + {Name: childSpan1.OperationName, SpanKind: "server"}, + } operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ + spanstore.OperationQueryParameters{ ServiceName: childSpan1.Process.ServiceName, SpanKind: "server", }) assert.NoError(t, err) assert.Len(t, operations, 1) - assert.EqualValues(t, childSpan1.OperationName, operations[0].Name) - assert.EqualValues(t, "server", operations[0].SpanKind) + assert.Equal(t, expected, operations) }) } func TestStoreGetOperationsNotFound(t *testing.T) { withPopulatedMemoryStore(func(store *Store) { - operations, err := store.GetOperations(context.Background(), - &spanstore.OperationQueryParameters{ServiceName: "notAService"}) + operations, err := store.GetOperations( + context.Background(), + spanstore.OperationQueryParameters{ServiceName: "notAService"}, + ) assert.NoError(t, err) assert.Len(t, operations, 0) }) diff --git a/proto-gen/storage_v1/storage.pb.go b/proto-gen/storage_v1/storage.pb.go index db6137ee4f5..20893a4fe29 100644 --- a/proto-gen/storage_v1/storage.pb.go +++ b/proto-gen/storage_v1/storage.pb.go @@ -458,8 +458,8 @@ func (m *Operation) GetSpanKind() string { } type GetOperationsResponse struct { - Operations []string `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` - OperationsV2 []*Operation `protobuf:"bytes,2,rep,name=operations_v2,json=operationsV2,proto3" json:"operations_v2,omitempty"` + OperationNames []string `protobuf:"bytes,1,rep,name=operationNames,proto3" json:"operationNames,omitempty"` + Operations []*Operation `protobuf:"bytes,2,rep,name=operations,proto3" json:"operations,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -498,16 +498,16 @@ func (m *GetOperationsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_GetOperationsResponse proto.InternalMessageInfo -func (m *GetOperationsResponse) GetOperations() []string { +func (m *GetOperationsResponse) GetOperationNames() []string { if m != nil { - return m.Operations + return m.OperationNames } return nil } -func (m *GetOperationsResponse) GetOperationsV2() []*Operation { +func (m *GetOperationsResponse) GetOperations() []*Operation { if m != nil { - return m.OperationsV2 + return m.Operations } return nil } @@ -835,67 +835,67 @@ func init() { proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffd func init() { golang_proto.RegisterFile("storage.proto", fileDescriptor_0d2c4ccf1453ffdb) } var fileDescriptor_0d2c4ccf1453ffdb = []byte{ - // 957 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4b, 0x73, 0xdb, 0x54, - 0x14, 0x46, 0x89, 0x5d, 0x5b, 0xc7, 0x4e, 0x49, 0x6e, 0x0c, 0x08, 0xd1, 0xda, 0x41, 0x90, 0x26, - 0x30, 0x83, 0x4c, 0xcc, 0x02, 0x86, 0xc7, 0x40, 0xdd, 0xa4, 0x9e, 0x00, 0x85, 0xa2, 0x66, 0xda, - 0x19, 0xca, 0xa0, 0xb9, 0x8e, 0x2e, 0x8a, 0x9a, 0xe8, 0x4a, 0x95, 0xae, 0x3c, 0x09, 0x6b, 0x7e, - 0x00, 0x4b, 0x56, 0x6c, 0xf9, 0x1b, 0x2c, 0xbb, 0x64, 0xcd, 0x22, 0x30, 0x61, 0xc9, 0x9f, 0x60, - 0xee, 0x43, 0xf2, 0x4b, 0x93, 0xa4, 0x19, 0x76, 0x3a, 0xe7, 0x7e, 0xe7, 0xbb, 0xe7, 0x71, 0xcf, - 0x67, 0xc3, 0x52, 0xca, 0xa2, 0x04, 0xfb, 0xc4, 0x8e, 0x93, 0x88, 0x45, 0x68, 0xe5, 0x09, 0x26, - 0x3e, 0x49, 0xec, 0xdc, 0x3b, 0xda, 0x32, 0x5b, 0x7e, 0xe4, 0x47, 0xe2, 0xb4, 0xcb, 0xbf, 0x24, - 0xd0, 0xec, 0xf8, 0x51, 0xe4, 0x1f, 0x91, 0xae, 0xb0, 0x86, 0xd9, 0x0f, 0x5d, 0x16, 0x84, 0x24, - 0x65, 0x38, 0x8c, 0x15, 0xa0, 0x3d, 0x0b, 0xf0, 0xb2, 0x04, 0xb3, 0x20, 0xa2, 0xea, 0xbc, 0x11, - 0x46, 0x1e, 0x39, 0x92, 0x86, 0xf5, 0xab, 0x06, 0x2f, 0x0f, 0x08, 0xdb, 0x26, 0x31, 0xa1, 0x1e, - 0xa1, 0xfb, 0x01, 0x49, 0x1d, 0xf2, 0x34, 0x23, 0x29, 0x43, 0x77, 0x00, 0x52, 0x86, 0x13, 0xe6, - 0xf2, 0x0b, 0x0c, 0x6d, 0x4d, 0xdb, 0x6c, 0xf4, 0x4c, 0x5b, 0x92, 0xdb, 0x39, 0xb9, 0xbd, 0x97, - 0xdf, 0xde, 0xaf, 0x3f, 0x3b, 0xed, 0xbc, 0xf0, 0xf3, 0x5f, 0x1d, 0xcd, 0xd1, 0x45, 0x1c, 0x3f, - 0x41, 0x9f, 0x42, 0x9d, 0x50, 0x4f, 0x52, 0x2c, 0x3c, 0x07, 0x45, 0x8d, 0x50, 0x8f, 0xfb, 0xad, - 0x21, 0xbc, 0x32, 0x97, 0x5f, 0x1a, 0x47, 0x34, 0x25, 0x68, 0x00, 0x4d, 0x6f, 0xc2, 0x6f, 0x68, - 0x6b, 0x8b, 0x9b, 0x8d, 0xde, 0x4d, 0x5b, 0x75, 0x12, 0xc7, 0x81, 0x3b, 0xea, 0xd9, 0x45, 0xe8, - 0xc9, 0x97, 0x01, 0x3d, 0xec, 0x57, 0xf8, 0x15, 0xce, 0x54, 0xa0, 0xf5, 0x11, 0x2c, 0x3f, 0x4a, - 0x02, 0x46, 0x1e, 0xc4, 0x98, 0xe6, 0xd5, 0x6f, 0x40, 0x25, 0x8d, 0x31, 0x55, 0x75, 0xaf, 0xce, - 0x90, 0x0a, 0xa4, 0x00, 0x58, 0xab, 0xb0, 0x32, 0x11, 0x2c, 0x53, 0xb3, 0x28, 0xbc, 0x38, 0x20, - 0x6c, 0x2f, 0xc1, 0xfb, 0x24, 0x27, 0x7c, 0x0c, 0x75, 0xc6, 0x6d, 0x37, 0xf0, 0x04, 0x69, 0xb3, - 0xff, 0x19, 0x4f, 0xe5, 0xcf, 0xd3, 0xce, 0x3b, 0x7e, 0xc0, 0x0e, 0xb2, 0xa1, 0xbd, 0x1f, 0x85, - 0x5d, 0x79, 0x0d, 0x07, 0x06, 0xd4, 0x57, 0x56, 0x57, 0x0e, 0x4c, 0xb0, 0xed, 0x6e, 0x9f, 0x9d, - 0x76, 0x6a, 0xea, 0xd3, 0xa9, 0x09, 0xc6, 0x5d, 0xcf, 0x6a, 0x01, 0x1a, 0x10, 0xf6, 0x80, 0x24, - 0xa3, 0x60, 0xbf, 0x98, 0xa0, 0xb5, 0x05, 0xab, 0x53, 0x5e, 0xd5, 0x37, 0x13, 0xea, 0xa9, 0xf2, - 0x89, 0x9e, 0xe9, 0x4e, 0x61, 0x5b, 0xf7, 0xa0, 0x35, 0x20, 0xec, 0xeb, 0x98, 0xc8, 0x27, 0x53, - 0x3c, 0x06, 0x03, 0x6a, 0x0a, 0x23, 0x92, 0xd7, 0x9d, 0xdc, 0x44, 0xaf, 0x81, 0xce, 0xfb, 0xe0, - 0x1e, 0x06, 0xd4, 0x13, 0x23, 0xe6, 0x74, 0x31, 0xa6, 0x5f, 0x04, 0xd4, 0xb3, 0x3e, 0x06, 0xbd, - 0xe0, 0x42, 0x08, 0x2a, 0x14, 0x87, 0x39, 0x81, 0xf8, 0x3e, 0x3f, 0xfa, 0x47, 0x78, 0x69, 0x26, - 0x19, 0x55, 0x41, 0x1b, 0x20, 0x2a, 0xbc, 0xaa, 0x86, 0x09, 0x0f, 0xba, 0x0d, 0x4b, 0x63, 0xcb, - 0x1d, 0xf5, 0x8c, 0x05, 0xf1, 0x34, 0x6e, 0xd8, 0x73, 0x4b, 0x66, 0x17, 0xec, 0x4e, 0x73, 0x1c, - 0xf2, 0xb0, 0x67, 0xfd, 0x56, 0x81, 0x96, 0x68, 0xf3, 0x37, 0x19, 0x49, 0x4e, 0xee, 0xe3, 0x04, - 0x87, 0x84, 0x91, 0x24, 0x45, 0xaf, 0x43, 0x53, 0x95, 0xee, 0x4e, 0x54, 0xd3, 0x50, 0xbe, 0xaf, - 0x78, 0x51, 0xeb, 0x70, 0xbd, 0xe0, 0x92, 0x20, 0x59, 0xd9, 0x38, 0x29, 0x01, 0xdb, 0x81, 0x0a, - 0xc3, 0x7e, 0x6a, 0x2c, 0x8a, 0xe4, 0xb6, 0x4a, 0x92, 0x2b, 0x4b, 0xc0, 0xde, 0xc3, 0x7e, 0xba, - 0x43, 0x59, 0x72, 0xe2, 0x88, 0x70, 0xf4, 0x39, 0x5c, 0x1f, 0xef, 0xa9, 0x1b, 0x06, 0xd4, 0xa8, - 0x3c, 0xc7, 0xa2, 0x35, 0x8b, 0x5d, 0xbd, 0x17, 0xd0, 0x59, 0x2e, 0x7c, 0x6c, 0x54, 0xaf, 0xc6, - 0x85, 0x8f, 0xd1, 0x5d, 0x68, 0xe6, 0xca, 0x23, 0xb2, 0xba, 0x26, 0x98, 0x5e, 0x9d, 0x63, 0xda, - 0x56, 0x20, 0x49, 0xf4, 0x0b, 0x27, 0x6a, 0xe4, 0x81, 0x3c, 0xa7, 0x29, 0x1e, 0x7c, 0x6c, 0xd4, - 0xae, 0xc2, 0x83, 0x8f, 0xd1, 0x4d, 0x00, 0x9a, 0x85, 0xae, 0x58, 0x99, 0xd4, 0xa8, 0xaf, 0x69, - 0x9b, 0x55, 0x47, 0xa7, 0x59, 0x28, 0x9a, 0x9c, 0x9a, 0xef, 0x83, 0x5e, 0x74, 0x16, 0x2d, 0xc3, - 0xe2, 0x21, 0x39, 0x51, 0xb3, 0xe5, 0x9f, 0xa8, 0x05, 0xd5, 0x11, 0x3e, 0xca, 0xf2, 0x51, 0x4a, - 0xe3, 0xc3, 0x85, 0x0f, 0x34, 0xcb, 0x81, 0x95, 0xbb, 0x01, 0xf5, 0x24, 0x4d, 0xbe, 0x2f, 0x9f, - 0x40, 0xf5, 0x29, 0x9f, 0x9b, 0xd2, 0x8f, 0x8d, 0x4b, 0x0e, 0xd7, 0x91, 0x51, 0xd6, 0x0e, 0x20, - 0xae, 0x27, 0xc5, 0x8b, 0xbf, 0x73, 0x90, 0xd1, 0x43, 0xd4, 0x85, 0x2a, 0xdf, 0x8d, 0x5c, 0xe9, - 0xca, 0x44, 0x49, 0xe9, 0x9b, 0xc4, 0x59, 0x7b, 0xb0, 0x5a, 0xa4, 0xb6, 0xbb, 0xfd, 0x7f, 0x25, - 0x37, 0x82, 0xd6, 0x34, 0xab, 0xda, 0xca, 0xef, 0x41, 0xcf, 0x15, 0x4e, 0xa6, 0xd8, 0xec, 0xdf, - 0xbe, 0xaa, 0xc4, 0xd5, 0x0b, 0xf6, 0xba, 0xd2, 0xb8, 0xb4, 0xf7, 0x04, 0x96, 0x79, 0x89, 0x42, - 0x6d, 0x93, 0xfb, 0x47, 0x99, 0x1f, 0x50, 0xf4, 0x10, 0xf4, 0x42, 0x7d, 0xd1, 0x1b, 0x25, 0x85, - 0xcc, 0x0a, 0xbb, 0xf9, 0xe6, 0xf9, 0x20, 0x59, 0x4b, 0xef, 0xdf, 0x45, 0x79, 0x99, 0x43, 0xb0, - 0x57, 0x5c, 0xf6, 0x08, 0xea, 0xb9, 0xaa, 0x23, 0xab, 0x84, 0x66, 0x46, 0xf2, 0xcd, 0xf5, 0x12, - 0xcc, 0xfc, 0x58, 0xdf, 0xd5, 0xd0, 0x77, 0xd0, 0x98, 0x10, 0x6a, 0xb4, 0x5e, 0xce, 0x3d, 0x23, - 0xef, 0xe6, 0xad, 0x8b, 0x60, 0x6a, 0x2e, 0x43, 0x58, 0x9a, 0x92, 0x51, 0xb4, 0x51, 0x1e, 0x38, - 0xa7, 0xfa, 0xe6, 0xe6, 0xc5, 0x40, 0x75, 0xc7, 0x63, 0x80, 0xf1, 0x12, 0xa0, 0xb2, 0x1e, 0xcf, - 0xed, 0xc8, 0xe5, 0xdb, 0xe3, 0x42, 0x73, 0xf2, 0xc1, 0xa1, 0x5b, 0xe7, 0xd1, 0x8f, 0xdf, 0xb9, - 0xb9, 0x71, 0x21, 0x4e, 0x4d, 0xfb, 0x27, 0x0d, 0x8c, 0xe9, 0xbf, 0x18, 0x13, 0x53, 0x3f, 0x10, - 0xbf, 0xe5, 0x93, 0xc7, 0xe8, 0xad, 0xf2, 0xbe, 0x94, 0xfc, 0x8b, 0x32, 0xdf, 0xbe, 0x0c, 0x54, - 0xa6, 0xd1, 0xbf, 0xf1, 0xec, 0xac, 0xad, 0xfd, 0x71, 0xd6, 0xd6, 0xfe, 0x3e, 0x6b, 0x6b, 0xbf, - 0xff, 0xd3, 0xd6, 0xbe, 0x05, 0x15, 0xe5, 0x8e, 0xb6, 0x86, 0xd7, 0x84, 0xd2, 0xbd, 0xf7, 0x5f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0xf7, 0xe6, 0x31, 0x39, 0x0a, 0x00, 0x00, + // 953 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4d, 0x73, 0xdb, 0x44, + 0x18, 0x46, 0x89, 0x5d, 0xdb, 0xaf, 0x9d, 0x92, 0x6c, 0x0c, 0x08, 0xd1, 0xda, 0x41, 0x90, 0x0f, + 0x98, 0x41, 0x26, 0xe6, 0x00, 0x03, 0x65, 0x00, 0x37, 0xa9, 0x27, 0x40, 0xa1, 0xa8, 0x19, 0x3a, + 0x43, 0x19, 0x34, 0xeb, 0x68, 0x51, 0xd4, 0x44, 0x2b, 0x55, 0x5a, 0x79, 0x92, 0x03, 0x37, 0x7e, + 0x00, 0x47, 0x4e, 0x5c, 0xf9, 0x1b, 0x1c, 0x7b, 0xe4, 0xcc, 0x21, 0x30, 0xe1, 0xc8, 0x9f, 0x60, + 0xf6, 0x43, 0x8a, 0x6c, 0x6b, 0xf2, 0x35, 0xbd, 0x69, 0xdf, 0x7d, 0xde, 0xe7, 0xfd, 0xda, 0xf7, + 0xb1, 0x61, 0x21, 0x61, 0x61, 0x8c, 0x3d, 0x62, 0x45, 0x71, 0xc8, 0x42, 0xb4, 0xf4, 0x04, 0x13, + 0x8f, 0xc4, 0x56, 0x66, 0x1d, 0x6f, 0x1a, 0x6d, 0x2f, 0xf4, 0x42, 0x71, 0xdb, 0xe3, 0x5f, 0x12, + 0x68, 0x74, 0xbd, 0x30, 0xf4, 0x0e, 0x49, 0x4f, 0x9c, 0x46, 0xe9, 0x8f, 0x3d, 0xe6, 0x07, 0x24, + 0x61, 0x38, 0x88, 0x14, 0xa0, 0x33, 0x0d, 0x70, 0xd3, 0x18, 0x33, 0x3f, 0xa4, 0xea, 0xbe, 0x19, + 0x84, 0x2e, 0x39, 0x94, 0x07, 0xf3, 0x37, 0x0d, 0x5e, 0x1e, 0x12, 0xb6, 0x45, 0x22, 0x42, 0x5d, + 0x42, 0xf7, 0x7c, 0x92, 0xd8, 0xe4, 0x69, 0x4a, 0x12, 0x86, 0xee, 0x02, 0x24, 0x0c, 0xc7, 0xcc, + 0xe1, 0x01, 0x74, 0x6d, 0x45, 0xdb, 0x68, 0xf6, 0x0d, 0x4b, 0x92, 0x5b, 0x19, 0xb9, 0xb5, 0x9b, + 0x45, 0x1f, 0xd4, 0x9f, 0x9d, 0x74, 0x5f, 0xf8, 0xe5, 0xef, 0xae, 0x66, 0x37, 0x84, 0x1f, 0xbf, + 0x41, 0x9f, 0x40, 0x9d, 0x50, 0x57, 0x52, 0xcc, 0x5d, 0x81, 0xa2, 0x46, 0xa8, 0xcb, 0xed, 0xe6, + 0x08, 0x5e, 0x99, 0xc9, 0x2f, 0x89, 0x42, 0x9a, 0x10, 0x34, 0x84, 0x96, 0x5b, 0xb0, 0xeb, 0xda, + 0xca, 0xfc, 0x46, 0xb3, 0x7f, 0xdb, 0x52, 0x9d, 0xc4, 0x91, 0xef, 0x8c, 0xfb, 0x56, 0xee, 0x7a, + 0xfc, 0xa5, 0x4f, 0x0f, 0x06, 0x15, 0x1e, 0xc2, 0x9e, 0x70, 0x34, 0x3f, 0x82, 0xc5, 0x47, 0xb1, + 0xcf, 0xc8, 0xc3, 0x08, 0xd3, 0xac, 0xfa, 0x75, 0xa8, 0x24, 0x11, 0xa6, 0xaa, 0xee, 0xe5, 0x29, + 0x52, 0x81, 0x14, 0x00, 0x73, 0x19, 0x96, 0x0a, 0xce, 0x32, 0x35, 0x93, 0xc2, 0x8b, 0x43, 0xc2, + 0x76, 0x63, 0xbc, 0x47, 0x32, 0xc2, 0xc7, 0x50, 0x67, 0xfc, 0xec, 0xf8, 0xae, 0x20, 0x6d, 0x0d, + 0x3e, 0xe5, 0xa9, 0xfc, 0x75, 0xd2, 0x7d, 0xc7, 0xf3, 0xd9, 0x7e, 0x3a, 0xb2, 0xf6, 0xc2, 0xa0, + 0x27, 0xc3, 0x70, 0xa0, 0x4f, 0x3d, 0x75, 0xea, 0xc9, 0x81, 0x09, 0xb6, 0x9d, 0xad, 0xd3, 0x93, + 0x6e, 0x4d, 0x7d, 0xda, 0x35, 0xc1, 0xb8, 0xe3, 0x9a, 0x6d, 0x40, 0x43, 0xc2, 0x1e, 0x92, 0x78, + 0xec, 0xef, 0xe5, 0x13, 0x34, 0x37, 0x61, 0x79, 0xc2, 0xaa, 0xfa, 0x66, 0x40, 0x3d, 0x51, 0x36, + 0xd1, 0xb3, 0x86, 0x9d, 0x9f, 0xcd, 0xfb, 0xd0, 0x1e, 0x12, 0xf6, 0x75, 0x44, 0xe4, 0x93, 0xc9, + 0x1f, 0x83, 0x0e, 0x35, 0x85, 0x11, 0xc9, 0x37, 0xec, 0xec, 0x88, 0x5e, 0x83, 0x06, 0xef, 0x83, + 0x73, 0xe0, 0x53, 0x57, 0x8c, 0x98, 0xd3, 0x45, 0x98, 0x7e, 0xe1, 0x53, 0xd7, 0xbc, 0x03, 0x8d, + 0x9c, 0x0b, 0x21, 0xa8, 0x50, 0x1c, 0x64, 0x04, 0xe2, 0xfb, 0x7c, 0xef, 0x9f, 0xe0, 0xa5, 0xa9, + 0x64, 0x54, 0x05, 0x6b, 0x70, 0x33, 0xcc, 0xac, 0x5f, 0xe1, 0x20, 0xaf, 0x63, 0xca, 0x8a, 0xee, + 0x00, 0xe4, 0x96, 0x44, 0x9f, 0x13, 0xef, 0xe3, 0x96, 0x35, 0xb3, 0x69, 0x56, 0x1e, 0xc2, 0x2e, + 0xe0, 0xcd, 0xdf, 0x2b, 0xd0, 0x16, 0x9d, 0xfe, 0x26, 0x25, 0xf1, 0xf1, 0x03, 0x1c, 0xe3, 0x80, + 0x30, 0x12, 0x27, 0xe8, 0x75, 0x68, 0xa9, 0xea, 0x9d, 0x42, 0x41, 0x4d, 0x65, 0xe3, 0xa1, 0xd1, + 0x6a, 0x21, 0x43, 0x09, 0x92, 0xc5, 0x2d, 0x4c, 0x64, 0x88, 0xb6, 0xa1, 0xc2, 0xb0, 0x97, 0xe8, + 0xf3, 0x22, 0xb5, 0xcd, 0x92, 0xd4, 0xca, 0x12, 0xb0, 0x76, 0xb1, 0x97, 0x6c, 0x53, 0x16, 0x1f, + 0xdb, 0xc2, 0x1d, 0x7d, 0x0e, 0x37, 0xcf, 0x56, 0xd5, 0x09, 0x7c, 0xaa, 0x57, 0xae, 0xb0, 0x6b, + 0xad, 0x7c, 0x5d, 0xef, 0xfb, 0x74, 0x9a, 0x0b, 0x1f, 0xe9, 0xd5, 0xeb, 0x71, 0xe1, 0x23, 0x74, + 0x0f, 0x5a, 0x99, 0xf8, 0x88, 0xac, 0x6e, 0x08, 0xa6, 0x57, 0x67, 0x98, 0xb6, 0x14, 0x48, 0x12, + 0xfd, 0xca, 0x89, 0x9a, 0x99, 0x23, 0xcf, 0x69, 0x82, 0x07, 0x1f, 0xe9, 0xb5, 0xeb, 0xf0, 0xe0, + 0x23, 0x74, 0x1b, 0x80, 0xa6, 0x81, 0x23, 0xb6, 0x26, 0xd1, 0xeb, 0x2b, 0xda, 0x46, 0xd5, 0x6e, + 0xd0, 0x34, 0x10, 0x4d, 0x4e, 0x8c, 0xf7, 0xa1, 0x91, 0x77, 0x16, 0x2d, 0xc2, 0xfc, 0x01, 0x39, + 0x56, 0xb3, 0xe5, 0x9f, 0xa8, 0x0d, 0xd5, 0x31, 0x3e, 0x4c, 0xb3, 0x51, 0xca, 0xc3, 0x87, 0x73, + 0x1f, 0x68, 0xa6, 0x0d, 0x4b, 0xf7, 0x7c, 0xea, 0x4a, 0x9a, 0x6c, 0x65, 0x3e, 0x86, 0xea, 0x53, + 0x3e, 0x37, 0x25, 0x21, 0xeb, 0x97, 0x1c, 0xae, 0x2d, 0xbd, 0xcc, 0x6d, 0x40, 0x5c, 0x52, 0xf2, + 0x47, 0x7f, 0x77, 0x3f, 0xa5, 0x07, 0xa8, 0x07, 0x55, 0xbe, 0x1e, 0x99, 0xd8, 0x95, 0xe9, 0x92, + 0x92, 0x38, 0x89, 0x33, 0x77, 0x61, 0x39, 0x4f, 0x6d, 0x67, 0xeb, 0x79, 0x25, 0x37, 0x86, 0xf6, + 0x24, 0xab, 0x5a, 0xcc, 0x1f, 0xa0, 0x91, 0x89, 0x9c, 0x4c, 0xb1, 0x35, 0xf8, 0xec, 0xba, 0x2a, + 0x57, 0xcf, 0xd9, 0xeb, 0x4a, 0xe6, 0x92, 0xfe, 0x13, 0x58, 0xe4, 0x25, 0x0a, 0xc1, 0x8d, 0x1f, + 0x1c, 0xa6, 0x9e, 0x4f, 0xd1, 0xb7, 0xd0, 0xc8, 0x05, 0x18, 0xbd, 0x51, 0x52, 0xc8, 0xb4, 0xb6, + 0x1b, 0x6f, 0x9e, 0x0f, 0x92, 0xb5, 0xf4, 0xff, 0x9b, 0x97, 0xc1, 0x6c, 0x82, 0xdd, 0x3c, 0xd8, + 0x23, 0xa8, 0x67, 0xc2, 0x8e, 0xcc, 0x12, 0x9a, 0x29, 0xd5, 0x37, 0x56, 0x4b, 0x30, 0xb3, 0x63, + 0x7d, 0x57, 0x43, 0xdf, 0x43, 0xb3, 0xa0, 0xd5, 0x68, 0xb5, 0x9c, 0x7b, 0x4a, 0xe1, 0x8d, 0xb5, + 0x8b, 0x60, 0x6a, 0x2e, 0x23, 0x58, 0x98, 0x50, 0x52, 0xb4, 0x5e, 0xee, 0x38, 0x23, 0xfc, 0xc6, + 0xc6, 0xc5, 0x40, 0x15, 0xe3, 0x31, 0xc0, 0xd9, 0x12, 0xa0, 0xb2, 0x1e, 0xcf, 0xec, 0xc8, 0xe5, + 0xdb, 0xe3, 0x40, 0xab, 0xf8, 0xe0, 0xd0, 0xda, 0x79, 0xf4, 0x67, 0xef, 0xdc, 0x58, 0xbf, 0x10, + 0xa7, 0xa6, 0xfd, 0xb3, 0x06, 0xfa, 0xe4, 0xbf, 0x8c, 0xc2, 0xd4, 0xf7, 0xc5, 0xcf, 0x79, 0xf1, + 0x1a, 0xbd, 0x55, 0xde, 0x97, 0x92, 0x3f, 0x52, 0xc6, 0xdb, 0x97, 0x81, 0xca, 0x34, 0x06, 0xb7, + 0x9e, 0x9d, 0x76, 0xb4, 0x3f, 0x4f, 0x3b, 0xda, 0x3f, 0xa7, 0x1d, 0xed, 0x8f, 0x7f, 0x3b, 0xda, + 0x77, 0xa0, 0xbc, 0x9c, 0xf1, 0xe6, 0xe8, 0x86, 0x50, 0xba, 0xf7, 0xfe, 0x0f, 0x00, 0x00, 0xff, + 0xff, 0x22, 0xdc, 0xa9, 0x3a, 0x3c, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1580,8 +1580,8 @@ func (m *GetOperationsResponse) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Operations) > 0 { - for _, s := range m.Operations { + if len(m.OperationNames) > 0 { + for _, s := range m.OperationNames { dAtA[i] = 0xa i++ l = len(s) @@ -1595,8 +1595,8 @@ func (m *GetOperationsResponse) MarshalTo(dAtA []byte) (int, error) { i += copy(dAtA[i:], s) } } - if len(m.OperationsV2) > 0 { - for _, msg := range m.OperationsV2 { + if len(m.Operations) > 0 { + for _, msg := range m.Operations { dAtA[i] = 0x12 i++ i = encodeVarintStorage(dAtA, i, uint64(msg.Size())) @@ -1989,14 +1989,14 @@ func (m *GetOperationsResponse) Size() (n int) { } var l int _ = l - if len(m.Operations) > 0 { - for _, s := range m.Operations { + if len(m.OperationNames) > 0 { + for _, s := range m.OperationNames { l = len(s) n += 1 + l + sovStorage(uint64(l)) } } - if len(m.OperationsV2) > 0 { - for _, e := range m.OperationsV2 { + if len(m.Operations) > 0 { + for _, e := range m.Operations { l = e.Size() n += 1 + l + sovStorage(uint64(l)) } @@ -2973,7 +2973,7 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OperationNames", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3001,11 +3001,11 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Operations = append(m.Operations, string(dAtA[iNdEx:postIndex])) + m.OperationNames = append(m.OperationNames, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OperationsV2", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3032,8 +3032,8 @@ func (m *GetOperationsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OperationsV2 = append(m.OperationsV2, &Operation{}) - if err := m.OperationsV2[len(m.OperationsV2)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Operations = append(m.Operations, &Operation{}) + if err := m.Operations[len(m.Operations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/storage/spanstore/interface.go b/storage/spanstore/interface.go index 4b1a2ba3ff2..207bc6c64f2 100644 --- a/storage/spanstore/interface.go +++ b/storage/spanstore/interface.go @@ -37,7 +37,7 @@ var ( type Reader interface { GetTrace(ctx context.Context, traceID model.TraceID) (*model.Trace, error) GetServices(ctx context.Context) ([]string, error) - GetOperations(ctx context.Context, query *OperationQueryParameters) ([]*Operation, error) + GetOperations(ctx context.Context, query OperationQueryParameters) ([]Operation, error) FindTraces(ctx context.Context, query *TraceQueryParameters) ([]*model.Trace, error) FindTraceIDs(ctx context.Context, query *TraceQueryParameters) ([]model.TraceID, error) } diff --git a/storage/spanstore/metrics/decorator.go b/storage/spanstore/metrics/decorator.go index c62807dec98..87a258d7f59 100644 --- a/storage/spanstore/metrics/decorator.go +++ b/storage/spanstore/metrics/decorator.go @@ -108,8 +108,8 @@ func (m *ReadMetricsDecorator) GetServices(ctx context.Context) ([]string, error // GetOperations implements spanstore.Reader#GetOperations func (m *ReadMetricsDecorator) GetOperations( ctx context.Context, - query *spanstore.OperationQueryParameters, -) ([]*spanstore.Operation, error) { + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { start := time.Now() retMe, err := m.spanReader.GetOperations(ctx, query) m.getOperationsMetrics.emit(err, time.Since(start), len(retMe)) diff --git a/storage/spanstore/metrics/decorator_test.go b/storage/spanstore/metrics/decorator_test.go index 4848d8350a7..3ac1c1ed0cb 100644 --- a/storage/spanstore/metrics/decorator_test.go +++ b/storage/spanstore/metrics/decorator_test.go @@ -36,9 +36,9 @@ func TestSuccessfulUnderlyingCalls(t *testing.T) { mrs := NewReadMetricsDecorator(&mockReader, mf) mockReader.On("GetServices", context.Background()).Return([]string{}, nil) mrs.GetServices(context.Background()) - operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something"} + operationQuery := spanstore.OperationQueryParameters{ServiceName: "something"} mockReader.On("GetOperations", context.Background(), operationQuery). - Return([]*spanstore.Operation{}, nil) + Return([]spanstore.Operation{}, nil) mrs.GetOperations(context.Background(), operationQuery) mockReader.On("GetTrace", context.Background(), model.TraceID{}).Return(&model.Trace{}, nil) mrs.GetTrace(context.Background(), model.TraceID{}) @@ -103,7 +103,7 @@ func TestFailingUnderlyingCalls(t *testing.T) { mockReader.On("GetServices", context.Background()). Return(nil, errors.New("Failure")) mrs.GetServices(context.Background()) - operationQuery := &spanstore.OperationQueryParameters{ServiceName: "something"} + operationQuery := spanstore.OperationQueryParameters{ServiceName: "something"} mockReader.On("GetOperations", context.Background(), operationQuery). Return(nil, errors.New("Failure")) mrs.GetOperations(context.Background(), operationQuery) diff --git a/storage/spanstore/mocks/Reader.go b/storage/spanstore/mocks/Reader.go index 135f576c802..be9377e0a45 100644 --- a/storage/spanstore/mocks/Reader.go +++ b/storage/spanstore/mocks/Reader.go @@ -74,22 +74,26 @@ func (_m *Reader) FindTraces(ctx context.Context, query *spanstore.TraceQueryPar } // GetOperations provides a mock function with given fields: ctx, query -func (_m *Reader) GetOperations(ctx context.Context, query *spanstore.OperationQueryParameters) ( - []*spanstore.Operation, error) { +func (_m *Reader) GetOperations( + ctx context.Context, + query spanstore.OperationQueryParameters, +) ([]spanstore.Operation, error) { ret := _m.Called(ctx, query) - var r0 []*spanstore.Operation - if rf, ok := ret.Get(0).(func(context.Context, - *spanstore.OperationQueryParameters) []*spanstore.Operation); ok { + var r0 []spanstore.Operation + if rf, ok := ret.Get(0).(func( + context.Context, + spanstore.OperationQueryParameters, + ) []spanstore.Operation); ok { r0 = rf(ctx, query) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*spanstore.Operation) + r0 = ret.Get(0).([]spanstore.Operation) } } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *spanstore.OperationQueryParameters) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, spanstore.OperationQueryParameters) error); ok { r1 = rf(ctx, query) } else { r1 = ret.Error(1) From 156af383f36631c1a7e06da9d530ecbef85e0ba1 Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Mon, 25 Nov 2019 14:51:53 -0500 Subject: [PATCH 11/12] Use operation as key for memory plugin Signed-off-by: Jun Guo --- cmd/query/app/http_handler_test.go | 4 --- cmd/query/app/querysvc/query_service.go | 2 ++ .../cassandra/spanstore/reader_test.go | 15 +++++----- .../storage/grpc/shared/grpc_client_test.go | 4 +-- .../storage/grpc/shared/grpc_server_test.go | 1 + .../fixtures/traces/example_trace.json | 12 ++++++-- .../storage/integration/integration_test.go | 4 +-- plugin/storage/memory/memory.go | 30 +++++++++---------- 8 files changed, 40 insertions(+), 32 deletions(-) diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index dd60fde1b6a..eb2c3c7d373 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -523,10 +523,6 @@ func TestGetOperationsLegacySuccess(t *testing.T) { defer server.Close() expectedOperationNames := []string{"", "get"} expectedOperations := []spanstore.Operation{{Name: ""}, {Name: "get", SpanKind: "server"}} - readMock.On("GetOperations", - mock.AnythingOfType("*context.valueCtx"), - "abc/trifle", - ).Return(expectedOperationNames, nil).Once() readMock.On( "GetOperations", mock.AnythingOfType("*context.valueCtx"), diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index bf462db667a..27d7b6a5dc1 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -83,6 +83,8 @@ func (qs QueryService) GetOperations(ctx context.Context, service string) ([]str operations, err := qs.spanReader.GetOperations(ctx, spanstore.OperationQueryParameters{ ServiceName: service, }) + + // TODO: remove below and simply return the result from query service if err != nil { return nil, err } diff --git a/plugin/storage/cassandra/spanstore/reader_test.go b/plugin/storage/cassandra/spanstore/reader_test.go index 5e5837cc438..66ca4450831 100644 --- a/plugin/storage/cassandra/spanstore/reader_test.go +++ b/plugin/storage/cassandra/spanstore/reader_test.go @@ -74,19 +74,20 @@ func TestSpanReaderGetServices(t *testing.T) { func TestSpanReaderGetOperations(t *testing.T) { withSpanReader(func(r *spanReaderTest) { + expectedOperations := []spanstore.Operation{ + { + Name: "operation-a", + SpanKind: "server", + }, + } r.reader.operationNamesReader = func(parameters spanstore.OperationQueryParameters) ([]spanstore.Operation, error) { - return []spanstore.Operation{ - { - Name: "operation-a", - SpanKind: "server", - }, - }, nil + return expectedOperations, nil } s, err := r.reader.GetOperations(context.Background(), spanstore.OperationQueryParameters{ServiceName: "service-x", SpanKind: "server"}) assert.NoError(t, err) - assert.Equal(t, []spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) + assert.Equal(t, expectedOperations, s) }) } diff --git a/plugin/storage/grpc/shared/grpc_client_test.go b/plugin/storage/grpc/shared/grpc_client_test.go index 13747547006..e31c9530a56 100644 --- a/plugin/storage/grpc/shared/grpc_client_test.go +++ b/plugin/storage/grpc/shared/grpc_client_test.go @@ -139,13 +139,13 @@ func TestGRPCClientGetOperationsV2(t *testing.T) { r.spanReader.On("GetOperations", mock.Anything, &storage_v1.GetOperationsRequest{ Service: "service-a", }).Return(&storage_v1.GetOperationsResponse{ - Operations: []*storage_v1.Operation{{Name: "operation-a"}}, + Operations: []*storage_v1.Operation{{Name: "operation-a", SpanKind: "server"}}, }, nil) s, err := r.client.GetOperations(context.Background(), spanstore.OperationQueryParameters{ServiceName: "service-a"}) assert.NoError(t, err) - assert.Equal(t, []spanstore.Operation{{Name: "operation-a"}}, s) + assert.Equal(t, []spanstore.Operation{{Name: "operation-a", SpanKind: "server"}}, s) }) } diff --git a/plugin/storage/grpc/shared/grpc_server_test.go b/plugin/storage/grpc/shared/grpc_server_test.go index d632e28602f..59fe23ee161 100644 --- a/plugin/storage/grpc/shared/grpc_server_test.go +++ b/plugin/storage/grpc/shared/grpc_server_test.go @@ -102,6 +102,7 @@ func TestGRPCServerGetOperations(t *testing.T) { Service: "service-a", }) assert.NoError(t, err) + assert.Equal(t, len(expOperations), len(resp.Operations)) for i, operation := range resp.Operations { assert.Equal(t, expOperations[i].Name, operation.Name) assert.Equal(t, expOperations[i].SpanKind, operation.SpanKind) diff --git a/plugin/storage/integration/fixtures/traces/example_trace.json b/plugin/storage/integration/fixtures/traces/example_trace.json index 8f8ec00f5da..d716b4b5719 100644 --- a/plugin/storage/integration/fixtures/traces/example_trace.json +++ b/plugin/storage/integration/fixtures/traces/example_trace.json @@ -76,7 +76,11 @@ "references": [], "startTime": "2017-01-26T16:46:31.639875Z", "duration": "100000ns", - "tags": [], + "tags": [{ + "key": "span.kind", + "vType": "STRING", + "vStr": "server" + }], "process": { "serviceName": "example-service-1", "tags": [] @@ -99,7 +103,11 @@ "references": [], "startTime": "2017-01-26T16:46:31.639875Z", "duration": "100000ns", - "tags": [], + "tags": [{ + "key": "span.kind", + "vType": "STRING", + "vStr": "client" + }], "process": { "serviceName": "example-service-1", "tags": [] diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index 17ae8b24201..3f59c04c85a 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -151,8 +151,8 @@ func (s *StorageIntegration) testGetOperations(t *testing.T) { expected := []spanstore.Operation{ {Name: "example-operation-1"}, - {Name: "example-operation-3"}, - {Name: "example-operation-4"}} + {Name: "example-operation-3", SpanKind: "server"}, + {Name: "example-operation-4", SpanKind: "client"}} s.loadParseAndWriteExampleTrace(t) s.refresh(t) diff --git a/plugin/storage/memory/memory.go b/plugin/storage/memory/memory.go index 5ea25bbba75..d8008a00c6d 100644 --- a/plugin/storage/memory/memory.go +++ b/plugin/storage/memory/memory.go @@ -34,7 +34,7 @@ type Store struct { ids []*model.TraceID traces map[model.TraceID]*model.Trace services map[string]struct{} - operations map[string]map[string]map[string]struct{} + operations map[string]map[spanstore.Operation]struct{} deduper adjuster.Adjuster config config.Configuration index int @@ -51,7 +51,7 @@ func WithConfiguration(configuration config.Configuration) *Store { ids: make([]*model.TraceID, configuration.MaxTraces), traces: map[model.TraceID]*model.Trace{}, services: map[string]struct{}{}, - operations: map[string]map[string]map[string]struct{}{}, + operations: map[string]map[spanstore.Operation]struct{}{}, deduper: adjuster.SpanIDDeduper(), config: configuration, } @@ -118,14 +118,19 @@ func (m *Store) WriteSpan(span *model.Span) error { m.Lock() defer m.Unlock() if _, ok := m.operations[span.Process.ServiceName]; !ok { - m.operations[span.Process.ServiceName] = map[string]map[string]struct{}{} - } - if _, ok := m.operations[span.Process.ServiceName][span.OperationName]; !ok { - m.operations[span.Process.ServiceName][span.OperationName] = map[string]struct{}{} + m.operations[span.Process.ServiceName] = map[spanstore.Operation]struct{}{} } spanKind, _ := span.GetSpanKind() - m.operations[span.Process.ServiceName][span.OperationName][spanKind] = struct{}{} + operation := spanstore.Operation{ + Name: span.OperationName, + SpanKind: spanKind, + } + + if _, ok := m.operations[span.Process.ServiceName][operation]; !ok { + m.operations[span.Process.ServiceName][operation] = struct{}{} + } + m.services[span.Process.ServiceName] = struct{}{} if _, ok := m.traces[span.TraceID]; !ok { m.traces[span.TraceID] = &model.Trace{} @@ -190,14 +195,9 @@ func (m *Store) GetOperations( defer m.RUnlock() var retMe []spanstore.Operation if operations, ok := m.operations[query.ServiceName]; ok { - for operationName, kinds := range operations { - for kind := range kinds { - if query.SpanKind == "" || query.SpanKind == kind { - retMe = append(retMe, spanstore.Operation{ - Name: operationName, - SpanKind: kind, - }) - } + for operation := range operations { + if query.SpanKind == "" || query.SpanKind == operation.SpanKind { + retMe = append(retMe, operation) } } } From 81ca9419c2a0f096580b8119e6b0ee97d68b005c Mon Sep 17 00:00:00 2001 From: Jun Guo Date: Mon, 25 Nov 2019 15:40:54 -0500 Subject: [PATCH 12/12] fix integration test Signed-off-by: Jun Guo --- .../storage/integration/badgerstore_test.go | 2 ++ .../storage/integration/elasticsearch_test.go | 4 +++- .../storage/integration/integration_test.go | 20 +++++++++++++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/plugin/storage/integration/badgerstore_test.go b/plugin/storage/integration/badgerstore_test.go index d02efab31df..407ad8225ee 100644 --- a/plugin/storage/integration/badgerstore_test.go +++ b/plugin/storage/integration/badgerstore_test.go @@ -59,6 +59,8 @@ func (s *BadgerIntegrationStorage) initialize() error { logger, _ := testutils.NewLogger() s.logger = logger + // TODO: remove this flag after badger support returning spanKind when get operations + s.notSupportSpanKindWithOperation = true return nil } diff --git a/plugin/storage/integration/elasticsearch_test.go b/plugin/storage/integration/elasticsearch_test.go index 8c53a437404..de138819330 100644 --- a/plugin/storage/integration/elasticsearch_test.go +++ b/plugin/storage/integration/elasticsearch_test.go @@ -31,7 +31,7 @@ import ( "go.uber.org/zap" "github.com/jaegertracing/jaeger/model" - "github.com/jaegertracing/jaeger/pkg/es/wrapper" + eswrapper "github.com/jaegertracing/jaeger/pkg/es/wrapper" "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/plugin/storage/es" "github.com/jaegertracing/jaeger/plugin/storage/es/dependencystore" @@ -94,6 +94,8 @@ func (s *ESStorageIntegration) initializeES(allTagsAsFields, archive bool) error } s.Refresh = s.esRefresh s.esCleanUp(allTagsAsFields, archive) + // TODO: remove this flag after ES support returning spanKind when get operations + s.notSupportSpanKindWithOperation = true return nil } diff --git a/plugin/storage/integration/integration_test.go b/plugin/storage/integration/integration_test.go index 3f59c04c85a..3fa9646e4b2 100644 --- a/plugin/storage/integration/integration_test.go +++ b/plugin/storage/integration/integration_test.go @@ -61,6 +61,8 @@ type StorageIntegration struct { SpanReader spanstore.Reader DependencyWriter dependencystore.Writer DependencyReader dependencystore.Reader + // TODO: remove this flag after all storage plugins returns spanKind with operationNames + notSupportSpanKindWithOperation bool // CleanUp() should ensure that the storage backend is clean before another test. // called either before or after each test, and should be idempotent @@ -149,10 +151,20 @@ func (s *StorageIntegration) testGetLargeSpan(t *testing.T) { func (s *StorageIntegration) testGetOperations(t *testing.T) { defer s.cleanUp(t) - expected := []spanstore.Operation{ - {Name: "example-operation-1"}, - {Name: "example-operation-3", SpanKind: "server"}, - {Name: "example-operation-4", SpanKind: "client"}} + var expected []spanstore.Operation + if s.notSupportSpanKindWithOperation { + expected = []spanstore.Operation{ + {Name: "example-operation-1"}, + {Name: "example-operation-3"}, + {Name: "example-operation-4"}, + } + } else { + expected = []spanstore.Operation{ + {Name: "example-operation-1"}, + {Name: "example-operation-3", SpanKind: "server"}, + {Name: "example-operation-4", SpanKind: "client"}, + } + } s.loadParseAndWriteExampleTrace(t) s.refresh(t)